Signed-off-by: Xiangfu Liu <[email protected]>
---
softusb-input/main.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 90 insertions(+), 5 deletions(-)
diff --git a/softusb-input/main.c b/softusb-input/main.c
index c481a81..3b467b8 100644
--- a/softusb-input/main.c
+++ b/softusb-input/main.c
@@ -57,6 +57,7 @@ enum {
USB_DT_CONFIG = 2,
USB_DT_INTERFACE = 4,
USB_DT_ENDPOINT = 5,
+ USB_DT_HID = 33,
};
enum {
@@ -86,6 +87,7 @@ enum {
PORT_STATE_GET_DEVICE_DESCRIPTOR,
PORT_STATE_GET_CONFIGURATION_DESCRIPTOR,
PORT_STATE_SET_CONFIGURATION,
+ PORT_STATE_GET_HID_REPORT_DESCRIPTOR,
PORT_STATE_RUNNING,
PORT_STATE_UNSUPPORTED
};
@@ -94,7 +96,10 @@ enum {
struct ep_status {
char ep;
+ char itf;
+ unsigned int report_len;
unsigned char expected_data;
+ char report_id;
};
struct port_status {
@@ -458,6 +463,11 @@ static char process_mouse(struct ep_status *ep, unsigned
char *buf,
{
unsigned char m, i;
+ if(ep->report_id) {
+ buf++;
+ len--;
+ }
+
if(len < 3)
return 0;
/*
@@ -559,8 +569,10 @@ static struct ep_status *identify_protocol(const unsigned
char *itf,
if (itf[5] == USB_CLASS_HID && itf[6] == USB_SUBCLASS_BOOT)
switch(itf[7]) { /* check bInterfaceProtocol */
case USB_PROTO_KEYBOARD:
+ p->keyboard.itf = itf[2];
return &p->keyboard;
case USB_PROTO_MOUSE:
+ p->mouse.itf = itf[2];
return &p->mouse;
default:
/* unknown protocol, fail */
@@ -578,22 +590,60 @@ static const char mouse[] PROGMEM = "mouse\n";
static const char keyboard[] PROGMEM = "keyboard\n";
static const char midi[] PROGMEM = "MIDI\n";
+static char validate_report_descriptor(const unsigned char *descriptor,
+ unsigned int len, struct port_status *p)
+{
+ unsigned int i;
+
+ /* We support MAX HID report descriptor length is 512 */
+ if(len > 512)
+ return 0;
+
+ p->mouse.report_id = 0;
+ for (i = 0; i < len; i+=2) {
+ /* See 6.2.2.2 Short Items */
+ if ((descriptor[i] & 0xfc) == 0x84) {
+ p->mouse.report_id = 1;
+ break;
+ }
+ }
+
+ return 1;
+}
+
static char validate_configuration_descriptor(const unsigned char *descriptor,
char len, struct port_status *p)
{
struct ep_status *ep = NULL;
char offset;
+ p->keyboard.report_len = 0;
+ p->mouse.report_len = 0;
+
offset = 0;
while(offset < len) {
- if(descriptor[offset+1] == USB_DT_INTERFACE) {
- ep = identify_protocol(descriptor+offset, p);
- } else if(descriptor[offset+1] == USB_DT_ENDPOINT &&
- (descriptor[offset+2] & 0x80) && ep) {
+ switch(descriptor[offset+1]) {
+ case USB_DT_INTERFACE:
+ ep = identify_protocol(descriptor+offset, p);
+ break;
+ case USB_DT_HID:
+ if(!ep)
+ break;
+ ep->report_len = descriptor[offset+8] << 8 |
+ descriptor[offset+7];
+ break;
+ case USB_DT_ENDPOINT:
+ if(!ep)
+ break;
+ if(!(descriptor[offset+2] & 0x80))
+ break;
ep->ep = descriptor[offset+2] & 0x7f;
ep->expected_data = USB_PID_DATA0;
- /* start with DATA0 */
+ /* start with DATA0 */
ep = NULL;
+ break;
+ default:
+ break;
}
offset += descriptor[offset+0];
}
@@ -812,8 +862,43 @@ static void port_service(struct port_status *p, char name)
if(control_transfer(ADDR, &packet, 1, NULL, 0,
p->ep0_size) == 0) {
p->retry_count = 0;
+ p->state = PORT_STATE_GET_HID_REPORT_DESCRIPTOR;
+ }
+ check_retry(p);
+ break;
+ }
+ case PORT_STATE_GET_HID_REPORT_DESCRIPTOR: {
+ struct setup_packet packet;
+ unsigned char report_descriptor[512];
+ int len;
+
+ /* Only take care mouse for now */
+ if(!p->mouse.ep) {
p->state = PORT_STATE_RUNNING;
+ break;
+ }
+
+ packet.bmRequestType = 0x81;
+ packet.bRequest = 0x06;
+ packet.wValue[0] = 0x01;
+ packet.wValue[1] = 0x22;
+ packet.wIndex[0] = p->mouse.itf; /* Interface */
+ packet.wIndex[1] = 0x00;
+ packet.wLength[0] = p->mouse.report_len & 0x00ff;
+ packet.wLength[1] = (p->mouse.report_len & 0xff00) >> 8;
+
+ len = control_transfer(ADDR, &packet, 0,
+ report_descriptor,
+ p->mouse.report_len,
+ p->ep0_size);
+
+ if(len != -1) {
+ if(!validate_report_descriptor(
+ report_descriptor, p->mouse.report_len, p))
+ unsupported(p);
}
+ p->retry_count = 0;
+ p->state = PORT_STATE_RUNNING;;
check_retry(p);
break;
}
--
1.7.5.4
_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode