11//! Minimal support for uart_16550 serial I/O.
22//!
33//! # 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
427//!
528//! ```no_run
6- //! use uart_16550::SerialPort ;
29+ //! use uart_16550::MmioSerialPort ;
730//!
8- //! const SERIAL_IO_PORT: u16 = 0x3F8 ;
31+ //! const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000 ;
932//!
10- //! let mut serial_port = unsafe { SerialPort ::new(SERIAL_IO_PORT ) };
33+ //! let mut serial_port = unsafe { MmioSerialPort ::new(SERIAL_PORT_BASE_ADDRESS ) };
1134//! serial_port.init();
1235//!
1336//! // Now the serial port is ready to be used. To send a byte:
1639//! // To receive a byte:
1740//! let data = serial_port.receive();
1841//! ```
19-
2042#![ no_std]
2143#![ 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" ) ;
2248
2349use bitflags:: bitflags;
24- use core:: fmt;
25- use x86_64:: instructions:: port:: { Port , PortReadOnly , PortWriteOnly } ;
2650
2751macro_rules! wait_for {
2852 ( $cond: expr) => {
@@ -32,6 +56,16 @@ macro_rules! wait_for {
3256 } ;
3357}
3458
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+
3569bitflags ! {
3670 /// Interrupt enable flags
3771 struct IntEnFlags : u8 {
@@ -52,102 +86,3 @@ bitflags! {
5286 // 6 and 7 unknown
5387 }
5488}
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