Renamed main folder to firmware

This commit is contained in:
Christina Quast
2015-04-07 18:24:06 +02:00
parent f5cd7efede
commit 5a67c0fef3
326 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,695 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file
* Implementation of the HIDDFunction class methods.
*/
/** \addtogroup usbd_hid
* @{
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <HIDDFunction.h>
#include <USBDescriptors.h>
#include <HIDDescriptors.h>
#include <USBLib_Trace.h>
/*------------------------------------------------------------------------------
* Definitions
*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
* Macros
*------------------------------------------------------------------------------*/
/**
* Get byte pointer
*/
#define _PU8(v) ((uint8_t*)&(v))
/**
* Get word from un-aligned value
*/
#define _Word(a) (_PU8(a)[0] + (_PU8(a)[1] << 8))
/*------------------------------------------------------------------------------
* Types
*------------------------------------------------------------------------------*/
/** Parse data extention for descriptor parsing */
typedef struct _HIDDParseData {
HIDDFunction * pHidd;
USBInterfaceDescriptor * pIfDesc;
} HIDDParseData;
/** Parse data extension for HID descriptor */
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
* Internal functions
*------------------------------------------------------------------------------*/
/**
* Returns the descriptor requested by the host.
* \param pHidd Pointer to HIDDFunction instance
* \param bType Descriptor type.
* \param wLength Maximum number of bytes to send.
* \return USBRC_SUCCESS if the request has been handled by this function,
* otherwise USBRC_PARAM_ERR.
*/
static uint32_t HIDDFunction_GetDescriptor(HIDDFunction *pHidd,
uint8_t bType,
uint32_t wLength)
{
HIDDescriptor1 *pHidDescriptor = (HIDDescriptor1 *)pHidd->pHidDescriptor;
uint16_t wDescriptorLength;
TRACE_INFO_WP("gDesc{%x) ", bType);
switch (bType) {
case HIDGenericDescriptor_REPORT:
/* Adjust length and send report descriptor */
/*
wDescriptorLength = pHidDescriptor->bDescriptorLength0[0]
+ pHidDescriptor->bDescriptorLength0[1];
*/
wDescriptorLength = _Word(pHidDescriptor->wDescriptorLength0);
if (wLength > wDescriptorLength)
wLength = wDescriptorLength;
TRACE_INFO_WP("Report(%d) ", wLength);
USBD_Write(0, pHidd->pReportDescriptor, wLength, 0, 0);
break;
case HIDGenericDescriptor_HID:
/* Adjust length and send HID descriptor */
if (wLength > sizeof(HIDDescriptor1))
wLength = sizeof(HIDDescriptor1);
TRACE_INFO_WP("HID(%d) ", wLength);
USBD_Write(0, pHidDescriptor, wLength, 0, 0);
break;
default:
return USBRC_PARAM_ERR;
}
return USBRC_SUCCESS;
}
/**
* Return expected report header pointer.
* \param pHidd Pointer to HIDDFunction instance
* \param bType Report type.
* \param bID Report ID.
*/
static HIDDReport* HIDDFunction_FindReport(const HIDDFunction *pHidd,
uint8_t bType,
uint8_t bID)
{
HIDDReport** pReportList;
int32_t listSize, i;
switch(bType) {
case HIDReportRequest_INPUT:
pReportList = pHidd->pInputList;
listSize = pHidd->bInputListSize;
break;
case HIDReportRequest_OUTPUT:
pReportList = pHidd->pOutputList;
listSize = pHidd->bOutputListSize;
break;
/* No other reports supported */
default:
TRACE_INFO("Report %x.%x not support\n\r", bType, bID);
return 0;
}
/* No list */
if (pReportList == 0)
return 0;
/* Find report in the list */
for (i = 0; i < listSize; i ++) {
if (bID == pReportList[i]->bID)
return pReportList[i];
}
/* Not found */
return 0;
}
/**
* Sends the current Idle rate of the input report to the host.
* \param pHidd Pointer to HIDDFunction instance
* \param bID Report ID
*/
static void HIDDFunction_GetIdle(HIDDFunction *pHidd,
uint8_t bID)
{
HIDDReport *pReport = HIDDFunction_FindReport(pHidd,
HIDReportRequest_INPUT,
bID);
TRACE_INFO_WP("gIdle(%x) ", bID);
if (pReport == 0) {
USBD_Stall(0);
return;
}
USBD_Write(0, &pReport->bIdleRate, 1, 0, 0);
}
/**
* Retrieves the new idle rate of the input report from the USB host.
* \param pHidd Pointer to HIDDFunction instance
* \param bType Report type
* \param bID Report ID
* \param bIdleRate Report idle rate.
*/
static void HIDDFunction_SetIdle(HIDDFunction *pHidd,
uint8_t bID,
uint8_t bIdleRate)
{
HIDDReport *pReport = HIDDFunction_FindReport(pHidd,
HIDReportRequest_INPUT,
bID);
TRACE_INFO_WP("sIdle(%x<%x) ", bID, bIdleRate);
if (pReport == 0) {
USBD_Stall(0);
return;
}
USBD_Write(0, 0, 0, 0, 0);
}
/**
* Callback function when GetReport request data sent to host
* \param pReport Pointer to report information.
* \param status Result status
* \param transferred Number of bytes transferred
* \param remaining Number of bytes that are not transferred yet
*/
static void _GetReportCallback(HIDDReport *pReport,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
pReport->wTransferred = transferred;
if (pReport->fCallback)
pReport->fCallback(HIDD_EC_GETREPORT, pReport->pArg);
USBD_Read(0, 0, 0, 0, 0);
}
/**
* Sends the requested report to the host.
* \param pHidd Pointer to HIDDFunction instance
* \param bType Report type.
* \param bID Report ID.
* \param wLength Maximum number of bytes to send.
*/
static void HIDDFunction_GetReport(HIDDFunction *pHidd,
uint8_t bType,
uint8_t bID,
uint8_t wLength)
{
HIDDReport *pReport = HIDDFunction_FindReport(pHidd,
bType,
bID);
TRACE_INFO_WP("gReport(%x.%x) ", bType, bID);
if (pReport == 0) {
USBD_Stall(0);
return;
}
if (wLength >= pReport->wMaxSize) {
wLength = pReport->wMaxSize;
}
USBD_Write(0, pReport->bData, wLength,
(TransferCallback)_GetReportCallback, pReport);
}
/**
* Callback function when GetReport request data sent to host
* \param pReport Pointer to report information.
* \param status Result status
* \param transferred Number of bytes transferred
* \param remaining Number of bytes that are not transferred yet
*/
static void _SetReportCallback(HIDDReport *pReport,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
pReport->wTransferred = transferred;
if (pReport->fCallback) {
pReport->fCallback(HIDD_EC_SETREPORT, pReport->pArg);
}
}
/**
* Reads the requested report from the host.
* \param pHidd Pointer to HIDDFunction instance
* \param bType Report type.
* \param bID Report ID.
* \param wLength Maximum number of bytes to read.
*/
static void HIDDFunction_SetReport(HIDDFunction *pHidd,
uint8_t bType,
uint8_t bID,
uint8_t wLength)
{
HIDDReport *pReport = HIDDFunction_FindReport(pHidd,
bType,
bID);
TRACE_INFO_WP("sReport(%x.%x) ", bType, bID);
if (pReport == 0) {
USBD_Stall(0);
return;
}
if (wLength >= pReport->wMaxSize) {
wLength = pReport->wMaxSize;
}
USBD_Read(0, pReport->bData, wLength,
(TransferCallback)_SetReportCallback, pReport);
}
/**
* Parse descriptors: Interface, Interrupt IN/OUT.
* \param desc Pointer to descriptor list.
* \param arg Argument, pointer to HIDDParseData instance.
*/
static uint32_t HIDDFunction_Parse(USBGenericDescriptor * pDesc,
HIDDParseData * pArg)
{
/* Find HID Interface */
if (pArg->pIfDesc == 0) {
if (pDesc->bDescriptorType == USBGenericDescriptor_INTERFACE) {
USBInterfaceDescriptor *pIf = (USBInterfaceDescriptor*)pDesc;
/* Right interface for HID:
HID Class + at least 1 endpoint */
if (pIf->bInterfaceClass == HIDInterfaceDescriptor_CLASS
&& pIf->bNumEndpoints >= 1) {
/* Obtain new interface setting */
if (pArg->pHidd->bInterface == 0xFF) {
pArg->pHidd->bInterface = pIf->bInterfaceNumber;
pArg->pIfDesc = pIf;
}
/* Find specific interface setting */
else if (pArg->pHidd->bInterface == pIf->bInterfaceNumber) {
pArg->pIfDesc = pIf;
}
}
}
}
/* Interface end */
else {
/* Start another interface ? */
if (pDesc->bDescriptorType == USBGenericDescriptor_INTERFACE) {
/* Terminate the parse */
return USBRC_PARTIAL_DONE;
}
/* Parse HID descriptor */
else if (pDesc->bDescriptorType == HIDGenericDescriptor_HID) {
pArg->pHidd->pHidDescriptor = (HIDDescriptor*)pDesc;
}
/* Parse endpoints */
else if (pDesc->bDescriptorType == USBGenericDescriptor_ENDPOINT) {
USBEndpointDescriptor *pEp = (USBEndpointDescriptor*)pDesc;
if (pEp->bEndpointAddress & 0x80)
pArg->pHidd->bPipeIN = pEp->bEndpointAddress & 0x7F;
else
pArg->pHidd->bPipeOUT = pEp->bEndpointAddress;
}
/* Check if all data is OK */
if (pArg->pHidd->bInterface != 0xFF
&& pArg->pHidd->bPipeIN != 0xFF
&& pArg->pHidd->bPipeOUT != 0xFF)
return USBRC_FINISHED;
}
return 0;
}
/**
* Callback function when interrupt OUT data received from host
* \param pHidd Pointer to HIDDFunction instance
* \param status Result status
* \param transferred Number of bytes transferred
* \param remaining Number of bytes that are not transferred yet
*/
static void HIDDFunction_ReportReceived(HIDDFunction *pHidd,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
HIDDReport *pOut = pHidd->pOutputList[pHidd->bCurrOutput];
if (status != USBRC_SUCCESS) {
TRACE_ERROR("HIDDFun::ReadReport: %x\n\r", status);
return;
}
/* Transfered information */
pOut->wTransferred = transferred;
/* Data Change callback */
if (pOut->fCallback)
pOut->fCallback(HIDD_EC_REPORTCHANGED, pOut->pArg);
/* Proceed to next output report */
pHidd->bCurrOutput ++;
if (pHidd->bCurrOutput >= pHidd->bOutputListSize)
pHidd->bCurrOutput = 0;
/* Start reading a report */
USBD_Read(pHidd->bPipeOUT,
pHidd->pOutputList[pHidd->bCurrOutput]->bData,
pHidd->pOutputList[pHidd->bCurrOutput]->wMaxSize,
(TransferCallback)HIDDFunction_ReportReceived,
(void*)pHidd);
}
/**
* Callback function when interrupt IN data sent to host
* \param pHidd Pointer to HIDDFunction instance
* \param status Result status
* \param transferred Number of bytes transferred
* \param remaining Number of bytes that are not transferred yet
*/
static void HIDDFunction_ReportSent(HIDDFunction *pHidd,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
HIDDReport *pIn = pHidd->pInputList[pHidd->bCurrInput];
if (status != USBRC_SUCCESS) {
TRACE_ERROR("HIDDFun::WriteReport: %x\n\r", status);
return;
}
/* Transfered information */
pIn->wTransferred = transferred;
/* Report Sent Callback */
if (pIn->fCallback)
pIn->fCallback(HIDD_EC_REPORTSENT, pIn->pArg);
/* Proceed to next output report */
pHidd->bCurrInput ++;
if (pHidd->bCurrInput >= pHidd->bInputListSize)
pHidd->bCurrInput = 0;
/* Start writing a report */
USBD_Write(pHidd->bPipeIN,
pHidd->pInputList[pHidd->bCurrInput]->bData,
pHidd->pInputList[pHidd->bCurrInput]->wMaxSize,
(TransferCallback)HIDDFunction_ReportReceived,
(void*)pHidd);
}
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* Initialize the USB Device HID function, for general HID device support.
* \param pHidd Pointer to HIDDFunction instance.
* \param pUsbd Pointer to USBDDriver instance.
* \param bInterfaceNb Interface number,
* can be 0xFF to obtain from descriptors.
* \param pReportDescriptor Pointer to report descriptor.
* \param pInputList Pointer to an HID input report list
* \param bInputListSize HID input report list size
* \param pOutputList Pointer to an HID output report list
* \param bOutputListSize HID output report list size
*/
void HIDDFunction_Initialize(HIDDFunction * pHidd,
USBDDriver * pUsbd, uint8_t bInterfaceNb,
const uint8_t * pReportDescriptor,
HIDDReport* pInputList[], uint8_t bInputListSize,
HIDDReport* pOutputList[], uint8_t bOutputListSize)
{
TRACE_INFO("HIDDFunction_Initialize\n\r");
pHidd->pUsbd = pUsbd;
pHidd->pReportDescriptor = (uint8_t *)pReportDescriptor;
pHidd->pHidDescriptor = 0;
pHidd->bInterface = bInterfaceNb;
pHidd->bPipeIN = 0xFF;
pHidd->bPipeOUT = 0xFF;
pHidd->bProtocol = HIDProtocol_REPORT; /* Non-boot protocol */
pHidd->pInputList = pInputList;
pHidd->pOutputList = pOutputList;
pHidd->bInputListSize = bInputListSize;
pHidd->bOutputListSize = bOutputListSize;
pHidd->bCurrInput = 0;
pHidd->bCurrOutput = 0;
}
/**
* Parse the USB HID Function Interface.
* Only first interface and its endpoints parsed.
* \param pHidd Pointer to HIDDFunction instance.
* \param pDescriptors Pointer to descriptor list.
* \param dwLength Descriptor list block length in bytes.
* \return Pointer to next descriptor. 0 means no other descriptor.
*/
USBGenericDescriptor *HIDDFunction_ParseInterface(HIDDFunction * pHidd,
USBGenericDescriptor * pDescriptors,
uint32_t dwLength)
{
HIDDParseData data;
pHidd->bPipeIN = 0xFF;
pHidd->bPipeOUT = 0xFF;
data.pHidd = pHidd;
data.pIfDesc = 0;
return USBGenericDescriptor_Parse(pDescriptors,
dwLength,
(USBDescriptorParseFunction)HIDDFunction_Parse,
(void*)&data);
}
/**
* Start polling interrupt OUT pipe
* (output report, host to device) if there is.
* \param pHidd Pointer to HIDDFunction instance.
*/
uint32_t HIDDFunction_StartPollingOutputs(HIDDFunction * pHidd)
{
/* No report, do nothing */
if (pHidd->bOutputListSize == 0
|| pHidd->pOutputList == 0)
return USBRC_PARAM_ERR;
/* Start reading a report */
return USBD_Read(pHidd->bPipeOUT,
pHidd->pOutputList[pHidd->bCurrOutput]->bData,
pHidd->pOutputList[pHidd->bCurrOutput]->wMaxSize,
(TransferCallback)HIDDFunction_ReportReceived,
(void*)pHidd);
}
/**
* Start sending reports via interrupt IN pipe
* (input report, device to host) if there is.
* \param pHidd Pointer to HIDDFunction instance.
*/
uint32_t HIDDFunction_StartSendingInputs(HIDDFunction * pHidd)
{
/* No report, do nothing */
if (pHidd->bInputListSize == 0
|| pHidd->pInputList == 0)
return USBRC_PARAM_ERR;
/* Start sending a report */
return USBD_Write(pHidd->bPipeIN,
pHidd->pInputList[pHidd->bCurrInput]->bData,
pHidd->pInputList[pHidd->bCurrInput]->wMaxSize,
(TransferCallback)HIDDFunction_ReportSent,
(void*)pHidd);
}
/**
* Handles HID-specific SETUP request sent by the host.
* \param pHidd Pointer to HIDDFunction instance.
* \param request Pointer to a USBGenericRequest instance
*/
uint32_t HIDDFunction_RequestHandler(HIDDFunction *pHidd,
const USBGenericRequest *request)
{
uint32_t reqCode = (request->bmRequestType << 8)
| (request->bRequest);
switch (reqCode) {
/* Get_Descriptor */
case USBGenericRequest_GETDESCRIPTOR|(0x81<<8):
return HIDDFunction_GetDescriptor(
pHidd,
USBGetDescriptorRequest_GetDescriptorType(request),
USBGenericRequest_GetLength(request));
/* Clear_Feature (EP) */
case USBGenericRequest_CLEARFEATURE|(0x02<<8):
if (USBFeatureRequest_GetFeatureSelector(request)
== USBFeatureRequest_ENDPOINTHALT) {
uint8_t ep = USBGenericRequest_GetEndpointNumber(request);
if (USBD_IsHalted(ep)) {
/* Unhalt EP */
USBD_Unhalt(ep);
/* Restart Polling OUT */
if (ep == pHidd->bPipeOUT) {
HIDDFunction_StartPollingOutputs(pHidd);
}
/* and send a zero-length packet */
USBD_Write(0, 0, 0, 0, 0);
}
break; /* Handled success */
}
return USBRC_PARAM_ERR;
/* Set_Descriptor */
case USBGenericRequest_SETDESCRIPTOR|(0x01<<8):
/* Optional, not implemented */
USBD_Stall(0);
break;
/* Get_Idle */
case (0xa1<<8)|HIDGenericRequest_GETIDLE:
HIDDFunction_GetIdle(pHidd,
HIDReportRequest_GetReportId(request));
break;
/* Set_Idle */
case (0x21<<8)|HIDGenericRequest_SETIDLE:
HIDDFunction_SetIdle(pHidd,
HIDReportRequest_GetReportId(request),
HIDIdleRequest_GetIdleRate(request));
break;
/* Get_Report */
case (0xa1<<8)|HIDGenericRequest_GETREPORT:
HIDDFunction_GetReport(pHidd,
HIDReportRequest_GetReportType(request),
HIDReportRequest_GetReportId(request),
USBGenericRequest_GetLength(request));
break;
/* Set_Report */
case (0x21<<8)|HIDGenericRequest_SETREPORT:
HIDDFunction_SetReport(pHidd,
HIDReportRequest_GetReportType(request),
HIDReportRequest_GetReportId(request),
USBGenericRequest_GetLength(request));
break;
/* Get_Protocol */
case (0xa1<<8)|HIDGenericRequest_SETPROTOCOL:
pHidd->bProtocol = request->wValue;
USBD_Write(0, 0, 0, 0, 0);
break;
/* Set_Protocol */
case (0x21<<8)|HIDGenericRequest_GETPROTOCOL:
USBD_Write(0, &pHidd->bProtocol, 1, 0, 0);
break;
default:
return USBRC_PARAM_ERR;
}
return USBRC_SUCCESS;
}
/**
* Read raw data through USB interrupt OUT EP.
* \param pHidd Pointer to HIDDFunction instance.
* \param pData Pointer to the data buffer.
* \param dwLength The data length.
* \param fCallback Callback function invoked when transferring done.
* \param pArg Pointer to additional arguments.
*/
uint32_t HIDDFunction_Read(const HIDDFunction *pHidd,
void* pData,
uint32_t dwLength,
TransferCallback fCallback,
void* pArg)
{
return USBD_Read(pHidd->bPipeIN,
pData, dwLength,
fCallback, pArg);
}
/**
* Write raw data through USB interrupt IN EP.
* \param pHidd Pointer to HIDDFunction instance.
* \param pData Pointer to the data sent.
* \param dwLength The data length.
* \param fCallback Callback function invoked when transferring done.
* \param pArg Pointer to additional arguments.
*/
uint32_t HIDDFunction_Write(const HIDDFunction *pHidd,
void* pData,
uint32_t dwLength,
TransferCallback fCallback,
void* pArg)
{
return USBD_Write(pHidd->bPipeIN,
pData, dwLength,
fCallback, pArg);
}
/**
* Initialize a report.
* \param pReport Pointer to HIDDReport instance.
* \param wSize Size of the report data.
* \param bID Report ID.
* \param fCallback Callback function for report events.
* \param pArg Pointer to event handler arguments.
*/
void HIDDFunction_InitializeReport(HIDDReport* pReport,
uint16_t wSize,
uint8_t bID,
HIDDReportEventCallback fCallback,
void* pArg)
{
pReport->wMaxSize = wSize;
pReport->wTransferred = 0;
pReport->bIdleRate = 0;
pReport->bDelay = 0;
pReport->bID = bID;
pReport->fCallback = fCallback;
pReport->pArg = pArg;
}
/**@}*/

