37
37
38
38
#![ no_std]
39
39
#![ warn( missing_docs) ]
40
- #![ cfg_attr( feature = "mmio_nightly" , feature( const_ptr_offset) ) ]
41
-
42
- use core:: fmt;
40
+ #![ cfg_attr( feature = "nightly" , feature( const_ptr_offset) ) ]
43
41
44
42
use bitflags:: bitflags;
45
43
46
- #[ cfg( any(
47
- all(
48
- not( any( feature = "port_stable" , feature = "port_nightly" ) ) ,
49
- not( any( feature = "mmio_stable" , feature = "mmio_nightly" ) )
50
- ) ,
51
- all(
52
- any( feature = "port_stable" , feature = "port_nightly" ) ,
53
- any( feature = "mmio_stable" , feature = "mmio_nightly" )
54
- )
55
- ) ) ]
56
- compile_error ! ( "One of these features must be enabled: `port_{stable, nightly}`, `mmio_{stable, nightly}`" ) ;
57
-
58
- #[ cfg( any( feature = "mmio_stable" , feature = "mmio_nightly" ) ) ]
59
- use core:: sync:: atomic:: {
60
- AtomicPtr ,
61
- Ordering ,
62
- } ;
63
-
64
- #[ cfg( any( feature = "port_stable" , feature = "port_nightly" ) ) ]
65
- use x86_64:: instructions:: port:: Port ;
44
+ #[ cfg( not( any( feature = "stable" , feature = "nightly" ) ) ) ]
45
+ compile_error ! ( "Either the `stable` or `nightly` feature must be enabled" ) ;
66
46
67
47
macro_rules! wait_for {
68
48
( $cond: expr) => {
@@ -72,6 +52,14 @@ macro_rules! wait_for {
72
52
} ;
73
53
}
74
54
55
+ pub mod mmio;
56
+ #[ cfg( target_arch = "x86_64" ) ]
57
+ pub mod x86_64;
58
+
59
+ #[ cfg( target_arch = "x86_64" ) ]
60
+ pub use crate :: x86_64:: SerialPort ;
61
+ pub use crate :: mmio:: MmioSerialPort ;
62
+
75
63
bitflags ! {
76
64
/// Interrupt enable flags
77
65
struct IntEnFlags : u8 {
@@ -92,235 +80,3 @@ bitflags! {
92
80
// 6 and 7 unknown
93
81
}
94
82
}
95
-
96
- #[ cfg( any( feature = "port_stable" , feature = "port_nightly" ) ) ]
97
- /// An interface to a serial port that allows sending out individual bytes.
98
- pub struct SerialPort {
99
- data : Port < u8 > ,
100
- int_en : Port < u8 > ,
101
- fifo_ctrl : Port < u8 > ,
102
- line_ctrl : Port < u8 > ,
103
- modem_ctrl : Port < u8 > ,
104
- line_sts : Port < u8 > ,
105
- }
106
-
107
- #[ cfg( any( feature = "port_stable" , feature = "port_nightly" ) ) ]
108
- impl SerialPort {
109
- /// Creates a new serial port interface on the given I/O port.
110
- ///
111
- /// This function is unsafe because the caller must ensure that the given base address
112
- /// really points to a serial port device.
113
- #[ cfg( feature = "port_nightly" ) ]
114
- pub const unsafe fn new ( base : u16 ) -> Self {
115
- Self {
116
- data : Port :: new ( base) ,
117
- int_en : Port :: new ( base + 1 ) ,
118
- fifo_ctrl : Port :: new ( base + 2 ) ,
119
- line_ctrl : Port :: new ( base + 3 ) ,
120
- modem_ctrl : Port :: new ( base + 4 ) ,
121
- line_sts : Port :: new ( base + 5 ) ,
122
- }
123
- }
124
-
125
- /// Creates a new serial port interface on the given I/O port.
126
- ///
127
- /// This function is unsafe because the caller must ensure that the given base address
128
- /// really points to a serial port device.
129
- #[ cfg( feature = "port_stable" ) ]
130
- pub unsafe fn new ( base : u16 ) -> Self {
131
- Self {
132
- data : Port :: new ( base) ,
133
- int_en : Port :: new ( base + 1 ) ,
134
- fifo_ctrl : Port :: new ( base + 2 ) ,
135
- line_ctrl : Port :: new ( base + 3 ) ,
136
- modem_ctrl : Port :: new ( base + 4 ) ,
137
- line_sts : Port :: new ( base + 5 ) ,
138
- }
139
- }
140
-
141
- /// Initializes the serial port.
142
- ///
143
- /// The default configuration of [38400/8-N-1](https://en.wikipedia.org/wiki/8-N-1) is used.
144
- pub fn init ( & mut self ) {
145
- unsafe {
146
- // Disable interrupts
147
- self . int_en . write ( 0x00 ) ;
148
-
149
- // Enable DLAB
150
- self . line_ctrl . write ( 0x80 ) ;
151
-
152
- // Set maximum speed to 38400 bps by configuring DLL and DLM
153
- self . data . write ( 0x03 ) ;
154
- self . int_en . write ( 0x00 ) ;
155
-
156
- // Disable DLAB and set data word length to 8 bits
157
- self . line_ctrl . write ( 0x03 ) ;
158
-
159
- // Enable FIFO, clear TX/RX queues and
160
- // set interrupt watermark at 14 bytes
161
- self . fifo_ctrl . write ( 0xC7 ) ;
162
-
163
- // Mark data terminal ready, signal request to send
164
- // and enable auxilliary output #2 (used as interrupt line for CPU)
165
- self . modem_ctrl . write ( 0x0B ) ;
166
-
167
- // Enable interrupts
168
- self . int_en . write ( 0x01 ) ;
169
- }
170
- }
171
-
172
- fn line_sts ( & mut self ) -> LineStsFlags {
173
- unsafe { LineStsFlags :: from_bits_truncate ( self . line_sts . read ( ) ) }
174
- }
175
-
176
- /// Sends a byte on the serial port.
177
- pub fn send ( & mut self , data : u8 ) {
178
- unsafe {
179
- match data {
180
- 8 | 0x7F => {
181
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
182
- self . data . write ( 8 ) ;
183
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
184
- self . data . write ( b' ' ) ;
185
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
186
- self . data . write ( 8 )
187
- } ,
188
- _ => {
189
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
190
- self . data . write ( data) ;
191
- } ,
192
- }
193
- }
194
- }
195
-
196
- /// Receives a byte on the serial port.
197
- pub fn receive ( & mut self ) -> u8 {
198
- unsafe {
199
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: INPUT_FULL ) ) ;
200
- self . data . read ( )
201
- }
202
- }
203
- }
204
-
205
- /// An interface to a serial port that allows sending out individual bytes.
206
- #[ cfg( any( feature = "mmio_stable" , feature = "mmio_nightly" ) ) ]
207
- pub struct MmioSerialPort {
208
- data : AtomicPtr < u8 > ,
209
- int_en : AtomicPtr < u8 > ,
210
- fifo_ctrl : AtomicPtr < u8 > ,
211
- line_ctrl : AtomicPtr < u8 > ,
212
- modem_ctrl : AtomicPtr < u8 > ,
213
- line_sts : AtomicPtr < u8 > ,
214
- }
215
-
216
- #[ cfg( any( feature = "mmio_stable" , feature = "mmio_nightly" ) ) ]
217
- impl SerialPort {
218
- /// Creates a new serial port interface on the given memory mapped address.
219
- ///
220
- /// This function is unsafe because the caller must ensure that the given base address
221
- /// really points to a serial port device.
222
- #[ cfg( feature = "mmio_nightly" ) ]
223
- pub const unsafe fn new ( base : usize ) -> Self {
224
- let base_pointer = base as * mut u8 ;
225
- Self {
226
- data : AtomicPtr :: new ( base_pointer) ,
227
- int_en : AtomicPtr :: new ( base_pointer. add ( 1 ) ) ,
228
- fifo_ctrl : AtomicPtr :: new ( base_pointer. add ( 2 ) ) ,
229
- line_ctrl : AtomicPtr :: new ( base_pointer. add ( 3 ) ) ,
230
- modem_ctrl : AtomicPtr :: new ( base_pointer. add ( 4 ) ) ,
231
- line_sts : AtomicPtr :: new ( base_pointer. add ( 5 ) ) ,
232
- }
233
- }
234
-
235
- #[ cfg( feature = "mmio_stable" ) ]
236
- pub unsafe fn new ( base : usize ) -> Self {
237
- let base_pointer = base as * mut u8 ;
238
- Self {
239
- data : AtomicPtr :: new ( base_pointer) ,
240
- int_en : AtomicPtr :: new ( base_pointer. add ( 1 ) ) ,
241
- fifo_ctrl : AtomicPtr :: new ( base_pointer. add ( 2 ) ) ,
242
- line_ctrl : AtomicPtr :: new ( base_pointer. add ( 3 ) ) ,
243
- modem_ctrl : AtomicPtr :: new ( base_pointer. add ( 4 ) ) ,
244
- line_sts : AtomicPtr :: new ( base_pointer. add ( 5 ) ) ,
245
- }
246
- }
247
-
248
- /// Initializes the serial port.
249
- ///
250
- /// The default configuration of [38400/8-N-1](https://en.wikipedia.org/wiki/8-N-1) is used.
251
- pub fn init ( & mut self ) {
252
- let self_int_en = self . int_en . load ( Ordering :: Relaxed ) ;
253
- let self_line_ctrl = self . line_ctrl . load ( Ordering :: Relaxed ) ;
254
- let self_data = self . data . load ( Ordering :: Relaxed ) ;
255
- let self_fifo_ctrl = self . fifo_ctrl . load ( Ordering :: Relaxed ) ;
256
- let self_modem_ctrl = self . modem_ctrl . load ( Ordering :: Relaxed ) ;
257
- unsafe {
258
- // Disable interrupts
259
- self_int_en. write ( 0x00 ) ;
260
-
261
- // Enable DLAB
262
- self_line_ctrl. write ( 0x80 ) ;
263
-
264
- // Set maximum speed to 38400 bps by configuring DLL and DLM
265
- self_data. write ( 0x03 ) ;
266
- self_int_en. write ( 0x00 ) ;
267
-
268
- // Disable DLAB and set data word length to 8 bits
269
- self_line_ctrl. write ( 0x03 ) ;
270
-
271
- // Enable FIFO, clear TX/RX queues and
272
- // set interrupt watermark at 14 bytes
273
- self_fifo_ctrl. write ( 0xC7 ) ;
274
-
275
- // Mark data terminal ready, signal request to send
276
- // and enable auxilliary output #2 (used as interrupt line for CPU)
277
- self_modem_ctrl. write ( 0x0B ) ;
278
-
279
- // Enable interrupts
280
- self_int_en. write ( 0x01 ) ;
281
- }
282
- }
283
-
284
- fn line_sts ( & mut self ) -> LineStsFlags {
285
- unsafe { LineStsFlags :: from_bits_truncate ( * self . line_sts . load ( Ordering :: Relaxed ) ) }
286
- }
287
-
288
- /// Sends a byte on the serial port.
289
- pub fn send ( & mut self , data : u8 ) {
290
- let self_data = self . data . load ( Ordering :: Relaxed ) ;
291
- unsafe {
292
- match data {
293
- 8 | 0x7F => {
294
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
295
- self_data. write ( 8 ) ;
296
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
297
- self_data. write ( b' ' ) ;
298
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
299
- self_data. write ( 8 )
300
- } ,
301
- _ => {
302
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
303
- self_data. write ( data) ;
304
- } ,
305
- }
306
- }
307
- }
308
-
309
- /// Receives a byte on the serial port.
310
- pub fn receive ( & mut self ) -> u8 {
311
- let self_data = self . data . load ( Ordering :: Relaxed ) ;
312
- unsafe {
313
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: INPUT_FULL ) ) ;
314
- self_data. read ( )
315
- }
316
- }
317
- }
318
-
319
- impl fmt:: Write for SerialPort {
320
- fn write_str ( & mut self , s : & str ) -> fmt:: Result {
321
- for byte in s. bytes ( ) {
322
- self . send ( byte) ;
323
- }
324
- Ok ( ( ) )
325
- }
326
- }
0 commit comments