+++ /dev/null
-/*\r
- LPCUSB, an USB device driver for LPC microcontrollers\r
- Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)\r
-\r
- Redistribution and use in source and binary forms, with or without\r
- modification, are permitted provided that the following conditions are met:\r
-\r
- 1. Redistributions of source code must retain the above copyright\r
- notice, this list of conditions and the following disclaimer.\r
- 2. Redistributions in binary form must reproduce the above copyright\r
- notice, this list of conditions and the following disclaimer in the\r
- documentation and/or other materials provided with the distribution.\r
- 3. The name of the author may not be used to endorse or promote products\r
- derived from this software without specific prior written permission.\r
-\r
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-*/\r
-\r
-\r
-/** @file\r
- USB hardware layer\r
- */\r
-\r
-\r
-#include "usbdebug.h"\r
-#include "usbhw_lpc.h"\r
-#include "usbapi.h"\r
-\r
-/** Installed device interrupt handler */\r
-static TFnDevIntHandler *_pfnDevIntHandler = NULL;\r
-/** Installed endpoint interrupt handlers */\r
-static TFnEPIntHandler *_apfnEPIntHandlers[16];\r
-/** Installed frame interrupt handlers */\r
-static TFnFrameHandler *_pfnFrameHandler = NULL;\r
-\r
-/** convert from endpoint address to endpoint index */\r
-#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))\r
-/** convert from endpoint index to endpoint address */\r
-#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))\r
-\r
-\r
-\r
-/**\r
- Local function to wait for a device interrupt (and clear it)\r
-\r
- @param [in] dwIntr Bitmask of interrupts to wait for\r
- */\r
-static void Wait4DevInt(unsigned long dwIntr)\r
-{\r
- // wait for specific interrupt\r
- while ((USB->USBDevIntSt & dwIntr) != dwIntr);\r
- // clear the interrupt bits\r
- USB->USBDevIntClr = dwIntr;\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command to the USB protocol engine\r
-\r
- @param [in] bCmd Command to send\r
- */\r
-static void USBHwCmd(unsigned char bCmd)\r
-{\r
- // clear CDFULL/CCEMTY\r
- USB->USBDevIntClr = CDFULL | CCEMTY;\r
- // write command code\r
- USB->USBCmdCode = 0x00000500 | (bCmd << 16);\r
- Wait4DevInt(CCEMTY);\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command + data to the USB protocol engine\r
-\r
- @param [in] bCmd Command to send\r
- @param [in] bData Data to send\r
- */\r
-static void USBHwCmdWrite(unsigned char bCmd, unsigned short bData)\r
-{\r
- // write command code\r
- USBHwCmd(bCmd);\r
-\r
- // write command data\r
- USB->USBCmdCode = 0x00000100 | (bData << 16);\r
- Wait4DevInt(CCEMTY);\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command to the USB protocol engine and read data\r
-\r
- @param [in] bCmd Command to send\r
-\r
- @return the data\r
- */\r
-static unsigned char USBHwCmdRead(unsigned char bCmd)\r
-{\r
- // write command code\r
- USBHwCmd(bCmd);\r
-\r
- // get data\r
- USB->USBCmdCode = 0x00000200 | (bCmd << 16);\r
- Wait4DevInt(CDFULL);\r
- return USB->USBCmdData;\r
-}\r
-\r
-\r
-/**\r
- 'Realizes' an endpoint, meaning that buffer space is reserved for\r
- it. An endpoint needs to be realised before it can be used.\r
-\r
- From experiments, it appears that a USB reset causes USBReEP to\r
- re-initialise to 3 (= just the control endpoints).\r
- However, a USB bus reset does not disturb the USBMaxPSize settings.\r
-\r
- @param [in] idx Endpoint index\r
- @param [in] wMaxPSize Maximum packet size for this endpoint\r
- */\r
-static void USBHwEPRealize(int idx, unsigned short wMaxPSize)\r
-{\r
- USB->USBReEP |= (1 << idx);\r
- USB->USBEpInd = idx;\r
- USB->USBMaxPSize = wMaxPSize;\r
- Wait4DevInt(EP_RLZED);\r
-}\r
-\r
-\r
-/**\r
- Enables or disables an endpoint\r
-\r
- @param [in] idx Endpoint index\r
- @param [in] fEnable TRUE to enable, FALSE to disable\r
- */\r
-static void USBHwEPEnable(int idx, BOOL fEnable)\r
-{\r
- USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);\r
-}\r
-\r
-\r
-/**\r
- Configures an endpoint and enables it\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] wMaxPacketSize Maximum packet size for this EP\r
- */\r
-void USBHwEPConfig(unsigned char bEP, unsigned short wMaxPacketSize)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // realise EP\r
- USBHwEPRealize(idx, wMaxPacketSize);\r
-\r
- // enable EP\r
- USBHwEPEnable(idx, TRUE);\r
-}\r
-\r
-\r
-/**\r
- Registers an endpoint event callback\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterEPIntHandler(unsigned char bEP, TFnEPIntHandler *pfnHandler)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- ASSERT(idx<32);\r
-\r
- /* add handler to list of EP handlers */\r
- _apfnEPIntHandlers[idx / 2] = pfnHandler;\r
-\r
- /* enable EP interrupt */\r
- USB->USBEpIntEn |= (1 << idx);\r
- USB->USBDevIntEn |= EP_SLOW;\r
-\r
- DBG("Registered handler for EP 0x%x\n", bEP);\r
-}\r
-\r
-\r
-/**\r
- Registers an device status callback\r
-\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)\r
-{\r
- _pfnDevIntHandler = pfnHandler;\r
-\r
- // enable device interrupt\r
- USB->USBDevIntEn |= DEV_STAT;\r
-\r
- DBG("Registered handler for device status\n");\r
-}\r
-\r
-\r
-/**\r
- Registers the frame callback\r
-\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)\r
-{\r
- _pfnFrameHandler = pfnHandler;\r
-\r
- // enable device interrupt\r
- USB->USBDevIntEn |= FRAME;\r
-\r
- DBG("Registered handler for frame\n");\r
-}\r
-\r
-\r
-/**\r
- Sets the USB address.\r
-\r
- @param [in] bAddr Device address to set\r
- */\r
-void USBHwSetAddress(unsigned char bAddr)\r
-{\r
- USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);\r
-}\r
-\r
-\r
-/**\r
- Connects or disconnects from the USB bus\r
-\r
- @param [in] fConnect If TRUE, connect, otherwise disconnect\r
- */\r
-void USBHwConnect(BOOL fConnect)\r
-{\r
- USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);\r
-}\r
-\r
-\r
-/**\r
- Enables interrupt on NAK condition\r
-\r
- For IN endpoints a NAK is generated when the host wants to read data\r
- from the device, but none is available in the endpoint buffer.\r
- For OUT endpoints a NAK is generated when the host wants to write data\r
- to the device, but the endpoint buffer is still full.\r
-\r
- The endpoint interrupt handlers can distinguish regular (ACK) interrupts\r
- from NAK interrupt by checking the bits in their bEPStatus argument.\r
-\r
- @param [in] bIntBits Bitmap indicating which NAK interrupts to enable\r
- */\r
-void USBHwNakIntEnable(unsigned char bIntBits)\r
-{\r
- USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);\r
-}\r
-\r
-\r
-/**\r
- Gets the status from a specific endpoint.\r
-\r
- @param [in] bEP Endpoint number\r
- @return Endpoint status byte (containing EP_STATUS_xxx bits)\r
- */\r
-unsigned char USBHwEPGetStatus(unsigned char bEP)\r
-{\r
- int idx = EP2IDX(bEP);\r
-\r
- return USBHwCmdRead(CMD_EP_SELECT | idx);\r
-}\r
-\r
-\r
-/**\r
- Sets the stalled property of an endpoint\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] fStall TRUE to stall, FALSE to unstall\r
- */\r
-void USBHwEPStall(unsigned char bEP, BOOL fStall)\r
-{\r
- int idx = EP2IDX(bEP);\r
-\r
- USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);\r
-}\r
-\r
-\r
-/**\r
- Writes data to an endpoint buffer\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pbBuf Endpoint data\r
- @param [in] iLen Number of bytes to write\r
-\r
- @return TRUE if the data was successfully written or <0 in case of error.\r
-*/\r
-int USBHwEPWrite(unsigned char bEP, unsigned char *pbBuf, int iLen)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // set write enable for specific endpoint\r
- USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2);\r
-\r
- // set packet length\r
- USB->USBTxPLen = iLen;\r
-\r
- // write data\r
- while (USB->USBCtrl & WR_EN) {\r
- USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];\r
- pbBuf += 4;\r
- }\r
-\r
- // select endpoint and validate buffer\r
- USBHwCmd(CMD_EP_SELECT | idx);\r
- USBHwCmd(CMD_EP_VALIDATE_BUFFER);\r
-\r
- return iLen;\r
-}\r
-\r
-\r
-/**\r
- Reads data from an endpoint buffer\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pbBuf Endpoint data\r
- @param [in] iMaxLen Maximum number of bytes to read\r
-\r
- @return the number of bytes available in the EP (possibly more than iMaxLen),\r
- or <0 in case of error.\r
- */\r
-int USBHwEPRead(unsigned char bEP, unsigned char *pbBuf, int iMaxLen)\r
-{\r
- unsigned int i, idx;\r
- unsigned long dwData, dwLen;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // set read enable bit for specific endpoint\r
- USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2);\r
-\r
- // wait for PKT_RDY\r
- do {\r
- dwLen = USB->USBRxPLen;\r
- } while ((dwLen & PKT_RDY) == 0);\r
-\r
- // packet valid?\r
- if ((dwLen & DV) == 0) {\r
- return -1;\r
- }\r
-\r
- // get length\r
- dwLen &= PKT_LNGTH_MASK;\r
-\r
- // get data\r
- dwData = 0;\r
- for (i = 0; i < dwLen; i++) {\r
- if ((i % 4) == 0) {\r
- dwData = USB->USBRxData;\r
- }\r
- if ((pbBuf != NULL) && (i < iMaxLen)) {\r
- pbBuf[i] = dwData & 0xFF;\r
- }\r
- dwData >>= 8;\r
- }\r
-\r
- // make sure RD_EN is clear\r
- USB->USBCtrl = 0;\r
-\r
- // select endpoint and clear buffer\r
- USBHwCmd(CMD_EP_SELECT | idx);\r
- USBHwCmd(CMD_EP_CLEAR_BUFFER);\r
-\r
- return dwLen;\r
-}\r
-\r
-\r
-/**\r
- Sets the 'configured' state.\r
-\r
- All registered endpoints are 'realised' and enabled, and the\r
- 'configured' bit is set in the device status register.\r
-\r
- @param [in] fConfigured If TRUE, configure device, else unconfigure\r
- */\r
-void USBHwConfigDevice(BOOL fConfigured)\r
-{\r
- // set configured bit\r
- USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);\r
-}\r
-\r
-\r
-/**\r
- USB interrupt handler\r
-\r
- @todo Get all 11 bits of frame number instead of just 8\r
-\r
- Endpoint interrupts are mapped to the slow interrupt\r
- */\r
-void USBHwISR(void)\r
-{\r
- unsigned long dwStatus;\r
- unsigned long dwIntBit;\r
- unsigned char bEPStat, bDevStat, bStat;\r
- int i;\r
- unsigned short wFrame;\r
-\r
- // handle device interrupts\r
- dwStatus = USB->USBDevIntSt;\r
-\r
- // frame interrupt\r
- if (dwStatus & FRAME) {\r
- // clear int\r
- USB->USBDevIntClr = FRAME;\r
- // call handler\r
- if (_pfnFrameHandler != NULL) {\r
- wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR);\r
- _pfnFrameHandler(wFrame);\r
- }\r
- }\r
-\r
- // device status interrupt\r
- if (dwStatus & DEV_STAT) {\r
- /* Clear DEV_STAT interrupt before reading DEV_STAT register.\r
- This prevents corrupted device status reads, see\r
- LPC2148 User manual revision 2, 25 july 2006.\r
- */\r
- USB->USBDevIntClr = DEV_STAT;\r
- bDevStat = USBHwCmdRead(CMD_DEV_STATUS);\r
- if (bDevStat & (CON_CH | SUS_CH | RST)) {\r
- // convert device status into something HW independent\r
- bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |\r
- ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |\r
- ((bDevStat & RST) ? DEV_STATUS_RESET : 0);\r
- // call handler\r
- if (_pfnDevIntHandler != NULL) {\r
- _pfnDevIntHandler(bStat);\r
- }\r
- }\r
- }\r
-\r
- // endpoint interrupt\r
- if (dwStatus & EP_SLOW) {\r
- // clear EP_SLOW\r
- USB->USBDevIntClr = EP_SLOW;\r
- // check all endpoints\r
- for (i = 0; i < 32; i++) {\r
- dwIntBit = (1 << i);\r
- if (USB->USBEpIntSt & dwIntBit) {\r
- // clear int (and retrieve status)\r
- USB->USBEpIntClr = dwIntBit;\r
- Wait4DevInt(CDFULL);\r
- bEPStat = USB->USBCmdData;\r
- // convert EP pipe stat into something HW independent\r
- bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |\r
- ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |\r
- ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r
- ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r
- ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);\r
- // call handler\r
- if (_apfnEPIntHandlers[i / 2] != NULL) {\r
- _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-\r
-\r
-/**\r
- Initialises the USB hardware\r
-\r
-\r
- @return TRUE if the hardware was successfully initialised\r
- */\r
-BOOL USBHwInit(void)\r
-{\r
- // P2.9 -> USB_CONNECT\r
- PINCON->PINSEL4 &= ~0x000C0000;\r
- PINCON->PINSEL4 |= 0x00040000;\r
-\r
- // P1.18 -> USB_UP_LED\r
- // P1.30 -> VBUS\r
- PINCON->PINSEL3 &= ~0x30000030;\r
- PINCON->PINSEL3 |= 0x20000010;\r
-\r
- // P0.29 -> USB_D+\r
- // P0.30 -> USB_D-\r
- PINCON->PINSEL1 &= ~0x3C000000;\r
- PINCON->PINSEL1 |= 0x14000000;\r
-\r
- // enable PUSB\r
- SC->PCONP |= (1 << 31);\r
-\r
- USB->OTGClkCtrl = 0x12; /* Dev clock, AHB clock enable */\r
- while ((USB->OTGClkSt & 0x12) != 0x12);\r
-\r
- // disable/clear all interrupts for now\r
- USB->USBDevIntEn = 0;\r
- USB->USBDevIntClr = 0xFFFFFFFF;\r
- USB->USBDevIntPri = 0;\r
-\r
- USB->USBEpIntEn = 0;\r
- USB->USBEpIntClr = 0xFFFFFFFF;\r
- USB->USBEpIntPri = 0;\r
-\r
- // by default, only ACKs generate interrupts\r
- USBHwNakIntEnable(0);\r
-\r
- return TRUE;\r
-}\r
-\r
+++ /dev/null
-/*\r
- LPCUSB, an USB device driver for LPC microcontrollers\r
- Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)\r
-\r
- Redistribution and use in source and binary forms, with or without\r
- modification, are permitted provided that the following conditions are met:\r
-\r
- 1. Redistributions of source code must retain the above copyright\r
- notice, this list of conditions and the following disclaimer.\r
- 2. Redistributions in binary form must reproduce the above copyright\r
- notice, this list of conditions and the following disclaimer in the\r
- documentation and/or other materials provided with the distribution.\r
- 3. The name of the author may not be used to endorse or promote products\r
- derived from this software without specific prior written permission.\r
-\r
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-*/\r
-\r
-\r
-/** @file\r
- USB hardware layer\r
- */\r
-\r
-\r
-#include "usbdebug.h"\r
-#include "usbhw_lpc.h"\r
-#include "usbapi.h"\r
-\r
-/** Installed device interrupt handler */\r
-static TFnDevIntHandler *_pfnDevIntHandler = NULL;\r
-/** Installed endpoint interrupt handlers */\r
-static TFnEPIntHandler *_apfnEPIntHandlers[16];\r
-/** Installed frame interrupt handlers */\r
-static TFnFrameHandler *_pfnFrameHandler = NULL;\r
-\r
-/** convert from endpoint address to endpoint index */\r
-#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))\r
-/** convert from endpoint index to endpoint address */\r
-#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))\r
-\r
-\r
-\r
-/**\r
- Local function to wait for a device interrupt (and clear it)\r
-\r
- @param [in] dwIntr Bitmask of interrupts to wait for\r
- */\r
-static void Wait4DevInt(unsigned long dwIntr)\r
-{\r
- // wait for specific interrupt\r
- while ((USB->USBDevIntSt & dwIntr) != dwIntr);\r
- // clear the interrupt bits\r
- USB->USBDevIntClr = dwIntr;\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command to the USB protocol engine\r
-\r
- @param [in] bCmd Command to send\r
- */\r
-static void USBHwCmd(unsigned char bCmd)\r
-{\r
- // clear CDFULL/CCEMTY\r
- USB->USBDevIntClr = CDFULL | CCEMTY;\r
- // write command code\r
- USB->USBCmdCode = 0x00000500 | (bCmd << 16);\r
- Wait4DevInt(CCEMTY);\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command + data to the USB protocol engine\r
-\r
- @param [in] bCmd Command to send\r
- @param [in] bData Data to send\r
- */\r
-static void USBHwCmdWrite(unsigned char bCmd, unsigned short bData)\r
-{\r
- // write command code\r
- USBHwCmd(bCmd);\r
-\r
- // write command data\r
- USB->USBCmdCode = 0x00000100 | (bData << 16);\r
- Wait4DevInt(CCEMTY);\r
-}\r
-\r
-\r
-/**\r
- Local function to send a command to the USB protocol engine and read data\r
-\r
- @param [in] bCmd Command to send\r
-\r
- @return the data\r
- */\r
-static unsigned char USBHwCmdRead(unsigned char bCmd)\r
-{\r
- // write command code\r
- USBHwCmd(bCmd);\r
-\r
- // get data\r
- USB->USBCmdCode = 0x00000200 | (bCmd << 16);\r
- Wait4DevInt(CDFULL);\r
- return USB->USBCmdData;\r
-}\r
-\r
-\r
-/**\r
- 'Realizes' an endpoint, meaning that buffer space is reserved for\r
- it. An endpoint needs to be realised before it can be used.\r
-\r
- From experiments, it appears that a USB reset causes USBReEP to\r
- re-initialise to 3 (= just the control endpoints).\r
- However, a USB bus reset does not disturb the USBMaxPSize settings.\r
-\r
- @param [in] idx Endpoint index\r
- @param [in] wMaxPSize Maximum packet size for this endpoint\r
- */\r
-static void USBHwEPRealize(int idx, unsigned short wMaxPSize)\r
-{\r
- USB->USBReEP |= (1 << idx);\r
- USB->USBEpInd = idx;\r
- USB->USBMaxPSize = wMaxPSize;\r
- Wait4DevInt(EP_RLZED);\r
-}\r
-\r
-\r
-/**\r
- Enables or disables an endpoint\r
-\r
- @param [in] idx Endpoint index\r
- @param [in] fEnable TRUE to enable, FALSE to disable\r
- */\r
-static void USBHwEPEnable(int idx, BOOL fEnable)\r
-{\r
- USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);\r
-}\r
-\r
-\r
-/**\r
- Configures an endpoint and enables it\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] wMaxPacketSize Maximum packet size for this EP\r
- */\r
-void USBHwEPConfig(unsigned char bEP, unsigned short wMaxPacketSize)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // realise EP\r
- USBHwEPRealize(idx, wMaxPacketSize);\r
-\r
- // enable EP\r
- USBHwEPEnable(idx, TRUE);\r
-}\r
-\r
-\r
-/**\r
- Registers an endpoint event callback\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterEPIntHandler(unsigned char bEP, TFnEPIntHandler *pfnHandler)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- ASSERT(idx<32);\r
-\r
- /* add handler to list of EP handlers */\r
- _apfnEPIntHandlers[idx / 2] = pfnHandler;\r
-\r
- /* enable EP interrupt */\r
- USB->USBEpIntEn |= (1 << idx);\r
- USB->USBDevIntEn |= EP_SLOW;\r
-\r
- DBG("Registered handler for EP 0x%x\n", bEP);\r
-}\r
-\r
-\r
-/**\r
- Registers an device status callback\r
-\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)\r
-{\r
- _pfnDevIntHandler = pfnHandler;\r
-\r
- // enable device interrupt\r
- USB->USBDevIntEn |= DEV_STAT;\r
-\r
- DBG("Registered handler for device status\n");\r
-}\r
-\r
-\r
-/**\r
- Registers the frame callback\r
-\r
- @param [in] pfnHandler Callback function\r
- */\r
-void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)\r
-{\r
- _pfnFrameHandler = pfnHandler;\r
-\r
- // enable device interrupt\r
- USB->USBDevIntEn |= FRAME;\r
-\r
- DBG("Registered handler for frame\n");\r
-}\r
-\r
-\r
-/**\r
- Sets the USB address.\r
-\r
- @param [in] bAddr Device address to set\r
- */\r
-void USBHwSetAddress(unsigned char bAddr)\r
-{\r
- USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);\r
-}\r
-\r
-\r
-/**\r
- Connects or disconnects from the USB bus\r
-\r
- @param [in] fConnect If TRUE, connect, otherwise disconnect\r
- */\r
-void USBHwConnect(BOOL fConnect)\r
-{\r
- USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);\r
-}\r
-\r
-\r
-/**\r
- Enables interrupt on NAK condition\r
-\r
- For IN endpoints a NAK is generated when the host wants to read data\r
- from the device, but none is available in the endpoint buffer.\r
- For OUT endpoints a NAK is generated when the host wants to write data\r
- to the device, but the endpoint buffer is still full.\r
-\r
- The endpoint interrupt handlers can distinguish regular (ACK) interrupts\r
- from NAK interrupt by checking the bits in their bEPStatus argument.\r
-\r
- @param [in] bIntBits Bitmap indicating which NAK interrupts to enable\r
- */\r
-void USBHwNakIntEnable(unsigned char bIntBits)\r
-{\r
- USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);\r
-}\r
-\r
-\r
-/**\r
- Gets the status from a specific endpoint.\r
-\r
- @param [in] bEP Endpoint number\r
- @return Endpoint status byte (containing EP_STATUS_xxx bits)\r
- */\r
-unsigned char USBHwEPGetStatus(unsigned char bEP)\r
-{\r
- int idx = EP2IDX(bEP);\r
-\r
- return USBHwCmdRead(CMD_EP_SELECT | idx);\r
-}\r
-\r
-\r
-/**\r
- Sets the stalled property of an endpoint\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] fStall TRUE to stall, FALSE to unstall\r
- */\r
-void USBHwEPStall(unsigned char bEP, BOOL fStall)\r
-{\r
- int idx = EP2IDX(bEP);\r
-\r
- USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);\r
-}\r
-\r
-\r
-/**\r
- Writes data to an endpoint buffer\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pbBuf Endpoint data\r
- @param [in] iLen Number of bytes to write\r
-\r
- @return TRUE if the data was successfully written or <0 in case of error.\r
-*/\r
-int USBHwEPWrite(unsigned char bEP, unsigned char *pbBuf, int iLen)\r
-{\r
- int idx;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // set write enable for specific endpoint\r
- USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2);\r
-\r
- // set packet length\r
- USB->USBTxPLen = iLen;\r
-\r
- // write data\r
- while (USB->USBCtrl & WR_EN) {\r
- USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];\r
- pbBuf += 4;\r
- }\r
-\r
- // select endpoint and validate buffer\r
- USBHwCmd(CMD_EP_SELECT | idx);\r
- USBHwCmd(CMD_EP_VALIDATE_BUFFER);\r
-\r
- return iLen;\r
-}\r
-\r
-\r
-/**\r
- Reads data from an endpoint buffer\r
-\r
- @param [in] bEP Endpoint number\r
- @param [in] pbBuf Endpoint data\r
- @param [in] iMaxLen Maximum number of bytes to read\r
-\r
- @return the number of bytes available in the EP (possibly more than iMaxLen),\r
- or <0 in case of error.\r
- */\r
-int USBHwEPRead(unsigned char bEP, unsigned char *pbBuf, int iMaxLen)\r
-{\r
- unsigned int i, idx;\r
- unsigned long dwData, dwLen;\r
-\r
- idx = EP2IDX(bEP);\r
-\r
- // set read enable bit for specific endpoint\r
- USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2);\r
-\r
- // wait for PKT_RDY\r
- do {\r
- dwLen = USB->USBRxPLen;\r
- } while ((dwLen & PKT_RDY) == 0);\r
-\r
- // packet valid?\r
- if ((dwLen & DV) == 0) {\r
- return -1;\r
- }\r
-\r
- // get length\r
- dwLen &= PKT_LNGTH_MASK;\r
-\r
- // get data\r
- dwData = 0;\r
- for (i = 0; i < dwLen; i++) {\r
- if ((i % 4) == 0) {\r
- dwData = USB->USBRxData;\r
- }\r
- if ((pbBuf != NULL) && (i < iMaxLen)) {\r
- pbBuf[i] = dwData & 0xFF;\r
- }\r
- dwData >>= 8;\r
- }\r
-\r
- // make sure RD_EN is clear\r
- USB->USBCtrl = 0;\r
-\r
- // select endpoint and clear buffer\r
- USBHwCmd(CMD_EP_SELECT | idx);\r
- USBHwCmd(CMD_EP_CLEAR_BUFFER);\r
-\r
- return dwLen;\r
-}\r
-\r
-\r
-/**\r
- Sets the 'configured' state.\r
-\r
- All registered endpoints are 'realised' and enabled, and the\r
- 'configured' bit is set in the device status register.\r
-\r
- @param [in] fConfigured If TRUE, configure device, else unconfigure\r
- */\r
-void USBHwConfigDevice(BOOL fConfigured)\r
-{\r
- // set configured bit\r
- USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);\r
-}\r
-\r
-\r
-/**\r
- USB interrupt handler\r
-\r
- @todo Get all 11 bits of frame number instead of just 8\r
-\r
- Endpoint interrupts are mapped to the slow interrupt\r
- */\r
-void USBHwISR(void)\r
-{\r
- unsigned long dwStatus;\r
- unsigned long dwIntBit;\r
- unsigned char bEPStat, bDevStat, bStat;\r
- int i;\r
- unsigned short wFrame;\r
-\r
- // handle device interrupts\r
- dwStatus = USB->USBDevIntSt;\r
-\r
- // frame interrupt\r
- if (dwStatus & FRAME) {\r
- // clear int\r
- USB->USBDevIntClr = FRAME;\r
- // call handler\r
- if (_pfnFrameHandler != NULL) {\r
- wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR);\r
- _pfnFrameHandler(wFrame);\r
- }\r
- }\r
-\r
- // device status interrupt\r
- if (dwStatus & DEV_STAT) {\r
- /* Clear DEV_STAT interrupt before reading DEV_STAT register.\r
- This prevents corrupted device status reads, see\r
- LPC2148 User manual revision 2, 25 july 2006.\r
- */\r
- USB->USBDevIntClr = DEV_STAT;\r
- bDevStat = USBHwCmdRead(CMD_DEV_STATUS);\r
- if (bDevStat & (CON_CH | SUS_CH | RST)) {\r
- // convert device status into something HW independent\r
- bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |\r
- ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |\r
- ((bDevStat & RST) ? DEV_STATUS_RESET : 0);\r
- // call handler\r
- if (_pfnDevIntHandler != NULL) {\r
- _pfnDevIntHandler(bStat);\r
- }\r
- }\r
- }\r
-\r
- // endpoint interrupt\r
- if (dwStatus & EP_SLOW) {\r
- // clear EP_SLOW\r
- USB->USBDevIntClr = EP_SLOW;\r
- // check all endpoints\r
- for (i = 0; i < 32; i++) {\r
- dwIntBit = (1 << i);\r
- if (USB->USBEpIntSt & dwIntBit) {\r
- // clear int (and retrieve status)\r
- USB->USBEpIntClr = dwIntBit;\r
- Wait4DevInt(CDFULL);\r
- bEPStat = USB->USBCmdData;\r
- // convert EP pipe stat into something HW independent\r
- bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |\r
- ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |\r
- ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |\r
- ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |\r
- ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);\r
- // call handler\r
- if (_apfnEPIntHandlers[i / 2] != NULL) {\r
- _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-\r
-\r
-/**\r
- Initialises the USB hardware\r
-\r
-\r
- @return TRUE if the hardware was successfully initialised\r
- */\r
-BOOL USBHwInit(void)\r
-{\r
- // P2.9 -> USB_CONNECT\r
- PINCON->PINSEL4 &= ~0x000C0000;\r
- PINCON->PINSEL4 |= 0x00040000;\r
-\r
- // P1.18 -> USB_UP_LED\r
- // P1.30 -> VBUS\r
- PINCON->PINSEL3 &= ~0x30000030;\r
- PINCON->PINSEL3 |= 0x20000010;\r
-\r
- // P0.29 -> USB_D+\r
- // P0.30 -> USB_D-\r
- PINCON->PINSEL1 &= ~0x3C000000;\r
- PINCON->PINSEL1 |= 0x14000000;\r
-\r
- // enable PUSB\r
- SC->PCONP |= (1 << 31);\r
-\r
- USB->OTGClkCtrl = 0x12; /* Dev clock, AHB clock enable */\r
- while ((USB->OTGClkSt & 0x12) != 0x12);\r
-\r
- // disable/clear all interrupts for now\r
- USB->USBDevIntEn = 0;\r
- USB->USBDevIntClr = 0xFFFFFFFF;\r
- USB->USBDevIntPri = 0;\r
-\r
- USB->USBEpIntEn = 0;\r
- USB->USBEpIntClr = 0xFFFFFFFF;\r
- USB->USBEpIntPri = 0;\r
-\r
- // by default, only ACKs generate interrupts\r
- USBHwNakIntEnable(0);\r
-\r
- return TRUE;\r
-}\r
-\r