diff --git a/psp/src/dialog.rs b/psp/src/dialog.rs index c5b8fbc..a96c228 100644 --- a/psp/src/dialog.rs +++ b/psp/src/dialog.rs @@ -77,11 +77,21 @@ fn make_message_buf(message: &str) -> [u8; 512] { const MAX_DIALOG_ITERATIONS: u32 = 600; /// Small display list for utility dialog GU frames (16KB, 16-byte aligned). +/// Only accessed from the main thread, never concurrently. #[repr(C, align(16))] -pub(crate) struct Align16(pub T); -/// Shared display list for all utility dialog loops. Only accessed from -/// the main thread, never concurrently. -pub(crate) static mut DIALOG_LIST: Align16<[u8; 0x4000]> = Align16([0u8; 0x4000]); +pub(crate) struct DialogListBuf(core::cell::UnsafeCell<[u8; 0x4000]>); + +// SAFETY: Only accessed from the main thread during dialog polling loops. +unsafe impl Sync for DialogListBuf {} + +impl DialogListBuf { + pub(crate) fn as_mut_ptr(&self) -> *mut core::ffi::c_void { + self.0.get() as *mut core::ffi::c_void + } +} + +pub(crate) static DIALOG_LIST: DialogListBuf = + DialogListBuf(core::cell::UnsafeCell::new([0u8; 0x4000])); /// Create a `UtilityDialogCommon` for the netconf dialog. pub(crate) fn make_netconf_common(size: u32) -> UtilityDialogCommon { @@ -120,10 +130,7 @@ fn run_dialog(params: &mut UtilityMsgDialogParams) -> Result i32; type SetPortModeFn = unsafe extern "C" fn(pin: u32, mode: u32) -> i32; type GetCaptureFn = unsafe extern "C" fn() -> u32; -static mut PORT_READ: Option = None; -static mut PORT_SET: Option = None; -static mut PORT_CLEAR: Option = None; -static mut SET_PORT_MODE: Option = None; -static mut SET_PORT_MODE2: Option = None; -static mut GET_CAPTURE: Option = None; +/// Stores a resolved function pointer as an `AtomicUsize` (0 = not resolved). +struct AtomicFnPtr(AtomicUsize); + +impl AtomicFnPtr { + const fn new() -> Self { + Self(AtomicUsize::new(0)) + } + + fn store(&self, addr: *mut u8) { + self.0.store(addr as usize, Ordering::Release); + } + + fn load(&self) -> Option { + let v = self.0.load(Ordering::Acquire); + if v == 0 { None } else { Some(v) } + } +} + +// SAFETY: Function pointers are resolved once in init() and then only read. +unsafe impl Sync for AtomicFnPtr {} + +static PORT_READ: AtomicFnPtr = AtomicFnPtr::new(); +static PORT_SET: AtomicFnPtr = AtomicFnPtr::new(); +static PORT_CLEAR: AtomicFnPtr = AtomicFnPtr::new(); +static SET_PORT_MODE: AtomicFnPtr = AtomicFnPtr::new(); +static SET_PORT_MODE2: AtomicFnPtr = AtomicFnPtr::new(); +static GET_CAPTURE: AtomicFnPtr = AtomicFnPtr::new(); static INITIALIZED: AtomicBool = AtomicBool::new(false); /// Resolve GPIO driver NIDs. Call once before using other functions. @@ -76,33 +97,22 @@ pub unsafe fn init() -> u32 { let l = nids::GPIO_LIBRARY.as_ptr(); let mut count = 0u32; - unsafe { - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_PORT_READ) { - PORT_READ = Some(core::mem::transmute(addr)); - count += 1; - } - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_PORT_SET) { - PORT_SET = Some(core::mem::transmute(addr)); - count += 1; - } - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_PORT_CLEAR) { - PORT_CLEAR = Some(core::mem::transmute(addr)); - count += 1; - } - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_SET_PORT_MODE) { - SET_PORT_MODE = Some(core::mem::transmute(addr)); - count += 1; - } - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_SET_PORT_MODE2) { - SET_PORT_MODE2 = Some(core::mem::transmute(addr)); - count += 1; - } - if let Some(addr) = crate::hook::find_function(m, l, nids::NID_GPIO_GET_CAPTURE_PORT) { - GET_CAPTURE = Some(core::mem::transmute(addr)); - count += 1; - } + macro_rules! try_resolve { + ($nid:expr, $slot:expr) => { + if let Some(addr) = unsafe { crate::hook::find_function(m, l, $nid) } { + $slot.store(addr); + count += 1; + } + }; } + try_resolve!(nids::NID_GPIO_PORT_READ, PORT_READ); + try_resolve!(nids::NID_GPIO_PORT_SET, PORT_SET); + try_resolve!(nids::NID_GPIO_PORT_CLEAR, PORT_CLEAR); + try_resolve!(nids::NID_GPIO_SET_PORT_MODE, SET_PORT_MODE); + try_resolve!(nids::NID_GPIO_SET_PORT_MODE2, SET_PORT_MODE2); + try_resolve!(nids::NID_GPIO_GET_CAPTURE_PORT, GET_CAPTURE); + INITIALIZED.store(true, Ordering::Release); count } @@ -111,7 +121,7 @@ pub unsafe fn init() -> u32 { /// /// Returns `None` if [`init()`] has not been called or NID was not resolved. pub fn read_port() -> Option { - let f = unsafe { PORT_READ }?; + let f: PortReadFn = unsafe { core::mem::transmute(PORT_READ.load()?) }; Some(unsafe { f() }) } @@ -128,7 +138,7 @@ pub fn read_pin(pin: u32) -> Option { /// Read the GPIO interrupt/capture status. pub fn capture_status() -> Option { - let f = unsafe { GET_CAPTURE }?; + let f: GetCaptureFn = unsafe { core::mem::transmute(GET_CAPTURE.load()?) }; Some(unsafe { f() }) } @@ -138,7 +148,7 @@ pub fn capture_status() -> Option { /// /// **Warning:** Actually drives pins. Crashes on pins 29-31+ on TA-090v2. pub fn set_pin_mode(pin: u32, mode: i32) -> Option { - let f = unsafe { SET_PORT_MODE }?; + let f: SetPortModeFn = unsafe { core::mem::transmute(SET_PORT_MODE.load()?) }; Some(unsafe { f(pin, mode as u32) }) } @@ -147,19 +157,19 @@ pub fn set_pin_mode(pin: u32, mode: i32) -> Option { /// Uses `sceGpioSetPortMode2` (NID 0x317D9D2C). Mode: 0=disable, 2=enable. /// Safe for probing — Output Enable register is silicon-locked on TA-090v2. pub fn set_pin_mode2(pin: u32, mode: i32) -> Option { - let f = unsafe { SET_PORT_MODE2 }?; + let f: SetPortModeFn = unsafe { core::mem::transmute(SET_PORT_MODE2.load()?) }; Some(unsafe { f(pin, mode as u32) }) } /// Drive GPIO pins high. pub fn set_pins(mask: u32) -> Option { - let f = unsafe { PORT_SET }?; + let f: PortSetFn = unsafe { core::mem::transmute(PORT_SET.load()?) }; Some(unsafe { f(mask) }) } /// Drive GPIO pins low. pub fn clear_pins(mask: u32) -> Option { - let f = unsafe { PORT_CLEAR }?; + let f: PortClearFn = unsafe { core::mem::transmute(PORT_CLEAR.load()?) }; Some(unsafe { f(mask) }) } diff --git a/psp/src/net.rs b/psp/src/net.rs index 478f3f1..a308a7a 100644 --- a/psp/src/net.rs +++ b/psp/src/net.rs @@ -256,7 +256,7 @@ pub fn connect_dialog() -> Result<(), NetError> { unsafe { sys::sceGuStart( sys::GuContextType::Direct, - &raw mut crate::dialog::DIALOG_LIST as *mut core::ffi::c_void, + crate::dialog::DIALOG_LIST.as_mut_ptr(), ); sys::sceGuClearColor(0xff00_0000); sys::sceGuClear(sys::ClearBuffer::COLOR_BUFFER_BIT); diff --git a/psp/src/osk.rs b/psp/src/osk.rs index eb2f81e..f0f278f 100644 --- a/psp/src/osk.rs +++ b/psp/src/osk.rs @@ -46,10 +46,9 @@ const SOUND_THREAD: i32 = 0x10; /// Maximum iterations for OSK polling (~30 seconds at 60 fps). const MAX_OSK_ITERATIONS: u32 = 1800; -/// Small display list for utility dialog GU frames (16KB, 16-byte aligned). -#[repr(C, align(16))] -struct Align16(T); -static mut DIALOG_LIST: Align16<[u8; 0x4000]> = Align16([0u8; 0x4000]); +// Reuse the shared display list buffer from dialog.rs (16KB, 16-byte aligned). +// All utility dialogs are mutually exclusive on the main thread, so sharing is safe. +use crate::dialog::DIALOG_LIST; fn make_common(size: u32) -> UtilityDialogCommon { UtilityDialogCommon { @@ -177,13 +176,10 @@ impl OskBuilder { // background, then close the frame before updating the // utility dialog. PSPSDK convention: the dialog update // must be called **outside** any open GU display list. - // SAFETY: DIALOG_LIST is only used by utility dialog loops - // which run on the main thread and never overlap. + // SAFETY: DIALOG_LIST is shared across dialog/osk/net but all run + // on the main thread and never overlap. unsafe { - crate::sys::sceGuStart( - crate::sys::GuContextType::Direct, - &raw mut DIALOG_LIST as *mut core::ffi::c_void, - ); + crate::sys::sceGuStart(crate::sys::GuContextType::Direct, DIALOG_LIST.as_mut_ptr()); crate::sys::sceGuClearColor(0xff00_0000); // opaque black crate::sys::sceGuClear(crate::sys::ClearBuffer::COLOR_BUFFER_BIT); crate::sys::sceGuFinish(); diff --git a/psp/src/syscon.rs b/psp/src/syscon.rs index 6af779e..876761e 100644 --- a/psp/src/syscon.rs +++ b/psp/src/syscon.rs @@ -15,7 +15,7 @@ //! ``` use crate::sys::syscon as nids; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; /// Error from a Syscon operation. #[derive(Clone, Copy, PartialEq, Eq)] @@ -39,14 +39,35 @@ type IsAcFn = unsafe extern "C" fn() -> i32; type CommonWriteFn = unsafe extern "C" fn(i32, *const u8, i32) -> i32; type CommonReadFn = unsafe extern "C" fn(i32, *mut u8, i32) -> i32; -static mut BARYON_VERSION: Option = None; -static mut GET_POWER_STATUS: Option = None; -static mut GET_BATTERY_REMAIN: Option = None; -static mut GET_BATTERY_VOLT: Option = None; -static mut GET_BATTERY_TEMP: Option = None; -static mut IS_AC_SUPPLIED: Option = None; -static mut COMMON_WRITE: Option = None; -static mut COMMON_READ: Option = None; +/// Stores a resolved function pointer as an `AtomicUsize` (0 = not resolved). +struct AtomicFnPtr(AtomicUsize); + +impl AtomicFnPtr { + const fn new() -> Self { + Self(AtomicUsize::new(0)) + } + + fn store(&self, addr: *mut u8) { + self.0.store(addr as usize, Ordering::Release); + } + + fn load(&self) -> Option { + let v = self.0.load(Ordering::Acquire); + if v == 0 { None } else { Some(v) } + } +} + +// SAFETY: Function pointers are resolved once in init() and then only read. +unsafe impl Sync for AtomicFnPtr {} + +static BARYON_VERSION: AtomicFnPtr = AtomicFnPtr::new(); +static GET_POWER_STATUS: AtomicFnPtr = AtomicFnPtr::new(); +static GET_BATTERY_REMAIN: AtomicFnPtr = AtomicFnPtr::new(); +static GET_BATTERY_VOLT: AtomicFnPtr = AtomicFnPtr::new(); +static GET_BATTERY_TEMP: AtomicFnPtr = AtomicFnPtr::new(); +static IS_AC_SUPPLIED: AtomicFnPtr = AtomicFnPtr::new(); +static COMMON_WRITE: AtomicFnPtr = AtomicFnPtr::new(); +static COMMON_READ: AtomicFnPtr = AtomicFnPtr::new(); static INITIALIZED: AtomicBool = AtomicBool::new(false); /// Resolve a NID from Syscon driver, trying multiple module names. @@ -71,54 +92,37 @@ unsafe fn resolve(nid: u32) -> Option<*mut u8> { pub unsafe fn init() -> u32 { let mut count = 0u32; - unsafe { - if let Some(a) = resolve(nids::NID_SYSCON_GET_BARYON_VERSION) { - BARYON_VERSION = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_GET_POWER_STATUS) { - GET_POWER_STATUS = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_GET_BATTERY_REMAIN) { - GET_BATTERY_REMAIN = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_GET_BATTERY_VOLT) { - GET_BATTERY_VOLT = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_GET_BATTERY_TEMP) { - GET_BATTERY_TEMP = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_IS_AC_SUPPLIED) { - IS_AC_SUPPLIED = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_COMMON_WRITE) { - COMMON_WRITE = Some(core::mem::transmute(a)); - count += 1; - } - if let Some(a) = resolve(nids::NID_SYSCON_COMMON_READ) { - COMMON_READ = Some(core::mem::transmute(a)); - count += 1; - } + macro_rules! try_resolve { + ($nid:expr, $slot:expr) => { + if let Some(addr) = unsafe { resolve($nid) } { + $slot.store(addr); + count += 1; + } + }; } + try_resolve!(nids::NID_SYSCON_GET_BARYON_VERSION, BARYON_VERSION); + try_resolve!(nids::NID_SYSCON_GET_POWER_STATUS, GET_POWER_STATUS); + try_resolve!(nids::NID_SYSCON_GET_BATTERY_REMAIN, GET_BATTERY_REMAIN); + try_resolve!(nids::NID_SYSCON_GET_BATTERY_VOLT, GET_BATTERY_VOLT); + try_resolve!(nids::NID_SYSCON_GET_BATTERY_TEMP, GET_BATTERY_TEMP); + try_resolve!(nids::NID_SYSCON_IS_AC_SUPPLIED, IS_AC_SUPPLIED); + try_resolve!(nids::NID_SYSCON_COMMON_WRITE, COMMON_WRITE); + try_resolve!(nids::NID_SYSCON_COMMON_READ, COMMON_READ); + INITIALIZED.store(true, Ordering::Release); count } /// Read the Baryon (Syscon) hardware version. pub fn baryon_version() -> Option { - let f = unsafe { BARYON_VERSION }?; + let f: BaryonVersionFn = unsafe { core::mem::transmute(BARYON_VERSION.load()?) }; Some(unsafe { f() } as u32) } /// Read battery remaining capacity as a percentage (0-100). pub fn battery_percent() -> Option> { - let f = unsafe { GET_BATTERY_REMAIN }?; + let f: GetI32Fn = unsafe { core::mem::transmute(GET_BATTERY_REMAIN.load()?) }; let mut val: i32 = 0; let ret = unsafe { f(&mut val) }; Some(if ret < 0 { @@ -130,7 +134,7 @@ pub fn battery_percent() -> Option> { /// Read battery voltage in millivolts. pub fn battery_voltage() -> Option> { - let f = unsafe { GET_BATTERY_VOLT }?; + let f: GetI32Fn = unsafe { core::mem::transmute(GET_BATTERY_VOLT.load()?) }; let mut val: i32 = 0; let ret = unsafe { f(&mut val) }; Some(if ret < 0 { @@ -142,7 +146,7 @@ pub fn battery_voltage() -> Option> { /// Read battery temperature in degrees Celsius. pub fn battery_temp() -> Option> { - let f = unsafe { GET_BATTERY_TEMP }?; + let f: GetI32Fn = unsafe { core::mem::transmute(GET_BATTERY_TEMP.load()?) }; let mut val: i32 = 0; let ret = unsafe { f(&mut val) }; Some(if ret < 0 { @@ -154,7 +158,7 @@ pub fn battery_temp() -> Option> { /// Read the power supply status word. pub fn power_status() -> Option> { - let f = unsafe { GET_POWER_STATUS }?; + let f: GetI32Fn = unsafe { core::mem::transmute(GET_POWER_STATUS.load()?) }; let mut val: i32 = 0; let ret = unsafe { f(&mut val) }; Some(if ret < 0 { @@ -166,7 +170,7 @@ pub fn power_status() -> Option> { /// Check if the AC adapter is connected. pub fn is_ac_connected() -> Option { - let f = unsafe { IS_AC_SUPPLIED }?; + let f: IsAcFn = unsafe { core::mem::transmute(IS_AC_SUPPLIED.load()?) }; Some(unsafe { f() } == 1) } @@ -176,7 +180,7 @@ pub fn is_ac_connected() -> Option { /// /// Command 0x34 causes hard crash. Command 0x45 causes shutdown. pub fn raw_read(cmd: u8, response: &mut [u8]) -> Option> { - let f = unsafe { COMMON_READ }?; + let f: CommonReadFn = unsafe { core::mem::transmute(COMMON_READ.load()?) }; let ret = unsafe { f(cmd as i32, response.as_mut_ptr(), response.len() as i32) }; Some(if ret < 0 { Err(SysconError(ret)) @@ -191,7 +195,7 @@ pub fn raw_read(cmd: u8, response: &mut [u8]) -> Option /// /// Command 0x34 causes hard crash. Command 0x45 causes shutdown. pub fn raw_write(cmd: u8, data: &[u8]) -> Option> { - let f = unsafe { COMMON_WRITE }?; + let f: CommonWriteFn = unsafe { core::mem::transmute(COMMON_WRITE.load()?) }; let ret = unsafe { f(cmd as i32, data.as_ptr(), data.len() as i32) }; Some(if ret < 0 { Err(SysconError(ret)) diff --git a/psp/src/sysreg.rs b/psp/src/sysreg.rs index 7b6f000..efa2cb4 100644 --- a/psp/src/sysreg.rs +++ b/psp/src/sysreg.rs @@ -15,7 +15,7 @@ //! ``` use crate::sys::sysreg as nids; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; /// Error from a SysReg operation. #[derive(Clone, Copy, PartialEq, Eq)] @@ -36,20 +36,41 @@ impl core::fmt::Display for SysregError { type VoidFn = unsafe extern "C" fn() -> i32; type SetStatusFn = unsafe extern "C" fn(i32) -> i32; -static mut GPIO_CLK_ENABLE: Option = None; -static mut GPIO_IO_ENABLE: Option = None; -static mut USB_CLK_ENABLE: Option = None; -static mut USB_CLK_DISABLE: Option = None; -static mut USB_IO_ENABLE: Option = None; -static mut USB_IO_DISABLE: Option = None; -static mut USB_BUS_CLK_ENABLE: Option = None; -static mut USB_BUS_CLK_DISABLE: Option = None; -static mut USB_RESET_ENABLE: Option = None; -static mut USB_RESET_DISABLE: Option = None; -static mut USB_GET_CONNECT: Option = None; -static mut USB_SET_CONNECT: Option = None; -static mut USB_QUERY_INTR: Option = None; -static mut USB_ACQUIRE_INTR: Option = None; +/// Stores a resolved function pointer as an `AtomicUsize` (0 = not resolved). +struct AtomicFnPtr(AtomicUsize); + +impl AtomicFnPtr { + const fn new() -> Self { + Self(AtomicUsize::new(0)) + } + + fn store(&self, addr: *mut u8) { + self.0.store(addr as usize, Ordering::Release); + } + + fn load(&self) -> Option { + let v = self.0.load(Ordering::Acquire); + if v == 0 { None } else { Some(v) } + } +} + +// SAFETY: Function pointers are resolved once in init() and then only read. +unsafe impl Sync for AtomicFnPtr {} + +static GPIO_CLK_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static GPIO_IO_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_CLK_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_CLK_DISABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_IO_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_IO_DISABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_BUS_CLK_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_BUS_CLK_DISABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_RESET_ENABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_RESET_DISABLE: AtomicFnPtr = AtomicFnPtr::new(); +static USB_GET_CONNECT: AtomicFnPtr = AtomicFnPtr::new(); +static USB_SET_CONNECT: AtomicFnPtr = AtomicFnPtr::new(); +static USB_QUERY_INTR: AtomicFnPtr = AtomicFnPtr::new(); +static USB_ACQUIRE_INTR: AtomicFnPtr = AtomicFnPtr::new(); static INITIALIZED: AtomicBool = AtomicBool::new(false); /// Resolve sceSysreg driver NIDs. Call once before using other functions. @@ -65,30 +86,28 @@ pub unsafe fn init() -> u32 { let mut count = 0u32; macro_rules! try_resolve { - ($nid:expr, $slot:ident) => { - if let Some(a) = crate::hook::find_function(m, l, $nid) { - $slot = Some(core::mem::transmute(a)); + ($nid:expr, $slot:expr) => { + if let Some(a) = unsafe { crate::hook::find_function(m, l, $nid) } { + $slot.store(a); count += 1; } }; } - unsafe { - try_resolve!(nids::NID_SYSREG_GPIO_CLK_ENABLE, GPIO_CLK_ENABLE); - try_resolve!(nids::NID_SYSREG_GPIO_IO_ENABLE, GPIO_IO_ENABLE); - try_resolve!(nids::NID_SYSREG_USB_CLK_ENABLE, USB_CLK_ENABLE); - try_resolve!(nids::NID_SYSREG_USB_CLK_DISABLE, USB_CLK_DISABLE); - try_resolve!(nids::NID_SYSREG_USB_IO_ENABLE, USB_IO_ENABLE); - try_resolve!(nids::NID_SYSREG_USB_IO_DISABLE, USB_IO_DISABLE); - try_resolve!(nids::NID_SYSREG_USB_BUS_CLK_ENABLE, USB_BUS_CLK_ENABLE); - try_resolve!(nids::NID_SYSREG_USB_BUS_CLK_DISABLE, USB_BUS_CLK_DISABLE); - try_resolve!(nids::NID_SYSREG_USB_RESET_ENABLE, USB_RESET_ENABLE); - try_resolve!(nids::NID_SYSREG_USB_RESET_DISABLE, USB_RESET_DISABLE); - try_resolve!(nids::NID_SYSREG_USB_GET_CONNECT_STATUS, USB_GET_CONNECT); - try_resolve!(nids::NID_SYSREG_USB_SET_CONNECT_STATUS, USB_SET_CONNECT); - try_resolve!(nids::NID_SYSREG_USB_QUERY_INTR, USB_QUERY_INTR); - try_resolve!(nids::NID_SYSREG_USB_ACQUIRE_INTR, USB_ACQUIRE_INTR); - } + try_resolve!(nids::NID_SYSREG_GPIO_CLK_ENABLE, GPIO_CLK_ENABLE); + try_resolve!(nids::NID_SYSREG_GPIO_IO_ENABLE, GPIO_IO_ENABLE); + try_resolve!(nids::NID_SYSREG_USB_CLK_ENABLE, USB_CLK_ENABLE); + try_resolve!(nids::NID_SYSREG_USB_CLK_DISABLE, USB_CLK_DISABLE); + try_resolve!(nids::NID_SYSREG_USB_IO_ENABLE, USB_IO_ENABLE); + try_resolve!(nids::NID_SYSREG_USB_IO_DISABLE, USB_IO_DISABLE); + try_resolve!(nids::NID_SYSREG_USB_BUS_CLK_ENABLE, USB_BUS_CLK_ENABLE); + try_resolve!(nids::NID_SYSREG_USB_BUS_CLK_DISABLE, USB_BUS_CLK_DISABLE); + try_resolve!(nids::NID_SYSREG_USB_RESET_ENABLE, USB_RESET_ENABLE); + try_resolve!(nids::NID_SYSREG_USB_RESET_DISABLE, USB_RESET_DISABLE); + try_resolve!(nids::NID_SYSREG_USB_GET_CONNECT_STATUS, USB_GET_CONNECT); + try_resolve!(nids::NID_SYSREG_USB_SET_CONNECT_STATUS, USB_SET_CONNECT); + try_resolve!(nids::NID_SYSREG_USB_QUERY_INTR, USB_QUERY_INTR); + try_resolve!(nids::NID_SYSREG_USB_ACQUIRE_INTR, USB_ACQUIRE_INTR); INITIALIZED.store(true, Ordering::Release); count @@ -96,8 +115,8 @@ pub unsafe fn init() -> u32 { /// Enable GPIO peripheral clock and I/O access. pub fn gpio_enable() -> Option> { - let f1 = unsafe { GPIO_CLK_ENABLE }?; - let f2 = unsafe { GPIO_IO_ENABLE }?; + let f1: VoidFn = unsafe { core::mem::transmute(GPIO_CLK_ENABLE.load()?) }; + let f2: VoidFn = unsafe { core::mem::transmute(GPIO_IO_ENABLE.load()?) }; let ret = unsafe { f1() }; if ret < 0 { return Some(Err(SysregError(ret))); @@ -112,9 +131,9 @@ pub fn gpio_enable() -> Option> { /// Enable USB peripheral (clock, I/O, and bus clock). pub fn usb_enable() -> Option> { - let f1 = unsafe { USB_CLK_ENABLE }?; - let f2 = unsafe { USB_IO_ENABLE }?; - let f3 = unsafe { USB_BUS_CLK_ENABLE }?; + let f1: VoidFn = unsafe { core::mem::transmute(USB_CLK_ENABLE.load()?) }; + let f2: VoidFn = unsafe { core::mem::transmute(USB_IO_ENABLE.load()?) }; + let f3: VoidFn = unsafe { core::mem::transmute(USB_BUS_CLK_ENABLE.load()?) }; let ret = unsafe { f1() }; if ret < 0 { return Some(Err(SysregError(ret))); @@ -133,9 +152,9 @@ pub fn usb_enable() -> Option> { /// Disable USB peripheral. pub fn usb_disable() -> Option> { - let f1 = unsafe { USB_BUS_CLK_DISABLE }?; - let f2 = unsafe { USB_IO_DISABLE }?; - let f3 = unsafe { USB_CLK_DISABLE }?; + let f1: VoidFn = unsafe { core::mem::transmute(USB_BUS_CLK_DISABLE.load()?) }; + let f2: VoidFn = unsafe { core::mem::transmute(USB_IO_DISABLE.load()?) }; + let f3: VoidFn = unsafe { core::mem::transmute(USB_CLK_DISABLE.load()?) }; let ret = unsafe { f1() }; if ret < 0 { return Some(Err(SysregError(ret))); @@ -154,13 +173,13 @@ pub fn usb_disable() -> Option> { /// Check if a USB cable is connected (system register level). pub fn usb_is_connected() -> Option { - let f = unsafe { USB_GET_CONNECT }?; + let f: VoidFn = unsafe { core::mem::transmute(USB_GET_CONNECT.load()?) }; Some(unsafe { f() } == 1) } /// Query pending USB interrupt status. pub fn usb_query_interrupt() -> Option { - let f = unsafe { USB_QUERY_INTR }?; + let f: VoidFn = unsafe { core::mem::transmute(USB_QUERY_INTR.load()?) }; Some(unsafe { f() }) }