1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-04-26 20:37:14 +00:00

HID: Read all string descriptors

Makes RETROFLAG Classic USB Gamepad return movement data
This commit is contained in:
Gyorgy Szombathelyi
2021-08-30 22:17:06 +02:00
parent a8eef6235f
commit 38b893b27b
7 changed files with 179 additions and 18 deletions

View File

@@ -12,7 +12,7 @@ TODAY = `date +"%m/%d/%y"`
PRJ = firmware
SRC = hw/AT91SAM/Cstartup_SAM7.c hw/AT91SAM/hardware.c hw/AT91SAM/spi.c hw/AT91SAM/mmc.c hw/AT91SAM/cdc_enumerate.c
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c osd.c state.c syscalls.c user_io.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c arc_file.c font.c utils.c
SRC += usb/max3421e.c usb/usb.c usb/hub.c usb/hid.c usb/hidparser.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/joymapping.c
SRC += usb/max3421e.c usb/usb.c usb/usbdebug.c usb/hub.c usb/hid.c usb/hidparser.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/joymapping.c
SRC += fat_compat.c
SRC += FatFs/diskio.c FatFs/ff.c FatFs/ffunicode.c
# SRC += usb/storage.c

View File

@@ -57,6 +57,12 @@
#endif
// ------------ usb debugging -----------
#if 0
// usb debug output in green
#define usb_debugf(a, ...) iprintf("\033[1;32mUSB: " a "\033[0m\n", ##__VA_ARGS__)
#else
#define usb_debugf(...)
#endif
#if 0
#define hidp_debugf(a, ...) iprintf("\033[1;34mHIDP: " a "\033[0m\n", ##__VA_ARGS__)

View File

