commit 9ed8a6fd9f80b008909548cb139420ed8dc34de0 Author: Nicolas Stalder Date: Sat May 2 04:14:46 2020 +0200 Basics for CCID from Zissou (ATR) diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7d4e774 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "usbd-ccid" +version = "0.0.0-unreleased" +authors = ["Nicolas Stalder "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cortex-m-semihosting = { version = "0.3.5", optional = true} +usb-device = { version = "0.2.3", features = ["control-buffer-256"] } + +[features] +default = [ + "cortex-m-semihosting", +] +highspeed-usb = [] + diff --git a/src/class.rs b/src/class.rs new file mode 100644 index 0000000..da04270 --- /dev/null +++ b/src/class.rs @@ -0,0 +1,130 @@ +use core::convert::TryFrom; + +use cortex_m_semihosting::hprintln; + +use crate::{ + constants::*, + pipe::Pipe, +}; + +use usb_device::class_prelude::*; + +type Result = core::result::Result; + +pub struct Ccid +where + Bus: 'static + UsbBus, +{ + interface_number: InterfaceNumber, + pipe: Pipe, + must_send_zlp: bool, +} + +impl Ccid +where + Bus: 'static + UsbBus, +{ + pub fn new(allocator: &'static UsbBusAllocator) -> Self { + let read_endpoint = allocator.bulk(PACKET_SIZE as _); + let write_endpoint = allocator.bulk(PACKET_SIZE as _); + let pipe = Pipe::new(read_endpoint, write_endpoint); + let interface_number = allocator.interface(); + Self { interface_number, pipe, must_send_zlp: false } + } +} + +pub enum ClassRequests { +} + +impl UsbClass for Ccid +where + Bus: 'static + UsbBus, +{ + fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) + -> Result<()> + { + writer.interface( + self.interface_number, + CLASS_CCID, + SUBCLASS_NONE, + TransferMode::Bulk as u8, + )?; + writer.write( + FUNCTIONAL_INTERFACE, + &FUNCTIONAL_INTERFACE_DESCRIPTOR, + )?; + writer.endpoint(&self.pipe.write); + writer.endpoint(&self.pipe.read); + Ok(()) + } + + fn poll(&mut self) { + self.pipe.maybe_write_packet(); + } + + fn endpoint_in_complete(&mut self, addr: EndpointAddress) { + if addr != self.pipe.write.address() { return; } + + if self.must_send_zlp { + self.pipe.write.write(&[]).ok(); + self.must_send_zlp = false; + } else { + self.pipe.maybe_write_packet(); + } + } + + fn endpoint_out(&mut self, addr: EndpointAddress) { + if addr != self.pipe.read.address() { return; } + + self.pipe.read_and_handle_packet(); + } + + fn control_in(&mut self, transfer: ControlIn) { + use usb_device::control::*; + + let Request { request_type, recipient, index, request, .. } = *transfer.request(); + + if index as u8 != u8::from(self.interface_number) { + return; + } + + if (request_type, recipient) == (RequestType::Class, Recipient::Interface) { + match ClassRequest::try_from(request) { + Ok(request) => { + match request { + ClassRequest::Abort => { + // oh yeah? + transfer.reject().ok(); + todo!(); + } + + // not strictly needed, as our bNumClockSupported = 0 + ClassRequest::GetClockFrequencies => { + transfer.accept(|data| { + data.copy_from_slice(&CLOCK_FREQUENCY_KHZ); + Ok(4) + }).ok(); + }, + + // not strictly needed, as our bNumDataRatesSupported = 0 + ClassRequest::GetDataRates => { + transfer.accept(|data| { + data.copy_from_slice(&DATA_RATE_BPS); + Ok(4) + }).ok(); + }, + } + } + + Err(()) => { + hprintln!("unexpected request: {}", request).ok(); + } + } + } + } + + fn control_out(&mut self, transfer: ControlOut) { + // todo!(); + } + +} diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..be1c1b0 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,137 @@ +// can be 8, 16, 32, 64 or 512 +#[cfg(feature = "highspeed-usb")] +pub const PACKET_SIZE: usize = 512; +#[cfg(not(feature = "highspeed-usb"))] +pub const PACKET_SIZE: usize = 64; + +pub const CLASS_CCID: u8 = 0x0B; +pub const SUBCLASS_NONE: u8 = 0x0; + +#[repr(u8)] +pub enum TransferMode { + // bulk transfers, optional interrupt IN + Bulk = 0, + // control transfers, no interrupt IN + ControlA = 1, + // control transfers, optional interrupt IN + ControlB = 2, +} + +pub const FUNCTIONAL_INTERFACE: u8 = 0x21; + +pub enum ClassRequest { + Abort = 1, + GetClockFrequencies = 2, + GetDataRates = 3, +} + +impl core::convert::TryFrom for ClassRequest { + type Error = (); + fn try_from(request: u8) -> core::result::Result { + Ok(match request { + 1 => Self::Abort, + 2 => Self::GetClockFrequencies, + 3 => Self::GetDataRates, + _ => return Err(()), + }) + } +} + +// NB: all numbers are little-endian + +// 4000 KHz = 4MHz +// pub const CLOCK_FREQUENCY: [u8; 4] = 4000u32.to_le_bytes(); +// instead, use Python: `import struct; struct.pack(" +where + Bus: UsbBus + 'static, +{ + pub(crate) read: EndpointOut<'static, Bus>, + pub(crate) write: EndpointIn<'static, Bus>, + // pub(crate) rpc: TransportEndpoint<'rpc>, + packet: Packet, + buffer: [u8; MAX_MSG_LENGTH], +} + +impl Pipe +where + Bus: 'static + UsbBus, +{ + pub(crate) fn new( + read: EndpointOut<'static, Bus>, + write: EndpointIn<'static, Bus>, + ) + -> Self { Self { + read, + write, + packet: Packet { buffer: [0u8; PACKET_SIZE] }, + buffer: [0u8; MAX_MSG_LENGTH], + } } +} + +#[derive(Copy, Clone)] +pub struct Packet { + buffer: [u8; PACKET_SIZE as _], +} + +impl core::fmt::Debug for Packet { + + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut debug_struct = f.debug_struct("Packet"); + let mut debug_struct = match self.msg_type() { + Ok(message_type) => debug_struct.field("type", &message_type), + Err(()) => debug_struct.field("type", &self[0]), + }; + debug_struct + .field("slot", &self.slot()) + .field("seq", &self.slot()) + // other fields? + // .field("data[..16]", &self.data()[..16]) + // .field("data", self.data()) + .finish() + } +} + +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum MessageType { + PowerOn = 0x62, + PowerOff = 0x63, + GetSlotStatus = 0x65, + TransferBlock = 0x6f, +} + +pub struct SlotStatus { + seq: u8 +} + +impl SlotStatus { + pub fn new(seq: u8) -> Self { + Self { seq } + } +} + +impl From for Packet { + fn from(slot_status: SlotStatus) -> Self { + let mut buffer = [0u8; PACKET_SIZE]; + buffer[0] = 0x81; + // buffer[1..5] = 0, no extra data + // buffer[5] = 0, only one slot + buffer[6] = slot_status.seq; + // buffer[7] = 0, status + // buffer[8] = 0, error + // buffer[9] = 0, chain parameter, this is complete + Packet { buffer } + } +} + +pub struct DataBlock<'a> { + seq: u8, + data: &'a [u8], + +} + +impl<'a> DataBlock<'a> { + pub fn new(seq: u8, data: &'a [u8]) -> Self { + assert!(data.len() + 10 <= PACKET_SIZE); + Self { seq, data } + } +} + +impl<'a> From> for Packet { + fn from(data_block: DataBlock) -> Self { + let mut buffer = [0u8; PACKET_SIZE]; + let len = data_block.data.len(); + buffer[0] = 0x80; + buffer[1..5].copy_from_slice(&len.to_le_bytes()); + // buffer[5] = 0, only one slot + buffer[6] = data_block.seq; + // buffer[7] = 0, status + // buffer[8] = 0, error + // buffer[9] = 0, chain parameter, this is complete + buffer[10..][..len].copy_from_slice(data_block.data); + Packet { buffer } + } +} + +impl core::convert::TryFrom for MessageType { + type Error = (); + + fn try_from(message_type_byte: u8) -> core::result::Result { + Ok(match message_type_byte { + 0x62 => Self::PowerOn, + 0x63 => Self::PowerOff, + 0x65 => Self::GetSlotStatus, + 0x6f => Self::TransferBlock, + _ => return Err(()), + }) + } +} + +impl Packet { + #[inline(always)] + pub fn msg_type(&self) -> core::result::Result { + self[0].try_into() + } + + #[inline(always)] + pub fn len(&self) -> usize { + u32::from_le_bytes(self[1..5].try_into().unwrap()) as usize + } + + #[inline(always)] + pub fn slot(&self) -> u8 { + // we have only one slot + assert!(self[5] == 0); + *&self[5] + } + + #[inline(always)] + pub fn seq(&self) -> u8 { *&self[6] } + + // either three message specific bytes, or + // a status field (1 byte), an error field and one message specific byte + + #[inline(always)] + pub fn data(&self) -> &[u8] { &self[10..] } +} + +// impl core::borrow::Borrow<[u8; PACKET_SIZE]> for Packet { +// fn borrow(&self) -> &[u8; PACKET_SIZE] { +// &self.buffer +// } +// } + +// impl core::borrow::BorrowMut<[u8; PACKET_SIZE]> for Packet { +// fn borrow_mut(&mut self) -> &mut [u8; PACKET_SIZE] { +// &mut self.buffer +// } +// } + +impl core::ops::Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + // let len = self.len(); + // &self.buffer[..10 + len] + &self.buffer + } +} + +impl core::ops::DerefMut for Packet { + fn deref_mut(&mut self) -> &mut Self::Target { + // let len = self.len(); + // &mut self.buffer[..10 + len] + &mut self.buffer + } +} + + +impl Pipe +where + Bus: 'static + UsbBus +{ + pub fn read_and_handle_packet(&mut self) { + // let data: &mut [u8; PACKET_SIZE] = self.packet.borrow_mut(); + // let read = match self.read.read(&mut data[..]) { + let read = match self.read.read(&mut self.packet) { + // let read = match self.read.read(&mut self.packet.borrow_mut()[..]) { + Ok(read) => { + // all packets have 10 byte header before eventual data + if read < 10 { panic!("unexpected small packet"); } + read + } + Err(_) => { + // usb-device lists WouldBlock + BufferOverflow as possible errors. + // both should not occur here, and we can't do anything anyway. + panic!("unexpected read error"); + } + }; + + hprintln!("got a packet of len {}: {:?}", read, &self.packet).ok(); + + if let Ok(msg_type) = self.packet.msg_type() { + match msg_type { + MessageType::PowerOff | + MessageType::GetSlotStatus => { + self.send_slot_status(); + } + + MessageType::PowerOn => { + self.send_atr(); + } + + MessageType::TransferBlock => { + // + } + } + } + } + + fn send_slot_status(&self) { + let packet = Packet::from(SlotStatus::new(self.packet.seq())); + hprintln!("answering with: {:?}", &packet).ok(); + match self.write.write(&packet[..10 + packet.len()]) { + Ok(10) => {} + + Ok(n) => panic!("expected to send exactly 10 bytes, sent {}", n), + Err(UsbError::WouldBlock) => panic!("would block not handled yet"), + Err(e) => panic!("unexpected error {:?}", e), + } + } + + fn send_atr(&self) { + let packet = Packet::from(DataBlock::new( + self.packet.seq(), + &[0x3b, 0x8c,0x80,0x01], + )); + hprintln!("answering with: {:?}", &packet).ok(); + + match self.write.write(&packet[..10 + packet.len()]) { + Ok(14) => {} + + Ok(n) => panic!("expected to send exactly 14 bytes, sent {}", n), + Err(UsbError::WouldBlock) => panic!("would block not handled yet"), + Err(e) => panic!("unexpected error {:?}", e), + } + } + + pub fn maybe_write_packet(&mut self) { + // let result = self.write.write(&packet); + + // match result { + // Err(UsbError::WouldBlock) => { + // // fine, can't write try later + // // this shouldn't happen probably + // }, + } + + // pub fn read_address(&self) -> EndpointAddress { + // self.read.address() + // } + + // pub fn write_address(&self) -> EndpointAddress { + // self.write.address() + // } + +}