View File

@@ -0,0 +1,481 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file
* \addtogroup usbd_hid_tran
*@{
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <stdint.h>
#include "HIDDTransferDriver.h"
#include <USBLib_Trace.h>
#include <USBRequests.h>
#include <HIDDescriptors.h>
#include <HIDDFunction.h>
#include <USBD_HAL.h>
#include <string.h>
/*------------------------------------------------------------------------------
* Internal types
*------------------------------------------------------------------------------*/
/**
* Report struct for HID transfer.
*/
typedef struct _HIDDTransferReport {
/** Callback when report done */
HIDDReportEventCallback fCallback;
/** Callback arguments */
void* pArg;
/** Report size (ID + DATA) */
uint16_t wMaxSize;
/** Transfered size */
uint16_t wTransferred;
/** Report idle rate */
uint8_t bIdleRate;
/** Delay count for Idle */
uint8_t bDelay;
/** Report ID */
uint8_t bID;
/** Report data address */
uint8_t bData[HIDDTransferDriver_REPORTSIZE];
} HIDDTransferReport;
/**
* Driver structure for an HID device implementing simple transfer
* functionalities.
*/
typedef struct _HIDDTransferDriver {
/** Standard HID function interface. */
HIDDFunction hidFunction;
/** HID Input report list */
HIDDReport *inputReports[1];
/** HID Output report list */
HIDDReport *outputReports[1];
/* OUT Report - block input for SET_REPORT */
/**< Output report block size */
uint16_t iReportLen;
/**< Output report data buffer */
uint8_t iReportBuf[HIDDTransferDriver_REPORTSIZE];
} HIDDTransferDriver;
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
/** Input report buffers */
static HIDDTransferReport inputReport;
/** Output report buffers */
static HIDDTransferReport outputReport;
/** Static instance of the HID Transfer device driver. */
static HIDDTransferDriver hiddTransferDriver;
/** Report descriptor used by the driver. */
static const uint8_t hiddTransferReportDescriptor[] = {
/* Global Usage Page */
HIDReport_GLOBAL_USAGEPAGE + 2, 0xFF, 0xFF, /* Vendor-defined */
/* Collection: Application */
HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined */
HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION,
/* Input report: Vendor-defined */
HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined usage */
HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE,
HIDReport_GLOBAL_REPORTSIZE + 1, 8,
HIDReport_GLOBAL_LOGICALMINIMUM + 1, (uint8_t) -128,
HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (uint8_t) 127,
HIDReport_INPUT + 1, 0, /* No Modifiers */
/* Output report: vendor-defined */
HIDReport_LOCAL_USAGE + 1, 0xFF, /* Vendor-defined usage */
HIDReport_GLOBAL_REPORTCOUNT + 1, HIDDTransferDriver_REPORTSIZE,
HIDReport_GLOBAL_REPORTSIZE + 1, 8,
HIDReport_GLOBAL_LOGICALMINIMUM + 1, (uint8_t) -128,
HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (uint8_t) 127,
HIDReport_OUTPUT + 1, 0, /* No Modifiers */
HIDReport_ENDCOLLECTION
};
/*------------------------------------------------------------------------------
* Internal functions
*------------------------------------------------------------------------------*/
/**
* Returns the descriptor requested by the host.
* \param type Descriptor type.
* \param length Maximum number of bytes to send.
* \return 1 if the request has been handled by this function, otherwise 0.
*/
static uint8_t HIDDTransferDriver_GetDescriptor(uint8_t type,
uint8_t length)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
HIDDFunction *pHidd = &pDrv->hidFunction;
const USBConfigurationDescriptor *pConfiguration;
HIDDescriptor *hidDescriptors[2];
switch (type) {
case HIDGenericDescriptor_REPORT:
TRACE_INFO("Report ");
/* Adjust length and send report descriptor */
if (length > HIDDTransferDriver_REPORTDESCRIPTORSIZE) {
length = HIDDTransferDriver_REPORTDESCRIPTORSIZE;
}
USBD_Write(0, &hiddTransferReportDescriptor, length, 0, 0);
break;
case HIDGenericDescriptor_HID:
TRACE_INFO("HID ");
/* Configuration descriptor is different depending on configuration */
if (USBD_IsHighSpeed()) {
pConfiguration =
pHidd->pUsbd->pDescriptors->pHsConfiguration;
}
else {
pConfiguration =
pHidd->pUsbd->pDescriptors->pFsConfiguration[0];
}
/* Parse the device configuration to get the HID descriptor */
USBConfigurationDescriptor_Parse(pConfiguration, 0, 0,
(USBGenericDescriptor **) hidDescriptors);
/* Adjust length and send HID descriptor */
if (length > sizeof(HIDDescriptor)) {
length = sizeof(HIDDescriptor);
}
USBD_Write(0, hidDescriptors[0], length, 0, 0);
break;
default:
return 0;
}
return 1;
}
/**
* Callback function when SetReport request data received from host
* \param pArg Pointer to additional argument struct
* \param status Result status
* \param transferred Number of bytes transferred
* \param remaining Number of bytes that are not transferred yet
*/
static void HIDDTransferDriver_ReportReceived(void *pArg,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
pDrv->iReportLen = transferred;
USBD_Write(0, 0, 0, 0, 0);
}
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* Initializes the HID Transfer %device driver.
* \param pDescriptors Pointer to USBDDriverDescriptors instance.
*/
void HIDDTransferDriver_Initialize(const USBDDriverDescriptors * pDescriptors)
{
HIDDTransferDriver * pDrv = &hiddTransferDriver;
USBDDriver *pUsbd = USBD_GetDriver();
/* One input report */
pDrv->inputReports[0] = (HIDDReport*)&inputReport;
HIDDFunction_InitializeReport((HIDDReport *)pDrv->inputReports[0],
HIDDTransferDriver_REPORTSIZE,
0,
0, 0);
/* One output report */
pDrv->outputReports[0] = (HIDDReport*)&outputReport;
HIDDFunction_InitializeReport((HIDDReport *)pDrv->outputReports[0],
HIDDTransferDriver_REPORTSIZE,
0,
0, 0);
/* Initialize USBD Driver instance */
USBDDriver_Initialize(pUsbd,
pDescriptors,
0); /* Multiple interface settings not supported */
/* Function instance initialize */
HIDDFunction_Initialize(&pDrv->hidFunction,
pUsbd, 0,
hiddTransferReportDescriptor,
(HIDDReport **)(&pDrv->inputReports), 1,
(HIDDReport **)(&pDrv->outputReports), 1);
/* Initialize USBD */
USBD_Init();
}
/**
* Handles configureation changed event.
* \param cfgnum New configuration number
*/
void HIDDTransferDriver_ConfigurationChangedHandler(uint8_t cfgnum)
{
const USBDDriverDescriptors * pDescriptors = USBD_GetDriver()->pDescriptors;
HIDDTransferDriver * pDrv = &hiddTransferDriver;
HIDDFunction * pHidd = &pDrv->hidFunction;
USBConfigurationDescriptor *pDesc;
if (cfgnum > 0) {
/* Parse endpoints for reports */
if (USBD_HAL_IsHighSpeed() && pDescriptors->pHsConfiguration)
pDesc = (USBConfigurationDescriptor*)pDescriptors->pHsConfiguration;
else
pDesc = (USBConfigurationDescriptor*)pDescriptors->pFsConfiguration[0];
HIDDFunction_ParseInterface(pHidd,
(USBGenericDescriptor*)pDesc,
pDesc->wTotalLength);
/* Start polling for Output Reports */
HIDDFunction_StartPollingOutputs(pHidd);
}
}
/**
* Handles HID-specific SETUP request sent by the host.
* \param request Pointer to a USBGenericRequest instance
*/
void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
HIDDFunction *pHidd = &pDrv->hidFunction;
TRACE_INFO("NewReq ");
/* Check if this is a standard request */
if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) {
/* This is a standard request */
switch (USBGenericRequest_GetRequest(request)) {
case USBGenericRequest_GETDESCRIPTOR:
/* Check if this is a HID descriptor, otherwise forward it to
the standard driver */
if (!HIDDTransferDriver_GetDescriptor(
USBGetDescriptorRequest_GetDescriptorType(request),
USBGenericRequest_GetLength(request))) {
USBDDriver_RequestHandler(pHidd->pUsbd,
request);
}
return; /* Handled, no need to do others */
case USBGenericRequest_CLEARFEATURE:
/* Check which is the requested feature */
switch (USBFeatureRequest_GetFeatureSelector(request)) {
case USBFeatureRequest_ENDPOINTHALT:
{ uint8_t ep =
USBGenericRequest_GetEndpointNumber(request);
if (USBD_IsHalted(ep)) {
/* Unhalt endpoint restart OUT EP
*/
USBD_Unhalt(ep);
if (ep == pHidd->bPipeOUT) {
HIDDFunction_StartPollingOutputs(pHidd);
}
}
/* and send a zero-length packet */
USBD_Write(0, 0, 0, 0, 0);
return; /* Handled, no need to do others */
}
}
break;
}
}
/* We use different buffer for SetReport */
else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) {
switch (USBGenericRequest_GetRequest(request)) {
case HIDGenericRequest_SETREPORT:
{
uint16_t length = USBGenericRequest_GetLength(request);
uint8_t type = HIDReportRequest_GetReportType(request);
if (type == HIDReportRequest_OUTPUT) {
if (length > HIDDTransferDriver_REPORTSIZE)
length = HIDDTransferDriver_REPORTSIZE;
USBD_Read(0,
pDrv->iReportBuf,
length,
HIDDTransferDriver_ReportReceived,
0); /* No argument to the callback function */
}
else {
USBD_Stall(0);
}
}
return; /* Handled, no need do others */
}
}
/* Process HID requests */
if (USBRC_SUCCESS == HIDDFunction_RequestHandler(pHidd,
request)) {
return;
}
else
USBDDriver_RequestHandler(pHidd->pUsbd, request);
}
/**
* Try to read request buffer of SetReport.
* Set pData to 0 to get current data length only.
* \param pData Pointer to data buffer
* \param dwLength Data buffer length
* \return Number of bytes read
*/
uint16_t HIDDTransferDriver_ReadReport(void *pData,
uint32_t dwLength)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
if (pData == 0) {
return pDrv->iReportLen;
}
if (dwLength > HIDDTransferDriver_REPORTSIZE) {
dwLength = HIDDTransferDriver_REPORTSIZE;
}
if (dwLength > pDrv->iReportLen) {
dwLength = pDrv->iReportLen;
}
pDrv->iReportLen = 0;
memcpy(pData, pDrv->iReportBuf, dwLength);
return dwLength;
}
/**
* Try to read request buffer of interrupt OUT EP.
* Set pData to 0 to get current data length only.
* \param pData Pointer to data buffer
* \param dLength Data buffer length
* \return Number of bytes read
*/
uint16_t HIDDTransferDriver_Read(void *pData,
uint32_t dLength)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
if (pData == 0) {
return pDrv->outputReports[0]->wTransferred;
}
if (dLength > HIDDTransferDriver_REPORTSIZE) {
dLength = HIDDTransferDriver_REPORTSIZE;
}
if (dLength > pDrv->outputReports[0]->wTransferred) {
dLength = pDrv->outputReports[0]->wTransferred;
}
pDrv->outputReports[0]->wTransferred = 0;
memcpy(pData, pDrv->outputReports[0]->bData, dLength);
return dLength;
}
/**
* Write data through USB interrupt IN EP.
* \param pData Pointer to the data sent.
* \param dLength The data length.
* \param fCallback Callback function invoked when transferring done.
* \param pArg Pointer to additional arguments.
*/
uint8_t HIDDTransferDriver_Write(const void *pData,
uint32_t dLength,
TransferCallback fCallback,
void *pArg)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
if (dLength != HIDDTransferDriver_REPORTSIZE) {
dLength = HIDDTransferDriver_REPORTSIZE;
}
return USBD_Write(pDrv->hidFunction.bPipeIN,
pData, dLength,
fCallback, pArg);
}
/**
* Starts a remote wake-up sequence if the host has explicitely enabled it
* by sending the appropriate SET_FEATURE request.
*/
void HIDDTransferDriver_RemoteWakeUp(void)
{
HIDDTransferDriver *pDrv = &hiddTransferDriver;
/* Remote wake-up has been enabled */
if (USBDDriver_IsRemoteWakeUpEnabled(pDrv->hidFunction.pUsbd)) {
USBD_RemoteWakeUp();
}
}
/**@}*/