From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- usb/device/hid-transfer/HIDDTransferDriver.c | 479 +++++++++++++++++++++++ usb/device/hid-transfer/HIDDTransferDriver.h | 87 ++++ usb/device/hid-transfer/HIDDTransferDriverDesc.c | 417 ++++++++++++++++++++ usb/device/hid-transfer/HIDDTransferDriverDesc.h | 87 ++++ usb/device/hid-transfer/hid-transfer.dir | 473 ++++++++++++++++++++++ 5 files changed, 1543 insertions(+) create mode 100644 usb/device/hid-transfer/HIDDTransferDriver.c create mode 100644 usb/device/hid-transfer/HIDDTransferDriver.h create mode 100644 usb/device/hid-transfer/HIDDTransferDriverDesc.c create mode 100644 usb/device/hid-transfer/HIDDTransferDriverDesc.h create mode 100644 usb/device/hid-transfer/hid-transfer.dir (limited to 'usb/device/hid-transfer') diff --git a/usb/device/hid-transfer/HIDDTransferDriver.c b/usb/device/hid-transfer/HIDDTransferDriver.c new file mode 100644 index 0000000..0810474 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriver.c @@ -0,0 +1,479 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDTransferDriver.h" +#include "HIDDTransferDriverDesc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Driver structure for an HID device implementing keyboard functionalities. +//------------------------------------------------------------------------------ +typedef struct { + + /// Standard USB device driver instance. + USBDDriver usbdDriver; + + // OUT Report - block input + unsigned short iReportLen; + unsigned char iReportBuf[HIDDTransferDriver_REPORTSIZE]; + + // IN Report - block output + unsigned short oReportLen; + unsigned char oReportBuf[HIDDTransferDriver_REPORTSIZE]; + + // Interrupt OUT Data - input + /// Input data length + unsigned short iLen; + /// Input (report) Buffer + unsigned char iBuf[HIDDTransferDriver_REPORTSIZE]; + + // Nothing more now... + +} HIDDTransferDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Static instance of the HID Transfer device driver. +static HIDDTransferDriver hiddTransferDriver; + +//------------------------------------------------------------------------------ +// 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 unsigned char HIDDTransferDriver_GetDescriptor(unsigned char type, + unsigned char length) +{ + const USBConfigurationDescriptor *pConfiguration; + HIDDescriptor *hidDescriptors[2]; + + switch (type) { + + case HIDGenericDescriptor_REPORT: + TRACE_INFO("Report "); + + // Adjust length and send report descriptor + if (length > HIDDTransferDriverDescriptors_REPORTSIZE) { + + length = HIDDTransferDriverDescriptors_REPORTSIZE; + } + USBD_Write(0, &hiddReportDescriptor, length, 0, 0); + break; + + case HIDGenericDescriptor_HID: + TRACE_INFO("HID "); + + // Configuration descriptor is different depending on configuration + if (USBD_IsHighSpeed()) { + + pConfiguration = + hiddTransferDriver.usbdDriver.pDescriptors->pHsConfiguration; + } + else { + + pConfiguration = + hiddTransferDriver.usbdDriver.pDescriptors->pFsConfiguration; + } + + // Parse the device configuration to get the HID descriptor + USBConfigurationDescriptor_Parse(pConfiguration, 0, 0, + (USBGenericDescriptor **) &hidDescriptors[0]); + + // 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, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + hiddTransferDriver.iReportLen = transferred; + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Callback function when GetReport request data sent to 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_ReportSent(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + USBD_Read(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Callback function when interrupt OUT data received from host +/// \param pArg Pointer to additional argument +/// \param status Result status +/// \param transferred Number of bytes transferred +/// \param remaining Number of bytes that are not transferred yet +//------------------------------------------------------------------------------ +static void HIDDTransferDriver_DataReceived(void *pArg, + unsigned char status, + unsigned int transferred, + unsigned int remaining) +{ + hiddTransferDriver.iLen = transferred; + + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + (TransferCallback)HIDDTransferDriver_DataReceived, + 0); +} + +//------------------------------------------------------------------------------ +// Optional RequestReceived() callback re-implementation +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) + +//------------------------------------------------------------------------------ +/// Callback function when new request receivce from host +/// \param request Pointer to the USBGenericRequest instance +//------------------------------------------------------------------------------ +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + HIDDTransferDriver_RequestHandler(request); +} + +#endif + +//------------------------------------------------------------------------------ +// ConfigurationChanged() callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback function when configureation changed +/// \param cfgnum New configuration number +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum) +{ + if (cfgnum > 0) { + + hiddTransferDriver.iLen = 0; + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + HIDDTransferDriver_DataReceived, + 0); + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +/// Initializes the HID Transfer %device driver. +//------------------------------------------------------------------------------ +void HIDDTransferDriver_Initialize() +{ + hiddTransferDriver.iReportLen = 0; + + USBDDriver_Initialize(&(hiddTransferDriver.usbdDriver), + &hiddTransferDriverDescriptors, + 0); // Multiple interface settings not supported + USBD_Init(); +} + +//------------------------------------------------------------------------------ +/// Handles HID-specific SETUP request sent by the host. +/// \param request Pointer to a USBGenericRequest instance +//------------------------------------------------------------------------------ +void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request) +{ + 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(&(hiddTransferDriver.usbdDriver), + request); + } + break; + + case USBGenericRequest_CLEARFEATURE: + /* Check which is the requested feature */ + switch (USBFeatureRequest_GetFeatureSelector(request)) { + case USBFeatureRequest_ENDPOINTHALT: + { unsigned char ep = + USBGenericRequest_GetEndpointNumber(request); + if (USBD_IsHalted(ep)) { + /* Unhalt endpoint restart OUT EP + */ + USBD_Unhalt(ep); + if (ep == HIDDTransferDriverDescriptors_INTERRUPTOUT) { + hiddTransferDriver.iLen = 0; + USBD_Read(HIDDTransferDriverDescriptors_INTERRUPTOUT, + hiddTransferDriver.iBuf, + HIDDTransferDriver_REPORTSIZE, + HIDDTransferDriver_DataReceived, + 0); + } + } + /* and send a zero-length packet */ + USBD_Write(0, 0, 0, 0, 0); + return; /* Done, no others */ + } + } + + default: + USBDDriver_RequestHandler(&(hiddTransferDriver.usbdDriver), + request); + } + } + // Check if this is a class request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + unsigned short length = USBGenericRequest_GetLength(request); + unsigned char type = HIDReportRequest_GetReportType(request); + + switch (USBGenericRequest_GetRequest(request)) { + + case HIDGenericRequest_SETREPORT: + + if (length <= HIDDTransferDriver_REPORTSIZE && + type == HIDReportRequest_OUTPUT) { + + USBD_Read(0, + hiddTransferDriver.iReportBuf, + length, + HIDDTransferDriver_ReportReceived, + 0); // No argument to the callback function + } + else { + + USBD_Stall(0); + } + break; + + case HIDGenericRequest_GETREPORT: + + if (length <= HIDDTransferDriver_REPORTSIZE && + type == HIDReportRequest_INPUT) { + + USBD_Write(0, + hiddTransferDriver.oReportBuf, + length, + HIDDTransferDriver_ReportSent, + 0); + } + else { + + USBD_Stall(0); + } + break; + + default: + TRACE_WARNING( + "HIDDTransferDriver_RequestHandler: request 0x%02X\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + else { + + // Vendor request ? + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Try to read request buffer of SetReport. +/// 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 +//------------------------------------------------------------------------------ +unsigned short HIDDTransferDriver_ReadReport(void *pData, + unsigned int dLength) +{ + if (pData == 0) { + + return hiddTransferDriver.iReportLen; + } + + if (dLength > HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (dLength > hiddTransferDriver.iReportLen) { + + dLength = hiddTransferDriver.iReportLen; + } + hiddTransferDriver.iReportLen = 0; + memcpy(pData, hiddTransferDriver.iReportBuf, dLength); + + return dLength; +} + +//------------------------------------------------------------------------------ +/// 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 +//------------------------------------------------------------------------------ +unsigned short HIDDTransferDriver_Read(void *pData, + unsigned int dLength) +{ + if (pData == 0) { + + return hiddTransferDriver.iLen; + } + + if (dLength > HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (dLength > hiddTransferDriver.iLen) { + + dLength = hiddTransferDriver.iLen; + } + hiddTransferDriver.iLen = 0; + memcpy(pData, hiddTransferDriver.iBuf, dLength); + + return dLength; +} + +//------------------------------------------------------------------------------ +/// Set data in IN report buffer, which will be sent when GetReport request +/// issued. +/// \param pData Pointer to the data sent. +/// \param dLength The data length. +//------------------------------------------------------------------------------ +void HIDDTransferDriver_SetReport(const void *pData, + unsigned int dLength) +{ + if (pData == 0 || dLength == 0) + return; + if (dLength != HIDDTransferDriver_REPORTSIZE) { + dLength = HIDDTransferDriver_REPORTSIZE; + } + if (hiddTransferDriver.oReportLen) { + TRACE_INFO("Changing IN report!\n\r"); + } + memcpy(hiddTransferDriver.oReportBuf, pData, dLength); + hiddTransferDriver.oReportLen = 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. +//------------------------------------------------------------------------------ +unsigned char HIDDTransferDriver_Write(const void *pData, + unsigned int dLength, + TransferCallback fCallback, + void *pArg) +{ + if (dLength != HIDDTransferDriver_REPORTSIZE) { + + dLength = HIDDTransferDriver_REPORTSIZE; + } + return USBD_Write(HIDDTransferDriverDescriptors_INTERRUPTIN, + 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) +{ + // Remote wake-up has been enabled + if (USBDDriver_IsRemoteWakeUpEnabled(&(hiddTransferDriver.usbdDriver))) { + + USBD_RemoteWakeUp(); + } +} + diff --git a/usb/device/hid-transfer/HIDDTransferDriver.h b/usb/device/hid-transfer/HIDDTransferDriver.h new file mode 100644 index 0000000..f374ae0 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriver.h @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definition of methods for using a HID transfer %device driver. + + !!!Usage + + -# Re-implement the USBDCallbacks_RequestReceived callback to forward + requests to HIDDTransferDriver_RequestHandler. This is done + automatically unless the NOAUTOCALLBACK symbol is defined during + compilation. + -# Initialize the driver using HIDDTransferDriver_Initialize. The + USB driver is automatically initialized by this method. + -# Call the HIDDTransferDriver_Write method when sendint data to host. + -# Call the HIDDTransferRead, HIDDTransferReadReport when checking and getting + received data from host. +*/ + +#ifndef HIDDKEYBOARDDRIVER_H +#define HIDDKEYBOARDDRIVER_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern void HIDDTransferDriver_Initialize(); + +extern void HIDDTransferDriver_RequestHandler(const USBGenericRequest *request); + +extern unsigned short HIDDTransferDriver_Read(void *pData, + unsigned int dLength); + +extern unsigned short HIDDTransferDriver_ReadReport(void *pData, + unsigned int dLength); + +extern unsigned char HIDDTransferDriver_Write(const void *pData, + unsigned int size, + TransferCallback callback, + void *pArg); + + +extern void HIDDTransferDriver_RemoteWakeUp(void); + +#endif //#ifndef HIDDKEYBOARDDRIVER_H + diff --git a/usb/device/hid-transfer/HIDDTransferDriverDesc.c b/usb/device/hid-transfer/HIDDTransferDriverDesc.c new file mode 100644 index 0000000..5cd6363 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriverDesc.c @@ -0,0 +1,417 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +/* + Title: HIDDTransferDriverDescriptors + + About: Purpose + Declaration of the descriptors used by the HID device Transfer driver. +*/ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "HIDDTransferDriverDesc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// \page "HID Transfer Device Descriptor IDs" +/// ... +/// +/// !IDs +/// - HIDDTransferDriverDescriptors_PRODUCTID +/// - HIDDTransferDriverDescriptors_VENDORID +/// - HIDDTransferDriverDescriptors_RELEASE + +/// Device product ID. +#define HIDDTransferDriverDescriptors_PRODUCTID 0x6201 +/// Device vendor ID. +#define HIDDTransferDriverDescriptors_VENDORID 0x03EB +/// Device release number. +#define HIDDTransferDriverDescriptors_RELEASE 0x0100 +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +/// Returns the minimum between two values. +#define MIN(a, b) ((a < b) ? a : b) + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +/// List of descriptors that make up the configuration descriptors of a +/// device using the HID Transfer driver. +//------------------------------------------------------------------------------ +typedef struct { + + /// Configuration descriptor. + USBConfigurationDescriptor configuration; + /// Interface descriptor. + USBInterfaceDescriptor interface; + /// HID descriptor. + HIDDescriptor hid; + /// Interrupt IN endpoint descriptor. + USBEndpointDescriptor interruptIn; + /// Interrupt OUT endpoint descriptor. + USBEndpointDescriptor interruptOut; + +} __attribute__ ((packed)) HIDDTransferDriverConfigurationDescriptors; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Device descriptor. +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDTransferDriverDescriptors_VENDORID, + HIDDTransferDriverDescriptors_PRODUCTID, + HIDDTransferDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Device qualifier descriptor (high-speed only). +static const USBDeviceQualifierDescriptor qualifierDescriptor = { + + sizeof(USBDeviceQualifierDescriptor), + USBGenericDescriptor_DEVICEQUALIFIER, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0), + 1, // One possible configuration + 0 // Reserved +}; +#endif + +/// Configuration descriptor. +static const HIDDTransferDriverConfigurationDescriptors configurationDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDTransferDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDTransferDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTIN), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDTransferDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTOUT), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTOUT_POLLING + } +}; + +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) +/// Other-speed configuration descriptor. +static const HIDDTransferDriverConfigurationDescriptors otherSpeedDescriptors = { + + // Configuration descriptor + { + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_OTHERSPEEDCONFIGURATION, + sizeof(HIDDTransferDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) + }, + // Interface descriptor + { + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor + }, + // HID descriptor + { + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDTransferDriverDescriptors_REPORTSIZE + }, + // Interrupt IN endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTIN), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_HS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + }, + // Interrupt OUT endpoint descriptor + { + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDTransferDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + MIN(CHIP_USB_ENDPOINTS_MAXPACKETSIZE( + HIDDTransferDriverDescriptors_INTERRUPTOUT), + MIN(USBEndpointDescriptor_MAXINTERRUPTSIZE_HS, + HIDDTransferDriver_REPORTSIZE)), + HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING + } +}; +#endif + +/* + Variables: String descriptors + languageIdDescriptor - Language ID string descriptor. + manufacturerDescriptor - Manufacturer name. + productDescriptor - Product name. + serialNumberDescriptor - Product serial number. + stringDescriptors - Array of pointers to string descriptors. +*/ +static const unsigned char languageIdDescriptor[] = { + + USBStringDescriptor_LENGTH(1), + USBGenericDescriptor_STRING, + USBStringDescriptor_ENGLISH_US +}; + +static const unsigned char manufacturerDescriptor[] = { + + USBStringDescriptor_LENGTH(5), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L') +}; + +static const unsigned char productDescriptor[] = { + + USBStringDescriptor_LENGTH(22), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('M'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('L'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('H'), + USBStringDescriptor_UNICODE('I'), + USBStringDescriptor_UNICODE('D'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('T'), + USBStringDescriptor_UNICODE('R'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('N'), + USBStringDescriptor_UNICODE('S'), + USBStringDescriptor_UNICODE('F'), + USBStringDescriptor_UNICODE('E'), + USBStringDescriptor_UNICODE('R'), +}; + +static const unsigned char serialNumberDescriptor[] = { + + USBStringDescriptor_LENGTH(12), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('A'), + USBStringDescriptor_UNICODE('F') +}; + +static const unsigned char *stringDescriptors[] = { + + languageIdDescriptor, + manufacturerDescriptor, + productDescriptor, + serialNumberDescriptor +}; + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ + +/// List of descriptors used by the HID Transfer driver. +USBDDriverDescriptors hiddTransferDriverDescriptors = { + + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, +#if defined (CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, + &deviceDescriptor, + (USBConfigurationDescriptor *) &configurationDescriptors, + &qualifierDescriptor, + (USBConfigurationDescriptor *) &otherSpeedDescriptors, +#else + 0, // No full-speed device qualifier descriptor + 0, // No full-speed other speed configuration + 0, // No high-speed device descriptor + 0, // No high-speed configuration descriptor + 0, // No high-speed device qualifier descriptor + 0, // No high-speed other speed configuration descriptor +#endif + stringDescriptors, + 4 // Four string descriptors in list +}; + +/// Report descriptor used by the driver. +const unsigned char hiddReportDescriptor[] = { + + // 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, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 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, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_OUTPUT + 1, 0, // No Modifiers + + HIDReport_ENDCOLLECTION +}; + diff --git a/usb/device/hid-transfer/HIDDTransferDriverDesc.h b/usb/device/hid-transfer/HIDDTransferDriverDesc.h new file mode 100644 index 0000000..6b9beb7 --- /dev/null +++ b/usb/device/hid-transfer/HIDDTransferDriverDesc.h @@ -0,0 +1,87 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +/** + \unit + + !!!Purpose + + Definitions of the descriptors required by the HID transfer %device driver. + + !!!Usage + + -# Use the hiddTransferDriverDescriptors variable to initialize a + USBDDriver instance. + -# Send hiddReportDescriptor to the host when a GET_DESCRIPTOR request + for the report descriptor is received. +*/ + +#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H +#define HIDDKEYBOARDDRIVERDESCRIPTORS_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Interrupt IN endpoint number. +#define HIDDTransferDriverDescriptors_INTERRUPTIN 1 +/// Polling rate in ms +#define HIDDTransferDriverDescriptors_INTERRUPTIN_POLLING 50 +/// Interrupt IN endpoint polling rate (in milliseconds). +#define HIDDTransferDriverDescriptors_INTERRUPTOUT 2 +/// Polling rate in ms +#define HIDDTransferDriverDescriptors_INTERRUPTOUT_POLLING 50 + +/// Size of the report descriptor in bytes. +#define HIDDTransferDriverDescriptors_REPORTSIZE 32 + +/// Size of the input and output report, in bytes +#define HIDDTransferDriver_REPORTSIZE 32 + +//------------------------------------------------------------------------------ +// Exported variables +//------------------------------------------------------------------------------ +/* + Variables: HID keyboard driver descriptors + hiddTransferDriverDescriptors - List of descriptors used by the HID + keyboard driver. + hiddReportDescriptor - Report descriptor used by the driver. +*/ +extern USBDDriverDescriptors hiddTransferDriverDescriptors; +extern const unsigned char hiddReportDescriptor[]; + +#endif //#ifndef HIDDKEYBOARDDRIVERDESCRIPTORS_H + diff --git a/usb/device/hid-transfer/hid-transfer.dir b/usb/device/hid-transfer/hid-transfer.dir new file mode 100644 index 0000000..a478e50 --- /dev/null +++ b/usb/device/hid-transfer/hid-transfer.dir @@ -0,0 +1,473 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \dir +/// +/// !!!Purpose +/// +/// This directory provides definitions, structs and functions for a USB HID +/// %device - USB HID Transfer driver, to implement an USB HID compatible +/// %device for customized data transmitting. +/// +/// !!!Contents +/// +/// There are three things for the implement of the USB HID Transfer driver: +/// - Implement the USB HID driver structs and functions for the %device, +/// to initialize, to handle HID-specific requests and dispach +/// standard requests in USBD callbacks, to read/write through assigned USB +/// endpoints, +/// - Create the HID Transfer device's descriptors that should be passed to +/// the USBDDriver instance on initialization, so that the host can +/// recognize the %device as a USB Transfer %device. +/// - Implement methods to read/write data through interrupt endpoints, so that +/// host and device can exchange data. +/// +/// For more information about what a particular group contains, please refer to +/// "USB HID Transfer". +//------------------------------------------------------------------------------ + +/** + \page "USB HID Transfer" + This page describes how to use the "AT91 USB device framework" to produce a USB + HID Transfer driver, which appears as a USB HID complient device on host. + + Details about the USB and the HID class can be found in the }USB specification + 2.0} and the }HID specification 1.11}, respectively. + + !!!References + - "AT91 USB device framework" + - "USB Device Enumeration" + - + Universal Serial Bus Revision 2.0 specification + (.zip file format, size 9.80 MB) + - + Device Class Definition for HID 1.11 + - + HID Usage Tables 1.12 + + !!!HID Basic + See "USB HID Basic". + + !!!Architecture + See "USB Device Framework Architecture". + + !!!Descriptors + + ... + + !!Device Descriptor + The Device descriptor of an HID %device is very basic, since the HID class + code is only specified at the Interface level. Thus, it only contains + standard values, as shown below: +\code +static const USBDeviceDescriptor deviceDescriptor = { + + sizeof(USBDeviceDescriptor), + USBGenericDescriptor_DEVICE, + USBDeviceDescriptor_USB2_00, + HIDDeviceDescriptor_CLASS, + HIDDeviceDescriptor_SUBCLASS, + HIDDeviceDescriptor_PROTOCOL, + BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), + HIDDKeyboardDriverDescriptors_VENDORID, + HIDDKeyboardDriverDescriptors_PRODUCTID, + HIDDKeyboardDriverDescriptors_RELEASE, + 1, // Index of manufacturer description + 2, // Index of product description + 3, // Index of serial number description + 1 // One possible configuration +}; +\endcode + Note that the Vendor ID is a special value attributed by the USB-IF + organization. The product ID can be chosen freely by the vendor. + + !!Configuration Descriptor + Since one interface is required by the HID specification, this must be + specified in the Configuration descriptor. There is no other value of + interest to put here. +\code +// Configuration descriptor +{ + sizeof(USBConfigurationDescriptor), + USBGenericDescriptor_CONFIGURATION, + sizeof(HIDDKeyboardDriverConfigurationDescriptors), + 1, // One interface in this configuration + 1, // This is configuration #1 + 0, // No associated string descriptor + BOARD_USB_BMATTRIBUTES, + USBConfigurationDescriptor_POWER(100) +}, +\endcode + When the Configuration descriptor is requested by the host (by using the + GET_DESCRIPTOR command), the %device must also sent all the related + descriptors, i.e. Interface, Endpoint and Class-Specific descriptors. It is + convenient to create a single structure to hold all this data, for sending + everything in one chunk. In the example software, a + HIDDKeyboardDriverConfigurationDescriptors structure has been declared for + that. + + !!HID Class Interface Descriptor + Since a keyboard %device needs to transmit as well as receive data, two + Interrupt (IN & OUT) endpoints are needed. This must be indicated in the + Interface descriptor. Conversely to the mouse example, the Boot protocol is + not implemented here, since there are more constraints on a keyboard %device. +\code +// Interface descriptor +{ + sizeof(USBInterfaceDescriptor), + USBGenericDescriptor_INTERFACE, + 0, // This is interface #0 + 0, // This is alternate setting #0 + 2, // Two endpoints used + HIDInterfaceDescriptor_CLASS, + HIDInterfaceDescriptor_SUBCLASS_NONE, + HIDInterfaceDescriptor_PROTOCOL_NONE, + 0 // No associated string descriptor +}, +\endcode + + !!HID Descriptor + While a HID keyboard produces two different reports, one Input and one Output, + only one Report descriptor can be used to describe them. Since having Physical + descriptors is also useless for a keyboard, there will only be one HID class + descriptor specified here. + + For a keyboard, the }bCountryCode} field can be used to specify the language + of the key caps. As this is optional, it is simply set to 00h in the example: +\code +// HID descriptor +{ + sizeof(HIDDescriptor), + HIDGenericDescriptor_HID, + HIDDescriptor_HID1_11, + 0, // Device is not localized, no country code + 1, // One HID-specific descriptor (apart from this one) + HIDGenericDescriptor_REPORT, + HIDDKeyboardDriverDescriptors_REPORTSIZE +}, +\endcode + + !!Report Descriptor + Two current reports are defined in the Report descriptor. The first one is + used to notify the host of which keys are pressed, with both modifier keys + (alt, ctrl, etc.) and alphanumeric keys. The second report is necessary for + the host to send the LED (num lock, caps lock, etc.) states. + + The Report descriptor starts with the global %device functionality, described + with a #Usage Page# and a #Usage# items: +\code +const unsigned char hiddReportDescriptor[] = { + + HIDReport_GLOBAL_USAGEPAGE + 2, 0xFF, 0xFF, // Vendor-defined + HIDReport_LOCAL_USAGE + 1, 0xFF, // Vendor-defined +\endcode + + An Application collection is then defined to group the reports together: +\code + HIDReport_COLLECTION + 1, HIDReport_COLLECTION_APPLICATION, +\endcode + + The first report to be defined is the input report, all data in the buffer + is vendor defined: +\code + // 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, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_INPUT + 1, 0, // No Modifiers +\endcode + + The output report is then defined, data is for the user to decode: +\code + // 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, (unsigned char) -128, + HIDReport_GLOBAL_LOGICALMAXIMUM + 1, (unsigned char) 127, + HIDReport_OUTPUT + 1, 0, // No Modifiers +\endcode + + The last item, }End Collection}, is necessary to close the previously opened + }Application Collection}. +\code + HIDReport_ENDCOLLECTION +}; +\endcode + + The input report and output report are all user defined. We define the first + byte as bit map of push buttons and LEDs, remaining bytes as data. + + !!Physical Descriptor + A Physical descriptor is useless for a general transfer %device, so none is + defined in this example. + + !!Endpoint Descriptor + Following the Interface and HID-specific descriptors, the two necessary + endpoints are defined. +\code +// Interrupt IN endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_IN, + HIDDKeyboardDriverDescriptors_INTERRUPTIN), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardInputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +}, +// Interrupt OUT endpoint descriptor +{ + sizeof(USBEndpointDescriptor), + USBGenericDescriptor_ENDPOINT, + USBEndpointDescriptor_ADDRESS( + USBEndpointDescriptor_OUT, + HIDDKeyboardDriverDescriptors_INTERRUPTOUT), + USBEndpointDescriptor_INTERRUPT, + sizeof(HIDDKeyboardOutputReport), + HIDDKeyboardDriverDescriptors_INTERRUPTIN_POLLING +} +\endcode + + !!String Descriptors + Please refer to "Usage: USBD VID, PID & Strings". + + !!!Class-specific requests + A driver request handler should first differentiate between class-specific and + standard requests using the corresponding bits in the }bmRequestType} field. + In most cases, standard requests can be immediately forwarded to the standard + request handler method; class-specific methods must be decoded and treated by + the custom handler. + + !!GetDescriptor + Three values have been added by the HID specification for the #GET_DESCRIPTOR# + request. The high byte of the }wValue} field contains the type of the + requested descriptor; in addition to the standard types, the #HID + specification# adds the #HID descriptor# (21h), the #Report descriptor# + (22h) and the #Physical descriptor# (23h) types. + + There is no particular action to perform besides sending the descriptor. This + can be done by using the USBD_Write method, after the requested descriptor has + been identified: +\code +switch (USBGenericRequest_GetRequest(request)) { + + case USBGenericRequest_GETDESCRIPTOR: + // Check if this is a HID descriptor, + // otherwise forward it to + // the standard driver + if (!HIDDKeyboardDriver_GetDescriptor( + USBGetDescriptorRequest_GetDescriptorType(request), + USBGenericRequest_GetLength(request))) { + + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); + } + break; + + default: + USBDDriver_RequestHandler(&(hiddKeyboardDriver.usbdDriver), + request); +} +\endcode + A slight complexity of the GET_DESCRIPTOR and SET_DESCRIPTOR requests is that + those are standard requests, but the standard request handler + (USBDDriver_RequestHandler) must not always be called to treat them (since + they may refer to HID descriptors). The solution is to first identify + GET/SET_DESCRIPTOR requests, treat the HID-specific cases and, finally, + forward any other request to the standard handler. + + In this case, a GET_DESCRIPTOR request for the Physical descriptor is first + forwarded to the standard handler, and STALLed there because it is not + recognized. This is done because the %device does not have any Physical + descriptors, and thus, does not need to handle the associated request. + + !!SetDescriptor + This request is optional and is never issued by most hosts. It is not + implemented in this example. + + !!GetReport + Since the HID keyboard defines two different reports, the Report Type value + specified by this request (upper byte of the }wValue} field) must be examined + to decide which report to send. If the type value is 01h, then the Input + report must be returned; if it is 02h, the Output report is requested: +\code +case HIDGenericRequest_GETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch (type) { + + case HIDReportRequest_INPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardInputReport)) { + + length = sizeof(HIDDKeyboardInputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.inputReport), + length, + 0, // No callback + 0); + break; + + case HIDReportRequest_OUTPUT: + + // Adjust size and send report + if (length > sizeof(HIDDKeyboardOutputReport)) { + + length = sizeof(HIDDKeyboardOutputReport); + } + USBD_Write(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + 0, // No callback + 0); + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetReport + For an HID keyboard, the #SET_REPORT# command can be sent by the host to + change the state of the LEDs. Normally, the dedicated Interrupt OUT endpoint + will be used for this; but in some cases, using the default Control endpoint + can save some bandwidth on the host side. + + Note that the SET_REPORT request can be directed at the Input report of the + keyboard; in this case, it can be safely discarded, according to the HID + specification. Normally, most host drivers only target the Output report. The + Report Type value is stored in the upper byte of the }wValue} field. + + The length of the data phase to follow is stored in the }wLength} field of the + request. It should be equal to the total length of the Output report. If it is + different, the report status must still be updated with the received data as + best as possible. + + When the reception of the new data is completed, some processing must be done + to enable/disable the corresponding LEDs. This is done in the callback + function passed as an argument to USBD_Read: +\code +case HIDGenericRequest_SETREPORT: +//------------------------------- + type = HIDReportRequest_GetReportType(request); + length = USBGenericRequest_GetLength(request); + switch(type) { + + case HIDReportRequest_INPUT: + // SET_REPORT requests on input reports are ignored + USBD_Stall(0); + break; + + case HIDReportRequest_OUTPUT: + // Check report length + if (length != sizeof(HIDDKeyboardOutputReport)) { + + USBD_Stall(0); + } + else { + + USBD_Read(0, // Endpoint #0 + &(hiddKeyboardDriver.outputReport), + length, + (TransferCallback) HIDDKeyboardDriver_ReportReceived, + 0); // No argument to the callback function + } + break; + + default: + USBD_Stall(0); + } +break; +\endcode + + !!SetIdle + In this case study, the #SET_IDLE# request is used to set a delay before a key + is repeated. This is common behavior on keyboard devices. Usually, this delay + is set to about 500 ms by the host. + + The only action here is to store the new Idle rate. The management of this + setting must be done in the main function, since Interrupt IN reports are sent + from there. + + In practice, it is not necessary to perform any action, apart from sending a + zero-length packet to acknowledge it. The main application however has to make + sure that only new reports are sent by the %device. +\code +case HIDGenericRequest_SETIDLE: +//----------------------------- + hiddKeyboardDriver.inputReportIdleRate = + HIDIdleRequest_GetIdleRate(request); + USBD_Write(0, 0, 0, 0, 0); +break; +\endcode + + !!GetIdle + The only necessary operation for this request is to send the previously saved + Idle rate. This is done by calling the USBD_Write method with the one-byte + variable as its parameter: +\code +case HIDGenericRequest_GETIDLE: +//----------------------------- + USBD_Write(0, &(hiddKeyboardDriver.inputReportIdleRate), 1, 0, 0); +break; +\endcode + + !!GetProtocol, SetProtocol + This HID keyboard example does not support the Boot protocol, so there is no + need to implement the SET_PROTOCOL and GET_PROTOCOL requests. This means they + can be safely STALLed when received. + + !!!Main Application + Like the mouse example, the main program must perform two different + operations. First, it has to monitor the physical inputs used as keys. In the + example software, the buttons present on the evaluation boards are used to + produce several modifier and alphanumeric keys. + + Also, the main program is in charge of sending reports as they are modified, + taking into account the Idle rate specified by the host. Idle rate management + can be carried out by firing/resetting a timer once a new report is sent; if + the timer expires, this means the Input report has not changed since. + According to the HID specification, a single instance of the report must be + sent in this case. + + Finally, the HID specification also defines that if too many keys are pressed + at the same time, the %device should report an }ErrorRollOver} usage value + (01h) in every byte of the key array. This has to be handled by the main + application as well. + +*/ \ No newline at end of file -- cgit v1.2.3