/* LPCUSB, an USB device driver for LPC microcontrollers Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* This is a very simple custom device (not belonging to a specific USB class). It implements primitive read and write in the ARM memory space. Each transfer is initiated by a control transfer to inform the device about the address and size of the following data transfer. The data transfer takes place over a bulk endpoint (BULK_IN_EP for reads and BULK_OUT_EP for writes). This example can be used to measure USB transfer speed. */ #include "type.h" #include "usbdebug.h" #include "console.h" #include "usbapi.h" #include "startup.h" #define BULK_IN_EP 0x82 #define BULK_OUT_EP 0x05 #define MAX_PACKET_SIZE 64 #define LE_WORD(x) ((x)&0xFF),((x)>>8) static const U8 abDescriptors[] = { /* Device descriptor */ 0x12, DESC_DEVICE, LE_WORD(0x0200), // bcdUSB 0xFF, // bDeviceClass 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol MAX_PACKET_SIZE0, // bMaxPacketSize LE_WORD(0xFFFF), // idVendor LE_WORD(0x0004), // idProduct LE_WORD(0x0100), // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x03, // iSerialNumber 0x01, // bNumConfigurations // configuration 0x09, DESC_CONFIGURATION, LE_WORD(0x20), // wTotalLength 0x01, // bNumInterfaces 0x01, // bConfigurationValue 0x00, // iConfiguration 0x80, // bmAttributes 0x32, // bMaxPower // interface 0x09, DESC_INTERFACE, 0x00, // bInterfaceNumber 0x00, // bAlternateSetting 0x02, // bNumEndPoints 0xFF, // bInterfaceClass 0x00, // bInterfaceSubClass 0x00, // bInterfaceProtocol 0x00, // iInterface // bulk in 0x07, DESC_ENDPOINT, BULK_IN_EP, // bEndpointAddress 0x02, // bmAttributes = BULK LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize 0, // bInterval // bulk out 0x07, DESC_ENDPOINT, BULK_OUT_EP, // bEndpointAddress 0x02, // bmAttributes = BULK LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize 0, // bInterval // string descriptors 0x04, DESC_STRING, LE_WORD(0x0409), // manufacturer string 0x0E, DESC_STRING, 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0, // product string 0x1A, DESC_STRING, 'M', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 'A', 0, 'c', 0, 'c', 0, 'e', 0, 's', 0, 's', 0, // serial number string 0x12, DESC_STRING, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0, // terminator 0 }; typedef struct { U32 dwAddress; U32 dwLength; } TMemoryCmd; static TMemoryCmd MemoryCmd; static U8 abVendorReqData[sizeof(TMemoryCmd)]; static U8 buffer[8192]; static void _HandleBulkIn(U8 bEP, U8 bEPStatus) { int iChunk; iChunk = MIN(MAX_PACKET_SIZE, MemoryCmd.dwLength); if (iChunk == 0) { DBG("_HandleBulkIn done\n"); return; } // send next part USBHwEPWrite(bEP, (U8 *)MemoryCmd.dwAddress, iChunk); MemoryCmd.dwAddress += iChunk; MemoryCmd.dwLength -= iChunk; // limit address range to prevent abort MemoryCmd.dwAddress &= ~(-512 * 1024); } void dump_packet(U32 addr,U32 len,U8 *packet){ U16 i,j; U16 sum =0; for (i=0;i=33 && packet[i+j]<=126 ) DBG("%c", packet[i+j]); else DBG("."); } DBG("|\n"); } } static void _HandleBulkOut(U8 bEP, U8 bEPStatus) { int iChunk; // get next part iChunk = USBHwEPRead(bEP, buffer, 0); MemoryCmd.dwAddress += iChunk; MemoryCmd.dwLength -= iChunk; //DBG("_HandleBulkOut addr=%X, len=%d\n",MemoryCmd.dwAddress,MemoryCmd.dwLength); dump_packet(MemoryCmd.dwAddress,iChunk,buffer); if (MemoryCmd.dwLength == 0) { DBG("_HandleBulkOut done\n"); } } /************************************************************************* HandleVendorRequest =================== Handles vendor specific requests Control transfer fields: * request: 0x01 = prepare memory read 0x02 = prepare memory write * index: ignored * value: ignored * data: U32 dwAddress U32 dwLength **************************************************************************/ static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) { TMemoryCmd *pCmd; pCmd = (TMemoryCmd *)*ppbData; switch (pSetup->bRequest) { // prepare read case 0x01: MemoryCmd = *pCmd; DBG("READ: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength); // send initial packet _HandleBulkIn(BULK_IN_EP, 0); *piLen = 0; break; // prepare write case 0x02: MemoryCmd = *pCmd; DBG("WRITE: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength); *piLen = 0; break; default: DBG("Unhandled class %X\n", pSetup->bRequest); return FALSE; } return TRUE; } #define BAUD_RATE 57600 /************************************************************************* main ==== **************************************************************************/ int main(void) { // PLL and MAM Initialize(); // init DBG ConsoleInit(60000000 / (16 * BAUD_RATE)); DBG("Initialising USB stack\n"); // initialise stack USBInit(); // register device descriptors USBRegisterDescriptors(abDescriptors); // override standard request handler USBRegisterRequestHandler(REQTYPE_TYPE_VENDOR, HandleVendorRequest, abVendorReqData); // register endpoints USBHwRegisterEPIntHandler(BULK_IN_EP, _HandleBulkIn); USBHwRegisterEPIntHandler(BULK_OUT_EP, _HandleBulkOut); DBG("Starting USB communication\n"); // connect to bus USBHwConnect(TRUE); // call USB interrupt handler continuously while (1) { USBHwISR(); } return 0; }