1
1
//! Minimal support for uart_16550 serial I/O.
2
2
//!
3
3
//! # Usage
4
+
5
+ #![ cfg_attr(
6
+ target_arch = "x86_64" ,
7
+ doc = "
8
+ ## With usual serial port
9
+ ```no_run
10
+ use uart_16550::SerialPort;
11
+
12
+ const SERIAL_IO_PORT: u16 = 0x3F8;
13
+
14
+ let mut serial_port = unsafe { SerialPort::new(SERIAL_IO_PORT) };
15
+ serial_port.init();
16
+
17
+ // Now the serial port is ready to be used. To send a byte:
18
+ serial_port.send(42);
19
+
20
+ // To receive a byte:
21
+ let data = serial_port.receive();
22
+ ```
23
+ "
24
+ ) ]
25
+
26
+ //! ## With memory mapped serial port
4
27
//!
5
28
//! ```no_run
6
- //! use uart_16550::SerialPort ;
29
+ //! use uart_16550::MmioSerialPort ;
7
30
//!
8
- //! const SERIAL_IO_PORT: u16 = 0x3F8 ;
31
+ //! const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000 ;
9
32
//!
10
- //! let mut serial_port = unsafe { SerialPort ::new(SERIAL_IO_PORT ) };
33
+ //! let mut serial_port = unsafe { MmioSerialPort ::new(SERIAL_PORT_BASE_ADDRESS ) };
11
34
//! serial_port.init();
12
35
//!
13
36
//! // Now the serial port is ready to be used. To send a byte:
16
39
//! // To receive a byte:
17
40
//! let data = serial_port.receive();
18
41
//! ```
19
-
20
42
#![ no_std]
21
43
#![ warn( missing_docs) ]
44
+ #![ cfg_attr( feature = "nightly" , feature( const_ptr_offset) ) ]
45
+
46
+ #[ cfg( not( any( feature = "stable" , feature = "nightly" ) ) ) ]
47
+ compile_error ! ( "Either the `stable` or `nightly` feature must be enabled" ) ;
22
48
23
49
use bitflags:: bitflags;
24
- use core:: fmt;
25
- use x86_64:: instructions:: port:: { Port , PortReadOnly , PortWriteOnly } ;
26
50
27
51
macro_rules! wait_for {
28
52
( $cond: expr) => {
@@ -32,6 +56,16 @@ macro_rules! wait_for {
32
56
} ;
33
57
}
34
58
59
+ /// Memory mapped implementation
60
+ pub mod mmio;
61
+ #[ cfg( target_arch = "x86_64" ) ]
62
+ /// Port asm commands implementation
63
+ pub mod x86_64;
64
+
65
+ pub use crate :: mmio:: MmioSerialPort ;
66
+ #[ cfg( target_arch = "x86_64" ) ]
67
+ pub use crate :: x86_64:: SerialPort ;
68
+
35
69
bitflags ! {
36
70
/// Interrupt enable flags
37
71
struct IntEnFlags : u8 {
@@ -52,102 +86,3 @@ bitflags! {
52
86
// 6 and 7 unknown
53
87
}
54
88
}
55
-
56
- /// An interface to a serial port that allows sending out individual bytes.
57
- pub struct SerialPort {
58
- data : Port < u8 > ,
59
- int_en : PortWriteOnly < u8 > ,
60
- fifo_ctrl : PortWriteOnly < u8 > ,
61
- line_ctrl : PortWriteOnly < u8 > ,
62
- modem_ctrl : PortWriteOnly < u8 > ,
63
- line_sts : PortReadOnly < u8 > ,
64
- }
65
-
66
- impl SerialPort {
67
- /// Creates a new serial port interface on the given I/O port.
68
- ///
69
- /// This function is unsafe because the caller must ensure that the given base address
70
- /// really points to a serial port device.
71
- pub const unsafe fn new ( base : u16 ) -> SerialPort {
72
- SerialPort {
73
- data : Port :: new ( base) ,
74
- int_en : PortWriteOnly :: new ( base + 1 ) ,
75
- fifo_ctrl : PortWriteOnly :: new ( base + 2 ) ,
76
- line_ctrl : PortWriteOnly :: new ( base + 3 ) ,
77
- modem_ctrl : PortWriteOnly :: new ( base + 4 ) ,
78
- line_sts : PortReadOnly :: new ( base + 5 ) ,
79
- }
80
- }
81
-
82
- /// Initializes the serial port.
83
- ///
84
- /// The default configuration of [38400/8-N-1](https://en.wikipedia.org/wiki/8-N-1) is used.
85
- pub fn init ( & mut self ) {
86
- unsafe {
87
- // Disable interrupts
88
- self . int_en . write ( 0x00 ) ;
89
-
90
- // Enable DLAB
91
- self . line_ctrl . write ( 0x80 ) ;
92
-
93
- // Set maximum speed to 38400 bps by configuring DLL and DLM
94
- self . data . write ( 0x03 ) ;
95
- self . int_en . write ( 0x00 ) ;
96
-
97
- // Disable DLAB and set data word length to 8 bits
98
- self . line_ctrl . write ( 0x03 ) ;
99
-
100
- // Enable FIFO, clear TX/RX queues and
101
- // set interrupt watermark at 14 bytes
102
- self . fifo_ctrl . write ( 0xC7 ) ;
103
-
104
- // Mark data terminal ready, signal request to send
105
- // and enable auxilliary output #2 (used as interrupt line for CPU)
106
- self . modem_ctrl . write ( 0x0B ) ;
107
-
108
- // Enable interrupts
109
- self . int_en . write ( 0x01 ) ;
110
- }
111
- }
112
-
113
- fn line_sts ( & mut self ) -> LineStsFlags {
114
- unsafe { LineStsFlags :: from_bits_truncate ( self . line_sts . read ( ) ) }
115
- }
116
-
117
- /// Sends a byte on the serial port.
118
- pub fn send ( & mut self , data : u8 ) {
119
- unsafe {
120
- match data {
121
- 8 | 0x7F => {
122
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
123
- self . data . write ( 8 ) ;
124
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
125
- self . data . write ( b' ' ) ;
126
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
127
- self . data . write ( 8 )
128
- }
129
- _ => {
130
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
131
- self . data . write ( data) ;
132
- }
133
- }
134
- }
135
- }
136
-
137
- /// Receives a byte on the serial port.
138
- pub fn receive ( & mut self ) -> u8 {
139
- unsafe {
140
- wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: INPUT_FULL ) ) ;
141
- self . data . read ( )
142
- }
143
- }
144
- }
145
-
146
- impl fmt:: Write for SerialPort {
147
- fn write_str ( & mut self , s : & str ) -> fmt:: Result {
148
- for byte in s. bytes ( ) {
149
- self . send ( byte) ;
150
- }
151
- Ok ( ( ) )
152
- }
153
- }
0 commit comments