IT WORKS!

This commit is contained in:
4lDO2
2020-02-08 17:18:09 +01:00
parent 3fd4bc4b3b
commit 1013daf606
11 changed files with 281 additions and 35 deletions
Generated
+1
View File
@@ -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",
]
+1
View File
@@ -0,0 +1 @@
/target
+66 -5
View File
@@ -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))
}
}
}
+80 -6
View File
@@ -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
View File
@@ -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> {
+45
View File
@@ -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
}
+1
View File
@@ -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" }
+7 -2
View File
@@ -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);
}
+30 -5
View File
@@ -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)
}
+24 -4
View File
@@ -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,
}
}
+8 -3
View File
@@ -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> {