aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-08-04 15:30:26 -0400
committerBrian Cully <bjc@kublai.com>2019-08-04 16:04:19 -0400
commit4b961b6110e3c0a1b6bc67a7694651d689b553f9 (patch)
tree9f2551806ab9baad1fc96efca82859ec82fea1c5 /src
downloadbootkbd-4b961b6110e3c0a1b6bc67a7694651d689b553f9.tar.gz
bootkbd-4b961b6110e3c0a1b6bc67a7694651d689b553f9.zip
Initial commitv0.1.0
Diffstat (limited to 'src')
-rwxr-xr-xsrc/lib.rs333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100755
index 0000000..dde9e71
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,333 @@
+#![no_std]
+
+use log::{debug, error, info};
+use usb_host::{
+ ConfigurationDescriptor, DescriptorType, DeviceDescriptor, Direction, Driver, DriverError,
+ Endpoint, RequestCode, RequestDirection, RequestKind, RequestRecipient, RequestType,
+ TransferError, TransferType, USBHost, WValue,
+};
+
+use core::mem::{self, MaybeUninit};
+use core::ptr;
+
+// How long to wait before talking to the device again after setting
+// its address. cf ยง9.2.6.3 of USB 2.0
+const SETTLE_DELAY: usize = 2;
+
+// How many total devices this driver can support.
+const MAX_DEVICES: usize = 1;
+
+// And how many endpoints we can support per-device.
+const MAX_ENDPOINTS: usize = 2;
+
+pub struct BootKeyboard {
+ devices: [Option<Device>; MAX_DEVICES],
+}
+impl core::fmt::Debug for BootKeyboard {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "BootKeyboard")
+ }
+}
+
+impl BootKeyboard {
+ pub fn new() -> Self {
+ Self {
+ devices: [None; MAX_DEVICES],
+ }
+ }
+}
+
+impl Driver for BootKeyboard {
+ fn want_device(&self, _device: &DeviceDescriptor) -> bool {
+ true
+ }
+
+ fn add_device(&mut self, _device: DeviceDescriptor, address: u8) -> Result<(), DriverError> {
+ for i in 0..self.devices.len() {
+ if self.devices[i].is_none() {
+ self.devices[i] = Some(Device::new(address));
+ return Ok(());
+ }
+ }
+ Err(DriverError::Permanent(address, "out of devices"))
+ }
+
+ fn remove_device(&mut self, address: u8) {
+ for i in 0..self.devices.len() {
+ if let Some(ref dev) = self.devices[i] {
+ if dev.addr == address {
+ self.devices[i] = None;
+ return;
+ }
+ }
+ }
+ }
+
+ fn tick(&mut self, millis: usize, host: &mut dyn USBHost) -> Result<(), DriverError> {
+ for d in &mut self.devices[..] {
+ if let Some(ref mut dev) = d {
+ if let Err(TransferError::Permanent(e)) = dev.fsm(millis, host) {
+ return Err(DriverError::Permanent(dev.addr, e));
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum DeviceState {
+ Addressed,
+ WaitForSettle(usize),
+ GetConfig,
+ SetConfig,
+ SetIdle,
+ SetReport,
+ Running,
+}
+
+struct Device {
+ addr: u8,
+ ep0: EP,
+ endpoints: [Option<EP>; MAX_ENDPOINTS],
+ state: DeviceState,
+}
+
+impl Device {
+ fn new(addr: u8) -> Self {
+ let endpoints: [Option<EP>; MAX_ENDPOINTS] = {
+ let mut eps: [MaybeUninit<Option<EP>>; MAX_ENDPOINTS] =
+ unsafe { mem::MaybeUninit::uninit().assume_init() };
+ for ep in &mut eps[..] {
+ unsafe { ptr::write(ep.as_mut_ptr(), None) }
+ }
+ unsafe { mem::transmute(eps) }
+ };
+
+ Self {
+ addr: addr,
+ ep0: EP::new(addr, 0, TransferType::Control, Direction::In),
+ endpoints: endpoints,
+ state: DeviceState::Addressed,
+ }
+ }
+
+ fn fsm(&mut self, millis: usize, host: &mut dyn USBHost) -> Result<(), TransferError> {
+ // TODO: either we need another `control_transfer` that
+ // doesn't take data, or this `none` value needs to be put in
+ // the usb-host layer. None of these options are good.
+ let none: Option<&mut [u8]> = None;
+ unsafe {
+ static mut LAST_STATE: DeviceState = DeviceState::Addressed;
+ if LAST_STATE != self.state {
+ debug!("{:?} -> {:?}", LAST_STATE, self.state);
+ LAST_STATE = self.state;
+ }
+ }
+
+ match self.state {
+ DeviceState::Addressed => {
+ self.state = DeviceState::WaitForSettle(millis + SETTLE_DELAY)
+ }
+
+ DeviceState::WaitForSettle(until) => {
+ if millis > until {
+ let mut dev_desc: MaybeUninit<DeviceDescriptor> = MaybeUninit::uninit();
+ let buf = unsafe { to_slice_mut(&mut dev_desc) };
+ let len = host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::DeviceToHost,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
+ RequestCode::GetDescriptor,
+ WValue::from((0, DescriptorType::Device as u8)),
+ 0,
+ Some(buf),
+ )?;
+ assert!(len == mem::size_of::<DeviceDescriptor>());
+ self.state = DeviceState::GetConfig
+ }
+ }
+
+ DeviceState::GetConfig => {
+ let mut conf_desc: MaybeUninit<ConfigurationDescriptor> = MaybeUninit::uninit();
+ let buf = unsafe { to_slice_mut(&mut conf_desc) };
+ let len = host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::DeviceToHost,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
+ RequestCode::GetDescriptor,
+ WValue::from((0, DescriptorType::Configuration as u8)),
+ 0,
+ Some(buf),
+ )?;
+ assert!(len == mem::size_of::<ConfigurationDescriptor>());
+ let conf_desc = unsafe { conf_desc.assume_init() };
+
+ // TODO: do a real allocation later.
+ assert!(conf_desc.w_total_length < 64);
+ let mut buf: [u8; 64] = [0; 64];
+ let mut tmp = &mut buf[..conf_desc.w_total_length as usize];
+ let len = host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::DeviceToHost,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
+ RequestCode::GetDescriptor,
+ WValue::from((0, DescriptorType::Configuration as u8)),
+ 0,
+ Some(&mut tmp),
+ )?;
+ assert!(len == conf_desc.w_total_length as usize);
+
+ self.state = DeviceState::SetConfig
+ }
+
+ DeviceState::SetConfig => {
+ // TODO: extract real configuration to choose.
+ let conf: u8 = 1;
+ host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::HostToDevice,
+ RequestKind::Standard,
+ RequestRecipient::Device,
+ )),
+ RequestCode::SetConfiguration,
+ WValue::from((conf, 0)),
+ 0,
+ none,
+ )?;
+
+ self.endpoints[0] = Some(EP::new(
+ self.addr,
+ 1,
+ TransferType::Interrupt,
+ Direction::In,
+ ));
+
+ self.state = DeviceState::SetIdle
+ }
+
+ DeviceState::SetIdle => {
+ host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::HostToDevice,
+ RequestKind::Class,
+ RequestRecipient::Interface,
+ )),
+ RequestCode::GetInterface,
+ WValue::from((0, 0)),
+ 0,
+ none,
+ )?;
+ self.state = DeviceState::SetReport
+ }
+
+ DeviceState::SetReport => {
+ let mut report: [u8; 1] = [0];
+ host.control_transfer(
+ &mut self.ep0,
+ RequestType::from((
+ RequestDirection::HostToDevice,
+ RequestKind::Class,
+ RequestRecipient::Interface,
+ )),
+ RequestCode::SetConfiguration,
+ WValue::from((0, 2)),
+ 0,
+ Some(&mut report),
+ )?;
+
+ self.state = DeviceState::Running
+ }
+
+ DeviceState::Running => {
+ let mut buf: [u8; 8] = [0; 8];
+ if let Some(ref mut ep) = self.endpoints[0] {
+ match host.in_transfer(ep, &mut buf) {
+ Err(TransferError::Permanent(msg)) => error!("reading report: {}", msg),
+ Err(TransferError::Retry(_)) => return Ok(()),
+ Ok(len) => info!("report: {} - {:?}", len, buf),
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+unsafe fn to_slice_mut<T>(v: &mut T) -> &mut [u8] {
+ let ptr = v as *mut T as *mut u8;
+ let len = mem::size_of::<T>();
+ core::slice::from_raw_parts_mut(ptr, len)
+}
+
+struct EP {
+ addr: u8,
+ num: u8,
+ transfer_type: TransferType,
+ direction: Direction,
+ in_toggle: bool,
+ out_toggle: bool,
+}
+
+impl EP {
+ fn new(addr: u8, num: u8, transfer_type: TransferType, direction: Direction) -> Self {
+ Self {
+ addr: addr,
+ num: num,
+ transfer_type: transfer_type,
+ direction: direction,
+ in_toggle: false,
+ out_toggle: false,
+ }
+ }
+}
+
+impl Endpoint for EP {
+ fn address(&self) -> u8 {
+ self.addr
+ }
+
+ fn endpoint_num(&self) -> u8 {
+ self.num
+ }
+
+ fn transfer_type(&self) -> TransferType {
+ self.transfer_type
+ }
+
+ fn direction(&self) -> Direction {
+ self.direction
+ }
+
+ fn max_packet_size(&self) -> u16 {
+ 8
+ }
+
+ fn in_toggle(&self) -> bool {
+ self.in_toggle
+ }
+
+ fn set_in_toggle(&mut self, toggle: bool) {
+ self.in_toggle = toggle
+ }
+
+ fn out_toggle(&self) -> bool {
+ self.out_toggle
+ }
+
+ fn set_out_toggle(&mut self, toggle: bool) {
+ self.out_toggle = toggle
+ }
+}