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:
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
6
debug.h
6
debug.h
@@ -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__)
|
||||
|
||||
82
usb/hid.c
82
usb/hid.c
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
13
usb/usb.c
13
usb/usb.c
@@ -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;
|
||||
};
|
||||
|
||||
26
usb/usb.h
26
usb/usb.h
@@ -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
67
usb/usbdebug.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user