chardev.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. use alloc::{
  2. boxed::Box,
  3. collections::btree_map::{BTreeMap, Entry},
  4. sync::Arc,
  5. };
  6. use bindings::{EEXIST, EIO};
  7. use crate::{io::Buffer, kernel::console::CONSOLE, prelude::*, sync::AsRefPosition as _};
  8. use super::{
  9. block::make_device,
  10. task::{ProcessList, Thread},
  11. terminal::Terminal,
  12. vfs::{
  13. file::{File, TerminalFile},
  14. DevId,
  15. },
  16. };
  17. use lazy_static::lazy_static;
  18. pub trait VirtualCharDevice: Send + Sync {
  19. fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize>;
  20. fn write(&self, data: &[u8]) -> KResult<usize>;
  21. }
  22. pub enum CharDeviceType {
  23. Terminal(Arc<Terminal>),
  24. Virtual(Box<dyn VirtualCharDevice>),
  25. }
  26. #[allow(dead_code)]
  27. pub struct CharDevice {
  28. name: Arc<str>,
  29. device: CharDeviceType,
  30. }
  31. lazy_static! {
  32. pub static ref CHAR_DEVICES: Spin<BTreeMap<DevId, Arc<CharDevice>>> =
  33. Spin::new(BTreeMap::new());
  34. }
  35. impl CharDevice {
  36. pub fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  37. match &self.device {
  38. CharDeviceType::Terminal(terminal) => terminal.read(buffer),
  39. CharDeviceType::Virtual(device) => device.read(buffer),
  40. }
  41. }
  42. pub fn write(&self, data: &[u8]) -> KResult<usize> {
  43. match &self.device {
  44. CharDeviceType::Virtual(device) => device.write(data),
  45. CharDeviceType::Terminal(terminal) => {
  46. for &ch in data.iter() {
  47. terminal.show_char(ch);
  48. }
  49. Ok(data.len())
  50. }
  51. }
  52. }
  53. pub fn get(devid: DevId) -> Option<Arc<CharDevice>> {
  54. CHAR_DEVICES.lock().get(&devid).cloned()
  55. }
  56. pub fn register(devid: DevId, name: Arc<str>, device: CharDeviceType) -> KResult<()> {
  57. match CHAR_DEVICES.lock().entry(devid) {
  58. Entry::Vacant(entry) => {
  59. entry.insert(Arc::new(CharDevice { name, device }));
  60. Ok(())
  61. }
  62. Entry::Occupied(_) => Err(EEXIST),
  63. }
  64. }
  65. pub fn open(self: &Arc<Self>) -> KResult<Arc<File>> {
  66. Ok(match &self.device {
  67. CharDeviceType::Terminal(terminal) => {
  68. let procs = ProcessList::get().lock_shared();
  69. let current = Thread::current();
  70. let session = current.process.session(procs.as_pos());
  71. // We only set the control terminal if the process is the session leader.
  72. if session.sid == Thread::current().process.pid {
  73. // Silently fail if we can't set the control terminal.
  74. dont_check!(session.set_control_terminal(&terminal, false, procs.as_pos()));
  75. }
  76. TerminalFile::new(terminal.clone())
  77. }
  78. CharDeviceType::Virtual(_) => Arc::new(File::CharDev(self.clone())),
  79. })
  80. }
  81. }
  82. struct NullDevice;
  83. impl VirtualCharDevice for NullDevice {
  84. fn read(&self, _buffer: &mut dyn Buffer) -> KResult<usize> {
  85. Ok(0)
  86. }
  87. fn write(&self, _data: &[u8]) -> KResult<usize> {
  88. Ok(_data.len())
  89. }
  90. }
  91. struct ZeroDevice;
  92. impl VirtualCharDevice for ZeroDevice {
  93. fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  94. // TODO: Copy from empty page.
  95. while let false = buffer.fill(&[0; 16])?.should_stop() {}
  96. Ok(buffer.wrote())
  97. }
  98. fn write(&self, _data: &[u8]) -> KResult<usize> {
  99. Ok(_data.len())
  100. }
  101. }
  102. struct ConsoleDevice;
  103. impl VirtualCharDevice for ConsoleDevice {
  104. fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  105. let console_terminal = CONSOLE.lock_irq().get_terminal().ok_or(EIO)?;
  106. console_terminal.read(buffer)
  107. }
  108. fn write(&self, data: &[u8]) -> KResult<usize> {
  109. let console_terminal = CONSOLE.lock_irq().get_terminal().ok_or(EIO)?;
  110. for &ch in data.iter() {
  111. console_terminal.show_char(ch);
  112. }
  113. Ok(data.len())
  114. }
  115. }
  116. impl CharDevice {
  117. pub fn init() -> KResult<()> {
  118. Self::register(
  119. make_device(1, 3),
  120. Arc::from("null"),
  121. CharDeviceType::Virtual(Box::new(NullDevice)),
  122. )?;
  123. Self::register(
  124. make_device(1, 5),
  125. Arc::from("zero"),
  126. CharDeviceType::Virtual(Box::new(ZeroDevice)),
  127. )?;
  128. Self::register(
  129. make_device(5, 1),
  130. Arc::from("console"),
  131. CharDeviceType::Virtual(Box::new(ConsoleDevice)),
  132. )?;
  133. Ok(())
  134. }
  135. }