IT WORKS!
This commit is contained in:
Generated
+1
@@ -1336,6 +1336,7 @@ dependencies = [
|
||||
name = "usbscsid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xhcid 0.1.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/target
|
||||
+66
-5
@@ -1,11 +1,17 @@
|
||||
use std::env;
|
||||
|
||||
use xhcid_interface::{DevDesc, PortReqRecipient, XhciClientHandle};
|
||||
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle};
|
||||
|
||||
mod report_desc;
|
||||
mod reqs;
|
||||
mod usage_tables;
|
||||
|
||||
use report_desc::{ReportFlatIter, ReportIter, REPORT_DESC_TY};
|
||||
use report_desc::{MainCollectionFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY};
|
||||
use reqs::ReportTy;
|
||||
|
||||
fn div_round_up(num: u32, denom: u32) -> u32 {
|
||||
if num % denom == 0 { num / denom } else { num / denom + 1 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
@@ -48,9 +54,64 @@ fn main() {
|
||||
)
|
||||
.expect("Failed to retrieve report descriptor");
|
||||
|
||||
let iterator = ReportIter::new(ReportFlatIter::new(&report_desc_bytes));
|
||||
let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::<Vec<_>>();
|
||||
|
||||
for item in iterator {
|
||||
println!("HID ITEM {:?}", item);
|
||||
for item in &report_desc {
|
||||
println!("{:?}", item);
|
||||
}
|
||||
|
||||
handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints");
|
||||
|
||||
let (mut state, mut stack) = (GlobalItemsState::default(), Vec::new());
|
||||
|
||||
let (_, application_collection) = report_desc.iter().inspect(|item: &&ReportIterItem| if let ReportIterItem::Item(ref item) = item {
|
||||
report_desc::update_state(&mut state, &mut stack, item).unwrap()
|
||||
}).filter_map(ReportIterItem::as_collection).find(|&(n, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection");
|
||||
|
||||
// Get all main items, and their global item options.
|
||||
{
|
||||
let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item {
|
||||
ReportItem::Global(_) => {
|
||||
report_desc::update_state(&mut state, &mut stack, item).unwrap();
|
||||
None
|
||||
}
|
||||
ReportItem::Main(m) => Some((state, m)),
|
||||
ReportItem::Local(_) => None,
|
||||
});
|
||||
let total_length = items.filter_map(|(state, item)| {
|
||||
let report_size = match state.report_size {
|
||||
Some(s) => s,
|
||||
None => return None,
|
||||
};
|
||||
let report_count = match state.report_count {
|
||||
Some(c) => c,
|
||||
None => return None,
|
||||
};
|
||||
let bit_length = report_size * report_count;
|
||||
|
||||
if item.report_ty() != Some(ReportTy::Input) {
|
||||
return None;
|
||||
}
|
||||
Some(bit_length)
|
||||
}).sum();
|
||||
let length = div_round_up(total_length, 8);
|
||||
|
||||
let mut report_buffer = vec! [0u8; length as usize];
|
||||
let mut last_buffer = report_buffer.clone();
|
||||
let report_ty = ReportTy::Input;
|
||||
let report_id = 0;
|
||||
|
||||
loop {
|
||||
std::mem::swap(&mut report_buffer, &mut last_buffer);
|
||||
reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report");
|
||||
if report_buffer != last_buffer {
|
||||
for byte in &report_buffer {
|
||||
print!("{:#0x} ", byte);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(10))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use bitflags::bitflags;
|
||||
use ux::{u2, u4};
|
||||
|
||||
use crate::reqs::ReportTy;
|
||||
|
||||
/*#[repr(u8)]
|
||||
enum Protocol {
|
||||
|
||||
@@ -40,6 +42,16 @@ pub enum MainItem {
|
||||
Collection(u8),
|
||||
EndOfCollection,
|
||||
}
|
||||
impl MainItem {
|
||||
pub fn report_ty(&self) -> Option<ReportTy> {
|
||||
match self {
|
||||
Self::Input(_) => Some(ReportTy::Input),
|
||||
Self::Output(_) => Some(ReportTy::Output),
|
||||
Self::Feature(_) => Some(ReportTy::Feature),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum GlobalItem {
|
||||
UsagePage(u32),
|
||||
@@ -50,11 +62,51 @@ pub enum GlobalItem {
|
||||
UnitExponent(u32),
|
||||
Unit(u32),
|
||||
ReportSize(u32),
|
||||
RepordId(u32),
|
||||
ReportId(u32),
|
||||
ReportCount(u32),
|
||||
Push(u32),
|
||||
Pop(u32),
|
||||
Push,
|
||||
Pop,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct GlobalItemsState {
|
||||
pub usage_page: Option<u32>,
|
||||
pub logical_min: Option<u32>,
|
||||
pub logical_max: Option<u32>,
|
||||
pub physical_min: Option<u32>,
|
||||
pub physical_max: Option<u32>,
|
||||
pub unit_exponent: Option<u32>,
|
||||
pub unit: Option<u32>,
|
||||
pub report_size: Option<u32>,
|
||||
pub report_id: Option<u32>,
|
||||
pub report_count: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Invalid;
|
||||
|
||||
pub fn update_state(current_state: &mut GlobalItemsState, stack: &mut Vec<GlobalItemsState>, report_item: &ReportItem) -> Result<(), Invalid> {
|
||||
match report_item {
|
||||
ReportItem::Global(global) => match global {
|
||||
&GlobalItem::UsagePage(u) => current_state.usage_page = Some(u),
|
||||
&GlobalItem::LogicalMinimum(m) => current_state.logical_min = Some(m),
|
||||
&GlobalItem::LogicalMaximum(m) => current_state.logical_max = Some(m),
|
||||
&GlobalItem::PhysicalMinimum(m) => current_state.physical_min = Some(m),
|
||||
&GlobalItem::PhysicalMaximum(m) => current_state.physical_max = Some(m),
|
||||
&GlobalItem::UnitExponent(e) => current_state.unit_exponent = Some(e),
|
||||
&GlobalItem::Unit(u) => current_state.unit = Some(u),
|
||||
&GlobalItem::ReportSize(s) => current_state.report_size = Some(s),
|
||||
&GlobalItem::ReportId(i) => current_state.report_id = Some(i),
|
||||
&GlobalItem::ReportCount(c) => current_state.report_count = Some(c),
|
||||
&GlobalItem::Push => stack.push(*current_state),
|
||||
&GlobalItem::Pop => *current_state = stack.pop().ok_or(Invalid)?,
|
||||
}
|
||||
ReportItem::Local(local) => (), // TODO
|
||||
ReportItem::Main(_) => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LocalItem {
|
||||
Usage(u32),
|
||||
@@ -74,6 +126,14 @@ pub enum ReportItem {
|
||||
Global(GlobalItem),
|
||||
Local(LocalItem),
|
||||
}
|
||||
impl ReportItem {
|
||||
pub fn as_main_item(&self) -> Option<&MainItem> {
|
||||
match self {
|
||||
Self::Main(m) => Some(m),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<MainItem> for ReportItem {
|
||||
fn from(main: MainItem) -> Self {
|
||||
Self::Main(main)
|
||||
@@ -135,10 +195,10 @@ impl ReportItem {
|
||||
0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size),
|
||||
0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size),
|
||||
0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size),
|
||||
0b1000 => (GlobalItem::RepordId(value).into(), 1 + real_size),
|
||||
0b1000 => (GlobalItem::ReportId(value).into(), 1 + real_size),
|
||||
0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size),
|
||||
0b1010 => (GlobalItem::Push(value).into(), 1 + real_size),
|
||||
0b1011 => (GlobalItem::Pop(value).into(), 1 + real_size),
|
||||
0b1010 => (GlobalItem::Push.into(), 1),
|
||||
0b1011 => (GlobalItem::Pop.into(), 1),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
@@ -232,6 +292,20 @@ pub enum ReportIterItem {
|
||||
Item(ReportItem),
|
||||
Collection(u8, Vec<ReportIterItem>),
|
||||
}
|
||||
impl ReportIterItem {
|
||||
pub fn as_item(&self) -> Option<&ReportItem> {
|
||||
match self {
|
||||
Self::Item(i) => Some(i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_collection(&self) -> Option<(u8, &[ReportIterItem])> {
|
||||
match self {
|
||||
&Self::Collection(n, ref c) => Some((n, c)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> ReportIter<'a> {
|
||||
pub fn new(flat: ReportFlatIter<'a>) -> Self {
|
||||
Self {
|
||||
|
||||
+18
-10
@@ -11,13 +11,21 @@ const SET_IDLE_REQ: u8 = 0xA;
|
||||
const GET_PROTOCOL_REQ: u8 = 0x3;
|
||||
const SET_PROTOCOL_REQ: u8 = 0xB;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ReportTy {
|
||||
Input = 1,
|
||||
Output,
|
||||
Feature,
|
||||
}
|
||||
|
||||
fn concat(hi: u8, lo: u8) -> u16 {
|
||||
(u16::from(hi) << 8) | u16::from(lo)
|
||||
}
|
||||
|
||||
pub fn get_report(
|
||||
handle: &mut XhciClientHandle,
|
||||
report_ty: u8,
|
||||
handle: &XhciClientHandle,
|
||||
report_ty: ReportTy,
|
||||
report_id: u8,
|
||||
if_num: u16,
|
||||
buffer: &mut [u8],
|
||||
@@ -26,14 +34,14 @@ pub fn get_report(
|
||||
PortReqTy::Class,
|
||||
PortReqRecipient::Interface,
|
||||
GET_REPORT_REQ,
|
||||
concat(report_ty, report_id),
|
||||
concat(report_ty as u8, report_id),
|
||||
if_num,
|
||||
DeviceReqData::In(buffer),
|
||||
)
|
||||
}
|
||||
pub fn set_report(
|
||||
handle: &mut XhciClientHandle,
|
||||
report_ty: u8,
|
||||
handle: &XhciClientHandle,
|
||||
report_ty: ReportTy,
|
||||
report_id: u8,
|
||||
if_num: u16,
|
||||
buffer: &[u8],
|
||||
@@ -42,13 +50,13 @@ pub fn set_report(
|
||||
PortReqTy::Class,
|
||||
PortReqRecipient::Interface,
|
||||
SET_REPORT_REQ,
|
||||
concat(report_id, report_ty),
|
||||
concat(report_id, report_ty as u8),
|
||||
if_num,
|
||||
DeviceReqData::Out(buffer),
|
||||
)
|
||||
}
|
||||
pub fn get_idle(
|
||||
handle: &mut XhciClientHandle,
|
||||
handle: &XhciClientHandle,
|
||||
report_id: u8,
|
||||
if_num: u16,
|
||||
) -> Result<u8, XhciClientHandleError> {
|
||||
@@ -65,7 +73,7 @@ pub fn get_idle(
|
||||
Ok(idle_rate)
|
||||
}
|
||||
pub fn set_idle(
|
||||
handle: &mut XhciClientHandle,
|
||||
handle: &XhciClientHandle,
|
||||
duration: u8,
|
||||
report_id: u8,
|
||||
if_num: u16,
|
||||
@@ -80,7 +88,7 @@ pub fn set_idle(
|
||||
)
|
||||
}
|
||||
pub fn get_protocol(
|
||||
handle: &mut XhciClientHandle,
|
||||
handle: &XhciClientHandle,
|
||||
if_num: u16,
|
||||
) -> Result<u8, XhciClientHandleError> {
|
||||
let mut protocol = 0;
|
||||
@@ -96,7 +104,7 @@ pub fn get_protocol(
|
||||
Ok(protocol)
|
||||
}
|
||||
pub fn set_protocol(
|
||||
handle: &mut XhciClientHandle,
|
||||
handle: &XhciClientHandle,
|
||||
protocol: u8,
|
||||
if_num: u16,
|
||||
) -> Result<(), XhciClientHandleError> {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum UsagePage {
|
||||
GenericDesktop = 1,
|
||||
SimulationsControl,
|
||||
VrControls,
|
||||
SportControls,
|
||||
GameControls,
|
||||
GenericDeviceControls,
|
||||
KeyboardOrKeypad,
|
||||
Led,
|
||||
Button,
|
||||
Ordinal,
|
||||
TelephonyDevice,
|
||||
Consumer,
|
||||
Digitizer,
|
||||
Unicode = 0x10,
|
||||
AlphanumericDisplay = 0x14,
|
||||
MedicalInstrument = 0x40,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum GenericDesktopUsage {
|
||||
Pointer = 0x01,
|
||||
Mouse,
|
||||
Joystick = 0x04,
|
||||
GamePad,
|
||||
Keyboard,
|
||||
Keypad,
|
||||
MultiAxisController,
|
||||
|
||||
// 0x0A-0x2F are reserved
|
||||
|
||||
CountedBuffer = 0x3A,
|
||||
SysControl = 0x80,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum KeyboardOrKeypadUsage {
|
||||
KbdErrorRollover = 0x1,
|
||||
KbdPostFail,
|
||||
KbdErrorUndefined,
|
||||
// the rest are used as regular keycodes
|
||||
}
|
||||
@@ -8,4 +8,5 @@ license = "MIT"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1"
|
||||
xhcid = { path = "../xhcid" }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::env;
|
||||
|
||||
use xhcid_interface::XhciClientHandle;
|
||||
|
||||
pub mod protocol;
|
||||
|
||||
fn main() {
|
||||
@@ -8,8 +10,11 @@ fn main() {
|
||||
const USAGE: &'static str = "usbscsid <scheme> <port> <protocol>";
|
||||
|
||||
let scheme = args.next().expect(USAGE);
|
||||
let port = args.next().expect(USAGE);
|
||||
let protocol = args.next().expect(USAGE);
|
||||
let port = args.next().expect(USAGE).parse::<usize>().expect("port has to be a number");
|
||||
let protocol = args.next().expect(USAGE).parse::<u8>().expect("protocol has to be a number 0-255");
|
||||
|
||||
println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol);
|
||||
|
||||
let handle = XhciClientHandle::new(scheme, port);
|
||||
let protocol = protocol::setup(&handle, protocol);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use super::Protocol;
|
||||
use std::slice;
|
||||
|
||||
use thiserror::Error;
|
||||
use xhcid_interface::{DeviceReqData, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError};
|
||||
|
||||
use super::{Protocol, ProtocolError};
|
||||
|
||||
pub const CBW_SIGNATURE: u32 = 0x43425355;
|
||||
|
||||
@@ -35,13 +40,33 @@ pub struct CommandStatusWrapper {
|
||||
pub status: u8,
|
||||
}
|
||||
|
||||
pub struct BulkOnlyTransport;
|
||||
pub struct BulkOnlyTransport<'a> {
|
||||
handle: &'a XhciClientHandle,
|
||||
}
|
||||
|
||||
impl Protocol for BulkOnlyTransport {
|
||||
fn send_command_block(&mut self, cb: &[u8]) {
|
||||
impl<'a> BulkOnlyTransport<'a> {
|
||||
pub fn init(handle: &'a XhciClientHandle) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Protocol for BulkOnlyTransport<'a> {
|
||||
fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError> {
|
||||
todo!()
|
||||
}
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]) {
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> Result<(), XhciClientHandleError> {
|
||||
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData)
|
||||
}
|
||||
pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result<u8, XhciClientHandleError> {
|
||||
let mut lun = 0;
|
||||
let buffer = slice::from_mut(&mut lun);
|
||||
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?;
|
||||
Ok(lun)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
use thiserror::Error;
|
||||
use xhcid_interface::{XhciClientHandle, XhciClientHandleError};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProtocolError {
|
||||
#[error("Too large command block ({0} > 16)")]
|
||||
TooLargeCommandBlock(usize),
|
||||
|
||||
#[error("xhcid connection error: {0}")]
|
||||
XhciError(#[from] XhciClientHandleError),
|
||||
}
|
||||
|
||||
pub trait Protocol {
|
||||
fn send_command_block(&mut self, cb: &[u8]);
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]);
|
||||
fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError>;
|
||||
fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError>;
|
||||
}
|
||||
|
||||
/// Bulk-only transport
|
||||
pub mod bot;
|
||||
|
||||
/// Control-Bulk-Interface transpoint
|
||||
mod cbi {
|
||||
mod uas {
|
||||
// TODO
|
||||
}
|
||||
|
||||
use bot::BulkOnlyTransport;
|
||||
|
||||
pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8) -> Option<Box<dyn Protocol + 'a>> {
|
||||
match protocol {
|
||||
0x50 => Some(Box::new(BulkOnlyTransport::init(handle).unwrap())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ pub extern crate serde;
|
||||
pub extern crate smallvec;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::{io, result, str};
|
||||
|
||||
@@ -315,8 +315,13 @@ impl XhciClientHandle {
|
||||
&self,
|
||||
req: &ConfigureEndpointsReq,
|
||||
) -> result::Result<(), XhciClientHandleError> {
|
||||
let path = format!("{}:port{}/configure_endpoints", self.scheme, self.port);
|
||||
serde_json::to_writer(File::open(path)?, req)?;
|
||||
let path = format!("{}:port{}/configure", self.scheme, self.port);
|
||||
let json = serde_json::to_vec(req)?;
|
||||
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
|
||||
let json_bytes_written = file.write(&json)?;
|
||||
if json_bytes_written != json.len() {
|
||||
return Err(XhciClientHandleError::InvalidResponse(Invalid));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn port_state(&self) -> result::Result<PortState, XhciClientHandleError> {
|
||||
|
||||
Reference in New Issue
Block a user