Fix Dualshock 3 Emulation

Missing reports were added and it will now work on an actual PS3.
This commit is contained in:
Frederik Walk 2024-11-17 00:10:22 +01:00
parent 33530a37fe
commit 678e5939c5

View File

@ -125,13 +125,41 @@ bool send_hid_ps3_report(usb_report_t report) {
return result; return result;
} }
static const uint8_t ps3_report_0x01[] = {
0x01, 0x04, 0x00, 0x0b, 0x0c, 0x01, 0x02, 0x18, 0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12,
0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04,
0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static int8_t ps3_report_0xef[] = {
0xef, 0x04, 0x00, 0x0b, 0x03, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
};
static uint8_t ps3_report_0xf2[] = { static uint8_t ps3_report_0xf2[] = {
0xff, 0xff, 0x00, // Unknown 0xff, 0xff, 0x00, // Unknown
0x00, 0x07, 0x04, // MAC address OUI (ALPS Co.) 0x00, 0x07, 0x04, 0x39, 0x39, 0x39, // Device MAC address
0x39, 0x39, 0x39, // MAC manufacturer specific 0x00, // Unknown
0x00, 0x03, 0x50, 0x81, 0xd8, 0x01, 0x8a // Unknown 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, // Host MAC address (must match 0xf5)
0x00, // Unkown
};
static const uint8_t ps3_report_0xf5[] = {
0x00, //
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, // Host MAC address (must match 0xf2)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static uint8_t ps3_report_0xf8[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; };
static const uint8_t ps3_report_0xf5[] = {0x00, 0xf0, 0xf0, 0x02, 0x5e, 0x16, 0x26}; // Unknown
uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer,
uint16_t reqlen) { uint16_t reqlen) {
@ -145,6 +173,12 @@ uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
return sizeof(hid_ps3_report_t); return sizeof(hid_ps3_report_t);
} else if (report_type == HID_REPORT_TYPE_FEATURE) { } else if (report_type == HID_REPORT_TYPE_FEATURE) {
switch (report_id) { switch (report_id) {
case 0x01:
memcpy(buffer, ps3_report_0x01, sizeof(ps3_report_0x01));
return sizeof(ps3_report_0x01);
case 0xef:
memcpy(buffer, ps3_report_0xef, sizeof(ps3_report_0xef));
return sizeof(ps3_report_0xef);
case 0xf2: case 0xf2:
if (do_init_mac) { if (do_init_mac) {
pico_unique_board_id_t uid; pico_unique_board_id_t uid;
@ -163,6 +197,9 @@ uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
case 0xf5: case 0xf5:
memcpy(buffer, ps3_report_0xf5, sizeof(ps3_report_0xf5)); memcpy(buffer, ps3_report_0xf5, sizeof(ps3_report_0xf5));
return sizeof(ps3_report_0xf5); return sizeof(ps3_report_0xf5);
case 0xf8:
memcpy(buffer, ps3_report_0xf8, sizeof(ps3_report_0xf8));
return sizeof(ps3_report_0xf8);
default: default:
} }
} }
@ -170,7 +207,7 @@ uint16_t hid_ps3_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
} }
typedef struct __attribute((packed, aligned(1))) { typedef struct __attribute((packed, aligned(1))) {
uint8_t rumble[4]; uint8_t rumble[4]; // Should be length 5, but for some reason we don't get the first byte on linux.
uint8_t padding[4]; uint8_t padding[4];
uint8_t leds_bitmap; uint8_t leds_bitmap;
uint8_t leds[5][5]; uint8_t leds[5][5];
@ -180,10 +217,16 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
uint16_t bufsize) { uint16_t bufsize) {
(void)itf; (void)itf;
if (report_type != HID_REPORT_TYPE_OUTPUT) { switch (report_type) {
return; case HID_REPORT_TYPE_FEATURE: {
switch (report_id) {
case 0xef:
ps3_report_0xef[6] = buffer[6];
ps3_report_0xf8[6] = buffer[6];
break;
} }
} break;
case HID_REPORT_TYPE_OUTPUT: {
if (report_id == 0 && bufsize > 0) { if (report_id == 0 && bufsize > 0) {
report_id = buffer[0]; report_id = buffer[0];
buffer = &buffer[1]; buffer = &buffer[1];
@ -191,8 +234,16 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
} }
switch (report_id) { switch (report_id) {
case 0x01: case 0x01: {
if (bufsize == sizeof(hid_ps3_ouput_report_t)) { // For some reason we don't see the first byte on linux. Since it is a padding
// byte and should always be 0x00, and linux always sets the following byte
// to 0xff, we skip it accordingly.
if (buffer[0] == 0x00 && bufsize > 0) {
buffer = &buffer[1];
bufsize--;
}
if (bufsize >= sizeof(hid_ps3_ouput_report_t)) {
hid_ps3_ouput_report_t *report = (hid_ps3_ouput_report_t *)buffer; hid_ps3_ouput_report_t *report = (hid_ps3_ouput_report_t *)buffer;
usb_player_led_t player_led = {.type = USB_PLAYER_LED_ID, .id = 0}; usb_player_led_t player_led = {.type = USB_PLAYER_LED_ID, .id = 0};
@ -203,7 +254,10 @@ void hid_ps3_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
usbd_driver_get_player_led_cb()(player_led); usbd_driver_get_player_led_cb()(player_led);
} }
break; } break;
default:
}
} break;
default: default:
} }
} }