N64 to USB HID interface

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbhid.cpp Source File

usbhid.cpp

00001 /* usbhid.cpp */
00002 /* USB HID class device */
00003 /* Copyright (c) Phil Wright 2008 */
00004 
00005 /* modified by Shinichiro Oba <http://mbed.org/users/bricklife/> */
00006 
00007 #include "mbed.h"
00008 #include "usbhid.h"
00009 #include "asciihid.h"
00010 
00011 /* Endpoint packet sizes */
00012 #define MAX_PACKET_SIZE_EP1 (64)
00013 
00014 /* HID Class */
00015 #define HID_CLASS         (3)
00016 #define HID_SUBCLASS_NONE (0)
00017 #define HID_PROTOCOL_NONE (0)
00018 #define HID_DESCRIPTOR    (33)
00019 #define REPORT_DESCRIPTOR (34)
00020 
00021 /* Class requests */
00022 #define GET_REPORT (0x1)
00023 #define GET_IDLE   (0x2)
00024 #define SET_REPORT (0x9)
00025 #define SET_IDLE   (0xa)
00026 
00027 /* Descriptors */
00028 unsigned char deviceDescriptor[] = {
00029     0x12,                    /* bLength */
00030     DEVICE_DESCRIPTOR,       /* bDescriptorType */
00031     0x00,                    /* bcdUSB (LSB) */
00032     0x02,                    /* bcdUSB (MSB) */
00033     0x00,                    /* bDeviceClass */
00034     0x00,                    /* bDeviceSubClass */
00035     0x00,                    /* bDeviceprotocol */
00036     MAX_PACKET_SIZE_EP0,     /* bMaxPacketSize0 */
00037     0x28,                    /* idVendor (LSB) */
00038     0x0d,                    /* idVendor (MSB) */
00039     0x05,                    /* idProduct (LSB) */
00040     0x02,                    /* idProduct (MSB) */
00041     0x00,                    /* bcdDevice (LSB) */
00042     0x00,                    /* bcdDevice (MSB) */
00043     0x00,                    /* iManufacturer */
00044     0x00,                    /* iProduct */
00045     0x00,                    /* iSerialNumber */
00046     0x01                     /* bNumConfigurations */
00047 };
00048 
00049 unsigned char configurationDescriptor[] = {
00050     0x09,                        /* bLength */
00051     CONFIGURATION_DESCRIPTOR,    /* bDescriptorType */
00052     0x09+0x09+0x09+0x07,         /* wTotalLength (LSB) */
00053     0x00,                        /* wTotalLength (MSB) */
00054     0x01,                        /* bNumInterfaces */
00055     0x01,                        /* bConfigurationValue */
00056     0x00,                        /* iConfiguration */
00057     0xc0,                        /* bmAttributes */
00058     0x00,                        /* bMaxPower */
00059 
00060     0x09,                        /* bLength */
00061     INTERFACE_DESCRIPTOR,        /* bDescriptorType */
00062     0x00,                        /* bInterfaceNumber */
00063     0x00,                        /* bAlternateSetting */
00064     0x01,                        /* bNumEndpoints */
00065     HID_CLASS,                   /* bInterfaceClass */
00066     HID_SUBCLASS_NONE,           /* bInterfaceSubClass */
00067     HID_PROTOCOL_NONE,           /* bInterfaceProtocol */
00068     0x00,                        /* iInterface */
00069 
00070     0x09,                        /* bLength */
00071     HID_DESCRIPTOR,              /* bDescriptorType */
00072     0x11,                        /* bcdHID (LSB) */
00073     0x01,                        /* bcdHID (MSB) */
00074     0x00,                        /* bCountryCode */
00075     0x01,                        /* bNumDescriptors */
00076     REPORT_DESCRIPTOR,           /* bDescriptorType */
00077     0x79,                        /* wDescriptorLength (LSB) */
00078     0x00,                        /* wDescriptorLength (MSB) */
00079 
00080     0x07,                        /* bLength */
00081     ENDPOINT_DESCRIPTOR,         /* bDescriptorType */
00082     0x81,                        /* bEndpointAddress */
00083     0x03,                        /* bmAttributes */
00084     MAX_PACKET_SIZE_EP1,         /* wMaxPacketSize (LSB) */
00085     0x00,                        /* wMaxPacketSize (MSB) */
00086     0x0a,                        /* bInterval */
00087 };
00088 
00089 /* HID Class Report Descriptor */
00090 /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */
00091 
00092 /* Main items */
00093 #define INPUT(size)             (0x80 | size)
00094 #define OUTPUT(size)            (0x90 | size)
00095 #define FEATURE(size)           (0xb0 | size)
00096 #define COLLECTION(size)        (0xa0 | size)
00097 #define END_COLLECTION(size)    (0xc0 | size)
00098 
00099 /* Global items */
00100 #define USAGE_PAGE(size)        (0x04 | size)
00101 #define LOGICAL_MIN(size)       (0x14 | size)
00102 #define LOGICAL_MAX(size)       (0x24 | size)
00103 #define PHYSICAL_MIN(size)      (0x34 | size)
00104 #define PHYSICAL_MAX(size)      (0x44 | size)
00105 #define UNIT_EXPONENT(size)     (0x54 | size)
00106 #define UNIT(size)              (0x64 | size)
00107 #define REPORT_SIZE(size)       (0x74 | size)
00108 #define REPORT_ID(size)         (0x84 | size)
00109 #define REPORT_COUNT(size)      (0x94 | size)
00110 #define PUSH(size)              (0xa4 | size)
00111 #define POP(size)               (0xb4 | size)
00112 
00113 /* Local items */
00114 #define USAGE(size)             (0x08 | size)
00115 #define USAGE_MIN(size)         (0x18 | size)
00116 #define USAGE_MAX(size)         (0x28 | size)
00117 #define DESIGNATOR_INDEX(size)  (0x38 | size)
00118 #define DESIGNATOR_MIN(size)    (0x48 | size)
00119 #define DESIGNATOR_MAX(size)    (0x58 | size)
00120 #define STRING_INDEX(size)      (0x78 | size)
00121 #define STRING_MIN(size)        (0x88 | size)
00122 #define STRING_MAX(size)        (0x98 | size)
00123 #define DELIMITER(size)         (0xa8 | size)
00124 
00125 #define REPORT_ID_KEYBOARD      (1)
00126 #define REPORT_ID_MOUSE         (2)
00127 
00128 #define MAX_REPORT_SIZE         (8)
00129 
00130 unsigned char reportDescriptor[] = {
00131     /* Keyboard */
00132     USAGE_PAGE(1),      0x01,
00133     USAGE(1),           0x06,
00134     COLLECTION(1),      0x01,
00135     REPORT_ID(1),       REPORT_ID_KEYBOARD,
00136     USAGE_PAGE(1),      0x07,
00137     USAGE_MIN(1),       0xE0,
00138     USAGE_MAX(1),       0xE7,
00139     LOGICAL_MIN(1),     0x00,
00140     LOGICAL_MAX(1),     0x01,
00141     REPORT_SIZE(1),     0x01,
00142     REPORT_COUNT(1),    0x08,
00143     INPUT(1),           0x02,
00144     REPORT_COUNT(1),    0x01,
00145     REPORT_SIZE(1),     0x08,
00146     INPUT(1),           0x01,
00147     REPORT_COUNT(1),    0x05,
00148     REPORT_SIZE(1),     0x01,
00149     USAGE_PAGE(1),      0x08,
00150     USAGE_MIN(1),       0x01,
00151     USAGE_MAX(1),       0x05,
00152     OUTPUT(1),          0x02,
00153     REPORT_COUNT(1),    0x01,
00154     REPORT_SIZE(1),     0x03,
00155     OUTPUT(1),          0x01,
00156     REPORT_COUNT(1),    0x06,
00157     REPORT_SIZE(1),     0x08,
00158     LOGICAL_MIN(1),     0x00,
00159     LOGICAL_MAX(2),     0xff, 0x00,
00160     USAGE_PAGE(1),      0x07,
00161     USAGE_MIN(1),       0x00,
00162     USAGE_MAX(2),       0xff, 0x00,
00163     INPUT(1),           0x00,
00164     END_COLLECTION(0),
00165 
00166     /* Mouse */
00167     USAGE_PAGE(1),      0x01,
00168     USAGE(1),           0x02,
00169     COLLECTION(1),      0x01,
00170     USAGE(1),           0x01,
00171     COLLECTION(1),      0x00,
00172     REPORT_ID(1),       REPORT_ID_MOUSE,
00173     REPORT_COUNT(1),    0x03,
00174     REPORT_SIZE(1),     0x01,
00175     USAGE_PAGE(1),      0x09,
00176     USAGE_MIN(1),       0x1,
00177     USAGE_MAX(1),       0x3,
00178     LOGICAL_MIN(1),     0x00,
00179     LOGICAL_MAX(1),     0x01,
00180     INPUT(1),           0x02,
00181     REPORT_COUNT(1),    0x01,
00182     REPORT_SIZE(1),     0x05,
00183     INPUT(1),           0x01,
00184     REPORT_COUNT(1),    0x03,
00185     REPORT_SIZE(1),     0x08,
00186     USAGE_PAGE(1),      0x01,
00187     USAGE(1),           0x30,
00188     USAGE(1),           0x31,
00189     USAGE(1),           0x38,
00190     LOGICAL_MIN(1),     0x81,
00191     LOGICAL_MAX(1),     0x7f,
00192     INPUT(1),           0x06,
00193     END_COLLECTION(0),
00194     END_COLLECTION(0),
00195 };
00196 
00197 volatile bool complete;
00198 volatile bool configured;
00199 unsigned char outputReport[MAX_REPORT_SIZE];
00200 
00201 usbhid::usbhid() {
00202     configured = false;
00203     connect();
00204 }
00205 
00206 void usbhid::deviceEventReset() {
00207     configured = false;
00208 
00209     /* Must call base class */
00210     usbdevice::deviceEventReset();
00211 }
00212 
00213 bool usbhid::requestSetConfiguration(void) {
00214     bool result;
00215 
00216     /* Configure IN interrupt endpoint */
00217     realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1);
00218     enableEndpointEvent(EP1IN);
00219 
00220     /* Must call base class */
00221     result = usbdevice::requestSetConfiguration();
00222 
00223     if (result) {
00224         /* Now configured */
00225         configured = true;
00226     }
00227 
00228     return result;
00229 }
00230 
00231 bool usbhid::requestGetDescriptor(void) {
00232     bool success = false;
00233 
00234     switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
00235         case DEVICE_DESCRIPTOR:
00236             transfer.remaining = sizeof(deviceDescriptor);
00237             transfer.ptr = deviceDescriptor;
00238             transfer.direction = DEVICE_TO_HOST;
00239             success = true;
00240             break;
00241         case CONFIGURATION_DESCRIPTOR:
00242             transfer.remaining =  sizeof(configurationDescriptor);
00243             transfer.ptr = configurationDescriptor;
00244             transfer.direction = DEVICE_TO_HOST;
00245             success = true;
00246             break;
00247         case STRING_DESCRIPTOR:
00248         case INTERFACE_DESCRIPTOR:
00249         case ENDPOINT_DESCRIPTOR:
00250             /* TODO: Support is optional, not implemented here */
00251             break;
00252         case HID_DESCRIPTOR:
00253             transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */
00254             transfer.ptr = &configurationDescriptor[18];
00255             transfer.direction = DEVICE_TO_HOST;
00256             success = true;
00257             break;
00258         case REPORT_DESCRIPTOR:
00259             transfer.remaining = sizeof(reportDescriptor);
00260             transfer.ptr = reportDescriptor;
00261             transfer.direction = DEVICE_TO_HOST;
00262             success = true;
00263             break;
00264         default:
00265             break;
00266     }
00267 
00268     return success;
00269 }
00270 
00271 bool usbhid::requestSetup(void) {
00272     /* Process class requests */
00273     bool success = false;
00274 
00275     if (transfer.setup.bmRequestType.Type == CLASS_TYPE) {
00276         switch (transfer.setup.bRequest) {
00277             case SET_REPORT:
00278                 switch (transfer.setup.wValue & 0xff) {
00279                     case REPORT_ID_KEYBOARD:
00280                         /* TODO: LED state */
00281                         transfer.remaining = sizeof(outputReport);
00282                         transfer.ptr = outputReport;
00283                         transfer.direction = HOST_TO_DEVICE;
00284                         success = true;
00285                         break;
00286                     default:
00287                         break;
00288                 }
00289                 break;
00290             default:
00291                 break;
00292         }
00293     }
00294 
00295     if (success) {
00296         /* We've handled this request */
00297         return true;
00298     }
00299 
00300     return usbdevice::requestSetup();
00301 }
00302 
00303 bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) {
00304     /* Send an Input Report */
00305     /* If data is NULL an all zero report is sent */
00306 
00307     static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */
00308     unsigned char i;
00309 
00310     if (size > MAX_REPORT_SIZE) {
00311         return false;
00312     }
00313 
00314     /* Add report ID */
00315     report[0]=id;
00316 
00317     /* Add report data */
00318     if (data != NULL) {
00319         for (i=0; i<size; i++) {
00320             report[i+1] = *data++;
00321         }
00322     } else {
00323         for (i=0; i<size; i++) {
00324             report[i+1] = 0;
00325         }
00326     }
00327 
00328     /* Block if not configured */
00329     while (!configured);
00330 
00331     /* Send report */
00332     complete = false;
00333     disableEvents();
00334     endpointWrite(EP1IN, report, size+1); /* +1 for report ID */
00335     enableEvents();
00336 
00337     /* Wait for completion */
00338     while (!complete && configured);
00339     return true;
00340 }
00341 
00342 void usbhid::endpointEventEP1In(void) {
00343     complete = true;
00344 }
00345 
00346 bool usbhid::keyboard(char c) {
00347     /* Send a simulated keyboard keypress. Returns true if successful. */
00348     unsigned char report[8]={0,0,0,0,0,0,0,0};
00349 
00350     report[0] = keymap[c].modifier;
00351     report[2] = keymap[c].usage;
00352 
00353     /* Key down */
00354     if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) {
00355         return false;
00356     }
00357 
00358     /* Key up */
00359     if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) {
00360         return false;
00361     }
00362 
00363     return true;
00364 }
00365 
00366 bool usbhid::keyboard(char *string) {
00367     /* Send a string of characters. Returns true if successful. */
00368     do {
00369         if (!keyboard(*string++)) {
00370             return false;
00371         }
00372     } while (*string != '\0');
00373 
00374     return true;
00375 }
00376 
00377 bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) {
00378     /* Send a simulated mouse event. Returns true if successful. */
00379     unsigned char report[4]={0,0,0,0};
00380 
00381     report[0] = buttons;
00382     report[1] = x;
00383     report[2] = y;
00384     report[3] = wheel;
00385 
00386     if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) {
00387         return false;
00388     }
00389 
00390     return true;
00391 }
00392 
00393 
00394 //
00395 // USBJoystick
00396 //
00397 
00398 unsigned char reportDescriptorJoystick[] = {
00399     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
00400     0x09, 0x05,                    // USAGE (Game Pad)
00401     0xa1, 0x01,                    // COLLECTION (Application)
00402     0xa1, 0x00,                    //   COLLECTION (Physical)
00403     0x05, 0x09,                    //     USAGE_PAGE (Button)
00404     0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
00405     0x29, 0x05,                    //     USAGE_MAXIMUM (Button 5)
00406     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
00407     0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
00408     0x95, 0x05,                    //     REPORT_COUNT (5)
00409     0x75, 0x01,                    //     REPORT_SIZE (1)
00410     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
00411     0x75, 0x03,                    //     REPORT_SIZE (3)
00412     0x95, 0x01,                    //     REPORT_COUNT (1)
00413     0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
00414     0x19, 0x06,                    //     USAGE_MINIMUM (Button 6)
00415     0x29, 0x0c,                    //     USAGE_MAXIMUM (Button 12)
00416     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
00417     0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
00418     0x95, 0x07,                    //     REPORT_COUNT (7)
00419     0x75, 0x01,                    //     REPORT_SIZE (1)
00420     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
00421     0x95, 0x01,                    //     REPORT_COUNT (1)
00422     0x75, 0x01,                    //     REPORT_SIZE (1)
00423     0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
00424     0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
00425     0x09, 0x30,                    //     USAGE (X)
00426     0x09, 0x31,                    //     USAGE (Y)
00427     0x09, 0x33,                    //     USAGE (Rx)
00428     0x09, 0x34,                    //     USAGE (Ry)
00429     0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
00430     0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
00431     0x75, 0x08,                    //     REPORT_SIZE (8)
00432     0x95, 0x04,                    //     REPORT_COUNT (4)
00433     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
00434     0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
00435     0x09, 0x36,                    //     USAGE (Slider)
00436     0x09, 0x37,                    //     USAGE (Dial)
00437     0x26, 0xff, 0x00,              //     LOGICAL_MAXIMUM (255)
00438     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
00439     0x75, 0x08,                    //     REPORT_SIZE (8)
00440     0x95, 0x02,                    //     REPORT_COUNT (2)
00441     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
00442     0xc0,                           //   END_COLLECTION
00443     0xc0                           // END_COLLECTION
00444 };
00445 
00446 USBJoystick::USBJoystick() {
00447     int reportDescriptorSize = sizeof(reportDescriptorJoystick);
00448     configurationDescriptor[25] = reportDescriptorSize & 0xff;
00449     configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff;
00450 }
00451 
00452 bool USBJoystick::requestGetDescriptor(void) {
00453     bool success = false;
00454 
00455     switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
00456         case REPORT_DESCRIPTOR:
00457             transfer.remaining = sizeof(reportDescriptorJoystick);
00458             transfer.ptr = reportDescriptorJoystick;
00459             transfer.direction = DEVICE_TO_HOST;
00460             success = true;
00461             break;
00462         default:
00463             success = usbhid::requestGetDescriptor();
00464             break;
00465     }
00466 
00467     return success;
00468 }
00469 
00470 bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) {
00471     /* Send an Input Report */
00472     /* If data is NULL an all zero report is sent */
00473 
00474     static unsigned char report[MAX_REPORT_SIZE];
00475     unsigned char i;
00476 
00477     if (size > MAX_REPORT_SIZE) {
00478         return false;
00479     }
00480 
00481     /* Add report data */
00482     if (data != NULL) {
00483         for (i=0; i<size; i++) {
00484             report[i] = *data++;
00485         }
00486     } else {
00487         for (i=0; i<size; i++) {
00488             report[i] = 0;
00489         }
00490     }
00491 
00492     /* Block if not configured */
00493     while (!configured);
00494 
00495     /* Send report */
00496     complete = false;
00497     disableEvents();
00498     endpointWrite(EP1IN, report, size);
00499     enableEvents();
00500 
00501     /* Wait for completion */
00502     while (!complete && configured);
00503     return true;
00504 }
00505 
00506 bool USBJoystick::joystick(unsigned char buttons1, unsigned short buttons2, signed char x, signed char y, signed char cx, signed char cy, unsigned char L, unsigned char R) {
00507     unsigned char report[9] = {0, 0, 0, 0, 0, 0, 0, 0};
00508     report[0] = buttons1;
00509     report[1] = buttons2;
00510     report[2] = x ;
00511     report[3] = -y ;
00512     report[4] = cx ;
00513     report[5] = cy ;
00514     report[6] = L ;
00515     report[7] = R ;
00516 
00517 
00518     if (!sendInputReport(report, 8)) {
00519         return false;
00520     }
00521 
00522     return true;
00523 }
00524