Dwayne Dilbeck / USBDevice

Dependents:   HW4_AudioControl

Fork of USBDevice by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHID.cpp Source File

USBHID.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 *
00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004 * and associated documentation files (the "Software"), to deal in the Software without
00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00007 * Software is furnished to do so, subject to the following conditions:
00008 *
00009 * The above copyright notice and this permission notice shall be included in all copies or
00010 * substantial portions of the Software.
00011 *
00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017 */
00018 
00019 #include "stdint.h"
00020 #include "USBHAL.h"
00021 #include "USBHID.h"
00022 
00023 /* new constructor
00024   This constructor adds the ability toset the feature_report length.  This constructor is not the default constructor to maintain backward compatibility.
00025 */
00026 USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint8_t feature_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
00027 {
00028     output_length = output_report_length;
00029     input_length = input_report_length;
00030     feature_length = feature_report_length;
00031     inputReport.length=input_length;
00032     outputReport.length=output_length;
00033     featureReport.length=feature_length;
00034     
00035     callbackSetInputReport = &HID_callbackSetReport;
00036     callbackGetInputReport = &HID_callbackGetReport;
00037     callbackSetOutputReport = &HID_callbackSetReport;
00038     callbackGetOutputReport = &HID_callbackGetReport;
00039     callbackSetFeatureReport = &HID_callbackSetReport;
00040     callbackGetFeatureReport = &HID_callbackGetReport;
00041 
00042     reportIdleRateInt=0x0;
00043     reportIdleRate=0.0;
00044     
00045     protocolState=1;
00046     
00047     if(connect) {
00048         USBDevice::connect();
00049     }
00050 }
00051 
00052 /*Original constructor 
00053     The original constructor, modified to set the defautls for new features
00054     Feature report will be disabled if the old/default constructor is used.
00055 */
00056 
00057 USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length,  uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
00058 {
00059     output_length = output_report_length;
00060     input_length = input_report_length;
00061     feature_length = 0;
00062     inputReport.length=input_length;
00063     outputReport.length=output_length;
00064     featureReport.length=feature_length+1;
00065     
00066     callbackSetInputReport = &HID_callbackSetReport;
00067     callbackGetInputReport = &HID_callbackGetReport;
00068     callbackSetOutputReport = &HID_callbackSetReport;
00069     callbackGetOutputReport = &HID_callbackGetReport;
00070     callbackSetFeatureReport = &HID_callbackSetReport;
00071     callbackGetFeatureReport = &HID_callbackGetReport;
00072 
00073     reportIdleRateInt=0x0;
00074     reportIdleRate=0.0;
00075     
00076     if(connect) {
00077         USBDevice::connect();
00078     }
00079 }
00080 
00081 /* IdlePeriodReSend is called when the IDLE rate is non-zero and the ticker period expires.
00082    By default: Windows will issue a set-idle rate to Zero when a device is connected.
00083    WARNING: The deviceIOcontrol commands for the poll rate get/set do not seem to be implemented in the windows hid driver.
00084    When the set_idle rate is greater than zero an input report will be resent every idle period even if there is no change. If the input report 
00085    changes via the FillReport command, the change is sent and the Ticker is reset.
00086 */
00087 void USBHID::IdlePeriodReSend(void) { 
00088       //Disable the Tickers during the function kicked off from the ticker. 
00089      NVIC_DisableIRQ(TIMER3_IRQn);
00090      SendReport();
00091      NVIC_EnableIRQ(TIMER3_IRQn);    
00092 }
00093 
00094 /* ResetIdleTicker
00095    Arms the ticker function in the idle period is greater than zero, otherwise the ticker is disarmed.
00096    If a changed report is sent, this command is used to Arm the ticker agian before it has triggered, effectively reseting the countdown.
00097 */
00098 void USBHID::ResetIdleTicker() {
00099    if(  reportIdleRateInt > 0 )
00100          countDownToReportTrigger.attach(this,&USBHID::IdlePeriodReSend,reportIdleRate);
00101      else
00102          countDownToReportTrigger.detach();
00103 }
00104 
00105 /* SetReportIdle handles the SET_IDLE controlTransfer.  The idle rate is a minimum of 4ms when enabled.
00106    The float conversion to seconds is computerd and the Ticker is armed or disarmed.
00107 */
00108 void USBHID::SetReportIdle(uint16_t wValue){
00109      reportIdleRateInt=(wValue>>8);
00110      reportIdleRate= reportIdleRateInt * 0.004;
00111      
00112      #ifdef DEBUG
00113      printf("IDLE: %f\r\n",reportIdleRate);
00114      #endif
00115      ResetIdleTicker();
00116 }
00117 
00118 
00119 /* Legacy method --> No change */
00120 bool USBHID::send(HID_REPORT *report)
00121 {   
00122     return write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
00123 }
00124 
00125 /* Legacy method --> No change */
00126 bool USBHID::sendNB(HID_REPORT *report)
00127 {
00128     return writeNB(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
00129 }
00130 
00131 /* Legacy method --> No change */
00132 bool USBHID::read(HID_REPORT *report)
00133 {
00134     uint32_t bytesRead = 0;
00135     bool result;
00136     result = USBDevice::readEP(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
00137     if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
00138         return false;
00139     report->length = bytesRead;
00140     return result;
00141 }
00142 
00143 
00144 /* Legacy method --> No change */
00145 bool USBHID::readNB(HID_REPORT *report)
00146 {
00147     uint32_t bytesRead = 0;
00148     bool result;
00149     result = USBDevice::readEP_NB(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
00150     report->length = bytesRead;
00151     if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
00152         return false;
00153     return result;
00154 }
00155 
00156 /* FillInputReport should be the main function that HID developers call. The develop sets a HID report with thier data. And pass it to FillInputReport
00157   The procedure will 1) Copy the HID report data to the input_report 2) check to see if the data has changed.
00158   Action #1 is important due to USB HID conformance.HID devices are required to implement the GET_REPORT control transfer. This transfer can be used to obtain the input report at any time.
00159       With the legacy HID methods, GET_REPORT was not implemented and SET_REPORT always wrote into the output_report. this means the contents of input_report would not be read by a control transfer.
00160   Action #2 is important for the IDLE RATE. Windows will set the IDLE rate to 0 for HID devices. Which means that reports should only be sent when the data changes.
00161       With the legacy HID methods, A send would always send a HID_REPORT even if it had not changed.     
00162 */
00163 bool USBHID::FillInputReport(HID_REPORT *report)
00164 {
00165     bool changed=false;
00166     
00167     for(int i =0; i<input_length; i++)
00168        if(inputReport.data[i] != report->data[i]) {
00169           inputReport.data[i] = report->data[i];
00170           changed=true;
00171         }
00172       
00173     if (changed)    
00174         return SendReport();
00175     else
00176         return true;
00177 }  
00178 
00179 
00180 bool USBHID::FillFeatureReport(HID_REPORT *report)
00181 {
00182     for(int i =0; i<feature_length; i++)
00183           featureReport.data[i] = report->data[i];
00184     return true;
00185 }  
00186 /* SendReport is called by FillReport if the data has changed. It performs 3 action
00187  *   1) Trigger an exposed CallBack  This call back is called if a control transfer or interrupt transfer wants to get a INPUT_REPORT
00188  *       This functions may be useful to notify your device when a transfer of the input_report is executed. NOTE: The call back occurs BEFORE the actual transfer.
00189  *   2) Reset the IDLE ticker. IF the IDEL rate is not zero, the tickerneeds to be reset since we are sending a changed report.
00190  *   3) Send the Report via NB transfer on the interupt endpoint.
00191 */
00192 bool USBHID::SendReport()
00193 {
00194     bool result=false;
00195  
00196     if ((*callbackGetInputReport)(&inputReport)) {
00197         ResetIdleTicker();   
00198         result=writeNB(EPINT_IN, inputReport.data, inputReport.length, MAX_HID_REPORT_SIZE);
00199     }    
00200     return result;
00201 }  
00202 
00203 
00204 
00205 /* Legacy method --> No change */
00206 uint16_t USBHID::reportDescLength() {
00207 //TODO: Is this a bug? reportDesc() is called and a value that isn't changed is returned.  Why execute the function
00208     reportDesc();
00209     return reportLength;
00210 }
00211 
00212 /* GetReportTargetPointer: HID class control transfers Set_report and Get_report require a pointer to the report to write and read data
00213    The actual read and write logic is the same only the target report is different. Given the wvalue which  has a value of MSB(TYPE) LSB(reportID), a point to a report can be returned.
00214    Multi report is not implemented in this release, but a small change in this function will allow support of multiple reports via control transfers.
00215    
00216    If a value of 0 for a report was entered when the HID class was instantiated, a NULL report pointer is return which will cause a E0STALL for get/set report action on that type.
00217 */
00218 
00219 HID_REPORT * USBHID::GetReportTargetPointer(uint16_t wValue){
00220    //TODO: Add support for multiple reports.
00221     HID_REPORT *targetPtr=NULL;
00222     switch(wValue>>8) {
00223       case 0x01:  if (input_length >0)
00224                      targetPtr=&inputReport;
00225                    break;
00226       case 0x03:  if (feature_length >0)
00227                      targetPtr=&featureReport; 
00228                    break;
00229       case 0x02:  
00230       default: if (output_length >0)
00231                    targetPtr=&outputReport; 
00232                 break;
00233     }
00234    return targetPtr;
00235 }
00236 
00237 
00238 //
00239 //  Route callbacks from lower layers to class(es)
00240 //
00241 
00242 // Called in ISR context
00243 // Called by USBDevice on Endpoint0 request
00244 // This is used to handle extensions to standard requests
00245 // and class specific requests
00246 // Return true if class handles this request
00247 //Legacy method-->modified to include GET_REPORT, GET_IDLE, SET_IDLE transfers
00248 //               modified the function of SET_REPORT for multiple types(INPUT,OUTPUT,FEATURE)
00249 bool USBHID::USBCallback_request() {
00250     bool success = false;
00251     CONTROL_TRANSFER * transfer = getTransferPtr();
00252     uint8_t *hidDescriptor;
00253 
00254     // Process additional standard requests
00255 
00256     if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
00257     {
00258         switch (transfer->setup.bRequest)
00259         {
00260             case GET_DESCRIPTOR:
00261                 switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
00262                 {
00263                     case REPORT_DESCRIPTOR:
00264                         if ((reportDesc() != NULL) \
00265                             && (reportDescLength() != 0))
00266                         {
00267                             transfer->remaining = reportDescLength();
00268                             transfer->ptr = reportDesc();
00269                             transfer->direction = DEVICE_TO_HOST;
00270                             success = true;
00271                         }
00272                         break;
00273                     case HID_DESCRIPTOR:
00274                             // Find the HID descriptor, after the configuration descriptor
00275                             hidDescriptor = findDescriptor(HID_DESCRIPTOR);
00276                             if (hidDescriptor != NULL)
00277                             {
00278                                 transfer->remaining = HID_DESCRIPTOR_LENGTH;
00279                                 transfer->ptr = hidDescriptor;
00280                                 transfer->direction = DEVICE_TO_HOST;
00281                                 success = true;
00282                             }
00283                             break;
00284                      
00285                     default:
00286                         break;
00287                 }
00288                 break;
00289             default:
00290                 break;
00291         }
00292     }
00293 
00294     // Process class-specific requests
00295 
00296     if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
00297     {
00298         
00299         HID_REPORT *targetPtr=NULL;
00300 //        printf("ReportID: %x\r\n", transfer->setup.wValue & 0xff );
00301         switch (transfer->setup.bRequest)
00302         {
00303              case SET_REPORT:
00304                 targetPtr=GetReportTargetPointer(transfer->setup.wValue);
00305                 if (targetPtr==NULL)
00306                     break;
00307                 // First byte will be used for report ID
00308                 // BUG: In a control transfer the first byte is the reportid and deviceiocontrol does transmit this byte
00309                 //      But the interupt transfer strips the reportid byte
00310                 targetPtr->data[0] = transfer->setup.wValue & 0xff;
00311                 targetPtr->length = transfer->setup.wLength + 1;
00312                 if(transfer->remaining >= sizeof(targetPtr->data) - 1) 
00313                    transfer->remaining = sizeof(targetPtr->data) - 1;
00314                 else
00315                    transfer->remaining = transfer->setup.wLength;
00316                 transfer->ptr = &targetPtr->data[1];
00317                 transfer->direction = HOST_TO_DEVICE;
00318                 transfer->notify = true;
00319                 success = true;
00320                 break;
00321              case GET_REPORT:
00322                 // Required by section 7.2 of the HID Device Class Definition: Mandatory implementation by all devices
00323                 targetPtr=GetReportTargetPointer(transfer->setup.wValue);
00324                 if (targetPtr==NULL)
00325                     break;
00326                 // First byte will be used for report ID
00327                 // BUG: In a control transfer the first byte is the reportid and deviceiocontrol does transmit this byte
00328                 //      But the interupt transfer strips the reportid byte
00329                 transfer->setup.wLength = targetPtr->length  - 1;
00330                 if(transfer->remaining >= sizeof(targetPtr->data) - 1) 
00331                    transfer->remaining = sizeof(targetPtr->data) - 1;
00332                 else
00333                    transfer->remaining = transfer->setup.wLength;
00334                 transfer->ptr = &targetPtr->data[1];
00335                 transfer->direction = DEVICE_TO_HOST;
00336                 transfer->notify = true;
00337                 //Provide a hook for developers to provide thier own call back for Get_Report, prior to the report data is sentin response to a 
00338                 //   Control IN.
00339                 success =HIDCallback_GetReportHandler(targetPtr);
00340                 break;
00341             
00342             case SET_IDLE:
00343                //SET_IDLE works very well, Microsoft is able to use this to set the IDLE rate to 0. Durring testing the default rate was set to 0x80. 
00344                //   Normal default setting is zero.
00345                //   The microsoft HID driver will throw an invlid function error when IOCTL_HID_GET_POLL_FREQUENCY_MSEC is used.
00346                //   wValue {duration:ReportID}
00347                //TODO:  To support multipe reports, a HID_REPORT Class should be defined. The ticker and idle methods and objects should be included.
00348                 SetReportIdle(transfer->setup.wValue);
00349                 transfer->setup.wLength = 0;
00350                 transfer->direction = HOST_TO_DEVICE;
00351                 transfer->remaining = transfer->setup.wLength;
00352                 transfer->notify = true;
00353                 success=true;
00354             case GET_IDLE:
00355                 //This functionality has not been tested. The microsoft HID driver will throw an invlid function error when IOCTL_HID_GET_POLL_FREQUENCY_MSEC is used.
00356                 transfer->remaining = 1;
00357                 transfer->ptr = getReportIdlePtr(transfer->setup.wValue & 0xff);
00358                 transfer->direction = DEVICE_TO_HOST;
00359                 transfer->notify = true;
00360                 success=true;
00361                 break;
00362             case SET_PROTOCOL:                
00363                //This functionality has not been tested. 
00364                 protocolState=transfer->setup.wValue;
00365                 success=true;
00366                 break;
00367             case GET_PROTOCOL:
00368                //This functionality has not been tested. 
00369                 transfer->remaining = 1;
00370                 transfer->ptr = &protocolState;
00371                 transfer->direction = DEVICE_TO_HOST;
00372                 transfer->notify = true;
00373                 success=true;
00374                 break;
00375             default:
00376                 break;
00377         }
00378     }
00379 
00380     return success;
00381 }
00382 
00383 /* HIDCallback_GetReportHandler provides a useful  set of callbacks for the getting of each type in a report.
00384    This can be used to generate the data on the fly(Useful for a feature report) or notification that a report was sent for the device.
00385    NOTE: CALLBACKS happen before the actuall data for the report is transmitted.
00386 */
00387 bool USBHID::HIDCallback_GetReportHandler(HID_REPORT *targetPtr) {
00388       bool (*callbackGetReport)(HID_REPORT *report);
00389       CONTROL_TRANSFER * transfer = getTransferPtr();
00390       
00391       switch(transfer->setup.wValue>>8) {
00392       case HID_INPUT_REPORT_TYPE:
00393            callbackGetReport=callbackGetInputReport;
00394            break;
00395       case HID_OUTPUT_REPORT_TYPE:
00396            callbackGetReport=callbackGetOutputReport;
00397            break;
00398       case HID_FEATURE_REPORT_TYPE:
00399            callbackGetReport=callbackGetFeatureReport;
00400            break;
00401       default:
00402         return false;
00403       }
00404       return (*callbackGetReport)(targetPtr); 
00405 }
00406 
00407 /* HIDCallback_SetReportHandler provides a useful  set of callbacks for the setting of each type in a report.
00408    This can be used to update displays after a value is change(Example:NUM lock LED change).
00409    NOTE: CALLBACKS happen after the actuall data for the report is recieved.
00410 */
00411 
00412 bool USBHID::HIDCallback_SetReportHandler(HID_REPORT *targetPtr) {
00413       void (*callbackSetReport)(HID_REPORT *report);
00414       CONTROL_TRANSFER * transfer = getTransferPtr();
00415       
00416       switch(transfer->setup.wValue>>8) {
00417       case HID_INPUT_REPORT_TYPE:
00418            callbackSetReport=callbackSetInputReport;
00419            break;
00420       case HID_OUTPUT_REPORT_TYPE:
00421            callbackSetReport=callbackSetOutputReport;
00422            break;
00423       case HID_FEATURE_REPORT_TYPE:
00424            callbackSetReport=callbackSetFeatureReport;
00425            break;
00426       default:
00427            return false;
00428       }
00429       (*callbackSetReport)(targetPtr);
00430       return true;
00431        
00432 }
00433 
00434 /* USBCallback_requestCompleted To implement the set_report call back ability we need to override the requestCompleted function to provide the callback handler hook
00435 */
00436 void USBHID::USBCallback_requestCompleted(uint8_t * buf, uint32_t length){
00437      CONTROL_TRANSFER * transfer;
00438      HID_REPORT *targetPtr;
00439       
00440      transfer = getTransferPtr();
00441      targetPtr = GetReportTargetPointer(transfer->setup.wValue);
00442      USBDevice::USBCallback_requestCompleted(buf, length);
00443      //Provide a callback hook for developer use of set_report, called after the completion of the control transfer.
00444      if(transfer->setup.bRequest==SET_REPORT) {
00445         HIDCallback_SetReportHandler(targetPtr);
00446      }      
00447 }
00448 
00449 /* To ensure that the output report is updated on a writeFile interupt transfer, the EP1_OUT_callback is overridden.
00450  * additionally a callback for setOutputReport type is trigger
00451 */
00452 bool USBHID::EP1_OUT_callback(){
00453     uint32_t bytesRead = 0;
00454     bool result;
00455     //TODO: Is there a buffer over run issue here? 
00456     //read to Buffer and copy just the report data to the HID_REPORT.
00457     result = endpointReadResult(EPINT_OUT, outputReport.data, &bytesRead);
00458 //    outputReport.length = bytesRead;
00459     (*callbackSetOutputReport)(&outputReport);
00460     return result;
00461 }
00462 
00463 
00464 #define DEFAULT_CONFIGURATION (1)
00465 
00466 
00467 // Called in ISR context
00468 // Set configuration. Return false if the
00469 // configuration is not supported
00470 bool USBHID::USBCallback_setConfiguration(uint8_t configuration) {
00471     if (configuration != DEFAULT_CONFIGURATION) {
00472         return false;
00473     }
00474 
00475     // Configure endpoints > 0
00476     addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
00477     addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
00478 
00479     // We activate the endpoint to be able to recceive data
00480     readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
00481     return true;
00482 }
00483 
00484 
00485 uint8_t * USBHID::stringIinterfaceDesc() {
00486     static uint8_t stringIinterfaceDescriptor[] = {
00487         0x08,               //bLength
00488         STRING_DESCRIPTOR,  //bDescriptorType 0x03
00489         'H',0,'I',0,'D',0,  //bString iInterface - HID
00490     };
00491     return stringIinterfaceDescriptor;
00492 }
00493 
00494 uint8_t * USBHID::stringIproductDesc() {
00495     static uint8_t stringIproductDescriptor[] = {
00496         0x16,                                                       //bLength
00497         STRING_DESCRIPTOR,                                          //bDescriptorType 0x03
00498         'H',0,'I',0,'D',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 //bString iProduct - HID device
00499     };
00500     return stringIproductDescriptor;
00501 }
00502 
00503 
00504 /* legacy method .. Modified
00505  *  1) Added feature report
00506  *  2) Used KEYWORDS for added user readability.
00507  */
00508 uint8_t * USBHID::reportDesc() {
00509     static uint8_t reportDescriptor[] = {
00510         USAGE_PAGE(2), LSB(0xFFAB), MSB(0xFFAB),
00511         USAGE(2), LSB(0x0200), MSB(0x0200),
00512         COLLECTION(1), 0x01,                     // Collection 0x01
00513         REPORT_SIZE(1), 0x08,                    // report size = 8 bits
00514         LOGICAL_MINIMUM(1), 0x00,                // logical minimum = 0
00515         LOGICAL_MAXIMUM(2), 0xFF, 0x00,          // logical maximum = 255
00516         REPORT_COUNT(1), input_length,           // report count
00517         USAGE(1), 0x01,                          // usage
00518         INPUT(1), 0x02,                          // Input (array)
00519         REPORT_COUNT(1), output_length,          // report count
00520         USAGE(1), 0x02,                          // usage
00521         OUTPUT(1), 0x02,                         // Output (array)
00522         REPORT_COUNT(1), feature_length,
00523         USAGE(1), 0x03,
00524         FEATURE(2), 0x02, 0x01,
00525         END_COLLECTION(0)                        // end collection
00526     };
00527     reportLength = sizeof(reportDescriptor);
00528     return reportDescriptor;
00529 }
00530 
00531 #define DEFAULT_CONFIGURATION (1)
00532 #define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
00533                                + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
00534                                + (1 * HID_DESCRIPTOR_LENGTH) \
00535                                + (2 * ENDPOINT_DESCRIPTOR_LENGTH))
00536 
00537 uint8_t * USBHID::configurationDesc() {
00538     static uint8_t configurationDescriptor[] = {
00539         CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
00540         CONFIGURATION_DESCRIPTOR,       // bDescriptorType
00541         LSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (LSB)
00542         MSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (MSB)
00543         0x01,                           // bNumInterfaces
00544         DEFAULT_CONFIGURATION,          // bConfigurationValue
00545         0x00,                           // iConfiguration
00546         C_RESERVED | C_SELF_POWERED,    // bmAttributes
00547         C_POWER(0),                     // bMaxPower
00548 
00549         INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00550         INTERFACE_DESCRIPTOR,           // bDescriptorType
00551         0x00,                           // bInterfaceNumber
00552         0x00,                           // bAlternateSetting
00553         0x02,                           // bNumEndpoints
00554         HID_CLASS,                      // bInterfaceClass
00555         HID_SUBCLASS_NONE,              // bInterfaceSubClass
00556         HID_PROTOCOL_NONE,              // bInterfaceProtocol
00557         0x00,                           // iInterface
00558 
00559         HID_DESCRIPTOR_LENGTH,          // bLength
00560         HID_DESCRIPTOR,                 // bDescriptorType
00561         LSB(HID_VERSION_1_11),          // bcdHID (LSB)
00562         MSB(HID_VERSION_1_11),          // bcdHID (MSB)
00563         0x00,                           // bCountryCode
00564         0x01,                           // bNumDescriptors
00565         REPORT_DESCRIPTOR,              // bDescriptorType
00566         LSB(this->reportDescLength()),  // wDescriptorLength (LSB)
00567         MSB(this->reportDescLength()),  // wDescriptorLength (MSB)
00568 
00569         ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00570         ENDPOINT_DESCRIPTOR,            // bDescriptorType
00571         PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
00572         E_INTERRUPT,                    // bmAttributes
00573         LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00574         MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00575         1,                             // bInterval (milliseconds)
00576 
00577         ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00578         ENDPOINT_DESCRIPTOR,            // bDescriptorType
00579         PHY_TO_DESC(EPINT_OUT),          // bEndpointAddress
00580         E_INTERRUPT,                    // bmAttributes
00581         LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00582         MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00583         1,                             // bInterval (milliseconds)
00584     };
00585     return configurationDescriptor;
00586 }