|
1 | 1 | //! Simple (and unsafe) wrappers around USB devices.
|
2 | 2 |
|
| 3 | +// TODO! Remove this. |
| 4 | +#![allow(dead_code)] |
| 5 | +#![allow(unused_variables)] |
| 6 | + |
| 7 | +use arraydeque::ArrayDeque; |
| 8 | + |
3 | 9 | use crate::raw;
|
4 | 10 | use crate::error::{Error, Result, to_result_void, to_result};
|
| 11 | +use crate::printkln; |
| 12 | +use crate::sys::sync::Semaphore; |
| 13 | +use crate::sync::{Arc, SpinMutex}; |
| 14 | +use crate::time::{NoWait, Timeout}; |
5 | 15 |
|
6 |
| -use core::ffi::{c_uchar, c_int}; |
| 16 | +use core::ffi::{c_int, c_uchar, c_void}; |
| 17 | +use core::ptr; |
7 | 18 |
|
8 | 19 | use super::Unique;
|
9 | 20 |
|
@@ -91,4 +102,194 @@ impl Uart {
|
91 | 102 | raw::uart_line_ctrl_get(self.device, item as u32, &mut result)
|
92 | 103 | }).map(|()| result)
|
93 | 104 | }
|
| 105 | + |
| 106 | + /// Set one of the UART line control values. |
| 107 | + pub unsafe fn line_ctrl_set(&mut self, item: LineControl, value: u32) -> Result<()> { |
| 108 | + to_result_void(unsafe { |
| 109 | + raw::uart_line_ctrl_set(self.device, item as u32, value) |
| 110 | + }) |
| 111 | + } |
| 112 | + |
| 113 | + /// Convert this UART into an async one. |
| 114 | + pub unsafe fn into_async(self) -> Result<UartAsync> { |
| 115 | + UartAsync::new(self) |
| 116 | + } |
| 117 | + |
| 118 | + /// Convert into an IRQ one. |
| 119 | + pub unsafe fn into_irq(self) -> Result<UartIrq> { |
| 120 | + UartIrq::new(self) |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +/// The uart is safe to Send, as long as it is only used from one thread at a time. As such, it is |
| 125 | +/// not Sync. |
| 126 | +unsafe impl Send for Uart {} |
| 127 | + |
| 128 | +/// This is the async interface to the uart. |
| 129 | +/// |
| 130 | +/// Until we can analyze this for safety, it will just be declared as unsafe. |
| 131 | +/// |
| 132 | +/// It is unclear from the docs what context this callback api is called from, so we will assume |
| 133 | +/// that it might be called from an irq. As such, we'll need to use a critical-section and it's |
| 134 | +/// mutex to protect the data. |
| 135 | +pub struct UartAsync(); |
| 136 | + |
| 137 | +impl UartAsync { |
| 138 | + /// Take a Uart device and turn it into an async interface. |
| 139 | + /// |
| 140 | + /// TODO: Return the uart back if this fails. |
| 141 | + pub unsafe fn new(uart: Uart) -> Result<UartAsync> { |
| 142 | + let ret = unsafe { |
| 143 | + raw::uart_callback_set(uart.device, Some(async_callback), ptr::null_mut()) |
| 144 | + }; |
| 145 | + to_result_void(ret)?; |
| 146 | + Ok(UartAsync()) |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +extern "C" fn async_callback( |
| 151 | + _dev: *const raw::device, |
| 152 | + _evt: *mut raw::uart_event, |
| 153 | + _user_data: *mut c_void, |
| 154 | +) { |
| 155 | + printkln!("Async"); |
| 156 | +} |
| 157 | + |
| 158 | +/// Size of the irq buffer used for UartIrq. |
| 159 | +/// |
| 160 | +/// TODO: Make this a parameter of the type. |
| 161 | +const BUFFER_SIZE: usize = 256; |
| 162 | + |
| 163 | +/// The "outer" struct holds the semaphore, and the mutex. The semaphore has to live outside of the |
| 164 | +/// mutex because it can only be waited on when the Mutex is not locked. |
| 165 | +struct IrqOuterData { |
| 166 | + read_sem: Semaphore, |
| 167 | + inner: SpinMutex<IrqInnerData>, |
| 168 | +} |
| 169 | + |
| 170 | +/// Data for communication with the UART IRQ. |
| 171 | +struct IrqInnerData { |
| 172 | + /// The Ring buffer holding incoming and read data. |
| 173 | + buffer: ArrayDeque<u8, BUFFER_SIZE>, |
| 174 | +} |
| 175 | + |
| 176 | +/// This is the irq-driven interface. |
| 177 | +pub struct UartIrq { |
| 178 | + /// The raw device. |
| 179 | + device: *const raw::device, |
| 180 | + /// Critical section protected data. |
| 181 | + data: Arc<IrqOuterData>, |
| 182 | +} |
| 183 | + |
| 184 | +// UartIrq is also Send, !Sync, for the same reasons as for Uart. |
| 185 | +unsafe impl Send for UartIrq {} |
| 186 | + |
| 187 | +impl UartIrq { |
| 188 | + /// Convert uart into irq driven one. |
| 189 | + pub unsafe fn new(uart: Uart) -> Result<UartIrq> { |
| 190 | + let data = Arc::new(IrqOuterData { |
| 191 | + read_sem: Semaphore::new(0, 1)?, |
| 192 | + inner: SpinMutex::new(IrqInnerData { |
| 193 | + buffer: ArrayDeque::new(), |
| 194 | + }), |
| 195 | + }); |
| 196 | + |
| 197 | + // Clone the arc, and convert to a raw pointer, to give to the callback. |
| 198 | + // This will leak the Arc (which prevents deallocation). |
| 199 | + let data_raw = Arc::into_raw(data.clone()); |
| 200 | + let data_raw = data_raw as *mut c_void; |
| 201 | + |
| 202 | + let ret = unsafe { |
| 203 | + raw::uart_irq_callback_user_data_set(uart.device, Some(irq_callback), data_raw) |
| 204 | + }; |
| 205 | + to_result_void(ret)?; |
| 206 | + // Should this be settable? |
| 207 | + unsafe { |
| 208 | + raw::uart_irq_tx_enable(uart.device); |
| 209 | + raw::uart_irq_rx_enable(uart.device); |
| 210 | + } |
| 211 | + Ok(UartIrq { |
| 212 | + device: uart.device, |
| 213 | + data, |
| 214 | + }) |
| 215 | + } |
| 216 | + |
| 217 | + /// Get the underlying UART to be able to change line control and such. |
| 218 | + pub unsafe fn inner(&mut self) -> Uart { |
| 219 | + Uart { |
| 220 | + device: self.device |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + /// Attempt to read data from the UART into the buffer. If no data is available, it will |
| 225 | + /// attempt, once, to wait using the given timeout. |
| 226 | + /// |
| 227 | + /// Returns the number of bytes that were read, with zero indicating that a timeout occurred. |
| 228 | + pub unsafe fn try_read<T>(&mut self, buf: &mut [u8], timeout: T) -> usize |
| 229 | + where T: Into<Timeout>, |
| 230 | + { |
| 231 | + // Start with a read, before any blocking. |
| 232 | + let count = self.data.try_read(buf); |
| 233 | + if count > 0 { |
| 234 | + return count; |
| 235 | + } |
| 236 | + |
| 237 | + // Otherwise, wait for the semaphore. Ignore the result, as we will try to read again, in |
| 238 | + // case there was a race. |
| 239 | + let _ = self.data.read_sem.take(timeout); |
| 240 | + |
| 241 | + self.data.try_read(buf) |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +impl IrqOuterData { |
| 246 | + /// Try reading from the inner data, filling the buffer with as much data as makes sense. |
| 247 | + /// Returns the number of bytes actually read, or Zero if none. |
| 248 | + fn try_read(&self, buf: &mut [u8]) -> usize { |
| 249 | + let mut inner = self.inner.lock().unwrap(); |
| 250 | + let mut pos = 0; |
| 251 | + while pos < buf.len() { |
| 252 | + if let Some(elt) = inner.buffer.pop_front() { |
| 253 | + buf[pos] = elt; |
| 254 | + pos += 1; |
| 255 | + } else { |
| 256 | + break; |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | + if pos > 0 { |
| 261 | + // Any time we do a read, clear the semaphore. |
| 262 | + let _ = self.read_sem.take(NoWait); |
| 263 | + } |
| 264 | + pos |
| 265 | + } |
| 266 | +} |
| 267 | + |
| 268 | +extern "C" fn irq_callback( |
| 269 | + dev: *const raw::device, |
| 270 | + user_data: *mut c_void, |
| 271 | +) { |
| 272 | + // Convert our user data, back to the CS Mutex. |
| 273 | + let outer = unsafe { &*(user_data as *const IrqOuterData) }; |
| 274 | + let mut inner = outer.inner.lock().unwrap(); |
| 275 | + |
| 276 | + // TODO: Make this more efficient. |
| 277 | + let mut byte = 0u8; |
| 278 | + let mut did_read = false; |
| 279 | + loop { |
| 280 | + match unsafe { raw::uart_fifo_read(dev, &mut byte, 1) } { |
| 281 | + 0 => break, |
| 282 | + 1 => { |
| 283 | + // TODO: should we warn about overflow here? |
| 284 | + let _ = inner.buffer.push_back(byte); |
| 285 | + did_read = true; |
| 286 | + } |
| 287 | + e => panic!("Uart fifo read not implemented: {}", e), |
| 288 | + } |
| 289 | + } |
| 290 | + |
| 291 | + // This is safe (and important) to do while the mutex is held. |
| 292 | + if did_read { |
| 293 | + outer.read_sem.give(); |
| 294 | + } |
94 | 295 | }
|
0 commit comments