Skip to content

Commit

Permalink
Support wired DS3 and alike devices
Browse files Browse the repository at this point in the history
  • Loading branch information
isage committed Jan 20, 2023
1 parent b18829b commit ec77366
Show file tree
Hide file tree
Showing 13 changed files with 462 additions and 130 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_executable(${PROJECT_NAME}
src/controller.c
src/controllers/xbox_360_controller.c
src/controllers/xbox_360w_controller.c
src/controllers/ds3_controller.c
)

target_link_libraries(${PROJECT_NAME}
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ For full list of supported devices see [here](src/devicelist.c)
* Add `ur0:tai/vixen.skprx` line under `*KERNEL` in tai config and reboot.
* For vita you need usb Y-cable and external power. See [this](https://github.com/isage/vita-usb-ether#hardware) for example.

## FAQ
* **Does it support joycon, xbox one s, _insert another wireless controller here_?**
NO. It supports **wired USB** controllers only. Yes, Xbox 360 is also wired (because you need receiver)
For wireless (bluetooth) use [ds34vita](https://github.com/MERLev/ds34vita), [VitaControl](https://github.com/Hydr8gon/VitaControl) or [MiniVitaTV](https://github.com/TheOfficialFloW/MiniVitaTV)
* **Can i connect mu Xbox 360 pad via charge'n'play?**
No. Because it's more charge than play. It doesn't support data. You need wireless receiver.
* **Does it support _insert controller name here_?**
Currently it supports plenty of x-input devices and wired ds3 (or ds3 compatible). See [here](src/devicelist.c)
If your device isn't in that list (or doesn't present itself as ds3 or xbox360 pad), see [that list](https://github.com/xboxdrv/xboxdrv/blob/stable/src/xpad_device.cpp#L29)
If it's in that list - i can add support. If it isn't - i, most likely, can't without having such device.
* **Can i install it alongside another input plugin?**
Generally that isn't recommended. Most input plugins (ds34vita/vitacontrol) hook same functions, conflicts will definitely arise.

## Building

* Install vitausb from https://github.com/isage/vita-packages-extra
Expand All @@ -32,4 +45,5 @@ MIT, see LICENSE.md
* [xboxdrv](https://github.com/xboxdrv/xboxdrv) - for vid/pid pairs and protocol description
* [xerpi](https://github.com/xerpi) - for ds3vita
* **CBPS discord** - for support and stupid ideas
* **rem** - for being lazy/buzy to do the same :P
* **rem** - for being lazy/buzy to do the same :P
* [Graphene](https://github.com/GrapheneCt) - for testing and ideas
6 changes: 6 additions & 0 deletions src/controller.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "controller.h"

#include "controllers/ds3_controller.h"
#include "controllers/xbox_360_controller.h"
#include "controllers/xbox_360w_controller.h"

Expand All @@ -20,6 +21,11 @@ void on_read_data(int32_t result, int32_t count, void *arg)
if (Xbox360Controller_processReport(c, count))
ksceKernelPowerTick(0); // cancel sleep timers.
}
else if (c->type == PAD_DS3)
{
if (DS3Controller_processReport(c, count))
ksceKernelPowerTick(0); // cancel sleep timers.
}
else
{
if (Xbox360WController_processReport(c, count))
Expand Down
5 changes: 3 additions & 2 deletions src/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include "devicelist.h"

#include <psp2common/types.h>
#include <psp2kern/usbd.h>
#include <psp2kern/kernel/debug.h>
#include <psp2kern/usbd.h>
#include <stdint.h>

typedef struct
Expand All @@ -30,7 +30,8 @@ typedef struct
uint8_t port;
SceUID pipe_in;
SceUID pipe_out;
unsigned char buffer[32] __attribute__((aligned(64)));
SceUID pipe_control;
unsigned char buffer[64] __attribute__((aligned(64)));
size_t buffer_size;

} Controller;
Expand Down
267 changes: 267 additions & 0 deletions src/controllers/ds3_controller.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
#include "ds3_controller.h"

#include "../unpack.h"
#include "ds3_report.h"

#include <psp2kern/ctrl.h>
#include <psp2kern/kernel/debug.h>
#include <psp2kern/kernel/threadmgr.h>

#define USB_ENDPOINT_OUT 0x02
#define USB_ENDPOINT_IN 0x81

#define HID_GET_REPORT 0x01
#define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03
#define HID_SET_REPORT 0x09
#define HID_SET_IDLE 0x0A
#define HID_SET_PROTOCOL 0x0B

#define HID_REPORT_TYPE_INPUT 0x01
#define HID_REPORT_TYPE_OUTPUT 0x02
#define HID_REPORT_TYPE_FEATURE 0x03

void oncontrol(int32_t result, int32_t count, void *arg)
{
ksceDebugPrintf("oncontrol: %x %d\n", result, count);
}

uint8_t DS3Controller_probe(Controller *c, int device_id, int port)
{
c->type = PAD_DS3;
c->buffer_size = 64;
c->device_id = device_id;
c->port = port;
c->battery_level = 5;

// init endpoints and stuff
SceUsbdEndpointDescriptor *endpoint;
#if defined(DEBUG)
ksceDebugPrintf("scanning endpoints for device %d\n", device_id);
#endif
endpoint = (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, 0, SCE_USBD_DESCRIPTOR_ENDPOINT);
while (endpoint)
{
#if defined(DEBUG)
ksceDebugPrintf("got EP: %02x\n", endpoint->bEndpointAddress);
#endif
if (endpoint->bEndpointAddress == USB_ENDPOINT_IN)
{
#if defined(DEBUG)
ksceDebugPrintf("opening in pipe\n");
#endif
c->pipe_in = ksceUsbdOpenPipe(device_id, endpoint);
#if defined(DEBUG)
ksceDebugPrintf("= 0x%08x\n", c->pipe_in);
ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes);
#endif
}
else if (endpoint->bEndpointAddress == USB_ENDPOINT_OUT)
{
#if defined(DEBUG)
ksceDebugPrintf("opening out pipe\n");
#endif
c->pipe_out = ksceUsbdOpenPipe(device_id, endpoint);
#if defined(DEBUG)
ksceDebugPrintf("= 0x%08x\n", c->pipe_out);
ksceDebugPrintf("bmAttributes = %x\n", endpoint->bmAttributes);
#endif
}
endpoint
= (SceUsbdEndpointDescriptor *)ksceUsbdScanStaticDescriptor(device_id, endpoint, SCE_USBD_DESCRIPTOR_ENDPOINT);
}

if (c->pipe_in > 0 && c->pipe_out > 0)
{
SceUsbdConfigurationDescriptor *cdesc;
if ((cdesc = (SceUsbdConfigurationDescriptor *)ksceUsbdScanStaticDescriptor(device_id, NULL,
SCE_USBD_DESCRIPTOR_CONFIGURATION))
== NULL)
return 0;

SceUID control_pipe_id = ksceUsbdOpenPipe(device_id, NULL);
c->pipe_control = control_pipe_id;
// set default config
int r = ksceUsbdSetConfiguration(control_pipe_id, cdesc->bConfigurationValue, &oncontrol, NULL);
#if defined(DEBUG)
ksceDebugPrintf("ksceUsbdSetConfiguration = 0x%08x\n", r);
#endif
if (r < 0)
return 0;
c->attached = 1;
c->inited = 1;
}

// init command
// TODO: use eventflag?
ksceKernelDelayThread(500000);
uint8_t cmd[] __attribute__((aligned(64)))
= {0x42, 0x0c, 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};

SceUsbdDeviceRequest _dr;
_dr.bmRequestType = 0x21;
_dr.bRequest = HID_SET_REPORT;
_dr.wValue = 0x03F4;
_dr.wIndex = 0;
_dr.wLength = 4;
ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, &oncontrol, NULL);

// TODO: use eventflag?
ksceKernelDelayThread(500000);
DS3Controller_setLed(c, port + 1);

usb_read(c);
return 1;
}

void DS3Controller_setRumble(Controller *c, uint8_t small, uint8_t large)
{
uint8_t cmd[] __attribute__((aligned(64))) = {0x00, 0xFE, small > 0 ? 0x01 : 0x00,
0xFE, large, // rumble values
0x00, 0x00, 0x00,
0x00, 0x03, // 0x10=LED1 .. 0x02=LED4
0xff, 0x27, 0x10,
0x00, 0x32, // LED 4
0xff, 0x27, 0x10,
0x00, 0x32, // LED 3
0xff, 0x27, 0x10,
0x00, 0x32, // LED 2
0xff, 0x27, 0x10,
0x00, 0x32, // LED 1
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};

SceUsbdDeviceRequest _dr;
_dr.bmRequestType = 0x21;
_dr.bRequest = HID_SET_REPORT;
_dr.wValue = (HID_REPORT_TYPE_OUTPUT << 8) | 0x01;
_dr.wIndex = 0;
_dr.wLength = sizeof(cmd);
int ret = ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, NULL, NULL);
ksceDebugPrintf("ksceUsbdControlTransfer(rumble): %x\n", ret);
}

void DS3Controller_setLed(Controller *c, uint8_t led)
{
uint8_t cmd[] __attribute__((aligned(64)))
= {0x00, 0x00, 0x00, 0x00, 0x00, // rumble values
0x00, 0x00, 0x00, 0x00, 0x01 << led, // 0x10=LED1 .. 0x02=LED4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 4
0xff, 0x27, 0x10, 0x00, 0x32, // LED 3
0xff, 0x27, 0x10, 0x00, 0x32, // LED 2
0xff, 0x27, 0x10, 0x00, 0x32, // LED 1
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};

SceUsbdDeviceRequest _dr;
_dr.bmRequestType = 0x21;
_dr.bRequest = HID_SET_REPORT;
_dr.wValue = (HID_REPORT_TYPE_OUTPUT << 8) | 0x01;
_dr.wIndex = 0;
_dr.wLength = sizeof(cmd);
ksceUsbdControlTransfer(c->pipe_control, (&_dr), (uint8_t *)&cmd, &oncontrol, NULL);
}

uint8_t DS3Controller_processReport(Controller *c, size_t length)
{
DS3Report report;

report.select = bit(c->buffer + 2, 0);
report.l3 = bit(c->buffer + 2, 1);
report.r3 = bit(c->buffer + 2, 2);
report.start = bit(c->buffer + 2, 3);

report.dpad_up = bit(c->buffer + 2, 4);
report.dpad_right = bit(c->buffer + 2, 5);
report.dpad_down = bit(c->buffer + 2, 6);
report.dpad_left = bit(c->buffer + 2, 7);

report.l2 = bit(c->buffer + 3, 0);
report.r2 = bit(c->buffer + 3, 1);
report.l1 = bit(c->buffer + 3, 2);
report.r1 = bit(c->buffer + 3, 3);

report.triangle = bit(c->buffer + 3, 4);
report.circle = bit(c->buffer + 3, 5);
report.cross = bit(c->buffer + 3, 6);
report.square = bit(c->buffer + 3, 7);

report.ps = bit(c->buffer + 4, 0);

report.x1 = c->buffer[6];
report.y1 = c->buffer[7];
report.x2 = c->buffer[8];
report.y2 = c->buffer[9];

report.l2a = c->buffer[18];
report.r2a = c->buffer[19];

c->controlData.buttons = 0;

if (report.cross)
c->controlData.buttons |= SCE_CTRL_CROSS;
if (report.circle)
c->controlData.buttons |= SCE_CTRL_CIRCLE;
if (report.triangle)
c->controlData.buttons |= SCE_CTRL_TRIANGLE;
if (report.square)
c->controlData.buttons |= SCE_CTRL_SQUARE;

if (report.dpad_up)
c->controlData.buttons |= SCE_CTRL_UP;
if (report.dpad_down)
c->controlData.buttons |= SCE_CTRL_DOWN;
if (report.dpad_left)
c->controlData.buttons |= SCE_CTRL_LEFT;
if (report.dpad_right)
c->controlData.buttons |= SCE_CTRL_RIGHT;

if (report.l1)
c->controlData.buttons |= SCE_CTRL_L1;
if (report.r1)
c->controlData.buttons |= SCE_CTRL_R1;
if (report.l3)
c->controlData.buttons |= SCE_CTRL_L3;
if (report.r3)
c->controlData.buttons |= SCE_CTRL_R3;

if (report.l2)
c->controlData.buttons |= SCE_CTRL_LTRIGGER;
if (report.r2)
c->controlData.buttons |= SCE_CTRL_RTRIGGER;

if (report.start)
c->controlData.buttons |= SCE_CTRL_START;
if (report.select)
c->controlData.buttons |= SCE_CTRL_SELECT;
if (report.ps)
c->controlData.buttons |= SCE_CTRL_PSBUTTON;

// ksceDebugPrintf("x1: %d\n", report.x1);

c->controlData.leftX = report.x1; // / 256 + 128;
c->controlData.leftY = report.y1; // / 256 + 128;
c->controlData.rightX = report.x2; // / 256 + 128;
c->controlData.rightY = report.y2; // / 256 + 128;

// up and down are reversed
// c->controlData.leftY = 255 - c->controlData.leftY;
// c->controlData.rightY = 255 - c->controlData.rightY;

c->controlData.lt = report.l2a;
c->controlData.rt = report.r2a;
return 1;
}
11 changes: 11 additions & 0 deletions src/controllers/ds3_controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef __DS3_CONTROLLER_H__
#define __DS3_CONTROLLER_H__

#include "../controller.h"

uint8_t DS3Controller_probe(Controller *c, int device_id, int port);
uint8_t DS3Controller_processReport(Controller *c, size_t length);
void DS3Controller_setRumble(Controller *c, uint8_t small, uint8_t large);
void DS3Controller_setLed(Controller *c, uint8_t led);

#endif // __DS3_CONTROLLER_H__
42 changes: 42 additions & 0 deletions src/controllers/ds3_report.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef __DS3_REPORT_H__
#define __DS3_REPORT_H__

#include <stdint.h>

typedef struct
{
uint8_t dpad_up : 1;
uint8_t dpad_down : 1;
uint8_t dpad_left : 1;
uint8_t dpad_right : 1;

uint8_t start : 1;
uint8_t select : 1;

uint8_t l3 : 1;
uint8_t r3 : 1;

uint8_t l1 : 1;
uint8_t r1 : 1;
uint8_t ps : 1;

uint8_t cross : 1;
uint8_t circle : 1;
uint8_t square : 1;
uint8_t triangle : 1;

uint8_t l2 : 8;
uint8_t r2 : 8;

uint8_t l2a : 8;
uint8_t r2a : 8;

int16_t x1 : 16;
int16_t y1 : 16;

int16_t x2 : 16;
int16_t y2 : 16;

} DS3Report;

#endif // __DS3_REPORT_H__
Loading

0 comments on commit ec77366

Please sign in to comment.