@@ -125,6 +125,12 @@ static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t i, uint16_t size)
return rcode;
}
static uint8_t hid_get_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t *duration ) {
// hid_debugf("%s(%x, if=%d id=%d, dur=%d)", __FUNCTION__, dev->bAddress, iface, reportID, duration);
return( usb_ctrl_req( dev, HID_REQ_HIDIN, HID_REQUEST_GET_IDLE, reportID,
0, iface, 0x0001, duration));
}
static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
// hid_debugf("%s(%x, if=%d id=%d, dur=%d)", __FUNCTION__, dev->bAddress, iface, reportID, duration);
@@ -132,6 +138,13 @@ static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID,
duration, iface, 0x0000, NULL));
}
static uint8_t hid_get_protocol(usb_device_t *dev, uint8_t iface, uint8_t *protocol) {
// hid_debugf("%s(%x, if=%d proto=%d)", __FUNCTION__, dev->bAddress, iface, protocol);
return( usb_ctrl_req( dev, HID_REQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0,
0x00, iface, 0x0001, protocol));
}
static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
// hid_debugf("%s(%x, if=%d proto=%d)", __FUNCTION__, dev->bAddress, iface, protocol);
@@ -171,19 +184,18 @@ static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len)
while(len > 0) {
switch(p->conf_desc.bDescriptorType) {
case USB_DESCRIPTOR_CONFIGURATION:
// hid_debugf("conf descriptor size %d", p->conf_desc.bLength);
// we already had this, so we simply ignore it
break;
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
// hid_debugf("iface descriptor size %d", p->iface_desc.bLength);
usb_dump_interface_descriptor(&p->iface_desc);
/* check the interface descriptors for supported class */
// only HID interfaces are supported
if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
// puts("iface is HID");
hid_debugf("iface is HID");
if(info->bNumIfaces < MAX_IFACES) {
// ok, let's use this interface
@@ -231,7 +243,7 @@ static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len)
break;
case USB_DESCRIPTOR_ENDPOINT:
// hid_debugf("endpoint descriptor size %d", p->ep_desc.bLength);
usb_dump_endpoint_descriptor(&p->ep_desc);
if(isGoodInterface) {
@@ -253,7 +265,7 @@ static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len)
break;
case HID_DESCRIPTOR_HID:
hid_debugf("hid descriptor size %d", p->ep_desc.bLength);
usb_dump_hid_descriptor(&p->hid_desc);
if(isGoodInterface) {
// we need a report descriptor
@@ -298,6 +310,12 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
usb_configuration_descriptor_t conf_desc;
} buf;
union {
usb_string_descriptor_t str_desc;
uint8_t buf[256];
} str;
uint8_t s[128+1];
// reset status
info->bPollEnable = false;
info->bNumIfaces = 0;
@@ -313,6 +331,38 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
// try to re-read full device descriptor from newly assigned address
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc ))
return rcode;
usb_dump_device_descriptor(&buf.dev_desc);
iprintf("USB vendor ID: %04X, product ID: %04x\n", buf.dev_desc.idVendor, buf.dev_desc.idProduct);
// The Retroflag Classic USB Gamepad doesn't report movement until the string descriptors are read,
// so read all of them here (and show them on the console)
usb_get_string_descr(dev, sizeof(str), 0, 0, &str.str_desc); // supported languages descriptor
if (buf.dev_desc.iManufacturer &&
!usb_get_string_descr(dev, sizeof(str), buf.dev_desc.iManufacturer, 0, &str.str_desc)) {
for (i=0; i<((str.str_desc.bLength-2)/2); i++) {
s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE);
}
s[i] = 0;
iprintf("Manufacturer: %s\n", s);
}
if (buf.dev_desc.iProduct &&
!usb_get_string_descr(dev, sizeof(str), buf.dev_desc.iProduct, 0, &str.str_desc)) {
for (i=0; i<((str.str_desc.bLength-2)/2); i++) {
s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE);
}
s[i] = 0;
iprintf("Product: %s\n", s);
}
if (buf.dev_desc.iSerialNumber &&
!usb_get_string_descr(dev, sizeof(str), buf.dev_desc.iSerialNumber, 0, &str.str_desc)) {
for (i=0; i<((str.str_desc.bLength-2)/2); i++) {
s[i] = ff_uni2oem(str.str_desc.bString[i], FF_CODE_PAGE);
}
s[i] = 0;
iprintf("Serial no.: %s\n", s);
}
// save vid/pid for automatic hack later
vid = buf.dev_desc.idVendor;
@@ -325,8 +375,7 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc))
return rcode;
// hid_debugf("conf descriptor %d has total size %d", i, buf.conf_desc.wTotalLength);
usb_dump_conf_descriptor(&buf.conf_desc);
// parse directly if it already fitted completely into the buffer
usb_hid_parse_conf(dev, i, buf.conf_desc.wTotalLength);
}
@@ -339,6 +388,7 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
// Set Configuration Value
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
if (rcode) hid_debugf("hid_set_conf error: %d", rcode);
// process all supported interfaces
for(i=0; i<info->bNumIfaces; i++) {
@@ -351,7 +401,10 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
// boot mode only supports two buttons and the archie wants three
if(!info->iface[i].has_boot_mode || info->iface[i].ignore_boot_mode) {
rcode = hid_get_report_descr(dev, i, info->iface[i].report_desc_size);
if(rcode) return rcode;
if(rcode) {
hid_debugf("hid_get_report_descr error: %d", rcode);
return rcode;
}
if(info->iface[i].device_type == REPORT_TYPE_NONE) {
// bInterfaceProtocol was 0 ("none") -> try to parse anyway
@@ -420,17 +473,16 @@ static uint8_t usb_hid_init(usb_device_t *dev) {
}
}
}
rcode = hid_set_idle(dev, info->iface[i].iface_idx, 0, 0);
if (rcode && rcode != hrSTALL)
return rcode;
// enable boot mode if its not diabled
if(info->iface[i].has_boot_mode && !info->iface[i].ignore_boot_mode) {
hid_debugf("enabling boot mode");
hid_set_protocol(dev, info->iface[i].iface_idx, HID_BOOT_PROTOCOL);
} else
hid_set_protocol(dev, info->iface[i].iface_idx, HID_RPT_PROTOCOL);
// enable boot mode if its not diabled
if(info->iface[i].has_boot_mode && !info->iface[i].ignore_boot_mode) {
hid_debugf("enabling boot mode");
hid_set_protocol(dev, info->iface[i].iface_idx, HID_BOOT_PROTOCOL);
} else
hid_set_protocol(dev, info->iface[i].iface_idx, HID_RPT_PROTOCOL);
}
puts("HID configured");

