Page 1 of 1

trying to port EMUPS3 firmware to linux with usb OTG

Posted: Fri Oct 05, 2018 4:04 pm
by m121
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):

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
and dmesg on the computer gives:

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
Now when I plug the dev board to the PS3 I am getting the following the first time I launch the program:

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
and then if I relaunch it:

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
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:

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);
}
device.h:

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,
};
usbstring.c

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];
}
usbstring.h:

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);
adapter_protocol.h:

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
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:

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);
 
}

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Fri Oct 05, 2018 4:09 pm
by m121
I forget to say I am using gadgetfs!

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Mon Oct 15, 2018 7:02 am
by m121
I haven't made any progress on it since laste time (saddly, I don't have a lot of time to work on it...)

As I don't have a DS3, can someone give me some logs of what is happening when you plug a ds3 on the ps3? I would like to know which messages are used and in what order (on control, in and out endpoints). I wonder when the ds3 starts streaming reports, etc.
This can help me to resolve the problem.

Thanks for your help!
Regards

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Mon Oct 15, 2018 7:35 am
by Matlo
https://github.com/matlo/GIMX-firmwares ... emu.c#L491
https://github.com/matlo/GIMX-firmwares ... emu.c#L516

I can send you a capture if you want (to the email you provided for registration?).

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Mon Oct 15, 2018 8:13 am
by m121
Hi,

Thanks for your answer. I already read the emups3 code.

Ok for the capture by mail or PM, thanks!

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Mon Oct 15, 2018 4:29 pm
by Matlo
I just sent the capture.

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Wed Oct 17, 2018 9:56 pm
by m121
Thanks Matlo.

After a little bit of debugging in the gadgetfs module, it seems that the message 21 09 f5 03 00 00 08 00 from the ps3 (when the ps3 is giving its bth mac address) is directly handled by the module. So the message is not sent to my application and I cannot change the f5 report with the good bth address.... When the ps3 asks again the f5 report, it is still with the dummy bth address.
The module is answering by itself the following message: 84 28 5e c7 08 00 00 00 to the ps3.

I will try to understand why the module handles the message by itself!

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Sat Oct 20, 2018 3:45 pm
by m121
so I have made some progress!

Firstly, I misunderstood the behaviour of the gadgetfs module; it is not answering by itself a message "84 28 5e c7 08 00 00 00" to the ps3 (when ps3 sends 21 09 f5 03 00 00 08 00). I was printing a buffer that was going to be filled by the module (but not yet really filled), with the content of the f5 SET_REPORT message (the bth address of the ps3 in fact).

So the module receives the 21 09 f5 03 00 00 08 00 message, followed by the bth address of the ps3. But before my user space app can read this message, the module receives a new message from the ps3 (I don't remember which one, maybe a ef GET_REPORT). In this case, the module discards the previous (unread by the user) setup messages! That is why I never get the bth address in my app (nor the ef byte6). This does not happen when I connect my dev board to a linux computer (message is read before a new one arrives). Maybe the ps3 is sending too fast...

This behaviour can be seen in the module's code (file drivers/usb/gadget/legacy/inode.c)

Code: Select all

next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
{
	struct usb_gadgetfs_event	*event;
	unsigned			i;

	switch (type) {
	/* these events purge the queue */
	case GADGETFS_DISCONNECT:
		if (dev->state == STATE_DEV_SETUP)
			dev->setup_abort = 1;
		// FALL THROUGH
	case GADGETFS_CONNECT:
		dev->ev_next = 0;
		break;
	case GADGETFS_SETUP:		/* previous request timed out */
	case GADGETFS_SUSPEND:		/* same effect */
		/* these events can't be repeated */
		for (i = 0; i != dev->ev_next; i++) {
			if (dev->event [i].type != type)
				continue;
			DBG(dev, "discard old event[%d] %d\n", i, type);

			dev->ev_next--;
			if (i == dev->ev_next)
				break;
			/* indices start at zero, for simplicity */
			memmove (&dev->event [i], &dev->event [i + 1],
				sizeof (struct usb_gadgetfs_event)
					* (dev->ev_next - i));
		}
		break;
	default:
		BUG ();
	}
	VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
	event = &dev->event [dev->ev_next++];
	BUG_ON (dev->ev_next > N_EVENT);
	memset (event, 0, sizeof *event);
	event->type = type;
	return event;
}
If we receive a new event of the same type (GADGETFS_SETUP in this case), the older one is discarded...
I am not an expert of the gadgetfs stack (nor usb stack); so I am not sure if it is a bug or not. I tried to remove the discard part: in this case I can get the message, but then the driver is in a wrong state and other messages cannot be read...

I am using a vanilla 4.9.51 kernel; there are few changes of the gadget module in newer kernels. I will try it asap.

For the moment, I have adapted my application code to give the good answers (for report f5 and ef) to the ps3. This way, I can successfully send the reports to the in endpoint. For the moment the report is fixed (no ds3 action) so I don't know if it is working but it should. Next step will be to link this to a gimx application by serial port and check if it works.

Re: trying to port EMUPS3 firmware to linux with usb OTG

Posted: Sun Oct 21, 2018 3:39 pm
by m121
same "problem" with the last stable kernel (4.18.16); packets are discarded...