()
| 80 | } |
| 81 | |
| 82 | fn init() -> bool { |
| 83 | let mut init = INITIALIZED.lock(); |
| 84 | match *init { |
| 85 | // Can directly give up, trying again won't help |
| 86 | Initialized::Failed => return false, |
| 87 | // Already initialized, no need to do anything. |
| 88 | Initialized::Succeeded | Initialized::SucceededMec => return true, |
| 89 | Initialized::NotYet => {} |
| 90 | } |
| 91 | |
| 92 | // In Linux userspace has to first request access to ioports |
| 93 | // TODO: Close these again after we're done |
| 94 | #[cfg(target_os = "linux")] |
| 95 | if !Uid::effective().is_root() { |
| 96 | error!("Must be root to use port based I/O for EC communication."); |
| 97 | *init = Initialized::Failed; |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | // First try on MEC |
| 102 | if !portio_mec::init() { |
| 103 | *init = Initialized::Failed; |
| 104 | return false; |
| 105 | } |
| 106 | let ec_id = portio_mec::transfer_read(MEC_MEMMAP_OFFSET + EC_MEMMAP_ID, 2); |
| 107 | if ec_id[0] == b'E' && ec_id[1] == b'C' { |
| 108 | *init = Initialized::SucceededMec; |
| 109 | return true; |
| 110 | } |
| 111 | |
| 112 | #[cfg(target_os = "linux")] |
| 113 | unsafe { |
| 114 | // 8 for request/response header, 0xFF for response |
| 115 | let res = ioperm(EC_LPC_ADDR_HOST_ARGS as u64, 8 + 0xFF, 1); |
| 116 | if res != 0 { |
| 117 | error!("ioperm failed. portio driver is likely block by Linux kernel lockdown mode"); |
| 118 | *init = Initialized::Failed; |
| 119 | return false; |
| 120 | } |
| 121 | |
| 122 | let res = ioperm(EC_LPC_ADDR_HOST_CMD as u64, 1, 1); |
| 123 | assert_eq!(res, 0); |
| 124 | let res = ioperm(EC_LPC_ADDR_HOST_DATA as u64, 1, 1); |
| 125 | assert_eq!(res, 0); |
| 126 | |
| 127 | let res = ioperm(NPC_MEMMAP_OFFSET as u64, super::EC_MEMMAP_SIZE as u64, 1); |
| 128 | assert_eq!(res, 0); |
| 129 | } |
| 130 | |
| 131 | *init = Initialized::Succeeded; |
| 132 | true |
| 133 | } |
| 134 | |
| 135 | fn wait_for_ready() { |
| 136 | if !init() { |
no test coverage detected