SAM3S8/SD8 Software Package: libraries/usb/device/hid-transfer/HIDDTransferDriver.c Source File

SAM3S8/SD8 Software Package 1.2

# HIDDTransferDriver.c

Go to the documentation of this file.

    00001 /* ----------------------------------------------------------------------------
    00002  *         ATMEL Microcontroller Software Support
    00003  * ----------------------------------------------------------------------------
    00004  * Copyright (c) 2008, Atmel Corporation
    00005  *
    00006  * All rights reserved.
    00007  *
    00008  * Redistribution and use in source and binary forms, with or without
    00009  * modification, are permitted provided that the following conditions are met:
    00010  *
    00011  * - Redistributions of source code must retain the above copyright notice,
    00012  * this list of conditions and the disclaimer below.
    00013  *
    00014  * Atmel's name may not be used to endorse or promote products derived from
    00015  * this software without specific prior written permission.
    00016  *
    00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
    00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
    00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
    00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
    00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00027  * ----------------------------------------------------------------------------
    00028  */
    00029
    00030 /** \file
    00031  * \addtogroup usbd_hid_tran
    00032  *@{
    00033  */
    00034
    00035 /*------------------------------------------------------------------------------
    00036  *         Headers
    00037  *------------------------------------------------------------------------------*/
    00038
    00039 #include <stdint.h>
    00040
    00041 #include "HIDDTransferDriver.h"
    00042 #include "USBLib_Trace.h"
    00043
    00044 #include "USBRequests.h"
    00045 #include "HIDDescriptors.h"
    00046 #include "HIDDFunction.h"
    00047
    00048 #include "USBD_HAL.h"
    00049
    00050 #include <string.h>
    00051
    00052 /*------------------------------------------------------------------------------
    00053  *         Internal types
    00054  *------------------------------------------------------------------------------*/
    00055
    00056 /**
    00057  * Report struct for HID transfer.
    00058  */
    00059 typedef struct _HIDDTransferReport {
    00060     /** Callback when report done */
    00061     HIDDReportEventCallback fCallback;
    00062     /** Callback arguments */
    00063     void* pArg;
    00064
    00065     /** Report size (ID + DATA) */
    00066     uint16_t wMaxSize;
    00067     /** Transfered size */
    00068     uint16_t wTransferred;
    00069     /** Report idle rate */
    00070     uint8_t bIdleRate;
    00071     /** Delay count for Idle */
    00072     uint8_t bDelay;
    00073     /** Report ID */
    00074     uint8_t bID;
    00075     /** Report data address */
    00076     uint8_t bData[HIDDTransferDriver_REPORTSIZE];
    00077 } HIDDTransferReport;
    00078
    00079 /**
    00080  * Driver structure for an HID device implementing simple transfer
    00081  * functionalities.
    00082  */
    00083 typedef struct _HIDDTransferDriver {
    00084
    00085     /** Standard HID function interface. */
    00086     HIDDFunction hidFunction;
    00087
    00088     /** HID Input report list */
    00089     HIDDReport *inputReports[1];
    00090     /** HID Output report list */
    00091     HIDDReport *outputReports[1];
    00092
    00093     /* OUT Report - block input for SET_REPORT */
    00094     /**< Output report block size */
    00095     uint16_t iReportLen;
    00096     /**< Output report data buffer */
    00097     uint8_t  iReportBuf[HIDDTransferDriver_REPORTSIZE];
    00098
    00099 } HIDDTransferDriver;
    00100
    00101 /*------------------------------------------------------------------------------
    00102  *         Internal variables
    00103  *------------------------------------------------------------------------------*/
    00104
    00105 /** Input report buffers */
    00106 static HIDDTransferReport inputReport;
    00107
    00108 /** Output report buffers */
    00109 static HIDDTransferReport outputReport;
    00110
    00111 /** Static instance of the HID Transfer device driver. */
    00112 static HIDDTransferDriver hiddTransferDriver;
    00113
    00114 /** Report descriptor used by the driver. */
    00115 static const uint8_t hiddTransferReportDescriptor[] = {
    00116
    00117     /* Global Usage Page */
    00118     HIDReport_GLOBAL_USAGEPAGE + 2, 0xFF, 0xFF, /* Vendor-defined */
    00119
    00120     /* Collection: Application */
    00121     HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined */
    00122     HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION,
    00123
    00124         /* Input report: Vendor-defined */
    00125         HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined usage */
    00126         HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE,
    00127         HIDReport_GLOBAL_REPORTSIZE + 1, 8,
    00128         HIDReport_GLOBAL_LOGICALMINIMUM + 1, (uint8_t) -128,
    00129         HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (uint8_t)  127,
    00130         HIDReport_INPUT + 1, 0,    /* No Modifiers */
    00131
    00132         /* Output report: vendor-defined */
    00133         HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined usage */
    00134         HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE,
    00135         HIDReport_GLOBAL_REPORTSIZE + 1, 8,
    00136         HIDReport_GLOBAL_LOGICALMINIMUM + 1, (uint8_t) -128,
    00137         HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (uint8_t)  127,
    00138         HIDReport_OUTPUT + 1, 0,    /* No Modifiers */
    00139     HIDReport_ENDCOLLECTION
    00140 };
    00141
    00142 /*------------------------------------------------------------------------------
    00143  *         Internal functions
    00144  *------------------------------------------------------------------------------*/
    00145
    00146 /**
    00147  * Returns the descriptor requested by the host.
    00148  * \param type Descriptor type.
    00149  * \param length Maximum number of bytes to send.
    00150  * \return 1 if the request has been handled by this function, otherwise 0.
    00151  */
    00152 static uint8_t HIDDTransferDriver_GetDescriptor(uint8_t type,
    00153                                                 uint8_t length)
    00154 {
    00155     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00156     HIDDFunction *pHidd = &pDrv->hidFunction;
    00157
    00158     const USBConfigurationDescriptor *pConfiguration;
    00159     HIDDescriptor *hidDescriptors[2];
    00160
    00161     switch (type) {
    00162
    00163         case HIDGenericDescriptor_REPORT:
    00164             TRACE_INFO("Report ");
    00165
    00166             /* Adjust length and send report descriptor */
    00167             if (length > HIDDTransferDriver_REPORTDESCRIPTORSIZE) {
    00168
    00169                 length = HIDDTransferDriver_REPORTDESCRIPTORSIZE;
    00170             }
    00171             USBD_Write(0, &hiddTransferReportDescriptor, length, 0, 0);
    00172             break;
    00173
    00174         case HIDGenericDescriptor_HID:
    00175             TRACE_INFO("HID ");
    00176
    00177             /* Configuration descriptor is different depending on configuration */
    00178             if (USBD_IsHighSpeed()) {
    00179
    00180                 pConfiguration =
    00181                    pHidd->pUsbd->pDescriptors->pHsConfiguration;
    00182             }
    00183             else {
    00184
    00185                 pConfiguration =
    00186                    pHidd->pUsbd->pDescriptors->pFsConfiguration;
    00187             }
    00188
    00189             /* Parse the device configuration to get the HID descriptor */
    00190             USBConfigurationDescriptor_Parse(pConfiguration, 0, 0,
    00191                                      (USBGenericDescriptor **) hidDescriptors);
    00192
    00193             /* Adjust length and send HID descriptor */
    00194             if (length > sizeof(HIDDescriptor)) {
    00195
    00196                 length = sizeof(HIDDescriptor);
    00197             }
    00198             USBD_Write(0, hidDescriptors[0], length, 0, 0);
    00199             break;
    00200
    00201         default:
    00202             return 0;
    00203     }
    00204
    00205     return 1;
    00206 }
    00207
    00208 /**
    00209  * Callback function when SetReport request data received from host
    00210  * \param pArg Pointer to additional argument struct
    00211  * \param status Result status
    00212  * \param transferred Number of bytes transferred
    00213  * \param remaining Number of bytes that are not transferred yet
    00214  */
    00215 static void HIDDTransferDriver_ReportReceived(void *pArg,
    00216                                               uint8_t status,
    00217                                               uint32_t transferred,
    00218                                               uint32_t remaining)
    00219 {
    00220     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00221
    00222     /* Stop warning */
    00223     pArg = pArg;
    00224     status = status;
    00225     remaining = remaining;
    00226
    00227     pDrv->iReportLen = transferred;
    00228     USBD_Write(0, 0, 0, 0, 0);
    00229 }
    00230
    00231 /*------------------------------------------------------------------------------
    00232  *      Exported functions
    00233  *------------------------------------------------------------------------------*/
    00234
    00235 /**
    00236  * Initializes the HID Transfer %device driver.
    00237  * \param pDescriptors Pointer to USBDDriverDescriptors instance.
    00238  */
    00239 void HIDDTransferDriver_Initialize(const USBDDriverDescriptors * pDescriptors)
    00240 {
    00241     HIDDTransferDriver * pDrv = &hiddTransferDriver;
    00242     USBDDriver *pUsbd = USBD_GetDriver();
    00243
    00244     /* One input report */
    00245     pDrv->inputReports[0] = (HIDDReport*)&inputReport;
    00246     HIDDFunction_InitializeReport((HIDDReport *)pDrv->inputReports[0],
    00247                                   HIDDTransferDriver_REPORTSIZE,
    00248                                   0,
    00249                                   0, 0);
    00250     /* One output report */
    00251     pDrv->outputReports[0] = (HIDDReport*)&outputReport;
    00252     HIDDFunction_InitializeReport((HIDDReport *)pDrv->outputReports[0],
    00253                                   HIDDTransferDriver_REPORTSIZE,
    00254                                   0,
    00255                                   0, 0);
    00256
    00257     /* Initialize USBD Driver instance */
    00258     USBDDriver_Initialize(pUsbd,
    00259                           pDescriptors,
    00260                           0); /* Multiple interface settings not supported */
    00261     /* Function instance initialize */
    00262     HIDDFunction_Initialize(&pDrv->hidFunction,
    00263                             pUsbd, 0,
    00264                             hiddTransferReportDescriptor,
    00265                             (HIDDReport **)(&pDrv->inputReports), 1,
    00266                             (HIDDReport **)(&pDrv->outputReports), 1);
    00267     /* Initialize USBD */
    00268     USBD_Init();
    00269 }
    00270
    00271 /**
    00272  * Handles configureation changed event.
    00273  * \param cfgnum New configuration number
    00274  */
    00275 void HIDDTransferDriver_ConfigurationChangedHandler(uint8_t cfgnum)
    00276 {
    00277     const USBDDriverDescriptors * pDescriptors = USBD_GetDriver()->pDescriptors;
    00278     HIDDTransferDriver * pDrv = &hiddTransferDriver;
    00279     HIDDFunction * pHidd = &pDrv->hidFunction;
    00280
    00281     USBConfigurationDescriptor *pDesc;
    00282
    00283     if (cfgnum > 0) {
    00284
    00285         /* Parse endpoints for reports */
    00286         if (USBD_HAL_IsHighSpeed() && pDescriptors->pHsConfiguration)
    00287             pDesc = (USBConfigurationDescriptor*)pDescriptors->pHsConfiguration;
    00288         else
    00289             pDesc = (USBConfigurationDescriptor*)pDescriptors->pFsConfiguration;
    00290         HIDDFunction_ParseInterface(pHidd,
    00291                                     (USBGenericDescriptor*)pDesc,
    00292                                     pDesc->wTotalLength);
    00293
    00294         /* Start polling for Output Reports */
    00295         HIDDFunction_StartPollingOutputs(pHidd);
    00296     }
    00297 }
    00298
    00299 /**
    00300  * Handles HID-specific SETUP request sent by the host.
    00301  * \param request Pointer to a USBGenericRequest instance
    00302  */
    00303 void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request)
    00304 {
    00305     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00306     HIDDFunction *pHidd = &pDrv->hidFunction;
    00307
    00308     TRACE_INFO("NewReq ");
    00309
    00310     /* Check if this is a standard request */
    00311     if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) {
    00312
    00313         /* This is a standard request */
    00314         switch (USBGenericRequest_GetRequest(request)) {
    00315
    00316         case USBGenericRequest_GETDESCRIPTOR:
    00317             /* Check if this is a HID descriptor, otherwise forward it to
    00318                the standard driver */
    00319             if (!HIDDTransferDriver_GetDescriptor(
    00320                     USBGetDescriptorRequest_GetDescriptorType(request),
    00321                     USBGenericRequest_GetLength(request))) {
    00322
    00323                 USBDDriver_RequestHandler(pHidd->pUsbd,
    00324                                           request);
    00325             }
    00326             return; /* Handled, no need to do others */
    00327
    00328         case USBGenericRequest_CLEARFEATURE:
    00329
    00330             /* Check which is the requested feature */
    00331             switch (USBFeatureRequest_GetFeatureSelector(request)) {
    00332                 case USBFeatureRequest_ENDPOINTHALT:
    00333                 {   uint8_t ep =
    00334                         USBGenericRequest_GetEndpointNumber(request);
    00335                         if (USBD_IsHalted(ep)) {
    00336                             /* Unhalt endpoint restart OUT EP
    00337                              */
    00338                             USBD_Unhalt(ep);
    00339                             if (ep == pHidd->bPipeOUT) {
    00340                                 HIDDFunction_StartPollingOutputs(pHidd);
    00341                             }
    00342                         }
    00343                         /* and send a zero-length packet */
    00344                         USBD_Write(0, 0, 0, 0, 0);
    00345                     return; /* Handled, no need to do others */
    00346                 }
    00347             }
    00348             break;
    00349
    00350         }
    00351     }
    00352     /* We use different buffer for SetReport */
    00353     else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) {
    00354
    00355         switch (USBGenericRequest_GetRequest(request)) {
    00356
    00357         case HIDGenericRequest_SETREPORT:
    00358             {
    00359                 uint16_t length = USBGenericRequest_GetLength(request);
    00360                 uint8_t  type = HIDReportRequest_GetReportType(request);
    00361                 if (type == HIDReportRequest_OUTPUT) {
    00362                     if (length > HIDDTransferDriver_REPORTSIZE)
    00363                         length = HIDDTransferDriver_REPORTSIZE;
    00364                     USBD_Read(0,
    00365                               pDrv->iReportBuf,
    00366                               length,
    00367                               HIDDTransferDriver_ReportReceived,
    00368                               0); /* No argument to the callback function */
    00369                 }
    00370                 else {
    00371
    00372                     USBD_Stall(0);
    00373                 }
    00374             }
    00375             return; /* Handled, no need do others */
    00376         }
    00377     }
    00378
    00379
    00380     /* Process HID requests */
    00381     if (USBRC_SUCCESS == HIDDFunction_RequestHandler(pHidd,
    00382                                                      request)) {
    00383         return;
    00384     }
    00385     else
    00386         USBDDriver_RequestHandler(pHidd->pUsbd, request);
    00387 }
    00388
    00389 /**
    00390  * Try to read request buffer of SetReport.
    00391  * Set pData to 0 to get current data length only.
    00392  * \param pData Pointer to data buffer
    00393  * \param dwLength Data buffer length
    00394  * \return Number of bytes read
    00395  */
    00396 uint16_t HIDDTransferDriver_ReadReport(void *pData,
    00397                                        uint32_t dwLength)
    00398 {
    00399     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00400
    00401     if (pData == 0) {
    00402
    00403         return pDrv->iReportLen;
    00404     }
    00405
    00406     if (dwLength > HIDDTransferDriver_REPORTSIZE) {
    00407
    00408         dwLength = HIDDTransferDriver_REPORTSIZE;
    00409     }
    00410     if (dwLength > pDrv->iReportLen) {
    00411
    00412         dwLength = pDrv->iReportLen;
    00413     }
    00414     pDrv->iReportLen = 0;
    00415     memcpy(pData, pDrv->iReportBuf, dwLength);
    00416
    00417     return dwLength;
    00418 }
    00419
    00420 /**
    00421  * Try to read request buffer of interrupt OUT EP.
    00422  * Set pData to 0 to get current data length only.
    00423  * \param pData Pointer to data buffer
    00424  * \param dLength Data buffer length
    00425  * \return Number of bytes read
    00426  */
    00427 uint16_t HIDDTransferDriver_Read(void *pData,
    00428                                  uint32_t dLength)
    00429 {
    00430     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00431     if (pData == 0) {
    00432
    00433         return pDrv->outputReports[0]->wTransferred;
    00434     }
    00435
    00436     if (dLength > HIDDTransferDriver_REPORTSIZE) {
    00437
    00438         dLength = HIDDTransferDriver_REPORTSIZE;
    00439     }
    00440     if (dLength > pDrv->outputReports[0]->wTransferred) {
    00441
    00442         dLength = pDrv->outputReports[0]->wTransferred;
    00443     }
    00444     pDrv->outputReports[0]->wTransferred = 0;
    00445     memcpy(pData, pDrv->outputReports[0]->bData, dLength);
    00446
    00447     return dLength;
    00448 }
    00449
    00450 /**
    00451  * Write data through USB interrupt IN EP.
    00452  * \param pData Pointer to the data sent.
    00453  * \param dLength The data length.
    00454  * \param fCallback Callback function invoked when transferring done.
    00455  * \param pArg Pointer to additional arguments.
    00456  */
    00457 uint8_t HIDDTransferDriver_Write(const void *pData,
    00458                                  uint32_t dLength,
    00459                                  TransferCallback fCallback,
    00460                                  void *pArg)
    00461 {
    00462     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00463     if (dLength != HIDDTransferDriver_REPORTSIZE) {
    00464
    00465         dLength = HIDDTransferDriver_REPORTSIZE;
    00466     }
    00467     return USBD_Write(pDrv->hidFunction.bPipeIN,
    00468                       pData, dLength,
    00469                       fCallback, pArg);
    00470 }
    00471
    00472 /**
    00473  * Starts a remote wake-up sequence if the host has explicitely enabled it
    00474  * by sending the appropriate SET_FEATURE request.
    00475  */
    00476 void HIDDTransferDriver_RemoteWakeUp(void)
    00477 {
    00478     HIDDTransferDriver *pDrv = &hiddTransferDriver;
    00479
    00480     /* Remote wake-up has been enabled */
    00481     if (USBDDriver_IsRemoteWakeUpEnabled(pDrv->hidFunction.pUsbd)) {
    00482
    00483         USBD_RemoteWakeUp();
    00484     }
    00485 }
    00486
    00487 /**@}*/

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines