@@ -20,10 +20,15 @@ use core::fmt::Write;
20
20
21
21
use spin:: Once ;
22
22
23
+ use crate :: arch:: interrupts:: { self , InterruptStack } ;
23
24
use crate :: arch:: io;
25
+ use crate :: userland:: task:: Task ;
24
26
use crate :: utils:: sync:: Mutex ;
25
27
26
- static COM_1 : Once < Mutex < SerialPort > > = Once :: new ( ) ;
28
+ use alloc:: sync:: Arc ;
29
+ use alloc:: vec:: Vec ;
30
+
31
+ pub static COM_1 : Once < Mutex < SerialPort > > = Once :: new ( ) ;
27
32
28
33
bitflags:: bitflags! {
29
34
pub struct InterruptEnable : u8 {
@@ -95,25 +100,35 @@ impl SerialPort {
95
100
}
96
101
97
102
pub fn send_byte ( & mut self , byte : u8 ) {
98
- unsafe {
99
- match byte {
100
- 8 | 0x7F => {
101
- self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
103
+ match byte {
104
+ 8 | 0x7F => {
105
+ self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
106
+ unsafe {
102
107
io:: outb ( self . 0 , 8 ) ;
108
+ }
103
109
104
- self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
110
+ self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
111
+ unsafe {
105
112
io:: outb ( self . 0 , b' ' ) ;
113
+ }
106
114
107
- self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
115
+ self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
116
+ unsafe {
108
117
io:: outb ( self . 0 , 8 ) ;
109
118
}
110
- _ => {
111
- self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
112
- io:: outb ( self . 0 , byte)
119
+ }
120
+ _ => {
121
+ self . wait_for_line_status ( LineStatus :: OUTPUT_EMPTY ) ;
122
+ unsafe {
123
+ io:: outb ( self . 0 , byte) ;
113
124
}
114
125
}
115
126
}
116
127
}
128
+
129
+ pub fn read_byte ( & mut self ) -> u8 {
130
+ unsafe { io:: inb ( self . 0 ) }
131
+ }
117
132
}
118
133
119
134
impl fmt:: Write for SerialPort {
@@ -126,15 +141,44 @@ impl fmt::Write for SerialPort {
126
141
}
127
142
}
128
143
144
+ fn irq_handler ( _stack : & mut InterruptStack ) {
145
+ if !unsafe { COM_1 . get_unchecked ( ) }
146
+ . lock_irq ( )
147
+ . line_status ( )
148
+ . contains ( LineStatus :: INPUT_FULL )
149
+ {
150
+ return ;
151
+ }
152
+
153
+ ( * LISTENERS )
154
+ . lock_irq ( )
155
+ . iter ( )
156
+ . for_each ( |task| task. wake_up ( ) ) ;
157
+ }
158
+
159
+ lazy_static:: lazy_static! {
160
+ static ref LISTENERS : Mutex <Vec <Arc <Task >>> = Mutex :: new( Vec :: new( ) ) ;
161
+ }
162
+
163
+ pub fn register_listener ( task : Arc < Task > ) {
164
+ ( * LISTENERS ) . lock_irq ( ) . push ( task) ;
165
+ }
166
+
129
167
/// Initialize the serial ports if available.
130
168
pub fn init ( ) {
131
169
unsafe {
132
- let com_1 = SerialPort :: new ( 0x3F8 ) . init ( ) ;
133
-
170
+ let com_1 = SerialPort :: new ( 0x3f8 ) . init ( ) ;
134
171
COM_1 . call_once ( move || Mutex :: new ( com_1) ) ;
135
172
}
136
173
}
137
174
175
+ pub fn setup_interrupts ( ) {
176
+ let vector = interrupts:: allocate_vector ( ) ;
177
+ interrupts:: register_handler ( vector, irq_handler) ;
178
+
179
+ crate :: arch:: apic:: io_apic_setup_legacy_irq ( 4 , vector, 1 ) ;
180
+ }
181
+
138
182
pub macro serial_print( $( $arg: tt) * ) {
139
183
crate :: drivers:: uart_16550:: _serial_print ( format_args ! ( $( $arg) * ) )
140
184
}
@@ -147,6 +191,8 @@ pub macro serial_println {
147
191
#[ doc( hidden) ]
148
192
pub fn _serial_print ( args: fmt:: Arguments ) {
149
193
if let Some ( c) = COM_1 . get ( ) {
150
- c. lock ( ) . write_fmt ( args) . expect ( "failed to write to COM1" )
194
+ c. lock_irq ( )
195
+ . write_fmt ( args)
196
+ . expect ( "failed to write to COM1" )
151
197
}
152
198
}
0 commit comments