Implement HID report descriptor handling

This commit is contained in:
Marc Riera Irigoyen 2023-04-16 14:23:26 +02:00
parent bb969204d0
commit 029f5c7af3
3 changed files with 108 additions and 31 deletions

View file

@ -20,7 +20,7 @@ const ENDPOINT0: &str = "/tmp/ffs/ep0";
const ENDPOINT1: &str = "/tmp/ffs/ep1";
const ANDROID_GADGET: &str = "/sys/class/android_usb/android0";
#[derive(PartialEq)]
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum ControllerModel {
DGOC44U,
TCPP20009,
@ -43,49 +43,55 @@ pub struct DeviceDescriptor {
}
pub fn set_model(state: &ControllerState) -> Option<ControllerModel> {
if state.button_right {
println!("Selected controller DGOC44-U.");
init_gadget(&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS);
return Some(ControllerModel::DGOC44U);
let model;
let model_name;
let descriptors: (&DeviceDescriptor, &[u8], &[u8]);
if !state.button_right {
model_name = "DGOC44-U";
model = ControllerModel::DGOC44U;
descriptors = (&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS);
}
else if state.button_d {
println!("Selected controller TCPP-20009.");
init_gadget(&tcpp20009::DEVICE_DESCRIPTOR, &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS);
return Some(ControllerModel::TCPP20009);
model_name = "TCPP-20009";
model = ControllerModel::TCPP20009;
descriptors = (&tcpp20009::DEVICE_DESCRIPTOR, &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS);
}
else if state.button_b {
println!("Selected controller TCPP-20011.");
init_gadget(&tcpp20011::DEVICE_DESCRIPTOR, &tcpp20011::DESCRIPTORS, &tcpp20011::STRINGS);
return Some(ControllerModel::TCPP20011);
model_name = "TCPP-20011";
model = ControllerModel::TCPP20011;
descriptors = (&tcpp20011::DEVICE_DESCRIPTOR, &tcpp20011::DESCRIPTORS, &tcpp20011::STRINGS);
}
else if state.button_c && state.power == 0 {
println!("Selected controller SOTP-031201 (P4/B7 mode).");
init_gadget(&sotp031201_p4b7::DEVICE_DESCRIPTOR, &sotp031201_p4b7::DESCRIPTORS, &sotp031201_p4b7::STRINGS);
return Some(ControllerModel::SOTP031201P4B7);
model_name = "SOTP-031201 (P4/B7 mode)";
model = ControllerModel::SOTP031201P4B7;
descriptors = (&sotp031201_p4b7::DEVICE_DESCRIPTOR, &sotp031201_p4b7::DESCRIPTORS, &sotp031201_p4b7::STRINGS);
}
else if state.button_c && state.power == 1 {
println!("Selected controller SOTP-031201 (P4/B2-B7 mode).");
init_gadget(&sotp031201_p4b2b7::DEVICE_DESCRIPTOR, &sotp031201_p4b2b7::DESCRIPTORS, &sotp031201_p4b2b7::STRINGS);
return Some(ControllerModel::SOTP031201P4B2B7);
model_name = "SOTP-031201 (P4/B2-B7 mode)";
model = ControllerModel::SOTP031201P4B2B7;
descriptors = (&sotp031201_p4b2b7::DEVICE_DESCRIPTOR, &sotp031201_p4b2b7::DESCRIPTORS, &sotp031201_p4b2b7::STRINGS);
}
else if state.button_c && state.power == 2 {
println!("Selected controller SOTP-031201 (P5/B5 mode).");
init_gadget(&sotp031201_p5b5::DEVICE_DESCRIPTOR, &sotp031201_p5b5::DESCRIPTORS, &sotp031201_p5b5::STRINGS);
return Some(ControllerModel::SOTP031201P5B5);
model_name = "SOTP-031201 (P5/B5 mode)";
model = ControllerModel::SOTP031201P5B5;
descriptors = (&sotp031201_p5b5::DEVICE_DESCRIPTOR, &sotp031201_p5b5::DESCRIPTORS, &sotp031201_p5b5::STRINGS);
}
else if state.button_c && state.power == 3 {
println!("Selected controller SOTP-031201 (P5/B7 mode).");
init_gadget(&sotp031201_p5b7::DEVICE_DESCRIPTOR, &sotp031201_p5b7::DESCRIPTORS, &sotp031201_p5b7::STRINGS);
return Some(ControllerModel::SOTP031201P5B7);
model_name = "SOTP-031201 (P5/B7 mode)";
model = ControllerModel::SOTP031201P5B7;
descriptors = (&sotp031201_p5b7::DEVICE_DESCRIPTOR, &sotp031201_p5b7::DESCRIPTORS, &sotp031201_p5b7::STRINGS);
}
/* else if state.button_a {
println!("Selected controller VOK-00106.");
return Some(ControllerModel::VOK00106);
} */
model_name = "VOK-00106";
model = ControllerModel::VOK00106;
} */
else {
println!("No controller selected.");
return None;
}
println!("Selected controller {}.", model_name);
init_gadget(&model, descriptors);
return Some(model);
}
pub fn set_state(state: &mut ControllerState, model: &ControllerModel) {
@ -117,7 +123,32 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) {
}
}
fn init_gadget(device: &DeviceDescriptor, descriptors: &[u8], strings: &[u8]) {
pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) {
if data[1] == 6 {
let report;
match model {
ControllerModel::DGOC44U => {
report = Some(&dgoc44u::HID_REPORT_DESCRIPTOR);
}
_ => {
report = None;
}
}
match report {
Some(rep) => {
if let Ok(mut file) = File::create(ENDPOINT0) {
file.write(rep).ok();
}
}
None => (),
}
}
else {
// Other control transfer, pass it to emulated controller loop
}
}
fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&DeviceDescriptor, &[u8], &[u8])) {
// Init g_ffs kernel module
Command::new("modprobe").arg("g_ffs")
.arg(String::from("bDeviceClass=")+&device.b_device_class.to_string())
@ -131,11 +162,19 @@ fn init_gadget(device: &DeviceDescriptor, descriptors: &[u8], strings: &[u8]) {
Command::new("mkdir").args(["-p",&FFS_MOUNT]).output().ok();
Command::new("mount").args(["-t","functionfs","ffs",&FFS_MOUNT]).output().ok();
let controller_model = model.clone();
thread::spawn(move || {
if let Ok(mut ep0) = File::open(&ENDPOINT0) {
let mut buffer = [0; 4];
let mut buffer = [0; 12];
loop {
ep0.read(&mut buffer).ok();
if let Ok(_result) = ep0.read(&mut buffer) {
if buffer[8] == 0x4 {
// Control transfer received
handle_ctrl_transfer(controller_model, &buffer[0..8]);
}
}
}
}
});

View file

@ -4,7 +4,10 @@ use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
pub const DESCRIPTORS: [u8; 41] = [0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14];
@ -12,6 +15,41 @@ pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"};
pub const HID_REPORT_DESCRIPTOR: [u8; 63] = [
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x06, // Usage Maximum (0x06)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0 // End Collection
];
const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00];
const BRAKE_NOTCHES: [u8; 10] = [0x79, 0x8A, 0x94, 0x9A, 0xA2, 0xA8, 0xAF, 0xB2, 0xB5, 0xB9];

View file

@ -59,4 +59,4 @@ pub fn update_gadget(state: &mut ControllerState) {
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok();
}
}
}