View File

@@ -35,6 +35,7 @@
#define HID_REQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define MAX_IFACES 2 // max supported interfaces per device. 2 to support kbd/mouse combos

View File

@@ -380,7 +380,7 @@ uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed) {
iprintf("Setting addr %x\n", i+1);
rcode = usb_set_addr(d, i+1);
if(rcode) {
puts("failed to assign address");
iprintf("failed to assign address (rcode=%d)", rcode);
return rcode;
}
@@ -564,12 +564,23 @@ uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr ) {
return rcode;
}
//get configuration
uint8_t usb_get_conf( usb_device_t *dev, uint8_t *conf_value ) {
return( usb_ctrl_req( dev, USB_REQ_GET, USB_REQUEST_GET_CONFIGURATION,
0x00, 0x00, 0x0000, 1, conf_value));
}
//set configuration
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value ) {
return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION,
conf_value, 0x00, 0x0000, 0x0000, NULL));
}
uint8_t usb_get_string_descr( usb_device_t *dev, uint16_t nbytes, uint8_t index, uint16_t lang_id, usb_string_descriptor_t* dataptr ) {
return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR,
index, USB_DESCRIPTOR_STRING, lang_id, nbytes, (uint8_t*)dataptr));
}
void usb_SetHubPreMask() {
bmHubPre |= MAX3421E_HUBPRE;
};

View File

