summaryrefslogtreecommitdiff
path: root/usb/device/hid-transfer
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-07-04 20:52:54 +0200
committerHarald Welte <laforge@gnumonks.org>2011-07-04 20:52:54 +0200
commit044ad7c3987460ede48ff27afd6bdb0ca05a0432 (patch)
tree924818cdb0d39ca08aec540d18da7bd406eaae8c /usb/device/hid-transfer
import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v1501120100901_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
Diffstat (limited to 'usb/device/hid-transfer')
-rw-r--r--usb/device/hid-transfer/HIDDTransferDriver.c479
-rw-r--r--usb/device/hid-transfer/HIDDTransferDriver.h87
-rw-r--r--usb/device/hid-transfer/HIDDTransferDriverDesc.c417
-rw-r--r--usb/device/hid-transfer/HIDDTransferDriverDesc.h87
-rw-r--r--usb/device/hid-transfer/hid-transfer.dir473
5 files changed, 1543 insertions, 0 deletions
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 <utility/trace.h>
+#include <usb/common/core/USBGetDescriptorRequest.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#include <usb/common/hid/HIDGenericDescriptor.h>
+#include <usb/common/hid/HIDDescriptor.h>
+#include <usb/common/hid/HIDGenericRequest.h>
+#include <usb/common/hid/HIDReportRequest.h>
+#include <usb/device/core/USBD.h>
+#include <usb/device/core/USBDDriver.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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 <usb/common/core/USBGenericRequest.h>
+#include <usb/device/core/USBD.h>
+
+//------------------------------------------------------------------------------
+// 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 <board.h>
+#include <usb/common/core/USBDeviceDescriptor.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/common/core/USBInterfaceDescriptor.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBStringDescriptor.h>
+#include <usb/common/hid/HIDGenericDescriptor.h>
+#include <usb/common/hid/HIDDeviceDescriptor.h>
+#include <usb/common/hid/HIDInterfaceDescriptor.h>
+#include <usb/common/hid/HIDDescriptor.h>
+#include <usb/common/hid/HIDReport.h>
+#include <usb/common/hid/HIDGenericDesktop.h>
+#include <usb/common/hid/HIDLeds.h>
+#include <usb/common/hid/HIDButton.h>
+#include <usb/device/core/USBDDriverDescriptors.h>
+
+//------------------------------------------------------------------------------
+// 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 <usb/device/core/USBDDriverDescriptors.h>
+#include <usb/common/hid/HIDKeypad.h>
+
+//------------------------------------------------------------------------------
+// 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"
+ - <a href="http://www.usb.org/developers/docs/usb_20_040908.zip">
+ Universal Serial Bus Revision 2.0 specification
+ </a> (.zip file format, size 9.80 MB)
+ - <a href="http://www.usb.org/developers/devclass_docs/HID1_11.pdf">
+ Device Class Definition for HID 1.11</a>
+ - <a href="http://www.usb.org/developers/devclass_docs/Hut1_12.pdf">
+ HID Usage Tables 1.12</a>
+
+ !!!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
personal git repositories of Harald Welte. Your mileage may vary