input.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. use super::*;
  2. use alloc::boxed::Box;
  3. use bitflags::*;
  4. use log::*;
  5. use volatile::{ReadOnly, WriteOnly};
  6. /// Virtual human interface devices such as keyboards, mice and tablets.
  7. ///
  8. /// An instance of the virtio device represents one such input device.
  9. /// Device behavior mirrors that of the evdev layer in Linux,
  10. /// making pass-through implementations on top of evdev easy.
  11. pub struct VirtIOInput<'a> {
  12. header: &'static mut VirtIOHeader,
  13. event_queue: VirtQueue<'a>,
  14. status_queue: VirtQueue<'a>,
  15. event_buf: Box<[InputEvent; 32]>,
  16. }
  17. impl<'a> VirtIOInput<'a> {
  18. /// Create a new VirtIO-Input driver.
  19. pub fn new(header: &'static mut VirtIOHeader) -> Result<Self> {
  20. let mut event_buf = Box::new([InputEvent::default(); QUEUE_SIZE]);
  21. header.begin_init(|features| {
  22. let features = Feature::from_bits_truncate(features);
  23. info!("Device features: {:?}", features);
  24. // negotiate these flags only
  25. let supported_features = Feature::empty();
  26. (features & supported_features).bits()
  27. });
  28. let mut event_queue = VirtQueue::new(header, QUEUE_EVENT, QUEUE_SIZE as u16)?;
  29. let status_queue = VirtQueue::new(header, QUEUE_STATUS, QUEUE_SIZE as u16)?;
  30. for (i, event) in event_buf.as_mut().iter_mut().enumerate() {
  31. let token = event_queue.add(&[], &[event.as_buf_mut()])?;
  32. assert_eq!(token, i as u16);
  33. }
  34. header.finish_init();
  35. Ok(VirtIOInput {
  36. header,
  37. event_queue,
  38. status_queue,
  39. event_buf,
  40. })
  41. }
  42. /// Acknowledge interrupt and process events.
  43. pub fn ack_interrupt(&mut self) -> bool {
  44. self.header.ack_interrupt()
  45. }
  46. /// Pop the pending event.
  47. pub fn pop_pending_event(&mut self) -> Option<InputEvent> {
  48. if let Ok((token, _)) = self.event_queue.pop_used() {
  49. let event = &mut self.event_buf[token as usize];
  50. // requeue
  51. if self.event_queue.add(&[], &[event.as_buf_mut()]).is_ok() {
  52. return Some(*event);
  53. }
  54. }
  55. None
  56. }
  57. /// Query a specific piece of information by `select` and `subsel`, and write
  58. /// result to `out`, return the result size.
  59. pub fn query_config_select(
  60. &mut self,
  61. select: InputConfigSelect,
  62. subsel: u8,
  63. out: &mut [u8],
  64. ) -> u8 {
  65. let config = unsafe { &mut *(self.header.config_space() as *mut Config) };
  66. config.select.write(select as u8);
  67. config.subsel.write(subsel);
  68. let size = config.size.read();
  69. let data = config.data.read();
  70. out[..size as usize].copy_from_slice(&data[..size as usize]);
  71. size
  72. }
  73. }
  74. /// Select value used for [`VirtIOInput::query_config_select()`].
  75. #[repr(u8)]
  76. #[derive(Debug, Clone, Copy)]
  77. pub enum InputConfigSelect {
  78. /// Returns the name of the device, in u.string. subsel is zero.
  79. IdName = 0x01,
  80. /// Returns the serial number of the device, in u.string. subsel is zero.
  81. IdSerial = 0x02,
  82. /// Returns ID information of the device, in u.ids. subsel is zero.
  83. IdDevids = 0x03,
  84. /// Returns input properties of the device, in u.bitmap. subsel is zero.
  85. /// Individual bits in the bitmap correspond to INPUT_PROP_* constants used
  86. /// by the underlying evdev implementation.
  87. PropBits = 0x10,
  88. /// subsel specifies the event type using EV_* constants in the underlying
  89. /// evdev implementation. If size is non-zero the event type is supported
  90. /// and a bitmap of supported event codes is returned in u.bitmap. Individual
  91. /// bits in the bitmap correspond to implementation-defined input event codes,
  92. /// for example keys or pointing device axes.
  93. EvBits = 0x11,
  94. /// subsel specifies the absolute axis using ABS_* constants in the underlying
  95. /// evdev implementation. Information about the axis will be returned in u.abs.
  96. AbsInfo = 0x12,
  97. }
  98. #[repr(C)]
  99. struct Config {
  100. select: WriteOnly<u8>,
  101. subsel: WriteOnly<u8>,
  102. size: ReadOnly<u8>,
  103. _reversed: [ReadOnly<u8>; 5],
  104. data: ReadOnly<[u8; 128]>,
  105. }
  106. #[repr(C)]
  107. #[derive(Debug)]
  108. struct AbsInfo {
  109. min: u32,
  110. max: u32,
  111. fuzz: u32,
  112. flat: u32,
  113. res: u32,
  114. }
  115. #[repr(C)]
  116. #[derive(Debug)]
  117. struct DevIDs {
  118. bustype: u16,
  119. vendor: u16,
  120. product: u16,
  121. version: u16,
  122. }
  123. /// Both queues use the same `virtio_input_event` struct. `type`, `code` and `value`
  124. /// are filled according to the Linux input layer (evdev) interface.
  125. #[repr(C)]
  126. #[derive(Clone, Copy, Debug, Default)]
  127. pub struct InputEvent {
  128. /// Event type.
  129. pub event_type: u16,
  130. /// Event code.
  131. pub code: u16,
  132. /// Event value.
  133. pub value: u32,
  134. }
  135. unsafe impl AsBuf for InputEvent {}
  136. bitflags! {
  137. struct Feature: u64 {
  138. // device independent
  139. const NOTIFY_ON_EMPTY = 1 << 24; // legacy
  140. const ANY_LAYOUT = 1 << 27; // legacy
  141. const RING_INDIRECT_DESC = 1 << 28;
  142. const RING_EVENT_IDX = 1 << 29;
  143. const UNUSED = 1 << 30; // legacy
  144. const VERSION_1 = 1 << 32; // detect legacy
  145. // since virtio v1.1
  146. const ACCESS_PLATFORM = 1 << 33;
  147. const RING_PACKED = 1 << 34;
  148. const IN_ORDER = 1 << 35;
  149. const ORDER_PLATFORM = 1 << 36;
  150. const SR_IOV = 1 << 37;
  151. const NOTIFICATION_DATA = 1 << 38;
  152. }
  153. }
  154. const QUEUE_EVENT: usize = 0;
  155. const QUEUE_STATUS: usize = 1;
  156. // a parameter that can change
  157. const QUEUE_SIZE: usize = 32;