serial.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. use core::task::Waker;
  2. use alloc::{collections::vec_deque::VecDeque, format, sync::Arc};
  3. use atomic_unique_refcell::AtomicUniqueRefCell;
  4. use bindings::EIO;
  5. use bitflags::bitflags;
  6. use crate::{
  7. kernel::{
  8. block::make_device,
  9. interrupt::register_irq_handler,
  10. task::{FutureRunnable, Scheduler, Task},
  11. CharDevice, CharDeviceType, Console, Terminal, TerminalDevice,
  12. },
  13. prelude::*,
  14. };
  15. use super::Port8;
  16. bitflags! {
  17. struct LineStatus: u8 {
  18. const RX_READY = 0x01;
  19. const TX_READY = 0x20;
  20. }
  21. }
  22. #[allow(dead_code)]
  23. struct Serial {
  24. id: u32,
  25. name: Arc<str>,
  26. terminal: Spin<Option<Arc<Terminal>>>,
  27. worker: AtomicUniqueRefCell<Option<Waker>>,
  28. working: Spin<bool>,
  29. tx_buffer: Spin<VecDeque<u8>>,
  30. tx_rx: Port8,
  31. int_ena: Port8,
  32. int_ident: Port8,
  33. line_control: Port8,
  34. modem_control: Port8,
  35. line_status: Port8,
  36. modem_status: Port8,
  37. scratch: Port8,
  38. }
  39. impl Serial {
  40. const COM0_BASE: u16 = 0x3f8;
  41. const COM1_BASE: u16 = 0x2f8;
  42. const COM0_IRQ: u8 = 4;
  43. const COM1_IRQ: u8 = 3;
  44. fn enable_interrupts(&self) {
  45. // Enable interrupt #0: Received data available
  46. self.int_ena.write(0x03);
  47. }
  48. fn disable_interrupts(&self) {
  49. // Disable interrupt #0: Received data available
  50. self.int_ena.write(0x00);
  51. }
  52. fn line_status(&self) -> LineStatus {
  53. LineStatus::from_bits_truncate(self.line_status.read())
  54. }
  55. async fn wait_for_interrupt(&self) {
  56. {
  57. let mut working = self.working.lock_irq();
  58. self.enable_interrupts();
  59. *working = false;
  60. Task::current().isleep();
  61. }
  62. Scheduler::sleep().await;
  63. *self.working.lock_irq() = true;
  64. self.disable_interrupts();
  65. }
  66. async fn worker(port: Arc<Self>) {
  67. let terminal = port.terminal.lock().clone();
  68. loop {
  69. while port.line_status().contains(LineStatus::RX_READY) {
  70. let ch = port.tx_rx.read();
  71. if let Some(terminal) = terminal.as_ref() {
  72. terminal.commit_char(ch);
  73. }
  74. }
  75. let should_wait = {
  76. let mut tx_buffer = port.tx_buffer.lock();
  77. // Give it a chance to receive data.
  78. let count = tx_buffer.len().min(64);
  79. for ch in tx_buffer.drain(..count) {
  80. if port.line_status().contains(LineStatus::TX_READY) {
  81. port.tx_rx.write(ch);
  82. } else {
  83. break;
  84. }
  85. }
  86. tx_buffer.is_empty()
  87. };
  88. if should_wait {
  89. port.wait_for_interrupt().await;
  90. } else {
  91. Scheduler::yield_now().await;
  92. }
  93. }
  94. }
  95. pub fn new(id: u32, base_port: u16) -> KResult<Self> {
  96. let port = Self {
  97. id,
  98. name: Arc::from(format!("ttyS{id}")),
  99. terminal: Spin::new(None),
  100. worker: AtomicUniqueRefCell::new(None),
  101. working: Spin::new(true),
  102. tx_buffer: Spin::new(VecDeque::new()),
  103. tx_rx: Port8::new(base_port),
  104. int_ena: Port8::new(base_port + 1),
  105. int_ident: Port8::new(base_port + 2),
  106. line_control: Port8::new(base_port + 3),
  107. modem_control: Port8::new(base_port + 4),
  108. line_status: Port8::new(base_port + 5),
  109. modem_status: Port8::new(base_port + 6),
  110. scratch: Port8::new(base_port + 7),
  111. };
  112. port.int_ena.write(0x00); // Disable all interrupts
  113. port.line_control.write(0x80); // Enable DLAB (set baud rate divisor)
  114. port.tx_rx.write(0x00); // Set divisor to 0 (lo byte) 115200 baud rate
  115. port.int_ena.write(0x00); // 0 (hi byte)
  116. port.line_control.write(0x03); // 8 bits, no parity, one stop bit
  117. port.int_ident.write(0xc7); // Enable FIFO, clear them, with 14-byte threshold
  118. port.modem_control.write(0x0b); // IRQs enabled, RTS/DSR set
  119. port.modem_control.write(0x1e); // Set in loopback mode, test the serial chip
  120. port.tx_rx.write(0x19); // Test serial chip (send byte 0x19 and check if serial returns
  121. // same byte)
  122. if port.tx_rx.read() != 0x19 {
  123. return Err(EIO);
  124. }
  125. port.modem_control.write(0x0f); // Return to normal operation mode
  126. Ok(port)
  127. }
  128. fn wakeup_worker(&self) {
  129. let working = self.working.lock_irq();
  130. if !*working {
  131. self.worker
  132. .borrow()
  133. .as_ref()
  134. .expect("Worker not initialized")
  135. .wake_by_ref();
  136. }
  137. }
  138. fn irq_handler(&self) {
  139. // Read the interrupt ID register to clear the interrupt.
  140. self.int_ident.read();
  141. self.wakeup_worker();
  142. }
  143. fn register_char_device(port: Self) -> KResult<()> {
  144. let port = Arc::new(port);
  145. let terminal = Terminal::new(port.clone());
  146. let task = Task::new(FutureRunnable::new(Self::worker(port.clone())));
  147. port.terminal.lock().replace(terminal.clone());
  148. port.worker.borrow().replace(task.waker());
  149. {
  150. let port = port.clone();
  151. let irq_no = match port.id {
  152. 0 => Serial::COM0_IRQ,
  153. 1 => Serial::COM1_IRQ,
  154. _ => unreachable!(),
  155. };
  156. register_irq_handler(irq_no as i32, move || {
  157. port.irq_handler();
  158. })?;
  159. }
  160. Scheduler::get().spawn(task);
  161. dont_check!(Console::register_terminal(&terminal));
  162. CharDevice::register(
  163. make_device(4, 64 + port.id),
  164. port.name.clone(),
  165. CharDeviceType::Terminal(terminal),
  166. )?;
  167. Ok(())
  168. }
  169. }
  170. impl TerminalDevice for Serial {
  171. fn putchar(&self, ch: u8) {
  172. let mut tx_buffer = self.tx_buffer.lock();
  173. tx_buffer.push_back(ch);
  174. self.wakeup_worker();
  175. }
  176. }
  177. pub fn init() -> KResult<()> {
  178. if let Ok(port) = Serial::new(0, Serial::COM0_BASE) {
  179. Serial::register_char_device(port)?;
  180. }
  181. if let Ok(port) = Serial::new(1, Serial::COM1_BASE) {
  182. Serial::register_char_device(port)?;
  183. }
  184. Ok(())
  185. }