use crate::server::usb::common::*;
pub fn build_device_descriptor(
vendor_id: u16,
product_id: u16,
device_class: u8,
device_subclass: u8,
device_protocol: u8,
manufacturer_str_index: u8,
product_str_index: u8,
serial_str_index: u8,
) -> Vec<u8> {
vec![
18, descriptor_type::DEVICE, 0x00,
0x02, device_class, device_subclass, device_protocol, 64, (vendor_id & 0xff) as u8, (vendor_id >> 8) as u8, (product_id & 0xff) as u8, (product_id >> 8) as u8, 0x00,
0x01, manufacturer_str_index, product_str_index, serial_str_index, 1, ]
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_hid_keyboard_report_descriptor() -> Vec<u8> {
vec![
0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0, ]
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_hid_keyboard_config_descriptor() -> Vec<u8> {
let mut desc = Vec::new();
desc.extend_from_slice(&[
9, descriptor_type::CONFIGURATION, 34,
0, 1, 1, 0, 0xA0, 50, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE, 0, 0, 1, device_class::HID, 1, 1, 0, ]);
let report_desc = build_hid_keyboard_report_descriptor();
let report_desc_len = report_desc.len() as u16;
desc.extend_from_slice(&[
9, descriptor_type::HID, 0x11,
0x01, 0x00, 0x01, descriptor_type::HID_REPORT, (report_desc_len & 0xff) as u8, (report_desc_len >> 8) as u8, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT, 0x81, transfer_type::INTERRUPT, 0x08,
0x00, 10, ]);
let total_len = desc.len() as u16;
desc[2] = (total_len & 0xff) as u8;
desc[3] = (total_len >> 8) as u8;
desc
}
pub fn build_string_descriptor(s: &str) -> Vec<u8> {
const MAX_CODE_UNITS: usize = (u8::MAX as usize - 2) / 2;
let mut desc = Vec::new();
let mut utf16: Vec<u16> = s.encode_utf16().collect();
if utf16.len() > MAX_CODE_UNITS {
let mut keep = MAX_CODE_UNITS;
if (0xD800..0xDC00).contains(&utf16[keep - 1]) {
keep -= 1;
}
utf16.truncate(keep);
}
let len = 2 + utf16.len() * 2;
desc.push(len as u8); desc.push(descriptor_type::STRING);
for ch in utf16 {
desc.push((ch & 0xff) as u8);
desc.push((ch >> 8) as u8);
}
desc
}
pub fn build_language_id_descriptor() -> Vec<u8> {
vec![
4, descriptor_type::STRING, 0x09,
0x04, ]
}
#[cfg(all(unix, feature = "libusb"))]
pub struct KeyboardReport {
pub modifiers: u8, pub keys: [u8; 6], }
#[cfg(all(unix, feature = "libusb"))]
impl KeyboardReport {
pub fn new() -> Self {
Self {
modifiers: 0,
keys: [0; 6],
}
}
pub fn to_bytes(&self) -> [u8; 8] {
[
self.modifiers,
0, self.keys[0],
self.keys[1],
self.keys[2],
self.keys[3],
self.keys[4],
self.keys[5],
]
}
}
#[cfg(all(unix, feature = "libusb"))]
impl Default for KeyboardReport {
fn default() -> Self {
Self::new()
}
}
#[cfg(all(unix, feature = "libusb"))]
pub mod keyboard_modifiers {
pub const LEFT_CTRL: u8 = 0x01;
pub const LEFT_SHIFT: u8 = 0x02;
pub const LEFT_ALT: u8 = 0x04;
pub const LEFT_GUI: u8 = 0x08;
pub const RIGHT_CTRL: u8 = 0x10;
pub const RIGHT_SHIFT: u8 = 0x20;
pub const RIGHT_ALT: u8 = 0x40;
pub const RIGHT_GUI: u8 = 0x80;
}
#[cfg(all(unix, feature = "libusb"))]
pub mod keyboard_usage {
pub const NONE: u8 = 0x00;
pub const ERROR_ROLLOVER: u8 = 0x01;
pub const A: u8 = 0x04;
pub const B: u8 = 0x05;
pub const C: u8 = 0x06;
pub const D: u8 = 0x07;
pub const E: u8 = 0x08;
pub const F: u8 = 0x09;
pub const G: u8 = 0x0a;
pub const H: u8 = 0x0b;
pub const I: u8 = 0x0c;
pub const J: u8 = 0x0d;
pub const K: u8 = 0x0e;
pub const L: u8 = 0x0f;
pub const M: u8 = 0x10;
pub const N: u8 = 0x11;
pub const O: u8 = 0x12;
pub const P: u8 = 0x13;
pub const Q: u8 = 0x14;
pub const R: u8 = 0x15;
pub const S: u8 = 0x16;
pub const T: u8 = 0x17;
pub const U: u8 = 0x18;
pub const V: u8 = 0x19;
pub const W: u8 = 0x1a;
pub const X: u8 = 0x1b;
pub const Y: u8 = 0x1c;
pub const Z: u8 = 0x1d;
pub const NUM_1: u8 = 0x1e;
pub const NUM_2: u8 = 0x1f;
pub const NUM_3: u8 = 0x20;
pub const NUM_4: u8 = 0x21;
pub const NUM_5: u8 = 0x22;
pub const NUM_6: u8 = 0x23;
pub const NUM_7: u8 = 0x24;
pub const NUM_8: u8 = 0x25;
pub const NUM_9: u8 = 0x26;
pub const NUM_0: u8 = 0x27;
pub const ENTER: u8 = 0x28;
pub const ESCAPE: u8 = 0x29;
pub const BACKSPACE: u8 = 0x2a;
pub const TAB: u8 = 0x2b;
pub const SPACE: u8 = 0x2c;
pub const MINUS: u8 = 0x2d;
pub const EQUALS: u8 = 0x2e;
pub const LEFT_BRACKET: u8 = 0x2f;
pub const RIGHT_BRACKET: u8 = 0x30;
pub const BACKSLASH: u8 = 0x31;
pub const SEMICOLON: u8 = 0x33;
pub const QUOTE: u8 = 0x34;
pub const GRAVE: u8 = 0x35;
pub const COMMA: u8 = 0x36;
pub const PERIOD: u8 = 0x37;
pub const SLASH: u8 = 0x38;
pub const CAPS_LOCK: u8 = 0x39;
pub const F1: u8 = 0x3a;
pub const F2: u8 = 0x3b;
pub const F3: u8 = 0x3c;
pub const F4: u8 = 0x3d;
pub const F5: u8 = 0x3e;
pub const F6: u8 = 0x3f;
pub const F7: u8 = 0x40;
pub const F8: u8 = 0x41;
pub const F9: u8 = 0x42;
pub const F10: u8 = 0x43;
pub const F11: u8 = 0x44;
pub const F12: u8 = 0x45;
}
#[cfg(all(unix, feature = "libusb"))]
pub fn char_to_usage(ch: char) -> Option<(u8, bool)> {
match ch {
'a'..='z' => Some((keyboard_usage::A + (ch as u8 - b'a'), false)),
'A'..='Z' => Some((keyboard_usage::A + (ch as u8 - b'A'), true)),
'1'..='9' => Some((keyboard_usage::NUM_1 + (ch as u8 - b'1'), false)),
'0' => Some((keyboard_usage::NUM_0, false)),
' ' => Some((keyboard_usage::SPACE, false)),
'\n' => Some((keyboard_usage::ENTER, false)),
'\t' => Some((keyboard_usage::TAB, false)),
'-' => Some((keyboard_usage::MINUS, false)),
'_' => Some((keyboard_usage::MINUS, true)),
'=' => Some((keyboard_usage::EQUALS, false)),
'+' => Some((keyboard_usage::EQUALS, true)),
'[' => Some((keyboard_usage::LEFT_BRACKET, false)),
'{' => Some((keyboard_usage::LEFT_BRACKET, true)),
']' => Some((keyboard_usage::RIGHT_BRACKET, false)),
'}' => Some((keyboard_usage::RIGHT_BRACKET, true)),
'\\' => Some((keyboard_usage::BACKSLASH, false)),
'|' => Some((keyboard_usage::BACKSLASH, true)),
';' => Some((keyboard_usage::SEMICOLON, false)),
':' => Some((keyboard_usage::SEMICOLON, true)),
'\'' => Some((keyboard_usage::QUOTE, false)),
'"' => Some((keyboard_usage::QUOTE, true)),
'`' => Some((keyboard_usage::GRAVE, false)),
'~' => Some((keyboard_usage::GRAVE, true)),
',' => Some((keyboard_usage::COMMA, false)),
'<' => Some((keyboard_usage::COMMA, true)),
'.' => Some((keyboard_usage::PERIOD, false)),
'>' => Some((keyboard_usage::PERIOD, true)),
'/' => Some((keyboard_usage::SLASH, false)),
'?' => Some((keyboard_usage::SLASH, true)),
'!' => Some((keyboard_usage::NUM_1, true)),
'@' => Some((keyboard_usage::NUM_2, true)),
'#' => Some((keyboard_usage::NUM_3, true)),
'$' => Some((keyboard_usage::NUM_4, true)),
'%' => Some((keyboard_usage::NUM_5, true)),
'^' => Some((keyboard_usage::NUM_6, true)),
'&' => Some((keyboard_usage::NUM_7, true)),
'*' => Some((keyboard_usage::NUM_8, true)),
'(' => Some((keyboard_usage::NUM_9, true)),
')' => Some((keyboard_usage::NUM_0, true)),
_ => None,
}
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_hid_mouse_report_descriptor() -> Vec<u8> {
vec![
0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x01, 0x81, 0x06, 0xC0, 0xC0, ]
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_hid_mouse_config_descriptor() -> Vec<u8> {
let mut desc = Vec::new();
desc.extend_from_slice(&[
9, descriptor_type::CONFIGURATION, 34,
0, 1, 1, 0, 0xA0, 50, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE, 0, 0, 1, device_class::HID, 1, 2, 0, ]);
let report_desc = build_hid_mouse_report_descriptor();
let report_desc_len = report_desc.len() as u16;
desc.extend_from_slice(&[
9, descriptor_type::HID, 0x11,
0x01, 0x00, 0x01, descriptor_type::HID_REPORT, (report_desc_len & 0xff) as u8, (report_desc_len >> 8) as u8, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT, 0x81, transfer_type::INTERRUPT, 0x04,
0x00, 10, ]);
let total_len = desc.len() as u16;
desc[2] = (total_len & 0xff) as u8;
desc[3] = (total_len >> 8) as u8;
desc
}
#[cfg(all(unix, feature = "libusb"))]
pub struct MouseReport {
pub buttons: u8, pub x: i8, pub y: i8, pub wheel: i8, }
#[cfg(all(unix, feature = "libusb"))]
impl MouseReport {
pub fn new() -> Self {
Self {
buttons: 0,
x: 0,
y: 0,
wheel: 0,
}
}
pub fn to_bytes(&self) -> [u8; 4] {
[self.buttons, self.x as u8, self.y as u8, self.wheel as u8]
}
}
#[cfg(all(unix, feature = "libusb"))]
impl Default for MouseReport {
fn default() -> Self {
Self::new()
}
}
#[cfg(all(unix, feature = "libusb"))]
pub mod mouse_buttons {
pub const LEFT: u8 = 0x01;
pub const RIGHT: u8 = 0x02;
pub const MIDDLE: u8 = 0x04;
}
#[cfg(all(unix, feature = "libusb"))]
pub const FIDO_HID_REPORT_DESCRIPTOR: &[u8] = &[
0x06, 0xD0, 0xF1, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91, 0x02, 0xC0, ];
#[cfg(all(unix, feature = "libusb"))]
pub fn build_fido2_hid_config_descriptor() -> Vec<u8> {
let mut desc = Vec::new();
desc.extend_from_slice(&[
9, descriptor_type::CONFIGURATION,
34,
0, 1, 1, 0, 0xA0, 50, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE,
0, 0, 2, device_class::HID, 0, 0, 0, ]);
desc.extend_from_slice(&[
9, descriptor_type::HID, 0x11,
0x01, 0, 1, descriptor_type::HID_REPORT, (FIDO_HID_REPORT_DESCRIPTOR.len() & 0xFF) as u8,
((FIDO_HID_REPORT_DESCRIPTOR.len() >> 8) & 0xFF) as u8,
]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x81, 0x03, 64,
0, 5, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x01, 0x03, 64,
0, 5, ]);
let total_len = desc.len() as u16;
desc[2] = (total_len & 0xFF) as u8;
desc[3] = ((total_len >> 8) & 0xFF) as u8;
desc
}
#[cfg(all(unix, feature = "libusb"))]
pub mod cdc_descriptor_subtype {
pub const HEADER: u8 = 0x00;
pub const CALL_MANAGEMENT: u8 = 0x01;
pub const ACM: u8 = 0x02;
pub const UNION: u8 = 0x06;
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_cdc_acm_config_descriptor() -> Vec<u8> {
let mut desc = Vec::new();
desc.extend_from_slice(&[
9, descriptor_type::CONFIGURATION,
67,
0, 2, 1, 0, 0xC0, 50, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE,
0, 0, 1, device_class::COMM, 0x02, 0x01, 0, ]);
desc.extend_from_slice(&[
5, 0x24, cdc_descriptor_subtype::HEADER,
0x10,
0x01, ]);
desc.extend_from_slice(&[
5, 0x24, cdc_descriptor_subtype::CALL_MANAGEMENT,
0x00, 0x01, ]);
desc.extend_from_slice(&[
4, 0x24, cdc_descriptor_subtype::ACM,
0x02, ]);
desc.extend_from_slice(&[
5, 0x24, cdc_descriptor_subtype::UNION,
0x00, 0x01, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x81, transfer_type::INTERRUPT,
0x08,
0x00, 16, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE,
1, 0, 2, device_class::CDC_DATA, 0x00, 0x00, 0, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x02, transfer_type::BULK,
0x40,
0x00, 0, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x83, transfer_type::BULK,
0x40,
0x00, 0, ]);
let total_len = desc.len() as u16;
desc[2] = (total_len & 0xff) as u8;
desc[3] = (total_len >> 8) as u8;
desc
}
#[cfg(all(unix, feature = "libusb"))]
#[derive(Debug, Clone, Copy)]
pub struct LineCoding {
pub baud_rate: u32, pub stop_bits: u8, pub parity: u8, pub data_bits: u8, }
#[cfg(all(unix, feature = "libusb"))]
impl LineCoding {
pub fn default_115200_8n1() -> Self {
Self {
baud_rate: 115200,
stop_bits: 0, parity: 0, data_bits: 8,
}
}
pub fn to_bytes(&self) -> [u8; 7] {
[
(self.baud_rate & 0xff) as u8,
((self.baud_rate >> 8) & 0xff) as u8,
((self.baud_rate >> 16) & 0xff) as u8,
((self.baud_rate >> 24) & 0xff) as u8,
self.stop_bits,
self.parity,
self.data_bits,
]
}
pub const WIRE_LEN: usize = 7;
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let b: &[u8; Self::WIRE_LEN] = bytes.get(..Self::WIRE_LEN)?.try_into().ok()?;
Some(Self {
baud_rate: u32::from_le_bytes([b[0], b[1], b[2], b[3]]),
stop_bits: b[4],
parity: b[5],
data_bits: b[6],
})
}
}
#[cfg(all(unix, feature = "libusb"))]
#[derive(Debug, Clone, Copy)]
pub struct ControlLineState {
pub dtr: bool, pub rts: bool, }
#[cfg(all(unix, feature = "libusb"))]
impl ControlLineState {
pub fn from_value(value: u16) -> Self {
Self {
dtr: (value & 0x01) != 0,
rts: (value & 0x02) != 0,
}
}
pub fn to_value(&self) -> u16 {
let mut value = 0u16;
if self.dtr {
value |= 0x01;
}
if self.rts {
value |= 0x02;
}
value
}
}
#[cfg(all(unix, feature = "libusb"))]
pub fn build_msc_config_descriptor() -> Vec<u8> {
let mut desc = Vec::new();
desc.extend_from_slice(&[
9, descriptor_type::CONFIGURATION,
32,
0, 1, 1, 0, 0xC0, 50, ]);
desc.extend_from_slice(&[
9, descriptor_type::INTERFACE,
0, 0, 2, 0x08, 0x06, 0x50, 0, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x81, transfer_type::BULK, 0x00,
0x02, 0, ]);
desc.extend_from_slice(&[
7, descriptor_type::ENDPOINT,
0x02, transfer_type::BULK, 0x00,
0x02, 0, ]);
let total_len = desc.len() as u16;
desc[2] = (total_len & 0xff) as u8;
desc[3] = (total_len >> 8) as u8;
desc
}
#[cfg(all(unix, feature = "libusb"))]
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct CommandBlockWrapper {
pub signature: u32, pub tag: u32, pub data_transfer_length: u32, pub flags: u8, pub lun: u8, pub cb_length: u8, pub cb: [u8; 16], }
#[cfg(all(unix, feature = "libusb"))]
impl CommandBlockWrapper {
pub const SIGNATURE: u32 = 0x43425355; pub const SIZE: usize = 31;
pub fn parse(data: &[u8]) -> Option<Self> {
if data.len() != Self::SIZE {
return None;
}
let signature = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
if signature != Self::SIGNATURE {
return None;
}
let tag = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
let data_transfer_length = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
let flags = data[12];
let lun = data[13];
let cb_length = data[14];
let mut cb = [0u8; 16];
cb.copy_from_slice(&data[15..31]);
Some(Self {
signature,
tag,
data_transfer_length,
flags,
lun,
cb_length,
cb,
})
}
pub fn is_data_in(&self) -> bool {
(self.flags & 0x80) != 0
}
pub fn scsi_command(&self) -> &[u8] {
&self.cb[0..(self.cb_length as usize).min(16)]
}
}
#[cfg(all(unix, feature = "libusb"))]
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct CommandStatusWrapper {
pub signature: u32, pub tag: u32, pub data_residue: u32, pub status: u8, }
#[cfg(all(unix, feature = "libusb"))]
impl CommandStatusWrapper {
pub const SIGNATURE: u32 = 0x53425355; pub const SIZE: usize = 13;
pub const STATUS_PASSED: u8 = 0x00;
pub const STATUS_FAILED: u8 = 0x01;
pub const STATUS_PHASE_ERROR: u8 = 0x02;
pub fn new(tag: u32, data_residue: u32, status: u8) -> Self {
Self {
signature: Self::SIGNATURE,
tag,
data_residue,
status,
}
}
pub fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut bytes = [0u8; Self::SIZE];
bytes[0..4].copy_from_slice(&self.signature.to_le_bytes());
bytes[4..8].copy_from_slice(&self.tag.to_le_bytes());
bytes[8..12].copy_from_slice(&self.data_residue.to_le_bytes());
bytes[12] = self.status;
bytes
}
}
#[cfg(all(unix, feature = "libusb"))]
pub mod scsi_opcode {
pub const TEST_UNIT_READY: u8 = 0x00;
pub const REQUEST_SENSE: u8 = 0x03;
pub const INQUIRY: u8 = 0x12;
pub const MODE_SENSE_6: u8 = 0x1A;
pub const START_STOP_UNIT: u8 = 0x1B;
pub const PREVENT_ALLOW_MEDIUM_REMOVAL: u8 = 0x1E;
pub const READ_FORMAT_CAPACITIES: u8 = 0x23;
pub const READ_CAPACITY_10: u8 = 0x25;
pub const READ_10: u8 = 0x28;
pub const WRITE_10: u8 = 0x2A;
}
#[cfg(all(unix, feature = "libusb"))]
pub mod scsi_sense_key {
pub const NO_SENSE: u8 = 0x00;
pub const RECOVERED_ERROR: u8 = 0x01;
pub const NOT_READY: u8 = 0x02;
pub const MEDIUM_ERROR: u8 = 0x03;
pub const HARDWARE_ERROR: u8 = 0x04;
pub const ILLEGAL_REQUEST: u8 = 0x05;
pub const UNIT_ATTENTION: u8 = 0x06;
pub const DATA_PROTECT: u8 = 0x07;
pub const ABORTED_COMMAND: u8 = 0x0B;
}