11use core:: fmt;
22
3- use x86_64:: instructions:: port:: { Port , PortReadOnly , PortWriteOnly } ;
4-
53use crate :: LineStsFlags ;
64
7- /// A port-mapped UART.
5+ /// A x86 I/O port-mapped UART.
86#[ cfg_attr( docsrs, doc( cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ) ) ]
9- pub struct SerialPort {
10- data : Port < u8 > ,
11- int_en : PortWriteOnly < u8 > ,
12- fifo_ctrl : PortWriteOnly < u8 > ,
13- line_ctrl : PortWriteOnly < u8 > ,
14- modem_ctrl : PortWriteOnly < u8 > ,
15- line_sts : PortReadOnly < u8 > ,
16- }
7+ #[ derive( Debug ) ]
8+ pub struct SerialPort ( u16 /* base port */ ) ;
179
1810impl SerialPort {
19- /// Creates a new serial port interface on the given I/O port.
11+ /// Base port.
12+ fn port_base ( & self ) -> u16 {
13+ self . 0
14+ }
15+
16+ /// Data port.
17+ ///
18+ /// Read and write.
19+ fn port_data ( & self ) -> u16 {
20+ self . port_base ( )
21+ }
22+
23+ /// Interrupt enable port.
24+ ///
25+ /// Write only.
26+ fn port_int_en ( & self ) -> u16 {
27+ self . port_base ( ) + 1
28+ }
29+
30+ /// Fifo control port.
31+ ///
32+ /// Write only.
33+ fn port_fifo_ctrl ( & self ) -> u16 {
34+ self . port_base ( ) + 2
35+ }
36+
37+ /// Line control port.
38+ ///
39+ /// Write only.
40+ fn port_line_ctrl ( & self ) -> u16 {
41+ self . port_base ( ) + 3
42+ }
43+
44+ /// Modem control port.
45+ ///
46+ /// Write only.
47+ fn port_modem_ctrl ( & self ) -> u16 {
48+ self . port_base ( ) + 4
49+ }
50+
51+ /// Line status port.
52+ ///
53+ /// Read only.
54+ fn port_line_sts ( & self ) -> u16 {
55+ self . port_base ( ) + 5
56+ }
57+
58+ /// Creates a new serial port interface on the given I/O base port.
2059 ///
2160 /// This function is unsafe because the caller must ensure that the given base address
22- /// really points to a serial port device.
61+ /// really points to a serial port device and that the caller has the necessary rights
62+ /// to perform the I/O operation.
2363 pub const unsafe fn new ( base : u16 ) -> Self {
24- Self {
25- data : Port :: new ( base) ,
26- int_en : PortWriteOnly :: new ( base + 1 ) ,
27- fifo_ctrl : PortWriteOnly :: new ( base + 2 ) ,
28- line_ctrl : PortWriteOnly :: new ( base + 3 ) ,
29- modem_ctrl : PortWriteOnly :: new ( base + 4 ) ,
30- line_sts : PortReadOnly :: new ( base + 5 ) ,
31- }
64+ Self ( base)
3265 }
3366
3467 /// Initializes the serial port.
@@ -37,33 +70,33 @@ impl SerialPort {
3770 pub fn init ( & mut self ) {
3871 unsafe {
3972 // Disable interrupts
40- self . int_en . write ( 0x00 ) ;
73+ x86 :: io :: outb ( self . port_int_en ( ) , 0x00 ) ;
4174
4275 // Enable DLAB
43- self . line_ctrl . write ( 0x80 ) ;
76+ x86 :: io :: outb ( self . port_line_ctrl ( ) , 0x80 ) ;
4477
4578 // Set maximum speed to 38400 bps by configuring DLL and DLM
46- self . data . write ( 0x03 ) ;
47- self . int_en . write ( 0x00 ) ;
79+ x86 :: io :: outb ( self . port_data ( ) , 0x03 ) ;
80+ x86 :: io :: outb ( self . port_int_en ( ) , 0x00 ) ;
4881
4982 // Disable DLAB and set data word length to 8 bits
50- self . line_ctrl . write ( 0x03 ) ;
83+ x86 :: io :: outb ( self . port_line_ctrl ( ) , 0x03 ) ;
5184
5285 // Enable FIFO, clear TX/RX queues and
5386 // set interrupt watermark at 14 bytes
54- self . fifo_ctrl . write ( 0xC7 ) ;
87+ x86 :: io :: outb ( self . port_fifo_ctrl ( ) , 0xc7 ) ;
5588
5689 // Mark data terminal ready, signal request to send
5790 // and enable auxilliary output #2 (used as interrupt line for CPU)
58- self . modem_ctrl . write ( 0x0B ) ;
91+ x86 :: io :: outb ( self . port_modem_ctrl ( ) , 0x0b ) ;
5992
6093 // Enable interrupts
61- self . int_en . write ( 0x01 ) ;
94+ x86 :: io :: outb ( self . port_int_en ( ) , 0x01 ) ;
6295 }
6396 }
6497
6598 fn line_sts ( & mut self ) -> LineStsFlags {
66- unsafe { LineStsFlags :: from_bits_truncate ( self . line_sts . read ( ) ) }
99+ unsafe { LineStsFlags :: from_bits_truncate ( x86 :: io :: inb ( self . port_line_sts ( ) ) ) }
67100 }
68101
69102 /// Sends a byte on the serial port.
@@ -72,15 +105,15 @@ impl SerialPort {
72105 match data {
73106 8 | 0x7F => {
74107 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
75- self . data . write ( 8 ) ;
108+ x86 :: io :: outb ( self . port_data ( ) , 8 ) ;
76109 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
77- self . data . write ( b' ' ) ;
110+ x86 :: io :: outb ( self . port_data ( ) , b' ' ) ;
78111 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
79- self . data . write ( 8 )
112+ x86 :: io :: outb ( self . port_data ( ) , 8 ) ;
80113 }
81114 _ => {
82115 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
83- self . data . write ( data) ;
116+ x86 :: io :: outb ( self . port_data ( ) , data) ;
84117 }
85118 }
86119 }
@@ -90,15 +123,15 @@ impl SerialPort {
90123 pub fn send_raw ( & mut self , data : u8 ) {
91124 unsafe {
92125 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
93- self . data . write ( data) ;
126+ x86 :: io :: outb ( self . port_data ( ) , data) ;
94127 }
95128 }
96129
97130 /// Receives a byte on the serial port.
98131 pub fn receive ( & mut self ) -> u8 {
99132 unsafe {
100133 wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: INPUT_FULL ) ) ;
101- self . data . read ( )
134+ x86 :: io :: inb ( self . port_data ( ) )
102135 }
103136 }
104137}
0 commit comments