SAMV71 Xplained Ultra Software Package 1.5

HIDDTransferDriver.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
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         } else {
00183 
00184             pConfiguration =
00185                 pHidd->pUsbd->pDescriptors->pFsConfiguration;
00186         }
00187 
00188         /* Parse the device configuration to get the HID descriptor */
00189         USBConfigurationDescriptor_Parse(pConfiguration, 0, 0,
00190                                          (USBGenericDescriptor **) hidDescriptors);
00191 
00192         /* Adjust length and send HID descriptor */
00193         if (length > sizeof(HIDDescriptor))
00194 
00195             length = sizeof(HIDDescriptor);
00196 
00197         USBD_Write(0, hidDescriptors[0], length, 0, 0);
00198         break;
00199 
00200     default:
00201         return 0;
00202     }
00203 
00204     return 1;
00205 }
00206 
00207 /**
00208  * Callback function when SetReport request data received from host
00209  * \param pArg Pointer to additional argument struct
00210  * \param status Result status
00211  * \param transferred Number of bytes transferred
00212  * \param remaining Number of bytes that are not transferred yet
00213  */
00214 static void HIDDTransferDriver_ReportReceived(void *pArg,
00215         uint8_t status,
00216         uint32_t transferred,
00217         uint32_t remaining)
00218 {
00219     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00220     remaining = remaining; status = status; pArg = pArg;
00221     pDrv->iReportLen = transferred;
00222     USBD_Write(0, 0, 0, 0, 0);
00223 }
00224 
00225 /*------------------------------------------------------------------------------
00226  *      Exported functions
00227  *------------------------------------------------------------------------------*/
00228 
00229 /**
00230  * Initializes the HID Transfer %device driver.
00231  * \param pDescriptors Pointer to USBDDriverDescriptors instance.
00232  */
00233 void HIDDTransferDriver_Initialize(const USBDDriverDescriptors *pDescriptors)
00234 {
00235     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00236     USBDDriver *pUsbd = USBD_GetDriver();
00237 
00238     /* One input report */
00239     pDrv->inputReports[0] = (HIDDReport *)&inputReport;
00240     HIDDFunction_InitializeReport((HIDDReport *)pDrv->inputReports[0],
00241                                   HIDDTransferDriver_REPORTSIZE,
00242                                   0,
00243                                   0, 0);
00244     /* One output report */
00245     pDrv->outputReports[0] = (HIDDReport *)&outputReport;
00246     HIDDFunction_InitializeReport((HIDDReport *)pDrv->outputReports[0],
00247                                   HIDDTransferDriver_REPORTSIZE,
00248                                   0,
00249                                   0, 0);
00250 
00251     /* Initialize USBD Driver instance */
00252     USBDDriver_Initialize(pUsbd,
00253                           pDescriptors,
00254                           0); /* Multiple interface settings not supported */
00255     /* Function instance initialize */
00256     HIDDFunction_Initialize(&pDrv->hidFunction,
00257                             pUsbd, 0,
00258                             hiddTransferReportDescriptor,
00259                             (HIDDReport **)(&pDrv->inputReports), 1,
00260                             (HIDDReport **)(&pDrv->outputReports), 1);
00261     /* Initialize USBD */
00262     USBD_Init();
00263 }
00264 
00265 /**
00266  * Handles configureation changed event.
00267  * \param cfgnum New configuration number
00268  */
00269 void HIDDTransferDriver_ConfigurationChangedHandler(uint8_t cfgnum)
00270 {
00271     const USBDDriverDescriptors *pDescriptors = USBD_GetDriver()->pDescriptors;
00272     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00273     HIDDFunction *pHidd = &pDrv->hidFunction;
00274 
00275     USBConfigurationDescriptor *pDesc;
00276 
00277     if (cfgnum > 0) {
00278 
00279         /* Parse endpoints for reports */
00280         if (USBD_HAL_IsHighSpeed() && pDescriptors->pHsConfiguration)
00281             pDesc = (USBConfigurationDescriptor *)pDescriptors->pHsConfiguration;
00282         else
00283             pDesc = (USBConfigurationDescriptor *)pDescriptors->pFsConfiguration;
00284 
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 
00313             /* Check if this is a HID descriptor, otherwise forward it to
00314                the standard driver */
00315             if (!HIDDTransferDriver_GetDescriptor(
00316                     USBGetDescriptorRequest_GetDescriptorType(request),
00317                     USBGenericRequest_GetLength(request))) {
00318 
00319                 USBDDriver_RequestHandler(pHidd->pUsbd,
00320                                           request);
00321             }
00322 
00323             return; /* Handled, no need to do others */
00324 
00325         case USBGenericRequest_CLEARFEATURE:
00326 
00327             /* Check which is the requested feature */
00328             switch (USBFeatureRequest_GetFeatureSelector(request)) {
00329             case USBFeatureRequest_ENDPOINTHALT: {
00330                 uint8_t ep =
00331                     USBGenericRequest_GetEndpointNumber(request);
00332 
00333                 if (USBD_IsHalted(ep)) {
00334                     /* Unhalt endpoint restart OUT EP
00335                      */
00336                     USBD_Unhalt(ep);
00337 
00338                     if (ep == pHidd->bPipeOUT)
00339                         HIDDFunction_StartPollingOutputs(pHidd);
00340                 }
00341 
00342                 /* and send a zero-length packet */
00343                 USBD_Write(0, 0, 0, 0, 0);
00344                 return; /* Handled, no need to do others */
00345             }
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             uint16_t length = USBGenericRequest_GetLength(request);
00359             uint8_t  type = HIDReportRequest_GetReportType(request);
00360 
00361             if (type == HIDReportRequest_OUTPUT) {
00362                 if (length > HIDDTransferDriver_REPORTSIZE)
00363                     length = HIDDTransferDriver_REPORTSIZE;
00364 
00365                 USBD_Read(0,
00366                           pDrv->iReportBuf,
00367                           length,
00368                           HIDDTransferDriver_ReportReceived,
00369                           0); /* No argument to the callback function */
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     else
00385         USBDDriver_RequestHandler(pHidd->pUsbd, request);
00386 }
00387 
00388 /**
00389  * Try to read request buffer of SetReport.
00390  * Set pData to 0 to get current data length only.
00391  * \param pData Pointer to data buffer
00392  * \param dwLength Data buffer length
00393  * \return Number of bytes read
00394  */
00395 uint16_t HIDDTransferDriver_ReadReport(void *pData,
00396                                        uint32_t dwLength)
00397 {
00398     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00399 
00400     if (pData == 0)
00401 
00402         return pDrv->iReportLen;
00403 
00404     if (dwLength > HIDDTransferDriver_REPORTSIZE)
00405 
00406         dwLength = HIDDTransferDriver_REPORTSIZE;
00407 
00408     if (dwLength > pDrv->iReportLen)
00409 
00410         dwLength = pDrv->iReportLen;
00411 
00412     pDrv->iReportLen = 0;
00413     memcpy(pData, pDrv->iReportBuf, dwLength);
00414 
00415     return dwLength;
00416 }
00417 
00418 /**
00419  * Try to read request buffer of interrupt OUT EP.
00420  * Set pData to 0 to get current data length only.
00421  * \param pData Pointer to data buffer
00422  * \param dLength Data buffer length
00423  * \return Number of bytes read
00424  */
00425 uint16_t HIDDTransferDriver_Read(void *pData,
00426                                  uint32_t dLength)
00427 {
00428     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00429 
00430     if (pData == 0)
00431 
00432         return pDrv->outputReports[0]->wTransferred;
00433 
00434     if (dLength > HIDDTransferDriver_REPORTSIZE)
00435 
00436         dLength = HIDDTransferDriver_REPORTSIZE;
00437 
00438     if (dLength > pDrv->outputReports[0]->wTransferred)
00439 
00440         dLength = pDrv->outputReports[0]->wTransferred;
00441 
00442     pDrv->outputReports[0]->wTransferred = 0;
00443     memcpy(pData, pDrv->outputReports[0]->bData, dLength);
00444 
00445     return dLength;
00446 }
00447 
00448 /**
00449  * Write data through USB interrupt IN EP.
00450  * \param pData Pointer to the data sent.
00451  * \param dLength The data length.
00452  * \param fCallback Callback function invoked when transferring done.
00453  * \param pArg Pointer to additional arguments.
00454  */
00455 uint8_t HIDDTransferDriver_Write(const void *pData,
00456                                  uint32_t dLength,
00457                                  TransferCallback fCallback,
00458                                  void *pArg)
00459 {
00460     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00461 
00462     if (dLength != HIDDTransferDriver_REPORTSIZE)
00463 
00464         dLength = HIDDTransferDriver_REPORTSIZE;
00465 
00466     return USBD_Write(pDrv->hidFunction.bPipeIN,
00467                       pData, dLength,
00468                       fCallback, pArg);
00469 }
00470 
00471 /**
00472  * Starts a remote wake-up sequence if the host has explicitely enabled it
00473  * by sending the appropriate SET_FEATURE request.
00474  */
00475 void HIDDTransferDriver_RemoteWakeUp(void)
00476 {
00477     HIDDTransferDriver *pDrv = &hiddTransferDriver;
00478 
00479     /* Remote wake-up has been enabled */
00480     if (USBDDriver_IsRemoteWakeUpEnabled(pDrv->hidFunction.pUsbd))
00481 
00482         USBD_RemoteWakeUp();
00483 }
00484 
00485 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines