From c6013f2b7409127e96e3e30c83070bb0f47df4cb Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sat, 20 May 2023 12:35:45 +0200 Subject: [PATCH 01/12] Basic support for SLPH-00051 --- src/controller/emulated.rs | 13 ++ src/controller/emulated/slph00051.rs | 198 +++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/controller/emulated/slph00051.rs diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index db0e55b..67dedde 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -18,6 +18,7 @@ mod sotp031201_p5b5; mod sotp031201_p5b7; mod vok00106; mod zkns001; +mod slph00051; const FFS_MOUNT: &str = "/tmp/ffs"; const ENDPOINT0: &str = "/tmp/ffs/ep0"; @@ -35,6 +36,7 @@ pub enum ControllerModel { SOTP031201P5B7, VOK00106, ZKNS001, + SLPH00051, } pub struct DeviceDescriptor { @@ -62,6 +64,11 @@ pub fn set_model(state: &ControllerState) -> Option { model = ControllerModel::ZKNS001; descriptors = (&zkns001::DEVICE_DESCRIPTOR, &zkns001::DESCRIPTORS, &zkns001::STRINGS); } + else if state.button_down && state.power == 0 { + model_name = "SLPH-00051"; + model = ControllerModel::SLPH00051; + descriptors = (&slph00051::DEVICE_DESCRIPTOR, &slph00051::DESCRIPTORS, &slph00051::STRINGS); + } else if state.button_d { model_name = "TCPP-20009"; model = ControllerModel::TCPP20009; @@ -136,6 +143,9 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::ZKNS001 => { zkns001::update_gadget(state); } + ControllerModel::SLPH00051 => { + slph00051::update_gadget(state); + } } } @@ -151,6 +161,9 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { ControllerModel::ZKNS001 => { report = Some(&zkns001::HID_REPORT_DESCRIPTOR); } + ControllerModel::SLPH00051 => { + report = Some(&slph00051::HID_REPORT_DESCRIPTOR); + } _ => { report = None; } diff --git a/src/controller/emulated/slph00051.rs b/src/controller/emulated/slph00051.rs new file mode 100644 index 0000000..c8296af --- /dev/null +++ b/src/controller/emulated/slph00051.rs @@ -0,0 +1,198 @@ +use std::fs::File; +use std::io::{Write}; +use bitflags::bitflags; +use crate::controller::physical::ControllerState; +use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; + +pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, +0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, +0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x94, 0x00, +0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, +0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, +0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, +0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x94, 0x00, +0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, +0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05]; +pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x054C, id_product: 0x0268, bcd_device: 0x0100, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (PS1 Two Handle mode)", i_serial_number: "SLPH-00051"}; + +pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Physical) + 0xA1, 0x02, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: reserved byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x13, // Report Count (19) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x13, // Usage Maximum (0x13) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0D, // Report Count (13) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Undefined) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: four joysticks + 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x75, 0x08, // Report Size (8) + 0x95, 0x27, // Report Count (39) + 0x09, 0x01, // Usage (Pointer) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0x02, // Report ID (2) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEE, // Report ID (238) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEF, // Report ID (239) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection +]; + +bitflags! { + struct Buttons1: u8 { + const NONE = 0; + const SELECT = 1; + const L3 = 2; + const R3 = 4; + const START = 8; + const UP = 16; + const RIGHT = 32; + const DOWN = 64; + const LEFT = 128; + } + struct Buttons2: u8 { + const NONE = 0; + const L2 = 1; + const R2 = 2; + const L1 = 4; + const R1 = 8; + const TRIANGLE = 16; + const CIRCLE = 32; + const CROSS = 64; + const SQUARE = 128; + } +} + +pub fn update_gadget(state: &mut ControllerState) { + let mut buttons1 = Buttons1::UP | Buttons1::DOWN; + let mut buttons2 = Buttons2::NONE; + + // Calculate data for handles + match state.power { + 0 => { + buttons1.insert(Buttons1::LEFT | Buttons1::RIGHT); + } + 1 => { + buttons1.insert(Buttons1::RIGHT); + buttons2.insert(Buttons2::TRIANGLE); + } + 2 => { + buttons1.insert(Buttons1::RIGHT); + } + 3 => { + buttons1.insert(Buttons1::LEFT); + buttons2.insert(Buttons2::TRIANGLE); + } + 4 => { + buttons1.insert(Buttons1::LEFT); + } + _ => { + buttons2.insert(Buttons2::TRIANGLE); + } + } + match state.brake { + 0 => { + buttons2.insert(Buttons2::L2 | Buttons2::R1 | Buttons2::R2); + } + 1 => { + buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::R2); + } + 2 => { + buttons2.insert(Buttons2::R1 | Buttons2::R2); + } + 3 => { + buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R2); + } + 4 => { + buttons2.insert(Buttons2::L2 | Buttons2::R2); + } + 5 => { + buttons2.insert(Buttons2::L1 | Buttons2::R2); + } + 6 => { + buttons2.insert(Buttons2::R2); + } + 7 => { + buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R1); + } + 8 => { + buttons2.insert(Buttons2::L2 | Buttons2::R1); + } + _ => () + } + + // Calculate data for buttons + if state.button_a { buttons2.insert(Buttons2::SQUARE) } + if state.button_b { buttons2.insert(Buttons2::CROSS) } + if state.button_c { buttons2.insert(Buttons2::CIRCLE) } + if state.button_start { buttons1.insert(Buttons1::START) } + if state.button_select { buttons1.insert(Buttons1::SELECT) } + + // Assemble data and send it to gadget + let data = [0x1, 0x0, buttons1.bits, buttons2.bits, 0x0, 0x0, 0x80, 0x80, 0x80, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xEF, 0x14, 0x0, 0x0, 0x0, 0x0, 0x23, 0x1A, 0x77, 0x1, 0x81, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE]; + if let Ok(mut file) = File::create(ENDPOINT1) { + file.write(&data).ok(); + } +} \ No newline at end of file From 1f84543091989c4f13ed29782a516b2b41e5303f Mon Sep 17 00:00:00 2001 From: Marc Riera Irigoyen Date: Mon, 22 May 2023 18:30:11 +0200 Subject: [PATCH 02/12] Handle control requests for Dualshock 3 --- src/controller/emulated.rs | 8 +++++- src/controller/emulated/slph00051.rs | 42 ++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 67dedde..5277c36 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -177,7 +177,13 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { None => (), } } - else if data[1] == 9 { + else { + match model { + ControllerModel::SLPH00051 => { + slph00051::handle_ctrl_transfer(data); + } + _ => () + } } } diff --git a/src/controller/emulated/slph00051.rs b/src/controller/emulated/slph00051.rs index c8296af..9ed0a8c 100644 --- a/src/controller/emulated/slph00051.rs +++ b/src/controller/emulated/slph00051.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::{Write}; use bitflags::bitflags; use crate::controller::physical::ControllerState; -use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::emulated::{DeviceDescriptor, ENDPOINT0, ENDPOINT1}; pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, @@ -98,6 +98,16 @@ pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ 0xC0, // End Collection ]; +const F2_REPORT: [u8; 64] = [0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, +0x8A, 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, +0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]; + +const F5_REPORT: [u8; 64] = [0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, +0x8A, 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, +0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]; + bitflags! { struct Buttons1: u8 { const NONE = 0; @@ -188,11 +198,39 @@ pub fn update_gadget(state: &mut ControllerState) { if state.button_start { buttons1.insert(Buttons1::START) } if state.button_select { buttons1.insert(Buttons1::SELECT) } + let btn_up = if buttons1.contains(Buttons1::UP) {0xFF} else {0x0}; + let btn_right = if buttons1.contains(Buttons1::RIGHT) {0xFF} else {0x0}; + let btn_down = if buttons1.contains(Buttons1::DOWN) {0xFF} else {0x0}; + let btn_left = if buttons1.contains(Buttons1::LEFT) {0xFF} else {0x0}; + let btn_l2 = if buttons2.contains(Buttons2::L2) {0xFF} else {0x0}; + let btn_r2 = if buttons2.contains(Buttons2::R2) {0xFF} else {0x0}; + let btn_l1 = if buttons2.contains(Buttons2::L1) {0xFF} else {0x0}; + let btn_r1 = if buttons2.contains(Buttons2::R1) {0xFF} else {0x0}; + let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) {0xFF} else {0x0}; + let btn_circle = if buttons2.contains(Buttons2::CIRCLE) {0xFF} else {0x0}; + let btn_cross = if buttons2.contains(Buttons2::CROSS) {0xFF} else {0x0}; + let btn_square = if buttons2.contains(Buttons2::SQUARE) {0xFF} else {0x0}; + // Assemble data and send it to gadget let data = [0x1, 0x0, buttons1.bits, buttons2.bits, 0x0, 0x0, 0x80, 0x80, 0x80, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, btn_up, btn_right, btn_down, btn_left, btn_l2, btn_r2, btn_l1, btn_r1, btn_triangle, btn_circle, btn_cross, btn_square, 0x0, 0x0, 0x0, 0x3, 0xEF, 0x14, 0x0, 0x0, 0x0, 0x0, 0x23, 0x1A, 0x77, 0x1, 0x81, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } +} + +pub fn handle_ctrl_transfer(data: &[u8]) { + if data[1] == 1 && data[2] == 0xF2 { + // Init 1 + if let Ok(mut file) = File::create(ENDPOINT0) { + file.write(&F2_REPORT).unwrap(); + } + } + else if data[1] == 1 && data[2] == 0xF5 { + // Init 2 + if let Ok(mut file) = File::create(ENDPOINT0) { + file.write(&F5_REPORT).unwrap(); + } + } } \ No newline at end of file From f317be0f1501fdaed220c5ce0ca3d877813ee973 Mon Sep 17 00:00:00 2001 From: Marc Riera Irigoyen Date: Thu, 1 Jun 2023 17:33:37 +0200 Subject: [PATCH 03/12] MTC: fix P5/B7 --- README.md | 1 + src/controller/emulated.rs | 4 ++-- src/controller/emulated/sotp031201_p4b7.rs | 2 +- src/controller/emulated/sotp031201_p5b5.rs | 2 +- src/controller/emulated/sotp031201_p5b7.rs | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9eb8994..385e090 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Connect the Plug & Play to a PC or console using the data cable. Press one of th | Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual. diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 5277c36..83df9ce 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -94,12 +94,12 @@ pub fn set_model(state: &ControllerState) -> Option { model = ControllerModel::SOTP031201P5B5; descriptors = (&sotp031201_p5b5::DEVICE_DESCRIPTOR, &sotp031201_p5b5::DESCRIPTORS, &sotp031201_p5b5::STRINGS); } -/* else if state.button_c && state.power == 3 { + else if state.button_c && state.power == 3 { 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 { +/* else if state.button_a { model_name = "VOK-00106"; model = ControllerModel::VOK00106; descriptors = (&vok00106::DEVICE_DESCRIPTOR, &vok00106::DESCRIPTORS, &vok00106::STRINGS); diff --git a/src/controller/emulated/sotp031201_p4b7.rs b/src/controller/emulated/sotp031201_p4b7.rs index ad38922..f9498c8 100644 --- a/src/controller/emulated/sotp031201_p4b7.rs +++ b/src/controller/emulated/sotp031201_p4b7.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0300, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; diff --git a/src/controller/emulated/sotp031201_p5b5.rs b/src/controller/emulated/sotp031201_p5b5.rs index a5f6c3e..edc650e 100644 --- a/src/controller/emulated/sotp031201_p5b5.rs +++ b/src/controller/emulated/sotp031201_p5b5.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, bcd_device: 0x0202, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01]; diff --git a/src/controller/emulated/sotp031201_p5b7.rs b/src/controller/emulated/sotp031201_p5b7.rs index e1654af..072ce13 100644 --- a/src/controller/emulated/sotp031201_p5b7.rs +++ b/src/controller/emulated/sotp031201_p5b7.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0800, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; From b2daa5d0174510ee96e59ac47e67f5e87b9821af Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Thu, 1 Jun 2023 21:58:32 +0200 Subject: [PATCH 04/12] Finish SLPH-00051 support --- README.md | 21 ++--- src/controller/emulated/slph00051.rs | 111 +++++++++++++++------------ 2 files changed, 72 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 385e090..c3f0a46 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,17 @@ This mod allows you to use your Densha de GO! Plug & Play as a USB controller fo Connect the Plug & Play to a PC or console using the data cable. Press one of the following button combinations to select the controller you want to emulate: -| Controller | Button combination | Notes | -|-----------------------------------------|-----------------------|--------------------------------------------------| -| One handle controller (Nintendo Switch) | UP | SELECT+START=HOME, SELECT+LEFT=L, SELECT+RIGHT=R | -| Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD | -| Two handle controller "Type 2" (PS2) | D | | -| Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | -| Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | -| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | -| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | -| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Controller | Button combination | Notes | +|-----------------------------------------|--------------------------|--------------------------------------------------| +| One handle controller (Nintendo Switch) | UP | SELECT+START=HOME, SELECT+LEFT=L, SELECT+RIGHT=R | +| Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD | +| Two handle controller (PS1) | DOWN + Power handle at 0 | Hold D to disable handles and enable D-Pad | +| Two handle controller "Type 2" (PS2) | D | | +| Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | +| Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual. diff --git a/src/controller/emulated/slph00051.rs b/src/controller/emulated/slph00051.rs index 9ed0a8c..aedda6f 100644 --- a/src/controller/emulated/slph00051.rs +++ b/src/controller/emulated/slph00051.rs @@ -134,61 +134,72 @@ bitflags! { } pub fn update_gadget(state: &mut ControllerState) { - let mut buttons1 = Buttons1::UP | Buttons1::DOWN; + let mut buttons1 = Buttons1::NONE; let mut buttons2 = Buttons2::NONE; - // Calculate data for handles - match state.power { - 0 => { - buttons1.insert(Buttons1::LEFT | Buttons1::RIGHT); + // If D is pressed, D-pad mode is active + if !state.button_d { + // Calculate data for handles + buttons1.insert(Buttons1::UP | Buttons1::DOWN); + match state.power { + 0 => { + buttons1.insert(Buttons1::LEFT | Buttons1::RIGHT); + } + 1 => { + buttons1.insert(Buttons1::RIGHT); + buttons2.insert(Buttons2::TRIANGLE); + } + 2 => { + buttons1.insert(Buttons1::RIGHT); + } + 3 => { + buttons1.insert(Buttons1::LEFT); + buttons2.insert(Buttons2::TRIANGLE); + } + 4 => { + buttons1.insert(Buttons1::LEFT); + } + _ => { + buttons2.insert(Buttons2::TRIANGLE); + } } - 1 => { - buttons1.insert(Buttons1::RIGHT); - buttons2.insert(Buttons2::TRIANGLE); + match state.brake { + 0 => { + buttons2.insert(Buttons2::L2 | Buttons2::R1 | Buttons2::R2); + } + 1 => { + buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::R2); + } + 2 => { + buttons2.insert(Buttons2::R1 | Buttons2::R2); + } + 3 => { + buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R2); + } + 4 => { + buttons2.insert(Buttons2::L2 | Buttons2::R2); + } + 5 => { + buttons2.insert(Buttons2::L1 | Buttons2::R2); + } + 6 => { + buttons2.insert(Buttons2::R2); + } + 7 => { + buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R1); + } + 8 => { + buttons2.insert(Buttons2::L2 | Buttons2::R1); + } + _ => () } - 2 => { - buttons1.insert(Buttons1::RIGHT); - } - 3 => { - buttons1.insert(Buttons1::LEFT); - buttons2.insert(Buttons2::TRIANGLE); - } - 4 => { - buttons1.insert(Buttons1::LEFT); - } - _ => { - buttons2.insert(Buttons2::TRIANGLE); - } } - match state.brake { - 0 => { - buttons2.insert(Buttons2::L2 | Buttons2::R1 | Buttons2::R2); - } - 1 => { - buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::R2); - } - 2 => { - buttons2.insert(Buttons2::R1 | Buttons2::R2); - } - 3 => { - buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R2); - } - 4 => { - buttons2.insert(Buttons2::L2 | Buttons2::R2); - } - 5 => { - buttons2.insert(Buttons2::L1 | Buttons2::R2); - } - 6 => { - buttons2.insert(Buttons2::R2); - } - 7 => { - buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R1); - } - 8 => { - buttons2.insert(Buttons2::L2 | Buttons2::R1); - } - _ => () + else { + // D-pad mode + if state.button_up { buttons1.insert(Buttons1::UP) } + if state.button_down { buttons1.insert(Buttons1::DOWN) } + if state.button_left { buttons1.insert(Buttons1::LEFT) } + if state.button_right { buttons1.insert(Buttons1::RIGHT) } } // Calculate data for buttons From 8b443ccb5e27fa34110a173cd72ba121e86182f0 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Thu, 1 Jun 2023 22:02:58 +0200 Subject: [PATCH 05/12] Release: 1.1.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cef682e..ad6fcab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ddgo-pnp-controller" -version = "1.0.0" +version = "1.1.0" edition = "2021" [dependencies] From 7011359bb6fd9dc2dacc0ea2d93c3d4a6d32a355 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Thu, 8 Jun 2023 23:52:35 +0200 Subject: [PATCH 06/12] Ensure the backup folder is created --- dist/hook_magic_36558b710a.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/hook_magic_36558b710a.sh b/dist/hook_magic_36558b710a.sh index 45f0568..f600c4f 100644 --- a/dist/hook_magic_36558b710a.sh +++ b/dist/hook_magic_36558b710a.sh @@ -33,6 +33,9 @@ if ! mount -o remount,rw /; then error_exit fi +# Create backup folder +mkdir -p "${USB_ROOT}/BACKUP" + # Backup original kernel if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] && [ ! -f "/usr/bin/input_relay" ] && [ ! -f "/usr/bin/ddgo-pnp-controller" ]; then if ! cp /tmp/boot/uImage "${USB_ROOT}/BACKUP/"; then From 8ed2d1300c6a44f015c8dadb5c07c13ded71915e Mon Sep 17 00:00:00 2001 From: Marc Riera Irigoyen Date: Wed, 28 Jun 2023 19:17:39 +0200 Subject: [PATCH 07/12] Remove unused code --- src/controller/emulated.rs | 10 ------ src/controller/emulated/vok00106.rs | 52 ----------------------------- 2 files changed, 62 deletions(-) delete mode 100644 src/controller/emulated/vok00106.rs diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 83df9ce..72d31d5 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -16,7 +16,6 @@ mod sotp031201_p4b7; mod sotp031201_p4b2b7; mod sotp031201_p5b5; mod sotp031201_p5b7; -mod vok00106; mod zkns001; mod slph00051; @@ -34,7 +33,6 @@ pub enum ControllerModel { SOTP031201P4B2B7, SOTP031201P5B5, SOTP031201P5B7, - VOK00106, ZKNS001, SLPH00051, } @@ -99,11 +97,6 @@ pub fn set_model(state: &ControllerState) -> Option { model = ControllerModel::SOTP031201P5B7; descriptors = (&sotp031201_p5b7::DEVICE_DESCRIPTOR, &sotp031201_p5b7::DESCRIPTORS, &sotp031201_p5b7::STRINGS); } -/* else if state.button_a { - model_name = "VOK-00106"; - model = ControllerModel::VOK00106; - descriptors = (&vok00106::DEVICE_DESCRIPTOR, &vok00106::DESCRIPTORS, &vok00106::STRINGS); - } */ else { println!("ddgo-pnp-controller: No controller selected, starting RNDIS gadget."); Command::new("rndis-gadget.sh").output().ok(); @@ -137,9 +130,6 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::SOTP031201P5B7 => { sotp031201_p5b7::update_gadget(state); } - ControllerModel::VOK00106 => { - vok00106::update_gadget(state); - } ControllerModel::ZKNS001 => { zkns001::update_gadget(state); } diff --git a/src/controller/emulated/vok00106.rs b/src/controller/emulated/vok00106.rs deleted file mode 100644 index 767593d..0000000 --- a/src/controller/emulated/vok00106.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::fs::File; -use std::io::{Write}; -use crate::controller::physical::ControllerState; -use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; - -pub const DESCRIPTORS: [u8; 76] = [0x01, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, -0x07, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, -0x07, 0x05, 0x02, 0x02, 0x20, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01, -0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, -0x07, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00, -0x07, 0x05, 0x02, 0x02, 0x20, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x02, b_device_sub_class: 0x0, id_vendor: 0x067B, id_product: 0x2303, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Master Controller II mode)", i_serial_number: "VOK-00106"}; - -const POWER_NOTCHES: [&str; 6] = ["TSA50", "TSA55", "TSA65", "TSA75", "TSA85", "TSA95"]; -const BRAKE_NOTCHES: [&str; 10] = ["TSA50", "TSA45", "TSA35", "TSA25", "TSA15", "TSA05", "TSE99", "TSB40", "TSB30", "TSB20"]; -const BUTTON_A: [&str; 2] = ["TSX00", "TSX99"]; -const BUTTON_B: [&str; 2] = ["TSY00", "TSY99"]; -const BUTTON_C: [&str; 2] = ["TSZ00", "TSZ99"]; -const BUTTON_S: [&str; 2] = ["TSK00", "TSK99"]; - - -pub fn update_gadget(state: &mut ControllerState) { - // Calculate data for handles - let mut handle = POWER_NOTCHES[state.power as usize]; - if state.brake > 0 { - handle = BRAKE_NOTCHES[state.brake as usize]; - } - - // Calculate data for buttons - let button_a = if state.button_a {BUTTON_A[1]} else {BUTTON_A[0]}; - let button_b = if state.button_b {BUTTON_B[1]} else {BUTTON_B[0]}; - let button_c = if state.button_c {BUTTON_C[1]} else {BUTTON_C[0]}; - let button_s = if state.button_d {BUTTON_S[1]} else {BUTTON_S[0]}; - - if let Ok(mut file) = File::create(ENDPOINT1) { - file.write(handle.as_bytes()).ok(); - file.write(&[0xD]).ok(); - file.write(button_a.as_bytes()).ok(); - file.write(&[0xD]).ok(); - file.write(button_b.as_bytes()).ok(); - file.write(&[0xD]).ok(); - file.write(button_c.as_bytes()).ok(); - file.write(&[0xD]).ok(); - file.write(button_s.as_bytes()).ok(); - file.write(&[0xD]).ok(); - } -} \ No newline at end of file From 8aa9a02c21bd35c5ae1fa02e7bf81c37bbe0e41d Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sun, 5 Nov 2023 09:50:17 +0100 Subject: [PATCH 08/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3f0a46..fb86bb3 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Connect the Plug & Play to a PC or console using the data cable. Press one of th | Two handle controller "Type 2" (PS2) | D | | | Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | | Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | -| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | +| Multi Train Controller (PS2) - P4/B2-B7 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | From bd2213f14f2cce8b190efdc7db74d2296c82291e Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sun, 10 Dec 2023 16:16:37 +0100 Subject: [PATCH 09/12] Fix D combo with MTC --- src/controller/emulated/dgoc44u.rs | 3 ++- src/controller/emulated/sotp031201_p4b2b7.rs | 4 ++-- src/controller/emulated/sotp031201_p4b7.rs | 4 ++-- src/controller/emulated/sotp031201_p5b5.rs | 4 ++-- src/controller/emulated/sotp031201_p5b7.rs | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/controller/emulated/dgoc44u.rs b/src/controller/emulated/dgoc44u.rs index 4168be3..07715ed 100644 --- a/src/controller/emulated/dgoc44u.rs +++ b/src/controller/emulated/dgoc44u.rs @@ -1,5 +1,6 @@ use std::fs::File; -use std::io::{Write}; +use std::io::Write; + use bitflags::bitflags; use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; diff --git a/src/controller/emulated/sotp031201_p4b2b7.rs b/src/controller/emulated/sotp031201_p4b2b7.rs index bc70929..8e54370 100644 --- a/src/controller/emulated/sotp031201_p4b2b7.rs +++ b/src/controller/emulated/sotp031201_p4b2b7.rs @@ -70,8 +70,8 @@ pub fn update_gadget(state: &mut ControllerState) { } if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if state.button_b { buttons1.insert(Buttons1::B) } - if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } + if state.button_c { buttons1.insert(Buttons1::C) } + if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } diff --git a/src/controller/emulated/sotp031201_p4b7.rs b/src/controller/emulated/sotp031201_p4b7.rs index f9498c8..2d6427b 100644 --- a/src/controller/emulated/sotp031201_p4b7.rs +++ b/src/controller/emulated/sotp031201_p4b7.rs @@ -70,8 +70,8 @@ pub fn update_gadget(state: &mut ControllerState) { } if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if state.button_b { buttons1.insert(Buttons1::B) } - if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } + if state.button_c { buttons1.insert(Buttons1::C) } + if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } diff --git a/src/controller/emulated/sotp031201_p5b5.rs b/src/controller/emulated/sotp031201_p5b5.rs index edc650e..ff30f65 100644 --- a/src/controller/emulated/sotp031201_p5b5.rs +++ b/src/controller/emulated/sotp031201_p5b5.rs @@ -70,8 +70,8 @@ pub fn update_gadget(state: &mut ControllerState) { } if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if state.button_b { buttons1.insert(Buttons1::B) } - if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } + if state.button_c { buttons1.insert(Buttons1::C) } + if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } diff --git a/src/controller/emulated/sotp031201_p5b7.rs b/src/controller/emulated/sotp031201_p5b7.rs index 072ce13..5cb5ee3 100644 --- a/src/controller/emulated/sotp031201_p5b7.rs +++ b/src/controller/emulated/sotp031201_p5b7.rs @@ -70,8 +70,8 @@ pub fn update_gadget(state: &mut ControllerState) { } if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if state.button_b { buttons1.insert(Buttons1::B) } - if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } + if state.button_c { buttons1.insert(Buttons1::C) } + if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } From 122ce1a82f0b137b4dc3e13bfa15e56d85514857 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sun, 10 Dec 2023 16:18:55 +0100 Subject: [PATCH 10/12] Release: 1.2.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ad6fcab..c6baeda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ddgo-pnp-controller" -version = "1.1.0" +version = "1.2.0" edition = "2021" [dependencies] From a6b99f281716ce65cc5af572007a5c2d05fe1cc7 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sun, 23 Mar 2025 21:21:45 +0100 Subject: [PATCH 11/12] Update to Rust 2024 and formatting changes --- Cargo.toml | 6 +- src/controller.rs | 2 +- src/controller/emulated.rs | 184 ++++++--- src/controller/emulated/dgoc44u.rs | 139 ++++--- src/controller/emulated/slph00051.rs | 400 ++++++++++++------- src/controller/emulated/sotp031201_p4b2b7.rs | 69 +++- src/controller/emulated/sotp031201_p4b7.rs | 71 +++- src/controller/emulated/sotp031201_p5b5.rs | 71 +++- src/controller/emulated/sotp031201_p5b7.rs | 71 +++- src/controller/emulated/tcpp20009.rs | 85 ++-- src/controller/emulated/tcpp20011.rs | 87 ++-- src/controller/emulated/zkns001.rs | 204 ++++++---- src/controller/physical.rs | 162 ++++++-- src/main.rs | 14 +- 14 files changed, 1067 insertions(+), 498 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c6baeda..1c12fe8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "ddgo-pnp-controller" -version = "1.2.0" -edition = "2021" +version = "1.2.1" +edition = "2024" [dependencies] bitflags = "1.3.2" -evdev = "0.12.1" +evdev = "0.12.2" diff --git a/src/controller.rs b/src/controller.rs index 4586bff..cb235eb 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -1,2 +1,2 @@ -pub mod physical; pub mod emulated; +pub mod physical; diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 72d31d5..8f054b8 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -1,23 +1,23 @@ -use std::thread; -use std::thread::sleep; -use std::time::Duration; use std::fs; use std::fs::File; use std::io::{Read, Write}; -use std::process::Command; use std::path::Path; +use std::process::Command; +use std::thread; +use std::thread::sleep; +use std::time::Duration; use crate::controller::physical::ControllerState; mod dgoc44u; -mod tcpp20009; -mod tcpp20011; -mod sotp031201_p4b7; +mod slph00051; mod sotp031201_p4b2b7; +mod sotp031201_p4b7; mod sotp031201_p5b5; mod sotp031201_p5b7; +mod tcpp20009; +mod tcpp20011; mod zkns001; -mod slph00051; const FFS_MOUNT: &str = "/tmp/ffs"; const ENDPOINT0: &str = "/tmp/ffs/ep0"; @@ -55,49 +55,76 @@ pub fn set_model(state: &ControllerState) -> Option { if state.button_right { model_name = "DGOC44-U"; model = ControllerModel::DGOC44U; - descriptors = (&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS); - } - else if state.button_up { + descriptors = ( + &dgoc44u::DEVICE_DESCRIPTOR, + &dgoc44u::DESCRIPTORS, + &dgoc44u::STRINGS, + ); + } else if state.button_up { model_name = "ZKNS-001"; model = ControllerModel::ZKNS001; - descriptors = (&zkns001::DEVICE_DESCRIPTOR, &zkns001::DESCRIPTORS, &zkns001::STRINGS); - } - else if state.button_down && state.power == 0 { + descriptors = ( + &zkns001::DEVICE_DESCRIPTOR, + &zkns001::DESCRIPTORS, + &zkns001::STRINGS, + ); + } else if state.button_down && state.power == 0 { model_name = "SLPH-00051"; model = ControllerModel::SLPH00051; - descriptors = (&slph00051::DEVICE_DESCRIPTOR, &slph00051::DESCRIPTORS, &slph00051::STRINGS); - } - else if state.button_d { + descriptors = ( + &slph00051::DEVICE_DESCRIPTOR, + &slph00051::DESCRIPTORS, + &slph00051::STRINGS, + ); + } else if state.button_d { model_name = "TCPP-20009"; model = ControllerModel::TCPP20009; - descriptors = (&tcpp20009::DEVICE_DESCRIPTOR, &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS); - } - else if state.button_b { + descriptors = ( + &tcpp20009::DEVICE_DESCRIPTOR, + &tcpp20009::DESCRIPTORS, + &tcpp20009::STRINGS, + ); + } else if state.button_b { model_name = "TCPP-20011"; model = ControllerModel::TCPP20011; - descriptors = (&tcpp20011::DEVICE_DESCRIPTOR, &tcpp20011::DESCRIPTORS, &tcpp20011::STRINGS); - } - else if state.button_c && state.power == 0 { + descriptors = ( + &tcpp20011::DEVICE_DESCRIPTOR, + &tcpp20011::DESCRIPTORS, + &tcpp20011::STRINGS, + ); + } else if state.button_c && state.power == 0 { 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 { + descriptors = ( + &sotp031201_p4b7::DEVICE_DESCRIPTOR, + &sotp031201_p4b7::DESCRIPTORS, + &sotp031201_p4b7::STRINGS, + ); + } else if state.button_c && state.power == 1 { 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 { + descriptors = ( + &sotp031201_p4b2b7::DEVICE_DESCRIPTOR, + &sotp031201_p4b2b7::DESCRIPTORS, + &sotp031201_p4b2b7::STRINGS, + ); + } else if state.button_c && state.power == 2 { 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 { + descriptors = ( + &sotp031201_p5b5::DEVICE_DESCRIPTOR, + &sotp031201_p5b5::DESCRIPTORS, + &sotp031201_p5b5::STRINGS, + ); + } else if state.button_c && state.power == 3 { model_name = "SOTP-031201 (P5/B7 mode)"; model = ControllerModel::SOTP031201P5B7; - descriptors = (&sotp031201_p5b7::DEVICE_DESCRIPTOR, &sotp031201_p5b7::DESCRIPTORS, &sotp031201_p5b7::STRINGS); - } - else { + descriptors = ( + &sotp031201_p5b7::DEVICE_DESCRIPTOR, + &sotp031201_p5b7::DESCRIPTORS, + &sotp031201_p5b7::STRINGS, + ); + } else { println!("ddgo-pnp-controller: No controller selected, starting RNDIS gadget."); Command::new("rndis-gadget.sh").output().ok(); return None; @@ -166,31 +193,38 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { } None => (), } - } - else { + } else { match model { ControllerModel::SLPH00051 => { slph00051::handle_ctrl_transfer(data); } - _ => () + _ => (), } } } -fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&DeviceDescriptor, &[u8], &[u8])) { +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()) - .arg(String::from("bDeviceSubClass=")+&device.b_device_sub_class.to_string()) - .arg(String::from("idVendor=")+&device.id_vendor.to_string()) - .arg(String::from("idProduct=")+&device.id_product.to_string()) - .arg(String::from("bcdDevice=")+&device.bcd_device.to_string()) - .arg(String::from("iManufacturer=")+device.i_manufacturer) - .arg(String::from("iProduct=")+device.i_product) - .arg(String::from("iSerialNumber=")+device.i_serial_number) - .output().ok(); - Command::new("mkdir").args(["-p",&FFS_MOUNT]).output().ok(); - Command::new("mount").args(["-t","functionfs","ffs",&FFS_MOUNT]).output().ok(); + Command::new("modprobe") + .arg("g_ffs") + .arg(String::from("bDeviceClass=") + &device.b_device_class.to_string()) + .arg(String::from("bDeviceSubClass=") + &device.b_device_sub_class.to_string()) + .arg(String::from("idVendor=") + &device.id_vendor.to_string()) + .arg(String::from("idProduct=") + &device.id_product.to_string()) + .arg(String::from("bcdDevice=") + &device.bcd_device.to_string()) + .arg(String::from("iManufacturer=") + device.i_manufacturer) + .arg(String::from("iProduct=") + device.i_product) + .arg(String::from("iSerialNumber=") + device.i_serial_number) + .output() + .ok(); + 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(); @@ -219,14 +253,46 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device // Init Android Gadget for old 3.4 kernel let gadget = Path::new(&ANDROID_GADGET); if gadget.is_dir() { - fs::write(gadget.join(Path::new("bDeviceClass")), &device.b_device_class.to_string()).ok(); - fs::write(gadget.join(Path::new("bDeviceSubClass")), &device.b_device_sub_class.to_string()).ok(); - fs::write(gadget.join(Path::new("idVendor")), format!("{:x}", &device.id_vendor)).ok(); - fs::write(gadget.join(Path::new("idProduct")), format!("{:x}", &device.id_product)).ok(); - fs::write(gadget.join(Path::new("bcdDevice")), format!("{:x}", &device.bcd_device)).ok(); - fs::write(gadget.join(Path::new("iManufacturer")), &device.i_manufacturer.to_string()).ok(); - fs::write(gadget.join(Path::new("iProduct")), &device.i_product.to_string()).ok(); - fs::write(gadget.join(Path::new("iSerial")), &device.i_serial_number.to_string()).ok(); + fs::write( + gadget.join(Path::new("bDeviceClass")), + &device.b_device_class.to_string(), + ) + .ok(); + fs::write( + gadget.join(Path::new("bDeviceSubClass")), + &device.b_device_sub_class.to_string(), + ) + .ok(); + fs::write( + gadget.join(Path::new("idVendor")), + format!("{:x}", &device.id_vendor), + ) + .ok(); + fs::write( + gadget.join(Path::new("idProduct")), + format!("{:x}", &device.id_product), + ) + .ok(); + fs::write( + gadget.join(Path::new("bcdDevice")), + format!("{:x}", &device.bcd_device), + ) + .ok(); + fs::write( + gadget.join(Path::new("iManufacturer")), + &device.i_manufacturer.to_string(), + ) + .ok(); + fs::write( + gadget.join(Path::new("iProduct")), + &device.i_product.to_string(), + ) + .ok(); + fs::write( + gadget.join(Path::new("iSerial")), + &device.i_serial_number.to_string(), + ) + .ok(); fs::write(gadget.join(Path::new("functions")), "ffs").ok(); fs::write(gadget.join(Path::new("f_ffs/aliases")), "ffs").ok(); fs::write(gadget.join(Path::new("enable")), "1").ok(); diff --git a/src/controller/emulated/dgoc44u.rs b/src/controller/emulated/dgoc44u.rs index 07715ed..9dd81f7 100644 --- a/src/controller/emulated/dgoc44u.rs +++ b/src/controller/emulated/dgoc44u.rs @@ -1,54 +1,65 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x42, 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, 0x05, -0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, -0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x05]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 66] = [ + 0x01, 0x00, 0x00, 0x00, 0x42, 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, 0x05, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, + 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, + 0x00, 0x05, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x0, + b_device_sub_class: 0x0, + id_vendor: 0x0AE4, + id_product: 0x0003, + bcd_device: 0x0102, + 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 + 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]; @@ -77,20 +88,40 @@ pub fn update_gadget(state: &mut ControllerState) { // Calculate data for buttons let mut buttons = Buttons::NONE; - if state.button_a { buttons.insert(Buttons::A) } - if state.button_b { buttons.insert(Buttons::B) } - if state.button_c { buttons.insert(Buttons::C) } - if state.button_d { buttons.insert(Buttons::D) } - if state.button_select { buttons.insert(Buttons::SELECT) } - if state.button_start { buttons.insert(Buttons::START) } - if state.button_up { buttons.insert(Buttons::UP) } - if state.button_down { buttons.insert(Buttons::DOWN) } - if state.button_left { buttons.insert(Buttons::LEFT) } - if state.button_right { buttons.insert(Buttons::RIGHT) } + if state.button_a { + buttons.insert(Buttons::A) + } + if state.button_b { + buttons.insert(Buttons::B) + } + if state.button_c { + buttons.insert(Buttons::C) + } + if state.button_d { + buttons.insert(Buttons::D) + } + if state.button_select { + buttons.insert(Buttons::SELECT) + } + if state.button_start { + buttons.insert(Buttons::START) + } + if state.button_up { + buttons.insert(Buttons::UP) + } + if state.button_down { + buttons.insert(Buttons::DOWN) + } + if state.button_left { + buttons.insert(Buttons::LEFT) + } + if state.button_right { + buttons.insert(Buttons::RIGHT) + } // Assemble data and send it to gadget let data = [brake, power, 0, buttons.bits, 0, 0]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/emulated/slph00051.rs b/src/controller/emulated/slph00051.rs index aedda6f..4d351a0 100644 --- a/src/controller/emulated/slph00051.rs +++ b/src/controller/emulated/slph00051.rs @@ -1,112 +1,130 @@ -use std::fs::File; -use std::io::{Write}; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT0, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; +use std::fs::File; +use std::io::Write; -pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, -0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x94, 0x00, -0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, -0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, -0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, -0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x94, 0x00, -0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, -0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; - -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x054C, id_product: 0x0268, bcd_device: 0x0100, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (PS1 Two Handle mode)", i_serial_number: "SLPH-00051"}; - -pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Physical) - 0xA1, 0x02, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: reserved byte - 0x75, 0x01, // Report Size (1) - 0x95, 0x13, // Report Count (19) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x35, 0x00, // Physical Minimum (0) - 0x45, 0x01, // Physical Maximum (1) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x13, // Usage Maximum (0x13) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0D, // Report Count (13) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Undefined) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: four joysticks - 0xC0, // End Collection - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x75, 0x08, // Report Size (8) - 0x95, 0x27, // Report Count (39) - 0x09, 0x01, // Usage (Pointer) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0x02, // Report ID (2) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEE, // Report ID (238) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEF, // Report ID (239) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xC0, // End Collection +pub const DESCRIPTORS: [u8; 80] = [ + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, + 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, + 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, + 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -const F2_REPORT: [u8; 64] = [0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, -0x8A, 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, -0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x0, + b_device_sub_class: 0x0, + id_vendor: 0x054C, + id_product: 0x0268, + bcd_device: 0x0100, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (PS1 Two Handle mode)", + i_serial_number: "SLPH-00051", +}; -const F5_REPORT: [u8; 64] = [0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, -0x8A, 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, -0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]; +pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Physical) + 0xA1, 0x02, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: reserved byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x13, // Report Count (19) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x13, // Usage Maximum (0x13) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0D, // Report Count (13) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Undefined) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: four joysticks + 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x75, 0x08, // Report Size (8) + 0x95, 0x27, // Report Count (39) + 0x09, 0x01, // Usage (Pointer) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0x91, + 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, + 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0x02, // Report ID (2) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, + 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEE, // Report ID (238) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, + 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEF, // Report ID (239) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, + 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection +]; + +const F2_REPORT: [u8; 64] = [ + 0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, + 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, + 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +]; + +const F5_REPORT: [u8; 64] = [ + 0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, + 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, + 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +]; bitflags! { struct Buttons1: u8 { @@ -161,7 +179,7 @@ pub fn update_gadget(state: &mut ControllerState) { } _ => { buttons2.insert(Buttons2::TRIANGLE); - } + } } match state.brake { 0 => { @@ -191,41 +209,154 @@ pub fn update_gadget(state: &mut ControllerState) { 8 => { buttons2.insert(Buttons2::L2 | Buttons2::R1); } - _ => () + _ => (), } - } - else { + } else { // D-pad mode - if state.button_up { buttons1.insert(Buttons1::UP) } - if state.button_down { buttons1.insert(Buttons1::DOWN) } - if state.button_left { buttons1.insert(Buttons1::LEFT) } - if state.button_right { buttons1.insert(Buttons1::RIGHT) } + if state.button_up { + buttons1.insert(Buttons1::UP) + } + if state.button_down { + buttons1.insert(Buttons1::DOWN) + } + if state.button_left { + buttons1.insert(Buttons1::LEFT) + } + if state.button_right { + buttons1.insert(Buttons1::RIGHT) + } } // Calculate data for buttons - if state.button_a { buttons2.insert(Buttons2::SQUARE) } - if state.button_b { buttons2.insert(Buttons2::CROSS) } - if state.button_c { buttons2.insert(Buttons2::CIRCLE) } - if state.button_start { buttons1.insert(Buttons1::START) } - if state.button_select { buttons1.insert(Buttons1::SELECT) } + if state.button_a { + buttons2.insert(Buttons2::SQUARE) + } + if state.button_b { + buttons2.insert(Buttons2::CROSS) + } + if state.button_c { + buttons2.insert(Buttons2::CIRCLE) + } + if state.button_start { + buttons1.insert(Buttons1::START) + } + if state.button_select { + buttons1.insert(Buttons1::SELECT) + } - let btn_up = if buttons1.contains(Buttons1::UP) {0xFF} else {0x0}; - let btn_right = if buttons1.contains(Buttons1::RIGHT) {0xFF} else {0x0}; - let btn_down = if buttons1.contains(Buttons1::DOWN) {0xFF} else {0x0}; - let btn_left = if buttons1.contains(Buttons1::LEFT) {0xFF} else {0x0}; - let btn_l2 = if buttons2.contains(Buttons2::L2) {0xFF} else {0x0}; - let btn_r2 = if buttons2.contains(Buttons2::R2) {0xFF} else {0x0}; - let btn_l1 = if buttons2.contains(Buttons2::L1) {0xFF} else {0x0}; - let btn_r1 = if buttons2.contains(Buttons2::R1) {0xFF} else {0x0}; - let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) {0xFF} else {0x0}; - let btn_circle = if buttons2.contains(Buttons2::CIRCLE) {0xFF} else {0x0}; - let btn_cross = if buttons2.contains(Buttons2::CROSS) {0xFF} else {0x0}; - let btn_square = if buttons2.contains(Buttons2::SQUARE) {0xFF} else {0x0}; + let btn_up = if buttons1.contains(Buttons1::UP) { + 0xFF + } else { + 0x0 + }; + let btn_right = if buttons1.contains(Buttons1::RIGHT) { + 0xFF + } else { + 0x0 + }; + let btn_down = if buttons1.contains(Buttons1::DOWN) { + 0xFF + } else { + 0x0 + }; + let btn_left = if buttons1.contains(Buttons1::LEFT) { + 0xFF + } else { + 0x0 + }; + let btn_l2 = if buttons2.contains(Buttons2::L2) { + 0xFF + } else { + 0x0 + }; + let btn_r2 = if buttons2.contains(Buttons2::R2) { + 0xFF + } else { + 0x0 + }; + let btn_l1 = if buttons2.contains(Buttons2::L1) { + 0xFF + } else { + 0x0 + }; + let btn_r1 = if buttons2.contains(Buttons2::R1) { + 0xFF + } else { + 0x0 + }; + let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) { + 0xFF + } else { + 0x0 + }; + let btn_circle = if buttons2.contains(Buttons2::CIRCLE) { + 0xFF + } else { + 0x0 + }; + let btn_cross = if buttons2.contains(Buttons2::CROSS) { + 0xFF + } else { + 0x0 + }; + let btn_square = if buttons2.contains(Buttons2::SQUARE) { + 0xFF + } else { + 0x0 + }; // Assemble data and send it to gadget - let data = [0x1, 0x0, buttons1.bits, buttons2.bits, 0x0, 0x0, 0x80, 0x80, 0x80, 0x80, - 0x0, 0x0, 0x0, 0x0, btn_up, btn_right, btn_down, btn_left, btn_l2, btn_r2, btn_l1, btn_r1, btn_triangle, btn_circle, btn_cross, btn_square, 0x0, 0x0, 0x0, - 0x3, 0xEF, 0x14, 0x0, 0x0, 0x0, 0x0, 0x23, 0x1A, 0x77, 0x1, 0x81, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE, 0x1, 0xFE]; + let data = [ + 0x1, + 0x0, + buttons1.bits, + buttons2.bits, + 0x0, + 0x0, + 0x80, + 0x80, + 0x80, + 0x80, + 0x0, + 0x0, + 0x0, + 0x0, + btn_up, + btn_right, + btn_down, + btn_left, + btn_l2, + btn_r2, + btn_l1, + btn_r1, + btn_triangle, + btn_circle, + btn_cross, + btn_square, + 0x0, + 0x0, + 0x0, + 0x3, + 0xEF, + 0x14, + 0x0, + 0x0, + 0x0, + 0x0, + 0x23, + 0x1A, + 0x77, + 0x1, + 0x81, + 0x1, + 0xFE, + 0x1, + 0xFE, + 0x1, + 0xFE, + 0x1, + 0xFE, + ]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } @@ -237,11 +368,10 @@ pub fn handle_ctrl_transfer(data: &[u8]) { if let Ok(mut file) = File::create(ENDPOINT0) { file.write(&F2_REPORT).unwrap(); } - } - else if data[1] == 1 && data[2] == 0xF5 { + } else if data[1] == 1 && data[2] == 0xF5 { // Init 2 if let Ok(mut file) = File::create(ENDPOINT0) { file.write(&F5_REPORT).unwrap(); } } -} \ No newline at end of file +} diff --git a/src/controller/emulated/sotp031201_p4b2b7.rs b/src/controller/emulated/sotp031201_p4b2b7.rs index 8e54370..56222c3 100644 --- a/src/controller/emulated/sotp031201_p4b2b7.rs +++ b/src/controller/emulated/sotp031201_p4b2b7.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0400, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x00, + b_device_sub_class: 0x0, + id_vendor: 0x0AE4, + id_product: 0x0101, + bcd_device: 0x0400, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", + i_serial_number: "SOTP-031201", +}; const POWER_NOTCHES: [u8; 6] = [0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x01]; @@ -68,16 +79,36 @@ pub fn update_gadget(state: &mut ControllerState) { state.reverser = 0x40; state.combo = true; } - if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } - if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } - if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } - if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } - if state.button_right { buttons2.insert(Buttons2::RIGHT) } - if state.button_start { buttons2.insert(Buttons2::START) } - if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_a { + buttons1.insert(Buttons1::A) + } + if state.button_b { + buttons1.insert(Buttons1::B) + } + if state.button_c { + buttons1.insert(Buttons1::C) + } + if !state.combo && state.button_d { + buttons1.insert(Buttons1::D) + } + if !state.combo && state.button_up { + buttons2.insert(Buttons2::UP) + } + if !state.combo && state.button_down { + buttons2.insert(Buttons2::DOWN) + } + if !state.combo && state.button_left { + buttons2.insert(Buttons2::LEFT) + } + if state.button_right { + buttons2.insert(Buttons2::RIGHT) + } + if state.button_start { + buttons2.insert(Buttons2::START) + } + if !state.combo && state.button_select_hold { + buttons2.insert(Buttons2::SELECT) + } // Assemble data and send it to endpoint let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; diff --git a/src/controller/emulated/sotp031201_p4b7.rs b/src/controller/emulated/sotp031201_p4b7.rs index 2d6427b..e13623c 100644 --- a/src/controller/emulated/sotp031201_p4b7.rs +++ b/src/controller/emulated/sotp031201_p4b7.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0300, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x00, + b_device_sub_class: 0x0, + id_vendor: 0x0AE4, + id_product: 0x0101, + bcd_device: 0x0300, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", + i_serial_number: "SOTP-031201", +}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; @@ -68,20 +79,40 @@ pub fn update_gadget(state: &mut ControllerState) { state.reverser = 0x40; state.combo = true; } - if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } - if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } - if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } - if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } - if state.button_right { buttons2.insert(Buttons2::RIGHT) } - if state.button_start { buttons2.insert(Buttons2::START) } - if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_a { + buttons1.insert(Buttons1::A) + } + if state.button_b { + buttons1.insert(Buttons1::B) + } + if state.button_c { + buttons1.insert(Buttons1::C) + } + if !state.combo && state.button_d { + buttons1.insert(Buttons1::D) + } + if !state.combo && state.button_up { + buttons2.insert(Buttons2::UP) + } + if !state.combo && state.button_down { + buttons2.insert(Buttons2::DOWN) + } + if !state.combo && state.button_left { + buttons2.insert(Buttons2::LEFT) + } + if state.button_right { + buttons2.insert(Buttons2::RIGHT) + } + if state.button_start { + buttons2.insert(Buttons2::START) + } + if !state.combo && state.button_select_hold { + buttons2.insert(Buttons2::SELECT) + } // Assemble data and send it to endpoint let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/emulated/sotp031201_p5b5.rs b/src/controller/emulated/sotp031201_p5b5.rs index ff30f65..344a2a5 100644 --- a/src/controller/emulated/sotp031201_p5b5.rs +++ b/src/controller/emulated/sotp031201_p5b5.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, bcd_device: 0x0202, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x00, + b_device_sub_class: 0x0, + id_vendor: 0x1C06, + id_product: 0x77A7, + bcd_device: 0x0202, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", + i_serial_number: "SOTP-031201", +}; const POWER_NOTCHES: [u8; 6] = [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01]; @@ -68,20 +79,40 @@ pub fn update_gadget(state: &mut ControllerState) { state.reverser = 0x10; state.combo = true; } - if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } - if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } - if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } - if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } - if state.button_right { buttons2.insert(Buttons2::RIGHT) } - if state.button_start { buttons2.insert(Buttons2::START) } - if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_a { + buttons1.insert(Buttons1::A) + } + if state.button_b { + buttons1.insert(Buttons1::B) + } + if state.button_c { + buttons1.insert(Buttons1::C) + } + if !state.combo && state.button_d { + buttons1.insert(Buttons1::D) + } + if !state.combo && state.button_up { + buttons2.insert(Buttons2::UP) + } + if !state.combo && state.button_down { + buttons2.insert(Buttons2::DOWN) + } + if !state.combo && state.button_left { + buttons2.insert(Buttons2::LEFT) + } + if state.button_right { + buttons2.insert(Buttons2::RIGHT) + } + if state.button_start { + buttons2.insert(Buttons2::START) + } + if !state.combo && state.button_select_hold { + buttons2.insert(Buttons2::SELECT) + } // Assemble data and send it to endpoint let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/emulated/sotp031201_p5b7.rs b/src/controller/emulated/sotp031201_p5b7.rs index 5cb5ee3..9b1f1b7 100644 --- a/src/controller/emulated/sotp031201_p5b7.rs +++ b/src/controller/emulated/sotp031201_p5b7.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0800, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x00, + b_device_sub_class: 0x0, + id_vendor: 0x0AE4, + id_product: 0x0101, + bcd_device: 0x0800, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", + i_serial_number: "SOTP-031201", +}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; @@ -68,20 +79,40 @@ pub fn update_gadget(state: &mut ControllerState) { state.reverser = 0x40; state.combo = true; } - if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if !state.combo && state.button_d { buttons1.insert(Buttons1::D) } - if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } - if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } - if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } - if state.button_right { buttons2.insert(Buttons2::RIGHT) } - if state.button_start { buttons2.insert(Buttons2::START) } - if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_a { + buttons1.insert(Buttons1::A) + } + if state.button_b { + buttons1.insert(Buttons1::B) + } + if state.button_c { + buttons1.insert(Buttons1::C) + } + if !state.combo && state.button_d { + buttons1.insert(Buttons1::D) + } + if !state.combo && state.button_up { + buttons2.insert(Buttons2::UP) + } + if !state.combo && state.button_down { + buttons2.insert(Buttons2::DOWN) + } + if !state.combo && state.button_left { + buttons2.insert(Buttons2::LEFT) + } + if state.button_right { + buttons2.insert(Buttons2::RIGHT) + } + if state.button_start { + buttons2.insert(Buttons2::START) + } + if !state.combo && state.button_select_hold { + buttons2.insert(Buttons2::SELECT) + } // Assemble data and send it to endpoint let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/emulated/tcpp20009.rs b/src/controller/emulated/tcpp20009.rs index f36217d..cf11812 100644 --- a/src/controller/emulated/tcpp20009.rs +++ b/src/controller/emulated/tcpp20009.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Type 2 mode)", i_serial_number: "TCPP20010"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0xFF, + b_device_sub_class: 0x4, + id_vendor: 0x0AE4, + id_product: 0x0004, + bcd_device: 0x0102, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (Type 2 mode)", + i_serial_number: "TCPP20010", +}; 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]; @@ -36,23 +47,51 @@ pub fn update_gadget(state: &mut ControllerState) { // Calculate data for buttons let mut buttons = Buttons::NONE; - if state.button_a { buttons.insert(Buttons::A) } - if state.button_b { buttons.insert(Buttons::B) } - if state.button_c { buttons.insert(Buttons::C) } - if state.button_d { buttons.insert(Buttons::D) } - if state.button_select { buttons.insert(Buttons::SELECT) } - if state.button_start { buttons.insert(Buttons::START) } + if state.button_a { + buttons.insert(Buttons::A) + } + if state.button_b { + buttons.insert(Buttons::B) + } + if state.button_c { + buttons.insert(Buttons::C) + } + if state.button_d { + buttons.insert(Buttons::D) + } + if state.button_select { + buttons.insert(Buttons::SELECT) + } + if state.button_start { + buttons.insert(Buttons::START) + } // Calculate data for D-pad let mut dpad: u8 = 0x8; - if state.button_up { dpad = 0x0 } - if state.button_down { dpad = 0x4 } - if state.button_left { dpad = 0x6 } - if state.button_right { dpad = 0x2 } - if state.button_up & state.button_left { dpad = 0x7 } - if state.button_up & state.button_right { dpad = 0x1 } - if state.button_down & state.button_left { dpad = 0x5 } - if state.button_down & state.button_right { dpad = 0x3 } + if state.button_up { + dpad = 0x0 + } + if state.button_down { + dpad = 0x4 + } + if state.button_left { + dpad = 0x6 + } + if state.button_right { + dpad = 0x2 + } + if state.button_up & state.button_left { + dpad = 0x7 + } + if state.button_up & state.button_right { + dpad = 0x1 + } + if state.button_down & state.button_left { + dpad = 0x5 + } + if state.button_down & state.button_right { + dpad = 0x3 + } // Assemble data and send it to endpoint let data = [0x1, brake, power, 0xFF, dpad, buttons.bits]; diff --git a/src/controller/emulated/tcpp20011.rs b/src/controller/emulated/tcpp20011.rs index 5136585..8c3f0da 100644 --- a/src/controller/emulated/tcpp20011.rs +++ b/src/controller/emulated/tcpp20011.rs @@ -1,18 +1,29 @@ use std::fs::File; use std::io::Write; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; -pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, -0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, -0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 48] = [ + 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, + 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x5, id_vendor: 0x0AE4, id_product: 0x0005, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Shinkansen mode)", i_serial_number: "TCPP20011"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0xFF, + b_device_sub_class: 0x5, + id_vendor: 0x0AE4, + id_product: 0x0005, + bcd_device: 0x0102, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (Shinkansen mode)", + i_serial_number: "TCPP20011", +}; const POWER_NOTCHES: [u8; 6] = [0x12, 0x36, 0x5A, 0x90, 0xC6, 0xFB]; const BRAKE_NOTCHES: [u8; 10] = [0x1C, 0x38, 0x54, 0x70, 0x8B, 0xA7, 0xC3, 0xDF, 0xDF, 0xFB]; @@ -36,27 +47,55 @@ pub fn update_gadget(state: &mut ControllerState) { // Calculate data for buttons let mut buttons = Buttons::NONE; - if state.button_a { buttons.insert(Buttons::A) } - if state.button_b { buttons.insert(Buttons::B) } - if state.button_c { buttons.insert(Buttons::C) } - if state.button_d { buttons.insert(Buttons::D) } - if state.button_select { buttons.insert(Buttons::SELECT) } - if state.button_start { buttons.insert(Buttons::START) } + if state.button_a { + buttons.insert(Buttons::A) + } + if state.button_b { + buttons.insert(Buttons::B) + } + if state.button_c { + buttons.insert(Buttons::C) + } + if state.button_d { + buttons.insert(Buttons::D) + } + if state.button_select { + buttons.insert(Buttons::SELECT) + } + if state.button_start { + buttons.insert(Buttons::START) + } // Calculate data for D-pad let mut dpad: u8 = 0x8; - if state.button_up { dpad = 0x0 } - if state.button_down { dpad = 0x4 } - if state.button_left { dpad = 0x6 } - if state.button_right { dpad = 0x2 } - if state.button_up & state.button_left { dpad = 0x7 } - if state.button_up & state.button_right { dpad = 0x1 } - if state.button_down & state.button_left { dpad = 0x5 } - if state.button_down & state.button_right { dpad = 0x3 } + if state.button_up { + dpad = 0x0 + } + if state.button_down { + dpad = 0x4 + } + if state.button_left { + dpad = 0x6 + } + if state.button_right { + dpad = 0x2 + } + if state.button_up & state.button_left { + dpad = 0x7 + } + if state.button_up & state.button_right { + dpad = 0x1 + } + if state.button_down & state.button_left { + dpad = 0x5 + } + if state.button_down & state.button_right { + dpad = 0x3 + } // Assemble data and send it to endpoint let data = [brake, power, 0xFF, dpad, buttons.bits, 0x0]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/emulated/zkns001.rs b/src/controller/emulated/zkns001.rs index 211b7fd..627f5eb 100644 --- a/src/controller/emulated/zkns001.rs +++ b/src/controller/emulated/zkns001.rs @@ -1,68 +1,79 @@ -use std::fs::File; -use std::io::{Write}; -use bitflags::bitflags; -use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; +use crate::controller::physical::ControllerState; +use bitflags::bitflags; +use std::fs::File; +use std::io::Write; -pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, -0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, -0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x5E, 0x00, -0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, -0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, -0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, -0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x5E, 0x00, -0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, -0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05]; -pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +pub const DESCRIPTORS: [u8; 80] = [ + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, + 0x5E, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, + 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, + 0x5E, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, +]; +pub const STRINGS: [u8; 16] = [ + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x33DD, id_product: 0x0001, bcd_device: 0x0106, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (NS One Handle mode)", i_serial_number: "ZKNS-001"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor { + b_device_class: 0x0, + b_device_sub_class: 0x0, + id_vendor: 0x33DD, + id_product: 0x0001, + bcd_device: 0x0106, + i_manufacturer: "TAITO", + i_product: "Densha de Go! Plug & Play (NS One Handle mode)", + i_serial_number: "ZKNS-001", +}; pub const HID_REPORT_DESCRIPTOR: [u8; 94] = [ - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x05, // Usage (Game Pad) - 0xA1, 0x01, // Collection (Application) - 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, 0x0E, // Report Count (14) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x0E, // Usage Maximum (0x0E) - 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) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x25, 0x07, // Logical Maximum (7) - 0x46, 0x3B, 0x01, // Physical Maximum (315) - 0x75, 0x04, // Report Size (4) - 0x95, 0x01, // Report Count (1) - 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) - 0x09, 0x39, // Usage (Hat switch) - 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) - 0x65, 0x00, // Unit (None) - 0x95, 0x01, // Report Count (1) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x0A, 0x4F, 0x48, // Usage (0x484F) - 0x75, 0x08, // Report Size (8) - 0x95, 0x08, // Report Count (8) - 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x0A, 0x4F, 0x48, // Usage (0x484F) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 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, 0x0E, // Report Count (14) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0E, // Usage Maximum (0x0E) + 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) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x75, 0x08, // Report Size (8) + 0x95, 0x08, // Report Count (8) + 0xB1, + 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x91, + 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection ]; const POWER_NOTCHES: [u8; 6] = [0x80, 0x9F, 0xB7, 0xCE, 0xE6, 0xFF]; @@ -109,28 +120,67 @@ pub fn update_gadget(state: &mut ControllerState) { buttons2.insert(Buttons2::HOME); state.combo = true; } - if state.button_a { buttons1.insert(Buttons1::Y) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::A) } - if state.button_d { buttons1.insert(Buttons1::X) } - if state.brake == 9 { buttons1.insert(Buttons1::ZL) } - if !state.combo && state.button_start { buttons2.insert(Buttons2::START) } - if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } + if state.button_a { + buttons1.insert(Buttons1::Y) + } + if state.button_b { + buttons1.insert(Buttons1::B) + } + if state.button_c { + buttons1.insert(Buttons1::A) + } + if state.button_d { + buttons1.insert(Buttons1::X) + } + if state.brake == 9 { + buttons1.insert(Buttons1::ZL) + } + if !state.combo && state.button_start { + buttons2.insert(Buttons2::START) + } + if !state.combo && state.button_select_hold { + buttons2.insert(Buttons2::SELECT) + } // Calculate data for D-pad let mut dpad: u8 = 0xF; - if state.button_up { dpad = 0x0 } - if state.button_down { dpad = 0x4 } - if !state.combo && state.button_left { dpad = 0x6 } - if !state.combo && state.button_right { dpad = 0x2 } - if !state.combo && state.button_up & state.button_left { dpad = 0x7 } - if !state.combo && state.button_up & state.button_right { dpad = 0x1 } - if !state.combo && state.button_down & state.button_left { dpad = 0x5 } - if !state.combo && state.button_down & state.button_right { dpad = 0x3 } + if state.button_up { + dpad = 0x0 + } + if state.button_down { + dpad = 0x4 + } + if !state.combo && state.button_left { + dpad = 0x6 + } + if !state.combo && state.button_right { + dpad = 0x2 + } + if !state.combo && state.button_up & state.button_left { + dpad = 0x7 + } + if !state.combo && state.button_up & state.button_right { + dpad = 0x1 + } + if !state.combo && state.button_down & state.button_left { + dpad = 0x5 + } + if !state.combo && state.button_down & state.button_right { + dpad = 0x3 + } // Assemble data and send it to gadget - let data = [buttons1.bits, buttons2.bits, dpad, 0x80, handle, 0x80, 0x80, 0x00]; + let data = [ + buttons1.bits, + buttons2.bits, + dpad, + 0x80, + handle, + 0x80, + 0x80, + 0x00, + ]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } -} \ No newline at end of file +} diff --git a/src/controller/physical.rs b/src/controller/physical.rs index c995b9f..4e0fb19 100644 --- a/src/controller/physical.rs +++ b/src/controller/physical.rs @@ -1,7 +1,7 @@ use std::fs::File; -use std::io::Write; use std::io::Result; -use std::time::{Instant,Duration}; +use std::io::Write; +use std::time::{Duration, Instant}; use evdev::Device; use evdev::Key; @@ -30,9 +30,34 @@ pub struct ControllerState { const HOLD_DELAY: Duration = Duration::from_millis(750); -const USED_KEYS: [Key; 26] = [Key::KEY_0, Key::KEY_1, Key::KEY_2, Key::KEY_3, Key::KEY_4, Key::KEY_5, - Key::KEY_B, Key::KEY_C, Key::KEY_D, Key::KEY_E, Key::KEY_F, Key::KEY_G, Key::KEY_H, Key::KEY_I, Key::KEY_J, Key::KEY_P, - Key::KEY_SPACE, Key::KEY_ENTER, Key::KEY_A, Key::KEY_Z, Key::KEY_X, Key::KEY_S, Key::KEY_UP, Key::KEY_DOWN, Key::KEY_LEFT, Key::KEY_RIGHT]; +const USED_KEYS: [Key; 26] = [ + Key::KEY_0, + Key::KEY_1, + Key::KEY_2, + Key::KEY_3, + Key::KEY_4, + Key::KEY_5, + Key::KEY_B, + Key::KEY_C, + Key::KEY_D, + Key::KEY_E, + Key::KEY_F, + Key::KEY_G, + Key::KEY_H, + Key::KEY_I, + Key::KEY_J, + Key::KEY_P, + Key::KEY_SPACE, + Key::KEY_ENTER, + Key::KEY_A, + Key::KEY_Z, + Key::KEY_X, + Key::KEY_S, + Key::KEY_UP, + Key::KEY_DOWN, + Key::KEY_LEFT, + Key::KEY_RIGHT, +]; pub fn init() -> Result<[Device; 2]> { let d1 = Device::open("/dev/input/event1")?; @@ -55,27 +80,90 @@ pub fn get_state(state: &mut ControllerState, dev: &[Device; 2]) { fn read_input(controller: &mut ControllerState, key: Key, value: bool) { // Save input status to object for processing match key { - Key::KEY_0=>if value {controller.power = 0}, - Key::KEY_1=>if value {controller.power = 1}, - Key::KEY_2=>if value {controller.power = 2}, - Key::KEY_3=>if value {controller.power = 3}, - Key::KEY_4=>if value {controller.power = 4}, - Key::KEY_5=>if value {controller.power = 5}, - Key::KEY_B=>if value {controller.brake = 0}, - Key::KEY_C=>if value {controller.brake = 1}, - Key::KEY_D=>if value {controller.brake = 2}, - Key::KEY_E=>if value {controller.brake = 3}, - Key::KEY_F=>if value {controller.brake = 4}, - Key::KEY_G=>if value {controller.brake = 5}, - Key::KEY_H=>if value {controller.brake = 6}, - Key::KEY_I=>if value {controller.brake = 7}, - Key::KEY_J=>if value {controller.brake = 8}, - Key::KEY_P=>if value {controller.brake = 9}, - Key::KEY_SPACE=> { + Key::KEY_0 => { + if value { + controller.power = 0 + } + } + Key::KEY_1 => { + if value { + controller.power = 1 + } + } + Key::KEY_2 => { + if value { + controller.power = 2 + } + } + Key::KEY_3 => { + if value { + controller.power = 3 + } + } + Key::KEY_4 => { + if value { + controller.power = 4 + } + } + Key::KEY_5 => { + if value { + controller.power = 5 + } + } + Key::KEY_B => { + if value { + controller.brake = 0 + } + } + Key::KEY_C => { + if value { + controller.brake = 1 + } + } + Key::KEY_D => { + if value { + controller.brake = 2 + } + } + Key::KEY_E => { + if value { + controller.brake = 3 + } + } + Key::KEY_F => { + if value { + controller.brake = 4 + } + } + Key::KEY_G => { + if value { + controller.brake = 5 + } + } + Key::KEY_H => { + if value { + controller.brake = 6 + } + } + Key::KEY_I => { + if value { + controller.brake = 7 + } + } + Key::KEY_J => { + if value { + controller.brake = 8 + } + } + Key::KEY_P => { + if value { + controller.brake = 9 + } + } + Key::KEY_SPACE => { if !controller.button_select && value { controller.button_select_time = Some(Instant::now()); - } - else if !value { + } else if !value { controller.button_select_time = None; controller.combo = false; } @@ -84,23 +172,23 @@ fn read_input(controller: &mut ControllerState, key: Key, value: bool) { if let Some(time) = controller.button_select_time { controller.button_select_hold = time.elapsed() > HOLD_DELAY && !controller.combo; } - }, - Key::KEY_ENTER=>controller.button_start = value, - Key::KEY_A=>controller.button_a = value, - Key::KEY_Z=>controller.button_b = value, - Key::KEY_X=>controller.button_c = value, - Key::KEY_S=>controller.button_d = value, - Key::KEY_UP=>controller.button_up = value, - Key::KEY_DOWN=>controller.button_down = value, - Key::KEY_LEFT=>controller.button_left = value, - Key::KEY_RIGHT=>controller.button_right = value, - _=>(), + } + Key::KEY_ENTER => controller.button_start = value, + Key::KEY_A => controller.button_a = value, + Key::KEY_Z => controller.button_b = value, + Key::KEY_X => controller.button_c = value, + Key::KEY_S => controller.button_d = value, + Key::KEY_UP => controller.button_up = value, + Key::KEY_DOWN => controller.button_down = value, + Key::KEY_LEFT => controller.button_left = value, + Key::KEY_RIGHT => controller.button_right = value, + _ => (), } } pub fn set_lamp(status: bool) { if let Ok(mut out) = File::create("/sys/class/leds/led2/brightness") { - out.write(if status {b"1"} else {b"0"}).ok(); + out.write(if status { b"1" } else { b"0" }).ok(); } /*else { println!("WARNING: Could not set door lamp status!") @@ -109,7 +197,7 @@ pub fn set_lamp(status: bool) { pub fn set_rumble(status: bool) { if let Ok(mut out) = File::create("/sys/class/leds/led1/brightness") { - out.write(if status {b"1"} else {b"0"}).ok(); + out.write(if status { b"1" } else { b"0" }).ok(); } /*else { println!("WARNING: Could not set rumble motor status!") diff --git a/src/main.rs b/src/main.rs index e3419dd..e07bbb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,10 +2,10 @@ mod controller; use std::io::Result; use std::process::Command; -use std::time::Duration; use std::thread::sleep; +use std::time::Duration; -use controller::physical::{set_lamp,set_rumble}; +use controller::physical::{set_lamp, set_rumble}; fn main() -> Result<()> { match controller::physical::init() { @@ -18,7 +18,6 @@ fn main() -> Result<()> { // Check selected controller model if let Some(controller_model) = controller::emulated::set_model(&controller_state) { - // Stop main game stop_game(); @@ -43,12 +42,15 @@ fn main() -> Result<()> { } } return Result::Ok(()); - }, + } Err(_e) => println!("ddgo-pnp-controller: ERROR: Could not read input devices! Exiting."), } Ok(()) } fn stop_game() { - Command::new("/etc/init.d/S99dgtype3").arg("stop").output().ok(); -} \ No newline at end of file + Command::new("/etc/init.d/S99dgtype3") + .arg("stop") + .output() + .ok(); +} From 5d70ae00d4f4b12455df01dc925cdf7fb36a4d48 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sun, 23 Mar 2025 21:38:42 +0100 Subject: [PATCH 12/12] Release: 1.2.1 --- README.md | 12 ++++++++++++ dist/hook_magic_36558b710a.sh | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/README.md b/README.md index fb86bb3..c275d7d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,18 @@ This mod allows you to use your Densha de GO! Plug & Play as a USB controller fo 4. Plug the USB drive to the OTG adapter, plug the adapter to the Plug & Play and plug the data cable to the adapter and a power source. 5. Turn on the Plug & Play. The door lamp will turn on to show the installation has begun. Once it has finished, the lamp will turn off. Turn off the unit and remove everything. +## Uninstallation + +To completely remove the mod, follow these steps. **You need the backup of the original kernel created during installation**. + +1. Prepare the USB flash drive by formatting it with a single FAT32 partition. +2. Download the latest release from the [Releases](https://github.com/MarcRiera/ddgo-pnp-controller/releases) section. +3. Extract the content to the root of the USB drive. +4. Create an empty file named `revert` on the root of the USB drive. +5. Put the original (backup) files `uImage` and `mali.ko` into a folder named `BACKUP` on the root of the USB drive. +6. Plug the USB drive to the OTG adapter, plug the adapter to the Plug & Play and plug the data cable to the adapter and a power source. +7. Turn on the Plug & Play. The door lamp will turn on to show the uninstallation has begun. Once it has finished, the lamp will turn off. Turn off the unit and remove everything. + ## Usage Connect the Plug & Play to a PC or console using the data cable. Press one of the following button combinations to select the controller you want to emulate: diff --git a/dist/hook_magic_36558b710a.sh b/dist/hook_magic_36558b710a.sh index f600c4f..96ce05e 100644 --- a/dist/hook_magic_36558b710a.sh +++ b/dist/hook_magic_36558b710a.sh @@ -36,6 +36,22 @@ fi # Create backup folder mkdir -p "${USB_ROOT}/BACKUP" +# Revert changes flag detected, restore original files +if [ -f "${USB_ROOT}/revert" ]; then + if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] || [ ! -f "${USB_ROOT}/BACKUP/mali.ko" ]; then + echo "Backup not found, cannot revert." + error_exit + fi + cp "${USB_ROOT}/BACKUP/uImage" /tmp/boot/uImage + cp "${USB_ROOT}/BACKUP/mali.ko" /lib/modules/3.4.113/extra/mali.ko + rm /etc/init.d/S40usbotg + rm /usr/bin/rndis-gadget.sh + rm /usr/bin/ddgo-pnp-controller + rm "${USB_ROOT}/revert" + poweroff + exit +fi + # Backup original kernel if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] && [ ! -f "/usr/bin/input_relay" ] && [ ! -f "/usr/bin/ddgo-pnp-controller" ]; then if ! cp /tmp/boot/uImage "${USB_ROOT}/BACKUP/"; then