@@ -11,7 +11,7 @@ use crate::error::{Error, Result, to_result_void, to_result};
1111use crate :: printkln;
1212use crate :: sys:: sync:: Semaphore ;
1313use crate :: sync:: { Arc , SpinMutex } ;
14- use crate :: time:: { NoWait , Timeout } ;
14+ use crate :: time:: { Forever , NoWait , Timeout } ;
1515
1616use core:: ffi:: { c_int, c_uchar, c_void} ;
1717use core:: ptr;
@@ -164,13 +164,35 @@ const BUFFER_SIZE: usize = 256;
164164/// mutex because it can only be waited on when the Mutex is not locked.
165165struct IrqOuterData {
166166 read_sem : Semaphore ,
167+ write_sem : Semaphore ,
167168 inner : SpinMutex < IrqInnerData > ,
168169}
169170
170171/// Data for communication with the UART IRQ.
171172struct IrqInnerData {
172173 /// The Ring buffer holding incoming and read data.
173174 buffer : ArrayDeque < u8 , BUFFER_SIZE > ,
175+ /// Data to be written, if that is the case.
176+ ///
177+ /// If this is Some, then the irq should be enabled.
178+ write : Option < WriteSlice > ,
179+ }
180+
181+ /// Represents a slice of data that the irq is going to write.
182+ struct WriteSlice {
183+ data : * const u8 ,
184+ len : usize ,
185+ }
186+
187+ impl WriteSlice {
188+ /// Add an offset to the beginning of this slice, returning a new slice. This is equivalent to
189+ /// &item[count..] with a slice.
190+ pub unsafe fn add ( & self , count : usize ) -> WriteSlice {
191+ WriteSlice {
192+ data : unsafe { self . data . add ( count) } ,
193+ len : self . len - count,
194+ }
195+ }
174196}
175197
176198/// This is the irq-driven interface.
@@ -189,8 +211,10 @@ impl UartIrq {
189211 pub unsafe fn new ( uart : Uart ) -> Result < UartIrq > {
190212 let data = Arc :: new ( IrqOuterData {
191213 read_sem : Semaphore :: new ( 0 , 1 ) ?,
214+ write_sem : Semaphore :: new ( 0 , 1 ) ?,
192215 inner : SpinMutex :: new ( IrqInnerData {
193216 buffer : ArrayDeque :: new ( ) ,
217+ write : None ,
194218 } ) ,
195219 } ) ;
196220
@@ -205,7 +229,7 @@ impl UartIrq {
205229 to_result_void ( ret) ?;
206230 // Should this be settable?
207231 unsafe {
208- raw:: uart_irq_tx_enable ( uart. device ) ;
232+ // raw::uart_irq_tx_enable(uart.device);
209233 raw:: uart_irq_rx_enable ( uart. device ) ;
210234 }
211235 Ok ( UartIrq {
@@ -240,6 +264,36 @@ impl UartIrq {
240264
241265 self . data . try_read ( buf)
242266 }
267+
268+ /// A blocking write to the UART.
269+ ///
270+ /// By making this blocking, we don't need to make an extra copy of the data.
271+ ///
272+ /// TODO: Async write.
273+ pub unsafe fn write ( & mut self , buf : & [ u8 ] ) {
274+ if buf. len ( ) == 0 {
275+ return ;
276+ }
277+
278+ // Make the data to be written available to the irq handler, and get it going.
279+ {
280+ let mut inner = self . data . inner . lock ( ) . unwrap ( ) ;
281+ assert ! ( inner. write. is_none( ) ) ;
282+
283+ inner. write = Some ( WriteSlice {
284+ data : buf. as_ptr ( ) ,
285+ len : buf. len ( ) ,
286+ } ) ;
287+
288+ unsafe { raw:: uart_irq_tx_enable ( self . device ) } ;
289+ }
290+
291+ // Wait for the transmission to complete. This shouldn't be racy, as the irq shouldn't be
292+ // giving the semaphore until there is 'write' data, and it has been consumed.
293+ let _ = self . data . write_sem . take ( Forever ) ;
294+
295+ // TODO: Should we check that the write actually finished?
296+ }
243297}
244298
245299impl IrqOuterData {
@@ -292,4 +346,31 @@ extern "C" fn irq_callback(
292346 if did_read {
293347 outer. read_sem . give ( ) ;
294348 }
349+
350+ // If there is data to write, ensure the fifo is full, and when we run out of data, disable the
351+ // interrupt and signal the waiting thread.
352+ if let Some ( write) = inner. write . take ( ) {
353+ let count = unsafe {
354+ raw:: uart_fifo_fill ( dev, write. data , write. len as i32 )
355+ } ;
356+ if count < 0 {
357+ panic ! ( "Incorrect use of device fifo" ) ;
358+ }
359+ let count = count as usize ;
360+
361+ if count == write. len {
362+ // The write finished, leave 'write' empty, and let the thread know we're done.
363+ outer. write_sem . give ( ) ;
364+
365+ // Disable the tx fifo, as we don't need it any more.
366+ unsafe { raw:: uart_irq_tx_disable ( dev) } ;
367+ } else {
368+ // We're not finished, so remember how much is left.
369+ inner. write = Some ( unsafe { write. add ( count) } ) ;
370+ }
371+ }
372+
373+ unsafe {
374+ raw:: uart_irq_update ( dev) ;
375+ }
295376}
0 commit comments