From 480d6352eabe95797a5836d10c3b10285ac1c79c Mon Sep 17 00:00:00 2001 From: Andreas Bogk Date: Thu, 23 Apr 2015 16:23:08 +0200 Subject: [PATCH] Bring type definitions in line with eLua standard conventions. --- src/platform/lpc17xx/conf.lua | 2 + .../lpc17xx/usbstack/inc/lpcusb_type.h | 68 - src/platform/lpc17xx/usbstack/inc/type.h | 38 - .../lpc17xx/usbstack/src/usbcontrol.c | 43 +- src/platform/lpc17xx/usbstack/src/usbhw_lpc.c | 1251 ++++++++--------- src/platform/lpc17xx/usbstack/src/usbinit.c | 25 +- src/platform/lpc17xx/usbstack/src/usbstdreq.c | 865 ++++++------ 7 files changed, 1088 insertions(+), 1204 deletions(-) delete mode 100644 src/platform/lpc17xx/usbstack/inc/lpcusb_type.h delete mode 100644 src/platform/lpc17xx/usbstack/inc/type.h diff --git a/src/platform/lpc17xx/conf.lua b/src/platform/lpc17xx/conf.lua index f91dec2e..cda5d2cb 100644 --- a/src/platform/lpc17xx/conf.lua +++ b/src/platform/lpc17xx/conf.lua @@ -1,8 +1,10 @@ -- Configuration file for the LPC17xx backend addi( sf( 'src/platform/%s/drivers/inc', platform ) ) +addi( sf( 'src/platform/%s/usbstack/inc', platform ) ) local fwlib_files = utils.get_files( sf( "src/platform/%s/drivers/src", platform ), ".*%.c$" ) +fwlib_files = fwlib_files .. " " .. utils.get_files( sf( "src/platform/%s/usbstack/src", platform ), ".*%.c$" ) specific_files = "startup_LPC17xx.c system_LPC17xx.c core_cm3.c platform.c" local board = comp.board:upper() diff --git a/src/platform/lpc17xx/usbstack/inc/lpcusb_type.h b/src/platform/lpc17xx/usbstack/inc/lpcusb_type.h deleted file mode 100644 index 1c765432..00000000 --- a/src/platform/lpc17xx/usbstack/inc/lpcusb_type.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - 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 - primitive types used in the USB stack - */ - -// *********************************************** -// Code Red Technologies - port to RDB1768 board -// In order to avoid clashing with the NXP-produced type.h file, this -// one has been renamed to lpcusb_type.h, the NXP-produced type.h has -// been included, and the duplicate contents of this file commented out. -// *********************************************** - - -#ifndef _LPCUSB_TYPE_H_ -#define _LPCUSB_TYPE_H_ - -// CodeRed - include NXP-produced type.h file -#include "type.h" - -typedef unsigned char U8; /**< unsigned 8-bit */ -typedef unsigned short int U16; /**< unsigned 16-bit */ -typedef unsigned int U32; /**< unsigned 32-bit */ - - -// CodeRed - comment out defines duplicated in NXP type.h - -//typedef int BOOL; /**< #TRUE or #FALSE */ - -//#define TRUE 1 /**< TRUE */ -//#define FALSE 0 /**< FALSE */ - -//#ifndef NULL -//#define NULL ((void*)0) /**< NULL pointer */ -//#endif -//#endif - -/* some other useful macros */ -#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */ -#define MAX(x,y) ((x)>(y)?(x):(y)) /**< MAX */ - -#endif /* _LPCUSB_TYPE_H_ */ - diff --git a/src/platform/lpc17xx/usbstack/inc/type.h b/src/platform/lpc17xx/usbstack/inc/type.h deleted file mode 100644 index 89d36850..00000000 --- a/src/platform/lpc17xx/usbstack/inc/type.h +++ /dev/null @@ -1,38 +0,0 @@ -/***************************************************************************** - * type.h: Type definition Header file for NXP LPC17xx Family - * Microprocessors - * - * Copyright(C) 2008, NXP Semiconductor - * All rights reserved. - * - * History - * 2008.08.21 ver 1.00 Prelimnary version, first Release - * -******************************************************************************/ -#ifndef __TYPE_H__ -#define __TYPE_H__ - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#ifndef FALSE -#define FALSE (0) -#endif - -#ifndef TRUE -#define TRUE (1) -#endif - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; -typedef unsigned int BOOL; - -typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; -typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; - -/* Pointer to Function returning Void (any number of parameters) */ -typedef void (*PFV)(); - -#endif /* __TYPE_H__ */ diff --git a/src/platform/lpc17xx/usbstack/src/usbcontrol.c b/src/platform/lpc17xx/usbstack/src/usbcontrol.c index baf90fe6..fd07486a 100644 --- a/src/platform/lpc17xx/usbstack/src/usbcontrol.c +++ b/src/platform/lpc17xx/usbstack/src/usbcontrol.c @@ -1,5 +1,5 @@ /* - LPCUSB, an USB device driver for LPC microcontrollers + 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 @@ -16,7 +16,7 @@ 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, + 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 @@ -28,10 +28,10 @@ /** @file Control transfer handler. - + This module handles control transfers and is normally installed on the endpoint 0 callback. - + Control transfers can be of the following type: 0 Standard; 1 Class; @@ -48,9 +48,7 @@ control transfer data. The data is then packetised and sent to the host. */ -// CodeRed - include the LPCUSB type.h file rather than NXP one directly -//#include "type.h" -#include "lpcusb_type.h" +#include "type.h" #include "usbdebug.h" @@ -64,34 +62,34 @@ static TSetupPacket Setup; /**< setup packet */ -static U8 *pbData; /**< pointer to data buffer */ +static u8 *pbData; /**< pointer to data buffer */ static int iResidue; /**< remaining bytes in buffer */ static int iLen; /**< total length of control transfer */ /** Array of installed request handler callbacks */ static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL}; /** Array of installed request data pointers */ -static U8 *apbDataStore[4] = {NULL, NULL, NULL, NULL}; +static u8 *apbDataStore[4] = {NULL, NULL, NULL, NULL}; /** Local function to handle a request by calling one of the installed request handlers. - + In case of data going from host to device, the data is at *ppbData. In case of data going from device to host, the handler can either choose to write its data at *ppbData or update the data pointer. - + @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 handles successfully */ -static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) +static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, u8 **ppbData) { TFnHandleRequest *pfnHandler; int iType; - + iType = REQTYPE_GET_TYPE(pSetup->bmRequestType); pfnHandler = apfnReqHandlers[iType]; if (pfnHandler == NULL) { @@ -105,19 +103,19 @@ static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) /** Local function to stall the control endpoint - + @param [in] bEPStat Endpoint status */ -static void StallControlPipe(U8 bEPStat) +static void StallControlPipe(u8 bEPStat) { - U8 *pb; + u8 *pb; int i; USBHwEPStall(0x80, TRUE); // dump setup packet DBG("STALL on ["); - pb = (U8 *)&Setup; + pb = (u8 *)&Setup; for (i = 0; i < 8; i++) { DBG(" %02x", *pb++); } @@ -145,7 +143,7 @@ static void DataIn(void) * @param [in] bEP Endpoint address * @param [in] bEPStat Endpoint status */ -void USBHandleControlTransfer(U8 bEP, U8 bEPStat) +void USBHandleControlTransfer(u8 bEP, u8 bEPStat) { int iChunk, iType; @@ -153,7 +151,7 @@ void USBHandleControlTransfer(U8 bEP, U8 bEPStat) // OUT transfer if (bEPStat & EP_STATUS_SETUP) { // setup packet, reset request message state machine - USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup)); + USBHwEPRead(0x00, (u8 *)&Setup, sizeof(Setup)); DBG("S%x", Setup.bRequest); // defaults for data pointer and residue @@ -176,7 +174,7 @@ void USBHandleControlTransfer(U8 bEP, U8 bEPStat) DataIn(); } } - else { + else { if (iResidue > 0) { // store data iChunk = USBHwEPRead(0x00, pbData, iResidue); @@ -219,16 +217,15 @@ void USBHandleControlTransfer(U8 bEP, U8 bEPStat) /** Registers a callback for handling requests - + @param [in] iType Type of request, e.g. REQTYPE_TYPE_STANDARD @param [in] *pfnHandler Callback function pointer @param [in] *pbDataStore Data storage area for this type of request */ -void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore) +void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, u8 *pbDataStore) { ASSERT(iType >= 0); ASSERT(iType < 4); apfnReqHandlers[iType] = pfnHandler; apbDataStore[iType] = pbDataStore; } - diff --git a/src/platform/lpc17xx/usbstack/src/usbhw_lpc.c b/src/platform/lpc17xx/usbstack/src/usbhw_lpc.c index 2f0f658c..c8256902 100644 --- a/src/platform/lpc17xx/usbstack/src/usbhw_lpc.c +++ b/src/platform/lpc17xx/usbstack/src/usbhw_lpc.c @@ -1,627 +1,624 @@ -/* - 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 - USB hardware layer - */ - -// CodeRed - include the LPCUSB type.h file rather than NXP one directly -//#include "type.h" -#include "lpcusb_type.h" - -#include "usbdebug.h" -#include "usbhw_lpc.h" -#include "usbapi.h" -// Configure LED pin functions -// -// LED pin functions -// -// Function Pin Port Bits Pin Select Register -// ------------------- --- ----- ---- ------------------- -// P2.0 GPIO Port 2.0 xx P2.0 1:0 PINSEL4 -// P2.1 GPIO Port 2.1 xx P2.1 3:2 PINSEL4 -// P2.2 GPIO Port 2.2 xx P2.2 5:4 PINSEL4 -// P2.3 GPIO Port 2.3 xx P2.3 7:6 PINSEL4 -// P2.4 GPIO Port 2.4 xx P2.4 9:8 PINSEL4 -// P2.5 GPIO Port 2.5 xx P2.5 11:10 PINSEL4 -// P2.6 GPIO Port 2.6 xx P2.6 13:12 PINSEL4 -// P2.7 GPIO Port 2.7 xx P2.7 15:14 PINSEL4 -// -// OFF - LED state 0 -// ON - LED state 1 -// -// '*' as GPIO - -#define NO_LEDS 8 - -#define LED_0 (1 << 0) -#define LED_1 (1 << 1) -#define LED_2 (1 << 2) -#define LED_3 (1 << 3) -#define LED_4 (1 << 4) -#define LED_5 (1 << 5) -#define LED_6 (1 << 6) -#define LED_7 (1 << 7) - -#ifdef DEBUG -// comment out the following line if you don't want to use debug LEDs -//#define DEBUG_LED -#endif - -#ifdef DEBUG_LED -#define DEBUG_LED_ON(x) FIO2SET = (1 << x); -#define DEBUG_LED_OFF(x) FIO2CLR = (1 << x); -#define DEBUG_LED_INIT(x) PINSEL2 &= ~(0x3 << (2*x)); FIO2DIR |= (1 << x); DEBUG_LED_OFF(x); -#else -#define DEBUG_LED_INIT(x) /**< LED initialisation macro */ -#define DEBUG_LED_ON(x) /**< turn LED on */ -#define DEBUG_LED_OFF(x) /**< turn LED off */ -#endif - -/** Installed device interrupt handler */ -static TFnDevIntHandler *_pfnDevIntHandler = NULL; -/** Installed endpoint interrupt handlers */ -static TFnEPIntHandler *_apfnEPIntHandlers[16]; -/** Installed frame interrupt handlers */ -static TFnFrameHandler *_pfnFrameHandler = NULL; - -/** convert from endpoint address to endpoint index */ -#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) -/** convert from endpoint index to endpoint address */ -#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) - - - -/** - Local function to wait for a device interrupt (and clear it) - - @param [in] dwIntr Bitmask of interrupts to wait for - */ -static void Wait4DevInt(U32 dwIntr) -{ - // wait for specific interrupt - while ((LPC_USB->USBDevIntSt & dwIntr) != dwIntr); - // clear the interrupt bits - LPC_USB->USBDevIntClr = dwIntr; -} - - -/** - Local function to send a command to the USB protocol engine - - @param [in] bCmd Command to send - */ -static void USBHwCmd(U8 bCmd) -{ - // clear CDFULL/CCEMTY - LPC_USB->USBDevIntClr = CDFULL | CCEMTY; - // write command code - LPC_USB->USBCmdCode = 0x00000500 | (bCmd << 16); - Wait4DevInt(CCEMTY); -} - - -/** - Local function to send a command + data to the USB protocol engine - - @param [in] bCmd Command to send - @param [in] bData Data to send - */ -static void USBHwCmdWrite(U8 bCmd, U16 bData) -{ - // write command code - USBHwCmd(bCmd); - - // write command data - LPC_USB->USBCmdCode = 0x00000100 | (bData << 16); - Wait4DevInt(CCEMTY); -} - - -/** - Local function to send a command to the USB protocol engine and read data - - @param [in] bCmd Command to send - - @return the data - */ -static U8 USBHwCmdRead(U8 bCmd) -{ - // write command code - USBHwCmd(bCmd); - - // get data - LPC_USB->USBCmdCode = 0x00000200 | (bCmd << 16); - Wait4DevInt(CDFULL); - return LPC_USB->USBCmdData; -} - - -/** - 'Realizes' an endpoint, meaning that buffer space is reserved for - it. An endpoint needs to be realised before it can be used. - - From experiments, it appears that a USB reset causes USBReEP to - re-initialise to 3 (= just the control endpoints). - However, a USB bus reset does not disturb the USBMaxPSize settings. - - @param [in] idx Endpoint index - @param [in] wMaxPSize Maximum packet size for this endpoint - */ -static void USBHwEPRealize(int idx, U16 wMaxPSize) -{ - LPC_USB->USBReEP |= (1 << idx); - LPC_USB->USBEpInd = idx; - LPC_USB->USBMaxPSize = wMaxPSize; - Wait4DevInt(EP_RLZED); -} - - -/** - Enables or disables an endpoint - - @param [in] idx Endpoint index - @param [in] fEnable TRUE to enable, FALSE to disable - */ -static void USBHwEPEnable(int idx, BOOL fEnable) -{ - USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA); -} - - -/** - Configures an endpoint and enables it - - @param [in] bEP Endpoint number - @param [in] wMaxPacketSize Maximum packet size for this EP - */ -void USBHwEPConfig(U8 bEP, U16 wMaxPacketSize) -{ - int idx; - - idx = EP2IDX(bEP); - - // realise EP - USBHwEPRealize(idx, wMaxPacketSize); - - // enable EP - USBHwEPEnable(idx, TRUE); -} - - -/** - Registers an endpoint event callback - - @param [in] bEP Endpoint number - @param [in] pfnHandler Callback function - */ -void USBHwRegisterEPIntHandler(U8 bEP, TFnEPIntHandler *pfnHandler) -{ - int idx; - - idx = EP2IDX(bEP); - - ASSERT(idx<32); - - /* add handler to list of EP handlers */ - _apfnEPIntHandlers[idx / 2] = pfnHandler; - - /* enable EP interrupt */ - LPC_USB->USBEpIntEn |= (1 << idx); - LPC_USB->USBDevIntEn |= EP_SLOW; - - DBG("Registered handler for EP 0x%x\n", bEP); -} - - -/** - Registers an device status callback - - @param [in] pfnHandler Callback function - */ -void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler) -{ - _pfnDevIntHandler = pfnHandler; - - // enable device interrupt - LPC_USB->USBDevIntEn |= DEV_STAT; - - DBG("Registered handler for device status\n"); -} - - -/** - Registers the frame callback - - @param [in] pfnHandler Callback function - */ -void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler) -{ - _pfnFrameHandler = pfnHandler; - - // enable device interrupt - LPC_USB->USBDevIntEn |= FRAME; - - DBG("Registered handler for frame\n"); -} - - -/** - Sets the USB address. - - @param [in] bAddr Device address to set - */ -void USBHwSetAddress(U8 bAddr) -{ - USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr); -} - - -/** - Connects or disconnects from the USB bus - - @param [in] fConnect If TRUE, connect, otherwise disconnect - */ -void USBHwConnect(BOOL fConnect) -{ - USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0); -} - - -/** - Enables interrupt on NAK condition - - For IN endpoints a NAK is generated when the host wants to read data - from the device, but none is available in the endpoint buffer. - For OUT endpoints a NAK is generated when the host wants to write data - to the device, but the endpoint buffer is still full. - - The endpoint interrupt handlers can distinguish regular (ACK) interrupts - from NAK interrupt by checking the bits in their bEPStatus argument. - - @param [in] bIntBits Bitmap indicating which NAK interrupts to enable - */ -void USBHwNakIntEnable(U8 bIntBits) -{ - USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits); -} - - -/** - Gets the status from a specific endpoint. - - @param [in] bEP Endpoint number - @return Endpoint status byte (containing EP_STATUS_xxx bits) - */ -U8 USBHwEPGetStatus(U8 bEP) -{ - int idx = EP2IDX(bEP); - - return USBHwCmdRead(CMD_EP_SELECT | idx); -} - - -/** - Sets the stalled property of an endpoint - - @param [in] bEP Endpoint number - @param [in] fStall TRUE to stall, FALSE to unstall - */ -void USBHwEPStall(U8 bEP, BOOL fStall) -{ - int idx = EP2IDX(bEP); - - USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0); -} - - -/** - Writes data to an endpoint buffer - - @param [in] bEP Endpoint number - @param [in] pbBuf Endpoint data - @param [in] iLen Number of bytes to write - - @return TRUE if the data was successfully written or <0 in case of error. -*/ -int USBHwEPWrite(U8 bEP, U8 *pbBuf, int iLen) -{ - int idx; - - idx = EP2IDX(bEP); - - // set write enable for specific endpoint - LPC_USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2); - - // set packet length - LPC_USB->USBTxPLen = iLen; - - // write data - while (LPC_USB->USBCtrl & WR_EN) { - LPC_USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0]; - pbBuf += 4; - } - - // select endpoint and validate buffer - USBHwCmd(CMD_EP_SELECT | idx); - USBHwCmd(CMD_EP_VALIDATE_BUFFER); - - return iLen; -} - - -/** - Reads data from an endpoint buffer - - @param [in] bEP Endpoint number - @param [in] pbBuf Endpoint data - @param [in] iMaxLen Maximum number of bytes to read - - @return the number of bytes available in the EP (possibly more than iMaxLen), - or <0 in case of error. - */ -int USBHwEPRead(U8 bEP, U8 *pbBuf, int iMaxLen) -{ - int i, idx; - U32 dwData, dwLen; - - idx = EP2IDX(bEP); - - // set read enable bit for specific endpoint - LPC_USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2); - - // wait for PKT_RDY - do { - dwLen = LPC_USB->USBRxPLen; - } while ((dwLen & PKT_RDY) == 0); - - // packet valid? - if ((dwLen & DV) == 0) { - return -1; - } - - // get length - dwLen &= PKT_LNGTH_MASK; - - // get data - dwData = 0; - for (i = 0; i < dwLen; i++) { - if ((i % 4) == 0) { - dwData = LPC_USB->USBRxData; - } - if ((pbBuf != NULL) && (i < iMaxLen)) { - pbBuf[i] = dwData & 0xFF; - } - dwData >>= 8; - } - - // make sure RD_EN is clear - LPC_USB->USBCtrl = 0; - - // select endpoint and clear buffer - USBHwCmd(CMD_EP_SELECT | idx); - USBHwCmd(CMD_EP_CLEAR_BUFFER); - - return dwLen; -} - - -/** - Sets the 'configured' state. - - All registered endpoints are 'realised' and enabled, and the - 'configured' bit is set in the device status register. - - @param [in] fConfigured If TRUE, configure device, else unconfigure - */ -void USBHwConfigDevice(BOOL fConfigured) -{ - // set configured bit - USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0); -} - - -/** - USB interrupt handler - - @todo Get all 11 bits of frame number instead of just 8 - - Endpoint interrupts are mapped to the slow interrupt - */ -void USBHwISR(void) -{ - U32 dwStatus; - U32 dwIntBit; - U8 bEPStat, bDevStat, bStat; - int i; - U16 wFrame; - - // LED9 monitors total time in interrupt routine - DEBUG_LED_ON(6); - - // handle device interrupts - dwStatus = LPC_USB->USBDevIntSt; - - // frame interrupt - if (dwStatus & FRAME) { - // clear int - LPC_USB->USBDevIntClr = FRAME; - // call handler - if (_pfnFrameHandler != NULL) { - wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); - _pfnFrameHandler(wFrame); - } - } - - // device status interrupt - if (dwStatus & DEV_STAT) { - /* Clear DEV_STAT interrupt before reading DEV_STAT register. - This prevents corrupted device status reads, see - LPC2148 User manual revision 2, 25 july 2006. - */ - LPC_USB->USBDevIntClr = DEV_STAT; - bDevStat = USBHwCmdRead(CMD_DEV_STATUS); - if (bDevStat & (CON_CH | SUS_CH | RST)) { - // convert device status into something HW independent - bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | - ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) | - ((bDevStat & RST) ? DEV_STATUS_RESET : 0); - // call handler - if (_pfnDevIntHandler != NULL) { - DEBUG_LED_ON(5); - _pfnDevIntHandler(bStat); - DEBUG_LED_OFF(5); - } - } - } - - // endpoint interrupt - if (dwStatus & EP_SLOW) { - // clear EP_SLOW - LPC_USB->USBDevIntClr = EP_SLOW; - // check all endpoints - for (i = 0; i < 32; i++) { - dwIntBit = (1 << i); - if (LPC_USB->USBEpIntSt & dwIntBit) { - // clear int (and retrieve status) - LPC_USB->USBEpIntClr = dwIntBit; - Wait4DevInt(CDFULL); - bEPStat = LPC_USB->USBCmdData; - // convert EP pipe stat into something HW independent - bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | - ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) | - ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | - ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) | - ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0); - // call handler - if (_apfnEPIntHandlers[i / 2] != NULL) { - DEBUG_LED_ON(7); - _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat); - DEBUG_LED_OFF(7); - } - } - } - } - - DEBUG_LED_OFF(6); -} - - - -/** - Initialises the USB hardware - - This function assumes that the hardware is connected as shown in - section 10.1 of the LPC2148 data sheet: - * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low. - * P0.23 is connected to USB VCC. - - Embedded artists board: make sure to disconnect P0.23 LED as it - acts as a pull-up and so prevents detection of USB disconnect. - - @return TRUE if the hardware was successfully initialised - */ -BOOL USBHwInit(void) -{ -/* CodeRed - comment out original code - * - // configure P0.23 for Vbus sense - PINSEL1 = (PINSEL1 & ~(3 << 14)) | (1 << 14); // P0.23 - // configure P0.31 for CONNECT - PINSEL1 = (PINSEL1 & ~(3 << 30)) | (2 << 30); // P0.31 -*/ - - // CodeRed - set up USB pins - - // P2.9 -> USB_CONNECT - LPC_PINCON->PINSEL4 &= ~0x000C0000; - LPC_PINCON->PINSEL4 |= 0x00040000; - - // P1.18 -> USB_UP_LED - // P1.30 -> VBUS - LPC_PINCON->PINSEL3 &= ~0x30000030; - LPC_PINCON->PINSEL3 |= 0x20000010; - - // P0.29 -> USB_D+ - // P0.30 -> USB_D- - LPC_PINCON->PINSEL1 &= ~0x3C000000; - LPC_PINCON->PINSEL1 |= 0x14000000; - - - // enable PUSB - LPC_SC->PCONP |= (1 << 31); - -/* CodeRed - Comment out original PLL code - * PLL now set up by NXP code in target.c within example projects - * - // initialise PLL - PLL1CON = 1; // enable PLL - PLL1CFG = (1 << 5) | 3; // P = 2, M = 4 - PLL1FEED = 0xAA; - PLL1FEED = 0x55; - while ((PLL1STAT & (1 << 10)) == 0); - - PLL1CON = 3; // enable and connect - PLL1FEED = 0xAA; - PLL1FEED = 0x55; - -*/ - - -// AWB added USB clock enable -// These are actually the USBClkCtrl and USBClkSt registers -// OTG_CLK_CTRL = 0x12; /* Dev clock, AHB clock enable */ -// while ((OTG_CLK_STAT & 0x12) != 0x12); - - LPC_USB->USBClkCtrl = 0x1A; /* Dev clock, AHB clock enable */ - while ((LPC_USB->USBClkSt & 0x1A) != 0x1A); - - - // disable/clear all interrupts for now - LPC_USB->USBDevIntEn = 0; - LPC_USB->USBDevIntClr = 0xFFFFFFFF; - LPC_USB->USBDevIntPri = 0; - - LPC_USB->USBEpIntEn = 0; - LPC_USB->USBEpIntClr = 0xFFFFFFFF; - LPC_USB->USBEpIntPri = 0; - - // by default, only ACKs generate interrupts - USBHwNakIntEnable(0); - - // CodeRed - commented out LEDs - not used by current port - // init debug leds - /* - DEBUG_LED_INIT(5); - DEBUG_LED_INIT(6); - DEBUG_LED_INIT(7); - */ - - return TRUE; -} - +/* + 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 + USB hardware layer + */ + +#include "type.h" + +#include "usbdebug.h" +#include "usbhw_lpc.h" +#include "usbapi.h" +// Configure LED pin functions +// +// LED pin functions +// +// Function Pin Port Bits Pin Select Register +// ------------------- --- ----- ---- ------------------- +// P2.0 GPIO Port 2.0 xx P2.0 1:0 PINSEL4 +// P2.1 GPIO Port 2.1 xx P2.1 3:2 PINSEL4 +// P2.2 GPIO Port 2.2 xx P2.2 5:4 PINSEL4 +// P2.3 GPIO Port 2.3 xx P2.3 7:6 PINSEL4 +// P2.4 GPIO Port 2.4 xx P2.4 9:8 PINSEL4 +// P2.5 GPIO Port 2.5 xx P2.5 11:10 PINSEL4 +// P2.6 GPIO Port 2.6 xx P2.6 13:12 PINSEL4 +// P2.7 GPIO Port 2.7 xx P2.7 15:14 PINSEL4 +// +// OFF - LED state 0 +// ON - LED state 1 +// +// '*' as GPIO + +#define NO_LEDS 8 + +#define LED_0 (1 << 0) +#define LED_1 (1 << 1) +#define LED_2 (1 << 2) +#define LED_3 (1 << 3) +#define LED_4 (1 << 4) +#define LED_5 (1 << 5) +#define LED_6 (1 << 6) +#define LED_7 (1 << 7) + +#ifdef DEBUG +// comment out the following line if you don't want to use debug LEDs +//#define DEBUG_LED +#endif + +#ifdef DEBUG_LED +#define DEBUG_LED_ON(x) FIO2SET = (1 << x); +#define DEBUG_LED_OFF(x) FIO2CLR = (1 << x); +#define DEBUG_LED_INIT(x) PINSEL2 &= ~(0x3 << (2*x)); FIO2DIR |= (1 << x); DEBUG_LED_OFF(x); +#else +#define DEBUG_LED_INIT(x) /**< LED initialisation macro */ +#define DEBUG_LED_ON(x) /**< turn LED on */ +#define DEBUG_LED_OFF(x) /**< turn LED off */ +#endif + +/** Installed device interrupt handler */ +static TFnDevIntHandler *_pfnDevIntHandler = NULL; +/** Installed endpoint interrupt handlers */ +static TFnEPIntHandler *_apfnEPIntHandlers[16]; +/** Installed frame interrupt handlers */ +static TFnFrameHandler *_pfnFrameHandler = NULL; + +/** convert from endpoint address to endpoint index */ +#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) +/** convert from endpoint index to endpoint address */ +#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) + + + +/** + Local function to wait for a device interrupt (and clear it) + + @param [in] dwIntr Bitmask of interrupts to wait for + */ +static void Wait4DevInt(u32 dwIntr) +{ + // wait for specific interrupt + while ((LPC_USB->USBDevIntSt & dwIntr) != dwIntr); + // clear the interrupt bits + LPC_USB->USBDevIntClr = dwIntr; +} + + +/** + Local function to send a command to the USB protocol engine + + @param [in] bCmd Command to send + */ +static void USBHwCmd(u8 bCmd) +{ + // clear CDFULL/CCEMTY + LPC_USB->USBDevIntClr = CDFULL | CCEMTY; + // write command code + LPC_USB->USBCmdCode = 0x00000500 | (bCmd << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command + data to the USB protocol engine + + @param [in] bCmd Command to send + @param [in] bData Data to send + */ +static void USBHwCmdWrite(u8 bCmd, u16 bData) +{ + // write command code + USBHwCmd(bCmd); + + // write command data + LPC_USB->USBCmdCode = 0x00000100 | (bData << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command to the USB protocol engine and read data + + @param [in] bCmd Command to send + + @return the data + */ +static u8 USBHwCmdRead(u8 bCmd) +{ + // write command code + USBHwCmd(bCmd); + + // get data + LPC_USB->USBCmdCode = 0x00000200 | (bCmd << 16); + Wait4DevInt(CDFULL); + return LPC_USB->USBCmdData; +} + + +/** + 'Realizes' an endpoint, meaning that buffer space is reserved for + it. An endpoint needs to be realised before it can be used. + + From experiments, it appears that a USB reset causes USBReEP to + re-initialise to 3 (= just the control endpoints). + However, a USB bus reset does not disturb the USBMaxPSize settings. + + @param [in] idx Endpoint index + @param [in] wMaxPSize Maximum packet size for this endpoint + */ +static void USBHwEPRealize(int idx, u16 wMaxPSize) +{ + LPC_USB->USBReEP |= (1 << idx); + LPC_USB->USBEpInd = idx; + LPC_USB->USBMaxPSize = wMaxPSize; + Wait4DevInt(EP_RLZED); +} + + +/** + Enables or disables an endpoint + + @param [in] idx Endpoint index + @param [in] fEnable TRUE to enable, FALSE to disable + */ +static void USBHwEPEnable(int idx, BOOL fEnable) +{ + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA); +} + + +/** + Configures an endpoint and enables it + + @param [in] bEP Endpoint number + @param [in] wMaxPacketSize Maximum packet size for this EP + */ +void USBHwEPConfig(u8 bEP, u16 wMaxPacketSize) +{ + int idx; + + idx = EP2IDX(bEP); + + // realise EP + USBHwEPRealize(idx, wMaxPacketSize); + + // enable EP + USBHwEPEnable(idx, TRUE); +} + + +/** + Registers an endpoint event callback + + @param [in] bEP Endpoint number + @param [in] pfnHandler Callback function + */ +void USBHwRegisterEPIntHandler(u8 bEP, TFnEPIntHandler *pfnHandler) +{ + int idx; + + idx = EP2IDX(bEP); + + ASSERT(idx<32); + + /* add handler to list of EP handlers */ + _apfnEPIntHandlers[idx / 2] = pfnHandler; + + /* enable EP interrupt */ + LPC_USB->USBEpIntEn |= (1 << idx); + LPC_USB->USBDevIntEn |= EP_SLOW; + + DBG("Registered handler for EP 0x%x\n", bEP); +} + + +/** + Registers an device status callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler) +{ + _pfnDevIntHandler = pfnHandler; + + // enable device interrupt + LPC_USB->USBDevIntEn |= DEV_STAT; + + DBG("Registered handler for device status\n"); +} + + +/** + Registers the frame callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler) +{ + _pfnFrameHandler = pfnHandler; + + // enable device interrupt + LPC_USB->USBDevIntEn |= FRAME; + + DBG("Registered handler for frame\n"); +} + + +/** + Sets the USB address. + + @param [in] bAddr Device address to set + */ +void USBHwSetAddress(u8 bAddr) +{ + USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr); +} + + +/** + Connects or disconnects from the USB bus + + @param [in] fConnect If TRUE, connect, otherwise disconnect + */ +void USBHwConnect(BOOL fConnect) +{ + USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0); +} + + +/** + Enables interrupt on NAK condition + + For IN endpoints a NAK is generated when the host wants to read data + from the device, but none is available in the endpoint buffer. + For OUT endpoints a NAK is generated when the host wants to write data + to the device, but the endpoint buffer is still full. + + The endpoint interrupt handlers can distinguish regular (ACK) interrupts + from NAK interrupt by checking the bits in their bEPStatus argument. + + @param [in] bIntBits Bitmap indicating which NAK interrupts to enable + */ +void USBHwNakIntEnable(u8 bIntBits) +{ + USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits); +} + + +/** + Gets the status from a specific endpoint. + + @param [in] bEP Endpoint number + @return Endpoint status byte (containing EP_STATUS_xxx bits) + */ +u8 USBHwEPGetStatus(u8 bEP) +{ + int idx = EP2IDX(bEP); + + return USBHwCmdRead(CMD_EP_SELECT | idx); +} + + +/** + Sets the stalled property of an endpoint + + @param [in] bEP Endpoint number + @param [in] fStall TRUE to stall, FALSE to unstall + */ +void USBHwEPStall(u8 bEP, BOOL fStall) +{ + int idx = EP2IDX(bEP); + + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0); +} + + +/** + Writes data to an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iLen Number of bytes to write + + @return TRUE if the data was successfully written or <0 in case of error. +*/ +int USBHwEPWrite(u8 bEP, u8 *pbBuf, int iLen) +{ + int idx; + + idx = EP2IDX(bEP); + + // set write enable for specific endpoint + LPC_USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2); + + // set packet length + LPC_USB->USBTxPLen = iLen; + + // write data + while (LPC_USB->USBCtrl & WR_EN) { + LPC_USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0]; + pbBuf += 4; + } + + // select endpoint and validate buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_VALIDATE_BUFFER); + + return iLen; +} + + +/** + Reads data from an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iMaxLen Maximum number of bytes to read + + @return the number of bytes available in the EP (possibly more than iMaxLen), + or <0 in case of error. + */ +int USBHwEPRead(u8 bEP, u8 *pbBuf, int iMaxLen) +{ + int i, idx; + u32 dwData, dwLen; + + idx = EP2IDX(bEP); + + // set read enable bit for specific endpoint + LPC_USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2); + + // wait for PKT_RDY + do { + dwLen = LPC_USB->USBRxPLen; + } while ((dwLen & PKT_RDY) == 0); + + // packet valid? + if ((dwLen & DV) == 0) { + return -1; + } + + // get length + dwLen &= PKT_LNGTH_MASK; + + // get data + dwData = 0; + for (i = 0; i < dwLen; i++) { + if ((i % 4) == 0) { + dwData = LPC_USB->USBRxData; + } + if ((pbBuf != NULL) && (i < iMaxLen)) { + pbBuf[i] = dwData & 0xFF; + } + dwData >>= 8; + } + + // make sure RD_EN is clear + LPC_USB->USBCtrl = 0; + + // select endpoint and clear buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_CLEAR_BUFFER); + + return dwLen; +} + + +/** + Sets the 'configured' state. + + All registered endpoints are 'realised' and enabled, and the + 'configured' bit is set in the device status register. + + @param [in] fConfigured If TRUE, configure device, else unconfigure + */ +void USBHwConfigDevice(BOOL fConfigured) +{ + // set configured bit + USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0); +} + + +/** + USB interrupt handler + + @todo Get all 11 bits of frame number instead of just 8 + + Endpoint interrupts are mapped to the slow interrupt + */ +void USBHwISR(void) +{ + u32 dwStatus; + u32 dwIntBit; + u8 bEPStat, bDevStat, bStat; + int i; + u16 wFrame; + + // LED9 monitors total time in interrupt routine + DEBUG_LED_ON(6); + + // handle device interrupts + dwStatus = LPC_USB->USBDevIntSt; + + // frame interrupt + if (dwStatus & FRAME) { + // clear int + LPC_USB->USBDevIntClr = FRAME; + // call handler + if (_pfnFrameHandler != NULL) { + wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); + _pfnFrameHandler(wFrame); + } + } + + // device status interrupt + if (dwStatus & DEV_STAT) { + /* Clear DEV_STAT interrupt before reading DEV_STAT register. + This prevents corrupted device status reads, see + LPC2148 User manual revision 2, 25 july 2006. + */ + LPC_USB->USBDevIntClr = DEV_STAT; + bDevStat = USBHwCmdRead(CMD_DEV_STATUS); + if (bDevStat & (CON_CH | SUS_CH | RST)) { + // convert device status into something HW independent + bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | + ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) | + ((bDevStat & RST) ? DEV_STATUS_RESET : 0); + // call handler + if (_pfnDevIntHandler != NULL) { + DEBUG_LED_ON(5); + _pfnDevIntHandler(bStat); + DEBUG_LED_OFF(5); + } + } + } + + // endpoint interrupt + if (dwStatus & EP_SLOW) { + // clear EP_SLOW + LPC_USB->USBDevIntClr = EP_SLOW; + // check all endpoints + for (i = 0; i < 32; i++) { + dwIntBit = (1 << i); + if (LPC_USB->USBEpIntSt & dwIntBit) { + // clear int (and retrieve status) + LPC_USB->USBEpIntClr = dwIntBit; + Wait4DevInt(CDFULL); + bEPStat = LPC_USB->USBCmdData; + // convert EP pipe stat into something HW independent + bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | + ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) | + ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | + ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) | + ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0); + // call handler + if (_apfnEPIntHandlers[i / 2] != NULL) { + DEBUG_LED_ON(7); + _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat); + DEBUG_LED_OFF(7); + } + } + } + } + + DEBUG_LED_OFF(6); +} + + + +/** + Initialises the USB hardware + + This function assumes that the hardware is connected as shown in + section 10.1 of the LPC2148 data sheet: + * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low. + * P0.23 is connected to USB VCC. + + Embedded artists board: make sure to disconnect P0.23 LED as it + acts as a pull-up and so prevents detection of USB disconnect. + + @return TRUE if the hardware was successfully initialised + */ +BOOL USBHwInit(void) +{ +/* CodeRed - comment out original code + * + // configure P0.23 for Vbus sense + PINSEL1 = (PINSEL1 & ~(3 << 14)) | (1 << 14); // P0.23 + // configure P0.31 for CONNECT + PINSEL1 = (PINSEL1 & ~(3 << 30)) | (2 << 30); // P0.31 +*/ + + // CodeRed - set up USB pins + + // P2.9 -> USB_CONNECT + LPC_PINCON->PINSEL4 &= ~0x000C0000; + LPC_PINCON->PINSEL4 |= 0x00040000; + + // P1.18 -> USB_UP_LED + // P1.30 -> VBUS + LPC_PINCON->PINSEL3 &= ~0x30000030; + LPC_PINCON->PINSEL3 |= 0x20000010; + + // P0.29 -> USB_D+ + // P0.30 -> USB_D- + LPC_PINCON->PINSEL1 &= ~0x3C000000; + LPC_PINCON->PINSEL1 |= 0x14000000; + + + // enable PUSB + LPC_SC->PCONP |= (1 << 31); + +/* CodeRed - Comment out original PLL code + * PLL now set up by NXP code in target.c within example projects + * + // initialise PLL + PLL1CON = 1; // enable PLL + PLL1CFG = (1 << 5) | 3; // P = 2, M = 4 + PLL1FEED = 0xAA; + PLL1FEED = 0x55; + while ((PLL1STAT & (1 << 10)) == 0); + + PLL1CON = 3; // enable and connect + PLL1FEED = 0xAA; + PLL1FEED = 0x55; + +*/ + + +// AWB added USB clock enable +// These are actually the USBClkCtrl and USBClkSt registers +// OTG_CLK_CTRL = 0x12; /* Dev clock, AHB clock enable */ +// while ((OTG_CLK_STAT & 0x12) != 0x12); + + LPC_USB->USBClkCtrl = 0x1A; /* Dev clock, AHB clock enable */ + while ((LPC_USB->USBClkSt & 0x1A) != 0x1A); + + + // disable/clear all interrupts for now + LPC_USB->USBDevIntEn = 0; + LPC_USB->USBDevIntClr = 0xFFFFFFFF; + LPC_USB->USBDevIntPri = 0; + + LPC_USB->USBEpIntEn = 0; + LPC_USB->USBEpIntClr = 0xFFFFFFFF; + LPC_USB->USBEpIntPri = 0; + + // by default, only ACKs generate interrupts + USBHwNakIntEnable(0); + + // CodeRed - commented out LEDs - not used by current port + // init debug leds + /* + DEBUG_LED_INIT(5); + DEBUG_LED_INIT(6); + DEBUG_LED_INIT(7); + */ + + return TRUE; +} diff --git a/src/platform/lpc17xx/usbstack/src/usbinit.c b/src/platform/lpc17xx/usbstack/src/usbinit.c index 90b9341d..41ea93fc 100644 --- a/src/platform/lpc17xx/usbstack/src/usbinit.c +++ b/src/platform/lpc17xx/usbstack/src/usbinit.c @@ -1,5 +1,5 @@ /* - LPCUSB, an USB device driver for LPC microcontrollers + 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 @@ -16,7 +16,7 @@ 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, + 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 @@ -30,24 +30,22 @@ USB stack initialisation */ -// CodeRed - include the LPCUSB type.h file rather than NXP one directly -//#include "type.h" -#include "lpcusb_type.h" +#include "type.h" #include "usbdebug.h" #include "usbapi.h" /** data storage area for standard requests */ -static U8 abStdReqData[8]; +static u8 abStdReqData[8]; /** USB reset handler - + @param [in] bDevStatus Device status */ -static void HandleUsbReset(U8 bDevStatus) +static void HandleUsbReset(u8 bDevStatus) { if (bDevStatus & DEV_STATUS_RESET) { DBG("\n!"); @@ -58,28 +56,27 @@ static void HandleUsbReset(U8 bDevStatus) /** Initialises the USB hardware and sets up the USB stack by installing default callbacks. - + @return TRUE if initialisation was successful */ BOOL USBInit(void) { // init hardware USBHwInit(); - + // register bus reset handler USBHwRegisterDevIntHandler(HandleUsbReset); - + // register control transfer handler on EP0 USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer); USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer); - + // setup control endpoints USBHwEPConfig(0x00, MAX_PACKET_SIZE0); USBHwEPConfig(0x80, MAX_PACKET_SIZE0); - + // register standard request handler USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData); return TRUE; } - diff --git a/src/platform/lpc17xx/usbstack/src/usbstdreq.c b/src/platform/lpc17xx/usbstack/src/usbstdreq.c index 5b159002..981cea8e 100644 --- a/src/platform/lpc17xx/usbstack/src/usbstdreq.c +++ b/src/platform/lpc17xx/usbstack/src/usbstdreq.c @@ -1,434 +1,431 @@ -/* - 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 -*/ - -// CodeRed - include the LPCUSB type.h file rather than NXP one directly -//#include "type.h" -#include "lpcusb_type.h" - -#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 U8 bConfiguration = 0; -/** Installed custom request handler */ -static TFnHandleRequest *pfnHandleCustomReq = NULL; -/** Pointer to registered descriptors */ -static const U8 *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 U8 *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(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData) -{ - U8 bType, bIndex; - U8 *pab; - int iCurIndex; - - ASSERT(pabDescrip != NULL); - - bType = GET_DESC_TYPE(wTypeIndex); - bIndex = GET_DESC_INDEX(wTypeIndex); - - pab = (U8 *)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(U8 bConfigIndex, U8 bAltSetting) -{ - U8 *pab; - U8 bCurConfig, bCurAltSetting; - U8 bEP; - U16 wMaxPktSize; - - ASSERT(pabDescrip != NULL); - - if (bConfigIndex == 0) { - // unconfigure device - USBHwConfigDevice(FALSE); - } - else { - // configure endpoints for this configuration/altsetting - pab = (U8 *)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, U8 **ppbData) -{ - U8 *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, U8 **ppbData) -{ - U8 *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, U8 **ppbData) -{ - U8 *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, U8 **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; -} - +/* + 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 "type.h" + +#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 u8 bConfiguration = 0; +/** Installed custom request handler */ +static TFnHandleRequest *pfnHandleCustomReq = NULL; +/** Pointer to registered descriptors */ +static const u8 *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 u8 *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(u16 wTypeIndex, u16 wLangID, int *piLen, u8 **ppbData) +{ + u8 bType, bIndex; + u8 *pab; + int iCurIndex; + + ASSERT(pabDescrip != NULL); + + bType = GET_DESC_TYPE(wTypeIndex); + bIndex = GET_DESC_INDEX(wTypeIndex); + + pab = (u8 *)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(u8 bConfigIndex, u8 bAltSetting) +{ + u8 *pab; + u8 bCurConfig, bCurAltSetting; + u8 bEP; + u16 wMaxPktSize; + + ASSERT(pabDescrip != NULL); + + if (bConfigIndex == 0) { + // unconfigure device + USBHwConfigDevice(FALSE); + } + else { + // configure endpoints for this configuration/altsetting + pab = (u8 *)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, u8 **ppbData) +{ + u8 *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, u8 **ppbData) +{ + u8 *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, u8 **ppbData) +{ + u8 *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, u8 **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; +}