@@ -34,6 +34,7 @@ typedef struct {
/* Common setup data constant combinations */
#define USB_REQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define USB_REQ_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get request type for all but 'get feature' and 'get interface'
#define USB_REQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define USB_REQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
@@ -204,6 +205,20 @@ typedef struct {
uint8_t bInterval; // Polling interval in frames.
} __attribute__((packed)) usb_endpoint_descriptor_t;
/* String index 0 descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // STRING descriptor type (USB_DESCRIPTOR_STRING).
uint8_t wLANGID[2]; // Supported language codes
} __attribute__((packed)) usb_string0_descriptor_t;
/* String descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // STRING descriptor type (USB_DESCRIPTOR_STRING).
uint16_t bString[]; // Unicode Encoded String
} __attribute__((packed)) usb_string_descriptor_t;
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
@@ -253,11 +268,20 @@ uint8_t usb_ctrl_req( usb_device_t *, uint8_t bmReqType,
uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
uint8_t usb_get_dev_descr( usb_device_t *, uint16_t nbytes, usb_device_descriptor_t* dataptr );
uint8_t usb_get_conf_descr( usb_device_t *, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* dataptr );
uint8_t usb_get_string_descr( usb_device_t *dev, uint16_t nbytes, uint8_t index, uint16_t lang_id, usb_string_descriptor_t* dataptr );
uint8_t usb_get_conf( usb_device_t *dev, uint8_t *conf_value );
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value );
uint8_t usb_in_transfer( usb_device_t *, ep_t *ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t usb_out_transfer( usb_device_t *, ep_t *ep, uint16_t nbytes, uint8_t* data );
uint8_t usb_release_device(uint8_t parent, uint8_t port);
usb_device_t *usb_get_devices();
uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed);
// debug functions
void usb_dump_device_descriptor(usb_device_descriptor_t *desc);
void usb_dump_conf_descriptor(usb_configuration_descriptor_t *desc);
void usb_dump_interface_descriptor(usb_interface_descriptor_t *desc);
void usb_dump_endpoint_descriptor(usb_endpoint_descriptor_t *desc);
void usb_dump_hid_descriptor(usb_hid_descriptor_t *desc);
#endif // USB_H

67
usb/usbdebug.c Normal file
View File

@@ -0,0 +1,67 @@
#include <stdio.h>
#include "usb.h"
#include "debug.h"
void usb_dump_device_descriptor(usb_device_descriptor_t *desc) {
usb_debugf("USB device descriptor:");
usb_debugf(" bLength: %d", desc->bLength);
usb_debugf(" bDescriptorType: %d", desc->bDescriptorType);
usb_debugf(" bcdUSB: %x", desc->bcdUSB);
usb_debugf(" bDeviceClass: %x", desc->bDeviceClass);
usb_debugf(" bDeviceSubClass: %x", desc->bDeviceSubClass);
usb_debugf(" bDeviceProtocol: %x", desc->bDeviceProtocol);
usb_debugf(" bMaxPacketSize0: %d", desc->bMaxPacketSize0);
usb_debugf(" idVendor: %04x", desc->idVendor);
usb_debugf(" idProduct: %04x", desc->idProduct);
usb_debugf(" bcdDevice: %x", desc->bcdDevice);
usb_debugf(" iManufacturer: %d", desc->iManufacturer);
usb_debugf(" iProduct: %d", desc->iProduct);
usb_debugf(" iSerialNumber: %d", desc->iSerialNumber);
usb_debugf(" bNumConfigurations: %d", desc->bNumConfigurations);
}
void usb_dump_conf_descriptor(usb_configuration_descriptor_t *desc) {
usb_debugf("USB configuration descriptor:");
usb_debugf(" bLength: %d", desc->bLength);
usb_debugf(" bDescriptorType: %d", desc->bDescriptorType);
usb_debugf(" wTotalLength: %d", desc->wTotalLength);
usb_debugf(" bNumInterfaces: %d", desc->bNumInterfaces);
usb_debugf(" bConfigurationValue: %d", desc->bConfigurationValue);
usb_debugf(" iConfiguration: %d", desc->iConfiguration);
usb_debugf(" bmAttributes: %d", desc->bmAttributes);
usb_debugf(" bMaxPower: %d", desc->bMaxPower);
}
void usb_dump_interface_descriptor(usb_interface_descriptor_t *desc) {
usb_debugf(" Interface descriptor:");
usb_debugf(" bLength: %d", desc->bLength);
usb_debugf(" bDescriptorType: %d", desc->bDescriptorType);
usb_debugf(" bInterfaceNumber: %d", desc->bInterfaceNumber);
usb_debugf(" bAlternateSetting: %d", desc->bAlternateSetting);
usb_debugf(" bNumEndpoints: %d", desc->bNumEndpoints);
usb_debugf(" bInterfaceClass: %d", desc->bInterfaceClass);
usb_debugf(" bInterfaceSubClass: %d", desc->bInterfaceSubClass);
usb_debugf(" bInterfaceProtocol: %d", desc->bInterfaceProtocol);
usb_debugf(" iInterface: %d", desc->iInterface);
}
void usb_dump_endpoint_descriptor(usb_endpoint_descriptor_t *desc) {
usb_debugf(" Endpoint descriptor:");
usb_debugf(" bLength: %d", desc->bLength);
usb_debugf(" bDescriptorType: %d", desc->bDescriptorType);
usb_debugf(" bEndpointAddress: %d", desc->bEndpointAddress);
usb_debugf(" bmAttributes: %d", desc->bmAttributes);
usb_debugf(" wMaxPacketSize: %d", desc->wMaxPacketSize[0] | desc->wMaxPacketSize[1]<<8);
usb_debugf(" bInterval: %d", desc->bInterval);
}
void usb_dump_hid_descriptor(usb_hid_descriptor_t *desc) {
usb_debugf(" HID descriptor:");
usb_debugf(" bLength: %d", desc->bLength);
usb_debugf(" bDescriptorType: %d", desc->bDescriptorType);
usb_debugf(" bcdHID: %x", desc->bcdHID);
usb_debugf(" bCountryCode: %d", desc->bCountryCode);
usb_debugf(" bNumDescriptors: %d", desc->bNumDescriptors);
usb_debugf(" bDescrType: %d", desc->bDescrType);
usb_debugf(" wDescriptorLength:%d", desc->wDescriptorLength[0] | desc->wDescriptorLength[1]<<8);
}