SAMV71 Xplained Ultra Software Package 1.4

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     remaining = remaining; status = status; pArg = pArg;
00222     pDrv->iReportLen = transferred;
00223     USBD_Write(0, 0, 0, 0, 0);
00224 }
00225 
00226 /*------------------------------------------------------------------------------
00227  *      Exported functions
00228  *------------------------------------------------------------------------------*/
00229 
00230 /**
00231  * Initializes the HID Transfer %device driver.
00232  * \param pDescriptors Pointer to USBDDriverDescriptors instance.
00233  */
00234 void HIDDTransferDriver_Initialize(const USBDDriverDescriptors * pDescriptors)
00235 {
00236     HIDDTransferDriver * pDrv = &hiddTransferDriver;
00237     USBDDriver *pUsbd = USBD_GetDriver();
00238 
00239     /* One input report */
00240     pDrv->inputReports[0] = (HIDDReport*)&inputReport;
00241     HIDDFunction_InitializeReport((HIDDReport *)pDrv->inputReports[0],
00242                                   HIDDTransferDriver_REPORTSIZE,
00243                                   0,
00244                                   0, 0);
00245     /* One output report */
00246     pDrv->outputReports[0] = (HIDDReport*)&outputReport;
00247     HIDDFunction_InitializeReport((HIDDReport *)pDrv->outputReports[0],
00248                                   HIDDTransferDriver_REPORTSIZE,
00249                                   0,
00250                                   0, 0);
00251 
00252     /* Initialize USBD Driver instance */
00253     USBDDriver_Initialize(pUsbd,
00254                           pDescriptors,
00255                           0); /* Multiple interface settings not supported */
00256     /* Function instance initialize */
00257     HIDDFunction_Initialize(&pDrv->hidFunction,
00258                             pUsbd, 0,
00259                             hiddTransferReportDescriptor,
00260                             (HIDDReport **)(&pDrv->inputReports), 1,
00261                             (HIDDReport **)(&pDrv->outputReports), 1);
00262     /* Initialize USBD */
00263     USBD_Init();
00264 }
00265 
00266 /**
00267  * Handles configureation changed event.
00268  * \param cfgnum New configuration number
00269  */
00270 void HIDDTransferDriver_ConfigurationChangedHandler(uint8_t cfgnum)
00271 {
00272     const USBDDriverDescriptors * pDescriptors = USBD_GetDriver()->pDescriptors;
00273     HIDDTransferDriver * pDrv = &hiddTransferDriver;
00274     HIDDFunction * pHidd = &pDrv->hidFunction;
00275 
00276     USBConfigurationDescriptor *pDesc;
00277 
00278     if (cfgnum > 0) {
00279 
00280         /* Parse endpoints for reports */
00281         if (USBD_HAL_IsHighSpeed() && pDescriptors->pHsConfiguration)
00282             pDesc = (USBConfigurationDescriptor*)pDescriptors->pHsConfiguration;
00283         else
00284             pDesc = (USBConfigurationDescriptor*)pDescriptors->pFsConfiguration;
00285         HIDDFunction_ParseInterface(pHidd,
00286                                     (USBGenericDescriptor*)pDesc,
00287                                     pDesc->wTotalLength);
00288 
00289         /* Start polling for Output Reports */
00290         HIDDFunction_StartPollingOutputs(pHidd);
00291     }
00292 }
00293 
00294 /**
00295  * Handles HID-specific SETUP request sent by the host.
00296  * \param request Pointer to a USBGenericRequest instance
00297  */
00298 void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request)
00299 {
00300     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00301     HIDDFunction *pHidd = &pDrv->hidFunction;
00302 
00303     TRACE_INFO("NewReq ");
00304 
00305     /* Check if this is a standard request */
00306     if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) {
00307 
00308         /* This is a standard request */
00309         switch (USBGenericRequest_GetRequest(request)) {
00310 
00311         case USBGenericRequest_GETDESCRIPTOR:
00312             /* Check if this is a HID descriptor, otherwise forward it to
00313                the standard driver */
00314             if (!HIDDTransferDriver_GetDescriptor(
00315                     USBGetDescriptorRequest_GetDescriptorType(request),
00316                     USBGenericRequest_GetLength(request))) {
00317 
00318                 USBDDriver_RequestHandler(pHidd->pUsbd,
00319                                           request);
00320             }
00321             return; /* Handled, no need to do others */
00322 
00323         case USBGenericRequest_CLEARFEATURE:
00324 
00325             /* Check which is the requested feature */
00326             switch (USBFeatureRequest_GetFeatureSelector(request)) {
00327                 case USBFeatureRequest_ENDPOINTHALT:
00328                 {   uint8_t ep =
00329                         USBGenericRequest_GetEndpointNumber(request);
00330                         if (USBD_IsHalted(ep)) {
00331                             /* Unhalt endpoint restart OUT EP
00332                              */
00333                             USBD_Unhalt(ep);
00334                             if (ep == pHidd->bPipeOUT) {
00335                                 HIDDFunction_StartPollingOutputs(pHidd);
00336                             }
00337                         }
00338                         /* and send a zero-length packet */
00339                         USBD_Write(0, 0, 0, 0, 0);
00340                     return; /* Handled, no need to do others */
00341                 }
00342             }
00343             break;
00344 
00345         }
00346     }
00347     /* We use different buffer for SetReport */
00348     else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) {
00349 
00350         switch (USBGenericRequest_GetRequest(request)) {
00351 
00352         case HIDGenericRequest_SETREPORT:
00353             {
00354                 uint16_t length = USBGenericRequest_GetLength(request);
00355                 uint8_t  type = HIDReportRequest_GetReportType(request);
00356                 if (type == HIDReportRequest_OUTPUT) {
00357                     if (length > HIDDTransferDriver_REPORTSIZE)
00358                         length = HIDDTransferDriver_REPORTSIZE;
00359                     USBD_Read(0,
00360                               pDrv->iReportBuf,
00361                               length,
00362                               HIDDTransferDriver_ReportReceived,
00363                               0); /* No argument to the callback function */
00364                 }
00365                 else {
00366 
00367                     USBD_Stall(0);
00368                 }
00369             }
00370             return; /* Handled, no need do others */
00371         }
00372     }
00373     
00374 
00375     /* Process HID requests */
00376     if (USBRC_SUCCESS == HIDDFunction_RequestHandler(pHidd,
00377                                                      request)) {
00378         return;
00379     }
00380     else
00381         USBDDriver_RequestHandler(pHidd->pUsbd, request);
00382 }
00383 
00384 /**
00385  * Try to read request buffer of SetReport.
00386  * Set pData to 0 to get current data length only.
00387  * \param pData Pointer to data buffer
00388  * \param dwLength Data buffer length
00389  * \return Number of bytes read
00390  */
00391 uint16_t HIDDTransferDriver_ReadReport(void *pData,
00392                                        uint32_t dwLength)
00393 {
00394     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00395 
00396     if (pData == 0) {
00397 
00398         return pDrv->iReportLen;
00399     }
00400 
00401     if (dwLength > HIDDTransferDriver_REPORTSIZE) {
00402 
00403         dwLength = HIDDTransferDriver_REPORTSIZE;
00404     }
00405     if (dwLength > pDrv->iReportLen) {
00406 
00407         dwLength = pDrv->iReportLen;
00408     }
00409     pDrv->iReportLen = 0;
00410     memcpy(pData, pDrv->iReportBuf, dwLength);
00411 
00412     return dwLength;
00413 }
00414 
00415 /**
00416  * Try to read request buffer of interrupt OUT EP.
00417  * Set pData to 0 to get current data length only.
00418  * \param pData Pointer to data buffer
00419  * \param dLength Data buffer length
00420  * \return Number of bytes read
00421  */
00422 uint16_t HIDDTransferDriver_Read(void *pData,
00423                                  uint32_t dLength)
00424 {
00425     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00426     if (pData == 0) {
00427 
00428         return pDrv->outputReports[0]->wTransferred;
00429     }
00430 
00431     if (dLength > HIDDTransferDriver_REPORTSIZE) {
00432 
00433         dLength = HIDDTransferDriver_REPORTSIZE;
00434     }
00435     if (dLength > pDrv->outputReports[0]->wTransferred) {
00436 
00437         dLength = pDrv->outputReports[0]->wTransferred;
00438     }
00439     pDrv->outputReports[0]->wTransferred = 0;
00440     memcpy(pData, pDrv->outputReports[0]->bData, dLength);
00441 
00442     return dLength;
00443 }
00444 
00445 /**
00446  * Write data through USB interrupt IN EP.
00447  * \param pData Pointer to the data sent.
00448  * \param dLength The data length.
00449  * \param fCallback Callback function invoked when transferring done.
00450  * \param pArg Pointer to additional arguments.
00451  */
00452 uint8_t HIDDTransferDriver_Write(const void *pData,
00453                                  uint32_t dLength,
00454                                  TransferCallback fCallback,
00455                                  void *pArg)
00456 {
00457     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00458     if (dLength != HIDDTransferDriver_REPORTSIZE) {
00459 
00460         dLength = HIDDTransferDriver_REPORTSIZE;
00461     }
00462     return USBD_Write(pDrv->hidFunction.bPipeIN,
00463                       pData, dLength,
00464                       fCallback, pArg);
00465 }
00466 
00467 /**
00468  * Starts a remote wake-up sequence if the host has explicitely enabled it
00469  * by sending the appropriate SET_FEATURE request.
00470  */
00471 void HIDDTransferDriver_RemoteWakeUp(void)
00472 {
00473     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00474 
00475     /* Remote wake-up has been enabled */
00476     if (USBDDriver_IsRemoteWakeUpEnabled(pDrv->hidFunction.pUsbd)) {
00477 
00478         USBD_RemoteWakeUp();
00479     }
00480 }
00481 
00482 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines