chardev.rs 4.4 KB

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