trying to port EMUPS3 firmware to linux with usb OTG
Posted: Fri Oct 05, 2018 4:04 pm
Hello,
I am trying to write a program in linux to replace EMUPS3 and the gimx adapter. For this purpose I use a APF28 dev board which has USB OTG.
Starting with gimx firmware code, I wrote something which is more and less working. When I plug my dev board to a linux computer, the DS3 is recognized by the kernel and I can send report to it (I still have some errors at the setup...). The log of my program is (from the dev board):
and dmesg on the computer gives:
Now when I plug the dev board to the PS3 I am getting the following the first time I launch the program:
and then if I relaunch it:
and the event REQ_GetReport ef is repeated a lot of time...
The problem seems to be that the PS3 is not sending its bluetooth mac address.
The send_thread of my program is blocked at the write function (writing to in end point).
So something is going wrong but I don't know what... Maybe someone here (Matlo?) has already tried to do something like that!
If anyone has an idea??
I am attaching my source code:
device.c:
device.h:
usbstring.c
usbstring.h:
adapter_protocol.h:
you can compile it with gcc -Wall -g -o usb device.c usbstring.c -lpthread
and here the program to test the reception of the report when plugged to a pc:
ds3_usb.c:
I am trying to write a program in linux to replace EMUPS3 and the gimx adapter. For this purpose I use a APF28 dev board which has USB OTG.
Starting with gimx firmware code, I wrote something which is more and less working. When I plug my dev board to a linux computer, the DS3 is recognized by the kernel and I can send report to it (I still have some errors at the setup...). The log of my program is (from the dev board):
Code: Select all
Start init
ep0 configured
waiting events on ep0
1 event(s)
EP0 CONNECT
waiting events on ep0
1 event(s)
EP0 DISCONNECT
waiting events on ep0
2 event(s)
EP0 CONNECT
EP0 SETUP
Setup request 6
USB_REQ_GET_DESCRIPTOR 300
Get string id #0 (max length 255)
Found 4 bytes
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 6
USB_REQ_GET_DESCRIPTOR 302
Get string id #2 (max length 255)
Found 54 bytes
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 6
USB_REQ_GET_DESCRIPTOR 301
Get string id #1 (max length 255)
Found 10 bytes
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 1
USB_TYPE_STANDARD 0
ep1 configured
ep2 configured
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request a
USB_REQ_GET_INTERFACE
error writting to usb_fd -1/1
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 6
USB_REQ_GET_DESCRIPTOR 2200
DTYPE_Report
waiting events on ep0
starting send_thread
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f2
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f2
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 201
USB_TYPE_CLASS 21 2 1
1 ff 0 ff 0 0 0 0 0 2 ff 27 10 0 32 ff 27 10 0 32 ff 27 10 0 32 ff 27 10 0 32 0 0 0 0 0
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f2
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 3f5
USB_TYPE_CLASS 21 3 f5
f5 1 xx xx xx xx xx xx (my bluetooth mac address)
REPORT_TYPE_FEATURE f5
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 201
USB_TYPE_CLASS 21 2 1
status of read = -1/35
ec 24 1 0 8 62 e0 b6 50 bd ed b6 ec 24 1 0 0 0 0 0 a 0 0 0 a 0 0 0 50 bd ed b6 b8 c6 ed
waiting events on ep0
Code: Select all
[17047.668109] usb 3-1: new high-speed USB device number 37 using xhci_hcd
[17047.826149] usb 3-1: New USB device found, idVendor=054c, idProduct=0268
[17047.826156] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[17047.826160] usb 3-1: Product: PLAYSTATION(R)3 Controller
[17047.826163] usb 3-1: Manufacturer: Sony
[17052.856313] sony 0003:054C:0268.001E: can't set operational mode: step 3, ignoring
[17052.856570] input: Sony PLAYSTATION(R)3 Controller Motion Sensors as /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:054C:0268.001E/input/input80
[17052.916462] input: Sony PLAYSTATION(R)3 Controller as /devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0/0003:054C:0268.001E/input/input79
[17052.916921] sony 0003:054C:0268.001E: input,hiddev0,hidraw1: USB HID v81.11 Joystick [Sony PLAYSTATION(R)3 Controller] on usb-0000:00:14.0-1/input0
Code: Select all
Start init
ep0 configured
waiting events on ep0
1 event(s)
EP0 CONNECT
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 1
USB_TYPE_STANDARD 0
ep1 configured
ep2 configured
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request a
USB_REQ_GET_INTERFACE
error writting to usb_fd -1/1
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport 1
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f2
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
starting send_thread
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 3ef
USB_TYPE_CLASS 21 3 ef
status of read = -1/48
ec 24 1 0 8 32 e9 b6 50 8d f6 b6 ec 24 1 0 0 0 0 0 a 0 0 0 a 0 0 0 50 8d f6 b6 b8 96 f6 b6 10 4e e9 b6 50 8d f6 b6 54 52 e9 b6
REPORT_TYPE_FEATURE ef
waiting events on ep0
Code: Select all
Start init
ep0 configured
waiting events on ep0
1 event(s)
EP0 CONNECT
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 9
USB_REQ_SET_CONFIGURATION 1
USB_TYPE_STANDARD 0
ep1 configured
ep2 configured
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request a
USB_REQ_GET_INTERFACE
error writting to usb_fd -1/1
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport 1
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f2
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
1 event(s)
starting send_thread
EP0 SETUP
Setup request 1
REQ_GetReport f5
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport ef
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport ef
waiting events on ep0
1 event(s)
EP0 SETUP
Setup request 1
REQ_GetReport ef
waiting events on ep0
1 event(s)
EP0 SETUP
The problem seems to be that the PS3 is not sending its bluetooth mac address.
The send_thread of my program is blocked at the write function (writing to in end point).
So something is going wrong but I don't know what... Maybe someone here (Matlo?) has already tried to do something like that!
If anyone has an idea??
I am attaching my source code:
device.c:
Code: Select all
/*
Copyright 2013 Mathieu Laurendeau (mat.lau [at] laposte [dot] net)
Redistributed under the GPLv3 licence.
Based on code by
Denver Gingerich (denver [at] ossguy [dot] com)
Dean Camera (dean [at] fourwalledcubicle [dot] com)
Original licence:
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
// $CC -Wall -g -o usb device.c usbstring.c -lpthread
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <linux/types.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadgetfs.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include "usbstring.h"
#include "device.h"
#include "adapter_protocol.h"
static uint8_t report[49] = {
0x01, 0x00, 0x00, 0x00,
0x00, //0x01 = PS3 button
0x00, 0x7a, 0x80, 0x82,
0x7d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x02, 0xee, 0x10, 0x00,
0x00, 0x00, 0x00, 0x02,
0xff, 0x77, 0x01, 0x80,
0x02, 0x1f, 0x02, 0x02,
0x01, 0x9c, 0x00, 0x05
};
int usb_fd,usb_in_fd, usb_out_fd;
static void* send_thread(void* arg) {
fd_set write_set;
int ret;
printf("starting send_thread\n");
while (1) {
FD_ZERO(&write_set);
FD_SET(usb_in_fd, &write_set);
ret = select(usb_in_fd+1, NULL, &write_set, NULL, NULL);
if (ret < 0) {
printf("select error in send_thread %i\n",ret);
break;
}
ret = write (usb_in_fd, report, sizeof(report));//blocked here when plugged to ps3
//printf("send\n");
if(ret!=sizeof(report)) {
printf("send_thread write error %i/%i\n", ret,sizeof(report));
break;
}
}
return NULL;
}
int init_ep() {
uint8_t init_config[2048];
uint8_t* cp;
int ret;
uint32_t send_size;
// Configure ep1 (low/full speed + high speed)
usb_in_fd = open(USB_EPIN, O_RDWR);
if (usb_in_fd <= 0) {
printf("Unable to open %s (%m)\n", USB_EPIN);
return -1;
}
*(uint32_t*)init_config = 1;
cp = &init_config[4];
FETCH(ep_descriptor_in);
FETCH(ep_descriptor_in);
send_size =cp-init_config;// (uint32_t)cp-(uint32_t)init_config;
ret = write(usb_in_fd, init_config, send_size);
if (ret != send_size) {
printf("Write error %d (%m)\n", ret);
return -1;
}
printf("ep1 configured\n");
// Configure ep2 (low/full speed + high speed)
usb_out_fd = open(USB_EPOUT, O_RDWR);
if (usb_out_fd <= 0) {
printf("Unable to open %s (%m)\n", USB_EPOUT);
return -1;
}
*(uint32_t*)init_config = 1;
cp = &init_config[4];
FETCH(ep_descriptor_out);
FETCH(ep_descriptor_out);
send_size = cp-init_config;//(uint32_t)cp-(uint32_t)init_config;
ret = write(usb_out_fd, init_config, send_size);
if (ret != send_size) {
printf("Write error %d (%m)\n", ret);
return -1;
}
printf("ep2 configured\n");
return 0;
}
static void handle_setup_request( struct usb_ctrlrequest* setup)
{
int nb_read,nb_write;
uint8_t buffer[64];
pthread_t thread;
//Indicates if the master bdaddr was already requested or not.
static unsigned char reply = 0;
//The master bdaddr.
static uint8_t masterBdaddr[6];
// A byte to save.
static uint8_t byte_6_ef;
printf("Setup request %x\n", setup->bRequest);
switch (setup->bRequest) {
case USB_REQ_GET_DESCRIPTOR://0x06
printf("USB_REQ_GET_DESCRIPTOR %x\n",setup->wValue);
switch (setup->wValue >> 8) {
case USB_DT_STRING://0x03
printf("Get string id #%d (max length %d)\n", setup->wValue & 0xff, setup->wLength);
nb_read = usb_gadget_get_string (&strings, setup->wValue & 0xff, buffer);
// Error
if (nb_read < 0) {
printf("String not found !!\n");
break;
} else {
printf("Found %i bytes\n", nb_read);
}
nb_write=write(usb_fd, buffer, nb_read);
if(nb_write!=nb_read) printf("error writting to usb_fd %i/%i\n",nb_write,nb_read);
return;
case DTYPE_Report:
printf("DTYPE_Report\n");
nb_write=write (usb_fd, Report, sizeof(Report));
if(nb_write!=sizeof(Report)) printf("error writting to usb_fd %i/%i\n",nb_write,sizeof(Report));
return;
default:
printf("Cannot return descriptor %i\n", (setup->wValue >> 8));
}
break;
case USB_REQ_SET_CONFIGURATION://0x09=REQ_SetReport
printf("USB_REQ_SET_CONFIGURATION %x\n",setup->wValue);
if (setup->bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
printf("USB_TYPE_STANDARD %x\n",setup->bRequestType);
switch (setup->wValue) {
case 1://config #1
init_ep();
pthread_create(&thread, NULL, send_thread, NULL);
break;
default:
printf("Unhandled configuration value %x\n", setup->wValue);
break;
}
// Just ACK
nb_read = read (usb_fd,NULL, 0);
if(nb_read!=0) printf("status of read ack= %x\n", nb_read);
return;
}
if (setup->bRequestType == (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) {
uint8_t reportType = setup->wValue >> 8;
uint8_t reportId = setup->wValue & 0xff;
printf("USB_TYPE_CLASS %x %x %x\n",setup->bRequestType,reportType,reportId);
nb_read = read (usb_fd, buffer, setup->wLength);
if(nb_read!=setup->wLength) printf("status of read = %i/%i\n", nb_read,setup->wLength);
for(int i=0;i< setup->wLength;i++) printf("%x ",buffer[i]);
printf("\n");
if(reportType == REPORT_TYPE_FEATURE) {
printf("REPORT_TYPE_FEATURE %x\n",reportId);
switch(reportId) {
case 0xf5:
memcpy(masterBdaddr, buffer+2, 6);
break;
case 0xef:
byte_6_ef = buffer[6];
break;
}
}
return;
}
case USB_REQ_GET_INTERFACE://0x10
printf("USB_REQ_GET_INTERFACE\n");
buffer[0] = 0;
nb_write=write(usb_fd, buffer, 1);
if(nb_write!=1) printf("error writting to usb_fd %i/1\n",nb_write);//always get an error here...
return;
case USB_REQ_CLEAR_FEATURE://0x01==REQ_GetReport
{
uint8_t reportId = setup->wValue & 0xff;
char* feature = NULL;
unsigned char len = 0;
printf("REQ_GetReport %x\n",reportId);
switch(reportId) {
case 0x01:
feature = report_01;
len = sizeof(report_01);
break;
case 0xf2:
feature = report_f2;
len = sizeof(report_f2);
break;
case 0xf5:
memcpy(buffer, report_f5, sizeof(buffer));
if(reply == 0) {
// First request, tell that the bdaddr is not the one of the PS3.
reply = 1;
} else {
// Next requests, tell that the bdaddr is the one of the PS3.
memcpy(buffer+2, masterBdaddr, 6);
}
len = sizeof(report_f5);
break;
case 0xef:
memcpy(buffer, report_ef, sizeof(buffer));
buffer[7] = byte_6_ef;
len = sizeof(report_ef);
break;
case 0xf8:
memcpy(buffer, report_f8, sizeof(buffer));
buffer[7] = byte_6_ef;//necessary??
len = sizeof(report_f8);
break;
case 0xf7:
feature = report_f7;
len = sizeof(report_f7);
break;
default:
printf("unhandled report\n");
break;
}
if(feature) {
nb_write=write (usb_fd, feature, setup->wLength);
if(nb_write!=setup->wLength) printf("write %i/%i\n",nb_write,setup->wLength);
} else if(len) {
nb_write=write (usb_fd, buffer, setup->wLength);
if(nb_write!=setup->wLength) printf("write %i/%i\n",nb_write,setup->wLength);
}
return;
}
}
}
static void handle_ep0(void) {
int ret, nevents, i;
fd_set read_set;
struct usb_gadgetfs_event events[5];
while (1) {
printf("waiting events on ep0\n");
FD_ZERO(&read_set);
FD_SET(usb_fd, &read_set);
ret=select(usb_fd+1, &read_set, NULL, NULL, NULL);
if (ret < 0) {
printf("select error %i\n", ret);
goto end;
}
ret = read(usb_fd, &events, sizeof(events));
if (ret < 0) {
printf("Read error %i\n", ret);
goto end;
}
nevents = ret / sizeof(events[0]);
printf("%i event(s)\n", nevents);
for (i=0; i<nevents; i++) {
switch (events[i].type) {
case GADGETFS_CONNECT:
printf("EP0 CONNECT\n");
break;
case GADGETFS_DISCONNECT:
printf("EP0 DISCONNECT\n");
break;
case GADGETFS_SETUP:
printf("EP0 SETUP\n");
handle_setup_request(&events[i].u.setup);
break;
case GADGETFS_NOP:
case GADGETFS_SUSPEND:
printf("unhandled event\n");
break;
}
}
}
end:
return;
}
int init_usb(void) {
int fd=-1, ret;
uint32_t send_size;
struct usb_config_descriptor config;
struct usb_device_descriptor device_descriptor;
struct usb_interface_descriptor if_descriptor;
struct USB_Descriptor_HID_t hid_descriptor;
uint8_t init_config[2048];
uint8_t* cp;
fd = open(USB_DEV, O_RDWR|O_SYNC);
if (fd <= 0) {
printf("Unable to open %s (%m)\n", USB_DEV);
return -1;
}
printf("Start init\n");
*(uint32_t*)init_config = 0;
cp = &init_config[4];
device_descriptor.bLength = USB_DT_DEVICE_SIZE;
device_descriptor.bDescriptorType = USB_DT_DEVICE;
device_descriptor.bDeviceClass = 0;
device_descriptor.bDeviceSubClass = 0;
device_descriptor.bDeviceProtocol = 0;
//device_descriptor.bMaxPacketSize0 = 255; Set by driver
device_descriptor.idVendor = 0x054c;
device_descriptor.idProduct = 0x0268;
device_descriptor.bcdDevice = 0x0100;
device_descriptor.iManufacturer = STRINGID_MANUFACTURER;
device_descriptor.iProduct = STRINGID_PRODUCT;
device_descriptor.iSerialNumber = 0;
device_descriptor.bNumConfigurations = 1; // Only one configuration
ep_descriptor_in.bLength = USB_DT_ENDPOINT_SIZE;
ep_descriptor_in.bDescriptorType = USB_DT_ENDPOINT;
ep_descriptor_in.bEndpointAddress = USB_DIR_IN | 1;
ep_descriptor_in.bmAttributes = USB_ENDPOINT_XFER_INT| USB_ENDPOINT_SYNC_NONE | USB_ENDPOINT_USAGE_DATA;
ep_descriptor_in.wMaxPacketSize = 64; // HS size
ep_descriptor_in.bInterval=1;
ep_descriptor_out.bLength = USB_DT_ENDPOINT_SIZE;
ep_descriptor_out.bDescriptorType = USB_DT_ENDPOINT;
ep_descriptor_out.bEndpointAddress = USB_DIR_OUT | 2;
ep_descriptor_out.bmAttributes = USB_ENDPOINT_XFER_INT| USB_ENDPOINT_SYNC_NONE | USB_ENDPOINT_USAGE_DATA;
ep_descriptor_out.wMaxPacketSize = 64; // HS size
ep_descriptor_out.bInterval=1;
if_descriptor.bLength = sizeof(if_descriptor);
if_descriptor.bDescriptorType = USB_DT_INTERFACE;
if_descriptor.bInterfaceNumber = 0;
if_descriptor.bAlternateSetting = 0;
if_descriptor.bNumEndpoints = 2;
if_descriptor.bInterfaceClass = USB_CLASS_HID;
if_descriptor.bInterfaceSubClass = 0;
if_descriptor.bInterfaceProtocol = 0;
if_descriptor.iInterface = 0;
hid_descriptor.bLength= sizeof(hid_descriptor);
hid_descriptor.bDescriptorType = DTYPE_HID;
hid_descriptor.HIDSpec = 0x0111;
hid_descriptor.CountryCode = 0x00;
hid_descriptor.TotalReportDescriptors = 1;
hid_descriptor.HIDReportType = DTYPE_Report;
hid_descriptor.HIDReportLength = sizeof(Report);
config.bLength = sizeof(config);
config.bDescriptorType = USB_DT_CONFIG;
config.wTotalLength = config.bLength +if_descriptor.bLength + hid_descriptor.bLength+ep_descriptor_in.bLength + ep_descriptor_out.bLength;
config.bNumInterfaces = 1;
config.bConfigurationValue = 1;
config.iConfiguration = 0;
config.bmAttributes = USB_CONFIG_ATT_ONE;
config.bMaxPower = 250;
FETCH(config);
FETCH(if_descriptor);
FETCH(hid_descriptor);
FETCH(ep_descriptor_in);
FETCH(ep_descriptor_out);
FETCH(config);//send a second time, normally it is config_hs not done in gimx!
FETCH(if_descriptor);
FETCH(hid_descriptor);
FETCH(ep_descriptor_in);
FETCH(ep_descriptor_out);
FETCH(device_descriptor);
// Configure ep0
send_size = cp-init_config;
ret = write(fd, init_config, send_size);
if (ret != send_size) {
printf("Write error %d (%m)\n", ret);
return -1;
}
printf("ep0 configured\n");
return fd;
}
int main() {
usb_fd=init_usb();
if(usb_fd<0) {
return -1;
}
handle_ep0();
close(usb_fd);
close (usb_in_fd);
close (usb_out_fd);
}
Code: Select all
/*
Copyright 2013 Mathieu Laurendeau (mat.lau [at] laposte [dot] net)
Redistributed under the GPLv3 licence.
Based on code by
Denver Gingerich (denver [at] ossguy [dot] com)
Dean Camera (dean [at] fourwalledcubicle [dot] com)
Original licence:
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
#define FETCH(_var_) \
memcpy(cp, &_var_, _var_.bLength); \
cp += _var_.bLength;
// specific to controller
//#define USB_DEV "/dev/gadget/dummy_udc"
//#define USB_EPIN "/dev/gadget/ep1in-bulk"
//#define USB_EPOUT "/dev/gadget/ep2out-bulk"
#define USB_DEV "/dev/gadget/80080000.usb"
#define USB_EPIN "/dev/gadget/ep1in"
#define USB_EPOUT "/dev/gadget/ep2out"
#define SERIAL_DEV "/dev/ttyAMA0"
#define MAX_CONTROL_TRANSFER_SIZE 64
enum {
STRINGID_MANUFACTURER = 1,
STRINGID_PRODUCT,
STRINGID_SERIAL,
STRINGID_CONFIG_HS,
STRINGID_CONFIG_LS,
STRINGID_INTERFACE,
STRINGID_MAX
};
static struct usb_string stringtab [] = {
{ STRINGID_MANUFACTURER, "Sony", },
{ STRINGID_PRODUCT, "PLAYSTATION(R)3 Controller", },
{ STRINGID_SERIAL, "0001", },
{ STRINGID_CONFIG_HS, "High speed configuration", },
{ STRINGID_CONFIG_LS, "Low speed configuration", },
{ STRINGID_INTERFACE, "Custom interface", },
{ STRINGID_MAX, NULL},
};
static struct usb_gadget_strings strings = {
.language = 0x0409, /* en-us */
.strings = stringtab,
};
static struct usb_endpoint_descriptor ep_descriptor_in;
static struct usb_endpoint_descriptor ep_descriptor_out;
/** Type define for the HID class specific HID descriptor, to describe the HID device's specifications. Refer to the HID
* specification for details on the structure elements.
*/
struct USB_Descriptor_HID_t
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t HIDSpec;
uint8_t CountryCode;
uint8_t TotalReportDescriptors;
uint8_t HIDReportType;
uint16_t HIDReportLength;
} __attribute__((packed));
/** Descriptor header type value, to indicate a HID class HID descriptor. */
#define DTYPE_HID 0x21
/** Descriptor header type value, to indicate a HID class HID report descriptor. */
#define DTYPE_Report 0x22
#define REPORT_TYPE_OUTPUT 0x02
#define REPORT_TYPE_FEATURE 0x03
/** Type define for the data type used to store HID report descriptor elements. */
typedef uint8_t USB_Descriptor_HIDReport_Datatype_t;
/** HID class report descriptor. This is a special descriptor constructed with values from the
* USBIF HID class specification to describe the reports and capabilities of the HID device. This
* descriptor is parsed by the host and its contents used to determine what data (and in what encoding)
* the device will send, and what it may be sent back from the host. Refer to the HID specification for
* more details on HID report descriptors.
*/
const USB_Descriptor_HIDReport_Datatype_t Report[] =
{
0x05, 0x01,
0x09, 0x04,
0xa1, 0x01,
0xa1, 0x02,
0x85, 0x01,
0x75, 0x08,
0x95, 0x01,
0x15, 0x00,
0x26, 0xff, 0x00,
0x81, 0x03,
0x75, 0x01,
0x95, 0x13,
0x15, 0x00,
0x25, 0x01,
0x35, 0x00,
0x45, 0x01,
0x05, 0x09,
0x19, 0x01,
0x29, 0x13,
0x81, 0x02,
0x75, 0x01,
0x95, 0x0d,
0x06, 0x00, 0xff,
0x81, 0x03,
0x15, 0x00,
0x26, 0xff, 0x00,
0x05, 0x01,
0x09, 0x01,
0xa1, 0x00,
0x75, 0x08,
0x95, 0x04,
0x35, 0x00,
0x46, 0xff, 0x00,
0x09, 0x30,
0x09, 0x31,
0x09, 0x32,
0x09, 0x35,
0x81, 0x02,
0xc0,
0x05, 0x01,
0x75, 0x08,
0x95, 0x27,
0x09, 0x01,
0x81, 0x02,
0x75, 0x08,
0x95, 0x30,
0x09, 0x01,
0x91, 0x02,
0x75, 0x08,
0x95, 0x30,
0x09, 0x01,
0xb1, 0x02,
0xc0,
0xa1, 0x02,
0x85, 0x02,
0x75, 0x08,
0x95, 0x30,
0x09, 0x01,
0xb1, 0x02,
0xc0,
0xa1, 0x02,
0x85, 0xee,
0x75, 0x08,
0x95, 0x30,
0x09, 0x01,
0xb1, 0x02,
0xc0,
0xa1, 0x02,
0x85, 0xef,
0x75, 0x08,
0x95, 0x30,
0x09, 0x01,
0xb1, 0x02,
0xc0,
0xc0
};
char report_01[] = {
//Sixaxis
/*0x00, 0x01, 0x03, 0x00, 0x04, 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, 0x01, 0x06, 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,*/
//Dualshock 3
0x00, 0x01, 0x04, 0x00, 0x07, 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,
};
char report_f2[] = {
//Sixaxis
/*0xf2, 0xff, 0xff, 0x00,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, //device bdaddr
0x00, 0x03, 0x50, 0x81, 0xd8, 0x01,
0x8a, 0x00, 0x00, 0x01, 0x64, 0x19, 0x01, 0x00,
0x64, 0x00, 0x01, 0x90, 0x00, 0x19, 0xfe, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,*/
//Dualshock 3
0xf2, 0xff, 0xff, 0x00,
0x00, 0x06, 0xF5, 0x48, 0xE2, 0x49, //device bdaddr
0x00, 0x03, 0x50, 0x81, 0xd8, 0x01,
0x8a, 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,
};
char report_f5[] = {
//Sixaxis
/*0x01, 0x00,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, //dummy PS3 bdaddr
0x23, 0x1e, 0x00, 0x03, 0x50, 0x81, 0xd8, 0x01,
0x8a, 0x00, 0x00, 0x01, 0x64, 0x19, 0x01, 0x00,
0x64, 0x00, 0x01, 0x90, 0x00, 0x19, 0xfe, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,*/
//Dualshock 3
0x01, 0x00,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, //dummy PS3 bdaddr
0xff, 0xf7, 0x00, 0x03, 0x50, 0x81, 0xd8, 0x01,
0x8a, 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,
};
char report_ef[] = {
//Sixaxis
/*0x00, 0xef, 0x03, 0x00, 0x04, 0x03, 0x01, 0xb0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x05, 0x01, 0x92, 0x02, 0x02, 0x01,
0x91, 0x02, 0x05, 0x01, 0x91, 0x02, 0x04, 0x00,
0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,*/
//Dualshock 3
0x00, 0xef, 0x04, 0x00, 0x07, 0x03, 0x01, 0xb0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x6b, 0x02, 0x68, 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,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
char report_f8[] = {
//Sixaxis
/*0x00, 0x01, 0x00, 0x00, 0x07, 0x03, 0x01, 0xb0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x6b, 0x02, 0x68, 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,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,*/
//Dualshock 3
0x00, 0x01, 0x00, 0x00, 0x07, 0x03, 0x01, 0xb0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x6b, 0x02, 0x68, 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,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
char report_f7[] = {
//Sixaxis
/*0x01, 0x00, 0x08, 0x03, 0xd2, 0x01, 0xee, 0xff,
0x10, 0x02, 0x00, 0x03, 0x50, 0x81, 0xd8, 0x01,
0x8a, 0x00, 0x00, 0x01, 0x64, 0x19, 0x01, 0x00,
0x64, 0x00, 0x01, 0x90, 0x00, 0x19, 0xfe, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,*/
//Dualshock 3
0x01, 0x04, 0xc4, 0x02, 0xd6, 0x01, 0xee, 0xff,
0x14, 0x13, 0x01, 0x02, 0xc4, 0x01, 0xd6, 0x00,
0x00, 0x02, 0x02, 0x02, 0x00, 0x03, 0x00, 0x00,
0x02, 0x00, 0x00, 0x02, 0x62, 0x01, 0x02, 0x01,
0x5e, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
Code: Select all
/*
* Copyright (C) 2003 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*/
#include <errno.h>
#include <string.h>
#include <linux/types.h>
#include <linux/usb/ch9.h>
#include "usbstring.h"
static inline void put_unaligned_le16(__u16 val, __u16 *cp)
{
__u8 *p = (void *)cp;
*p++ = (__u8) val;
*p++ = (__u8) (val >> 8);
}
static int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len)
{
int count = 0;
__u8 c;
__u16 uchar;
/* this insists on correct encodings, though not minimal ones.
* BUT it currently rejects legit 4-byte UTF-8 code points,
* which need surrogate pairs. (Unicode 3.1 can use them.)
*/
while (len != 0 && (c = (__u8) *s++) != 0) {
if (c & 0x80) {
// 2-byte sequence:
// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
if ((c & 0xe0) == 0xc0) {
uchar = (c & 0x1f) << 6;
c = (__u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c;
// 3-byte sequence (most CJKV characters):
// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
} else if ((c & 0xf0) == 0xe0) {
uchar = (c & 0x0f) << 12;
c = (__u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c << 6;
c = (__u8) *s++;
if ((c & 0xc0) != 0xc0)
goto fail;
c &= 0x3f;
uchar |= c;
/* no bogus surrogates */
if (0xd800 <= uchar && uchar <= 0xdfff)
goto fail;
// 4-byte sequence (surrogate pairs, currently rare):
// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
// = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
// (uuuuu = wwww + 1)
// FIXME accept the surrogate code points (only)
} else
goto fail;
} else
uchar = c;
put_unaligned_le16 (uchar, cp++);
count++;
len--;
}
return count;
fail:
return -1;
}
/**
* usb_gadget_get_string - fill out a string descriptor
* @table: of c strings encoded using UTF-8
* @id: string id, from low byte of wValue in get string descriptor
* @buf: at least 256 bytes
*
* Finds the UTF-8 string matching the ID, and converts it into a
* string descriptor in utf16-le.
* Returns length of descriptor (always even) or negative errno
*
* If your driver needs strings in multiple languages, you'll probably
* "switch (wIndex) { ... }" in your ep0 string descriptor logic,
* using this routine after choosing which set of UTF-8 strings to use.
*
* Note that US-ASCII is a strict subset of UTF-8; any string bytes with
* the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
* characters.
*/
int
usb_gadget_get_string (struct usb_gadget_strings *table, int id, __u8 *buf)
{
struct usb_string *s;
int len;
/* descriptor 0 has the language id */
if (id == 0) {
buf [0] = 4;
buf [1] = USB_DT_STRING;
buf [2] = (__u8) table->language;
buf [3] = (__u8) (table->language >> 8);
return 4;
}
for (s = table->strings; s && s->s; s++)
if (s->id == id)
break;
/* unrecognized: stall. */
if (!s || !s->s)
return -EINVAL;
/* string descriptors have length, tag, then UTF16-LE text */
len = strlen (s->s);
if (len > 126)
len = 126;
memset (buf + 2, 0, 2 * len); /* zero all the bytes */
len = utf8_to_utf16le(s->s, (__u16 *)&buf[2], len);
if (len < 0)
return -EINVAL;
buf [0] = (len + 1) * 2;
buf [1] = USB_DT_STRING;
return buf [0];
}
Code: Select all
/*
* (c) Copyright 2003 by David Brownell
* All Rights Reserved.
*
* This software is licensed under the GNU LGPL version 2.
*/
/* utility to simplify dealing with string descriptors */
/**
* struct usb_string - wraps a C string and its USB id
* @id: the (nonzero) ID for this string
* @s: the string, in UTF-8 encoding
*
* If you're using usb_gadget_get_string(), use this to wrap a string
* together with its ID.
*/
struct usb_string {
__u8 id;
const char *s;
};
/**
* struct usb_gadget_strings - a set of USB strings in a given language
* @language: identifies the strings' language (0x0409 for en-us)
* @strings: array of strings with their ids
*
* If you're using usb_gadget_get_string(), use this to wrap all the
* strings for a given language.
*/
struct usb_gadget_strings {
__u16 language; /* 0x0409 for en-us */
struct usb_string *strings;
};
/* put descriptor for string with that id into buf (buflen >= 256) */
int usb_gadget_get_string (struct usb_gadget_strings *table, int id, __u8 *buf);
Code: Select all
/*
Copyright (c) 2013 Mathieu Laurendeau
License: GPLv3
*/
#ifndef _ADAPTER_PROTOCOL_H_
#define _ADAPTER_PROTOCOL_H_
#define BYTE_NO_PACKET 0x00
#define BYTE_TYPE 0x11
#define BYTE_STATUS 0x22
#define BYTE_START 0x33
#define BYTE_CONTROL_DATA 0x44
#define BYTE_RESET 0x55
#define BYTE_DEBUG 0x99
#define BYTE_OUT_REPORT 0xee
#define BYTE_IN_REPORT 0xff
#define BYTE_TYPE_JOYSTICK 0x00
#define BYTE_TYPE_X360 0x01
#define BYTE_TYPE_SIXAXIS 0x02
#define BYTE_TYPE_PS2 0x03
#define BYTE_TYPE_XBOX 0x04
#define BYTE_TYPE_DS4 0x05
#define BYTE_TYPE_XBOXONE 0x06
#define BYTE_TYPE_T300RS_PS4 0x07
#define BYTE_TYPE_G27_PS3 0x08
#define BYTE_TYPE_G29_PS4 0x09
#define BYTE_TYPE_DF_PS2 0x0a
#define BYTE_TYPE_DFP_PS2 0x0b
#define BYTE_TYPE_GTF_PS2 0x0c
#define BYTE_STATUS_NSPOOFED 0x00
#define BYTE_STATUS_SPOOFED 0x01
#define BYTE_LEN_0_BYTE 0x00
#define BYTE_LEN_1_BYTE 0x01
#endif
and here the program to test the reception of the report when plugged to a pc:
ds3_usb.c:
Code: Select all
// Compile with: g++ -Wall ds3_usb.c -lusb -o ds3_usb
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sstream>
#include <stdio.h>
#include <linux/input.h>
#include <linux/hidraw.h>
int main(int argc, char *argv[]) {
int nr, i;
int usb_fd;
unsigned char buf[128];
for (i = 0; i < 255; i++) {
std::ostringstream dev_name;
dev_name << "/dev/hidraw" << i;
if ((usb_fd = open(dev_name.str().c_str(), O_RDONLY)) >= 0) {
int res = 0;
struct hidraw_devinfo info;
res = ioctl(usb_fd, HIDIOCGRAWINFO, &info);
if (res < 0) {
printf("ioctl error (HIDIOCGRAWINFO) on %s\n",dev_name.str().c_str());
} else {
if (info.vendor == 0x054c && info.product == 0x0268) {
printf("successfully opened %s\n", dev_name.str().c_str());
printf("Press PS button to turn the controller on\n");
break;
}
}
close(usb_fd);
}
}
if (i == 255) {
printf("sixad-raw::open(hidrawX) - failed to open hidraw device\n");
exit(0);
}
// block until PS button is pressed
if ((nr = read(usb_fd, buf, sizeof(buf))) < 0) {
printf("sixad-raw::read(fd) - failed to read from device\n");
}
if (nr < 49 || nr > 50) {
printf("sixad-raw::read(fd) - not a sixaxis (nr = %i )\n", nr);
exit(0);
}
while ( 1 ) {
unsigned char report[256];
nr = read(usb_fd, report, sizeof(report));
if (report[0] == 0x01 && report[1] == 0 && nr >= 49) {
/*datas[0] = r[2];
datas[1] = r[3];
datas[2] = compute_dead_zone(0, r[6]);
datas[3] = compute_dead_zone(1, r[7]);
datas[4] = compute_dead_zone(2, r[8]);
datas[5] = compute_dead_zone(3, r[9]);*/
printf("%x %x %x %x %x %x\n",report[6],report[7],report[8],report[9],report[2],report[3]);
}
}
close(usb_fd);
}