mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-19 09:38:32 -04:00
Add simple USB CDC task.
This commit is contained in:
parent
a83d9d93e8
commit
df338c84c3
15 changed files with 2756 additions and 49 deletions
430
Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c
Normal file
430
Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c
Normal file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
LPCUSB, an USB device driver for LPC microcontrollers
|
||||
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/** @file
|
||||
Standard request handler.
|
||||
|
||||
This modules handles the 'chapter 9' processing, specifically the
|
||||
standard device requests in table 9-3 from the universal serial bus
|
||||
specification revision 2.0
|
||||
|
||||
Specific types of devices may specify additional requests (for example
|
||||
HID devices add a GET_DESCRIPTOR request for interfaces), but they
|
||||
will not be part of this module.
|
||||
|
||||
@todo some requests have to return a request error if device not configured:
|
||||
@todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
|
||||
@todo this applies to the following if endpoint != 0:
|
||||
@todo SET_FEATURE, GET_FEATURE
|
||||
*/
|
||||
|
||||
#include "usbdebug.h"
|
||||
#include "usbstruct.h"
|
||||
#include "usbapi.h"
|
||||
|
||||
#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */
|
||||
|
||||
|
||||
/* general descriptor field offsets */
|
||||
#define DESC_bLength 0 /**< length offset */
|
||||
#define DESC_bDescriptorType 1 /**< descriptor type offset */
|
||||
|
||||
/* config descriptor field offsets */
|
||||
#define CONF_DESC_wTotalLength 2 /**< total length offset */
|
||||
#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */
|
||||
#define CONF_DESC_bmAttributes 7 /**< configuration characteristics */
|
||||
|
||||
/* interface descriptor field offsets */
|
||||
#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */
|
||||
|
||||
/* endpoint descriptor field offsets */
|
||||
#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */
|
||||
#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */
|
||||
|
||||
|
||||
/** Currently selected configuration */
|
||||
static unsigned char bConfiguration = 0;
|
||||
/** Installed custom request handler */
|
||||
static TFnHandleRequest *pfnHandleCustomReq = NULL;
|
||||
/** Pointer to registered descriptors */
|
||||
static const unsigned char *pabDescrip = NULL;
|
||||
|
||||
|
||||
/**
|
||||
Registers a pointer to a descriptor block containing all descriptors
|
||||
for the device.
|
||||
|
||||
@param [in] pabDescriptors The descriptor byte array
|
||||
*/
|
||||
void USBRegisterDescriptors(const unsigned char *pabDescriptors)
|
||||
{
|
||||
pabDescrip = pabDescriptors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parses the list of installed USB descriptors and attempts to find
|
||||
the specified USB descriptor.
|
||||
|
||||
@param [in] wTypeIndex Type and index of the descriptor
|
||||
@param [in] wLangID Language ID of the descriptor (currently unused)
|
||||
@param [out] *piLen Descriptor length
|
||||
@param [out] *ppbData Descriptor data
|
||||
|
||||
@return TRUE if the descriptor was found, FALSE otherwise
|
||||
*/
|
||||
BOOL USBGetDescriptor(unsigned short wTypeIndex, unsigned short wLangID, int *piLen, unsigned char **ppbData)
|
||||
{
|
||||
unsigned char bType, bIndex;
|
||||
unsigned char *pab;
|
||||
int iCurIndex;
|
||||
|
||||
ASSERT(pabDescrip != NULL);
|
||||
|
||||
bType = GET_DESC_TYPE(wTypeIndex);
|
||||
bIndex = GET_DESC_INDEX(wTypeIndex);
|
||||
|
||||
pab = (unsigned char *)pabDescrip;
|
||||
iCurIndex = 0;
|
||||
|
||||
while (pab[DESC_bLength] != 0) {
|
||||
if (pab[DESC_bDescriptorType] == bType) {
|
||||
if (iCurIndex == bIndex) {
|
||||
// set data pointer
|
||||
*ppbData = pab;
|
||||
// get length from structure
|
||||
if (bType == DESC_CONFIGURATION) {
|
||||
// configuration descriptor is an exception, length is at offset 2 and 3
|
||||
*piLen = (pab[CONF_DESC_wTotalLength]) |
|
||||
(pab[CONF_DESC_wTotalLength + 1] << 8);
|
||||
}
|
||||
else {
|
||||
// normally length is at offset 0
|
||||
*piLen = pab[DESC_bLength];
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
iCurIndex++;
|
||||
}
|
||||
// skip to next descriptor
|
||||
pab += pab[DESC_bLength];
|
||||
}
|
||||
// nothing found
|
||||
DBG("Desc %x not found!\n", wTypeIndex);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configures the device according to the specified configuration index and
|
||||
alternate setting by parsing the installed USB descriptor list.
|
||||
A configuration index of 0 unconfigures the device.
|
||||
|
||||
@param [in] bConfigIndex Configuration index
|
||||
@param [in] bAltSetting Alternate setting number
|
||||
|
||||
@todo function always returns TRUE, add stricter checking?
|
||||
|
||||
@return TRUE if successfully configured, FALSE otherwise
|
||||
*/
|
||||
static BOOL USBSetConfiguration(unsigned char bConfigIndex, unsigned char bAltSetting)
|
||||
{
|
||||
unsigned char *pab;
|
||||
unsigned char bCurConfig, bCurAltSetting;
|
||||
unsigned char bEP;
|
||||
unsigned short wMaxPktSize;
|
||||
|
||||
ASSERT(pabDescrip != NULL);
|
||||
|
||||
if (bConfigIndex == 0) {
|
||||
// unconfigure device
|
||||
USBHwConfigDevice(FALSE);
|
||||
}
|
||||
else {
|
||||
// configure endpoints for this configuration/altsetting
|
||||
pab = (unsigned char *)pabDescrip;
|
||||
bCurConfig = 0xFF;
|
||||
bCurAltSetting = 0xFF;
|
||||
|
||||
while (pab[DESC_bLength] != 0) {
|
||||
|
||||
switch (pab[DESC_bDescriptorType]) {
|
||||
|
||||
case DESC_CONFIGURATION:
|
||||
// remember current configuration index
|
||||
bCurConfig = pab[CONF_DESC_bConfigurationValue];
|
||||
break;
|
||||
|
||||
case DESC_INTERFACE:
|
||||
// remember current alternate setting
|
||||
bCurAltSetting = pab[INTF_DESC_bAlternateSetting];
|
||||
break;
|
||||
|
||||
case DESC_ENDPOINT:
|
||||
if ((bCurConfig == bConfigIndex) &&
|
||||
(bCurAltSetting == bAltSetting)) {
|
||||
// endpoint found for desired config and alternate setting
|
||||
bEP = pab[ENDP_DESC_bEndpointAddress];
|
||||
wMaxPktSize = (pab[ENDP_DESC_wMaxPacketSize]) |
|
||||
(pab[ENDP_DESC_wMaxPacketSize + 1] << 8);
|
||||
// configure endpoint
|
||||
USBHwEPConfig(bEP, wMaxPktSize);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// skip to next descriptor
|
||||
pab += pab[DESC_bLength];
|
||||
}
|
||||
|
||||
// configure device
|
||||
USBHwConfigDevice(TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Local function to handle a standard device request
|
||||
|
||||
@param [in] pSetup The setup packet
|
||||
@param [in,out] *piLen Pointer to data length
|
||||
@param [in,out] ppbData Data buffer.
|
||||
|
||||
@return TRUE if the request was handled successfully
|
||||
*/
|
||||
static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)
|
||||
{
|
||||
unsigned char *pbData = *ppbData;
|
||||
|
||||
switch (pSetup->bRequest) {
|
||||
|
||||
case REQ_GET_STATUS:
|
||||
// bit 0: self-powered
|
||||
// bit 1: remote wakeup = not supported
|
||||
pbData[0] = 0;
|
||||
pbData[1] = 0;
|
||||
*piLen = 2;
|
||||
break;
|
||||
|
||||
case REQ_SET_ADDRESS:
|
||||
USBHwSetAddress(pSetup->wValue);
|
||||
break;
|
||||
|
||||
case REQ_GET_DESCRIPTOR:
|
||||
DBG("D%x", pSetup->wValue);
|
||||
return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);
|
||||
|
||||
case REQ_GET_CONFIGURATION:
|
||||
// indicate if we are configured
|
||||
pbData[0] = bConfiguration;
|
||||
*piLen = 1;
|
||||
break;
|
||||
|
||||
case REQ_SET_CONFIGURATION:
|
||||
if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {
|
||||
DBG("USBSetConfiguration failed!\n");
|
||||
return FALSE;
|
||||
}
|
||||
// configuration successful, update current configuration
|
||||
bConfiguration = pSetup->wValue & 0xFF;
|
||||
break;
|
||||
|
||||
case REQ_CLEAR_FEATURE:
|
||||
case REQ_SET_FEATURE:
|
||||
if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
|
||||
// put DEVICE_REMOTE_WAKEUP code here
|
||||
}
|
||||
if (pSetup->wValue == FEA_TEST_MODE) {
|
||||
// put TEST_MODE code here
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case REQ_SET_DESCRIPTOR:
|
||||
DBG("Device req %d not implemented\n", pSetup->bRequest);
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
DBG("Illegal device req %d\n", pSetup->bRequest);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Local function to handle a standard interface request
|
||||
|
||||
@param [in] pSetup The setup packet
|
||||
@param [in,out] *piLen Pointer to data length
|
||||
@param [in] ppbData Data buffer.
|
||||
|
||||
@return TRUE if the request was handled successfully
|
||||
*/
|
||||
static BOOL HandleStdInterfaceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)
|
||||
{
|
||||
unsigned char *pbData = *ppbData;
|
||||
|
||||
switch (pSetup->bRequest) {
|
||||
|
||||
case REQ_GET_STATUS:
|
||||
// no bits specified
|
||||
pbData[0] = 0;
|
||||
pbData[1] = 0;
|
||||
*piLen = 2;
|
||||
break;
|
||||
|
||||
case REQ_CLEAR_FEATURE:
|
||||
case REQ_SET_FEATURE:
|
||||
// not defined for interface
|
||||
return FALSE;
|
||||
|
||||
case REQ_GET_INTERFACE: // TODO use bNumInterfaces
|
||||
// there is only one interface, return n-1 (= 0)
|
||||
pbData[0] = 0;
|
||||
*piLen = 1;
|
||||
break;
|
||||
|
||||
case REQ_SET_INTERFACE: // TODO use bNumInterfaces
|
||||
// there is only one interface (= 0)
|
||||
if (pSetup->wValue != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
*piLen = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG("Illegal interface req %d\n", pSetup->bRequest);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Local function to handle a standard endpoint request
|
||||
|
||||
@param [in] pSetup The setup packet
|
||||
@param [in,out] *piLen Pointer to data length
|
||||
@param [in] ppbData Data buffer.
|
||||
|
||||
@return TRUE if the request was handled successfully
|
||||
*/
|
||||
static BOOL HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)
|
||||
{
|
||||
unsigned char *pbData = *ppbData;
|
||||
|
||||
switch (pSetup->bRequest) {
|
||||
case REQ_GET_STATUS:
|
||||
// bit 0 = endpointed halted or not
|
||||
pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0;
|
||||
pbData[1] = 0;
|
||||
*piLen = 2;
|
||||
break;
|
||||
|
||||
case REQ_CLEAR_FEATURE:
|
||||
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
|
||||
// clear HALT by unstalling
|
||||
USBHwEPStall(pSetup->wIndex, FALSE);
|
||||
break;
|
||||
}
|
||||
// only ENDPOINT_HALT defined for endpoints
|
||||
return FALSE;
|
||||
|
||||
case REQ_SET_FEATURE:
|
||||
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
|
||||
// set HALT by stalling
|
||||
USBHwEPStall(pSetup->wIndex, TRUE);
|
||||
break;
|
||||
}
|
||||
// only ENDPOINT_HALT defined for endpoints
|
||||
return FALSE;
|
||||
|
||||
case REQ_SYNCH_FRAME:
|
||||
DBG("EP req %d not implemented\n", pSetup->bRequest);
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
DBG("Illegal EP req %d\n", pSetup->bRequest);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Default handler for standard ('chapter 9') requests
|
||||
|
||||
If a custom request handler was installed, this handler is called first.
|
||||
|
||||
@param [in] pSetup The setup packet
|
||||
@param [in,out] *piLen Pointer to data length
|
||||
@param [in] ppbData Data buffer.
|
||||
|
||||
@return TRUE if the request was handled successfully
|
||||
*/
|
||||
BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData)
|
||||
{
|
||||
// try the custom request handler first
|
||||
if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {
|
||||
case REQTYPE_RECIP_DEVICE: return HandleStdDeviceReq(pSetup, piLen, ppbData);
|
||||
case REQTYPE_RECIP_INTERFACE: return HandleStdInterfaceReq(pSetup, piLen, ppbData);
|
||||
case REQTYPE_RECIP_ENDPOINT: return HandleStdEndPointReq(pSetup, piLen, ppbData);
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Registers a callback for custom device requests
|
||||
|
||||
In USBHandleStandardRequest, the custom request handler gets a first
|
||||
chance at handling the request before it is handed over to the 'chapter 9'
|
||||
request handler.
|
||||
|
||||
This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
|
||||
request is sent to an interface, which is not covered by the 'chapter 9'
|
||||
specification.
|
||||
|
||||
@param [in] pfnHandler Callback function pointer
|
||||
*/
|
||||
void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)
|
||||
{
|
||||
pfnHandleCustomReq = pfnHandler;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue