1
1
use core:: fmt;
2
2
3
- use x86_64:: instructions:: port:: { Port , PortReadOnly , PortWriteOnly } ;
4
-
5
3
use crate :: LineStsFlags ;
6
4
7
- /// A port-mapped UART.
5
+ /// A x86 I/O port-mapped UART.
8
6
#[ 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 */ ) ;
17
9
18
10
impl 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.
20
59
///
21
60
/// 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.
23
63
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)
32
65
}
33
66
34
67
/// Initializes the serial port.
@@ -37,33 +70,33 @@ impl SerialPort {
37
70
pub fn init ( & mut self ) {
38
71
unsafe {
39
72
// Disable interrupts
40
- self . int_en . write ( 0x00 ) ;
73
+ x86 :: io :: outb ( self . port_int_en ( ) , 0x00 ) ;
41
74
42
75
// Enable DLAB
43
- self . line_ctrl . write ( 0x80 ) ;
76
+ x86 :: io :: outb ( self . port_line_ctrl ( ) , 0x80 ) ;
44
77
45
78
// 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 ) ;
48
81
49
82
// 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 ) ;
51
84
52
85
// Enable FIFO, clear TX/RX queues and
53
86
// set interrupt watermark at 14 bytes
54
- self . fifo_ctrl . write ( 0xC7 ) ;
87
+ x86 :: io :: outb ( self . port_fifo_ctrl ( ) , 0xc7 ) ;
55
88
56
89
// Mark data terminal ready, signal request to send
57
90
// 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 ) ;
59
92
60
93
// Enable interrupts
61
- self . int_en . write ( 0x01 ) ;
94
+ x86 :: io :: outb ( self . port_int_en ( ) , 0x01 ) ;
62
95
}
63
96
}
64
97
65
98
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 ( ) ) ) }
67
100
}
68
101
69
102
/// Sends a byte on the serial port.
@@ -72,15 +105,15 @@ impl SerialPort {
72
105
match data {
73
106
8 | 0x7F => {
74
107
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
75
- self . data . write ( 8 ) ;
108
+ x86 :: io :: outb ( self . port_data ( ) , 8 ) ;
76
109
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
77
- self . data . write ( b' ' ) ;
110
+ x86 :: io :: outb ( self . port_data ( ) , b' ' ) ;
78
111
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
79
- self . data . write ( 8 )
112
+ x86 :: io :: outb ( self . port_data ( ) , 8 ) ;
80
113
}
81
114
_ => {
82
115
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
83
- self . data . write ( data) ;
116
+ x86 :: io :: outb ( self . port_data ( ) , data) ;
84
117
}
85
118
}
86
119
}
@@ -90,15 +123,15 @@ impl SerialPort {
90
123
pub fn send_raw ( & mut self , data : u8 ) {
91
124
unsafe {
92
125
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: OUTPUT_EMPTY ) ) ;
93
- self . data . write ( data) ;
126
+ x86 :: io :: outb ( self . port_data ( ) , data) ;
94
127
}
95
128
}
96
129
97
130
/// Receives a byte on the serial port.
98
131
pub fn receive ( & mut self ) -> u8 {
99
132
unsafe {
100
133
wait_for ! ( self . line_sts( ) . contains( LineStsFlags :: INPUT_FULL ) ) ;
101
- self . data . read ( )
134
+ x86 :: io :: inb ( self . port_data ( ) )
102
135
}
103
136
}
104
137
}
0 commit comments