Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ASCII logging at 115200 baud drops packets about every 176144 bytes.

  • Loading branch information...
commit 388e3835286c3f0fa9c735416281eaf713a5cef8 0 parents
unknown authored
Showing with 13,195 additions and 0 deletions.
  1. BIN  FW.SFE
  2. +85 −0 LPCUSB/armVIC.c
  3. +157 −0 LPCUSB/armVIC.h
  4. +10 −0 LPCUSB/blockdev.h
  5. +360 −0 LPCUSB/blockdev_sd.c
  6. +149 −0 LPCUSB/lpc2000_spi.c
  7. +205 −0 LPCUSB/main_msc.c
  8. +1 −0  LPCUSB/main_msc.h
  9. +467 −0 LPCUSB/main_serial.c
  10. +5 −0 LPCUSB/main_serial.h
  11. +418 −0 LPCUSB/msc_bot.c
  12. +9 −0 LPCUSB/msc_bot.h
  13. +333 −0 LPCUSB/msc_scsi.c
  14. +5 −0 LPCUSB/msc_scsi.h
  15. +85 −0 LPCUSB/serial_fifo.c
  16. +42 −0 LPCUSB/serial_fifo.h
  17. +44 −0 LPCUSB/spi.h
  18. +57 −0 LPCUSB/type.h
  19. +121 −0 LPCUSB/usbapi.h
  20. +232 −0 LPCUSB/usbcontrol.c
  21. +38 −0 LPCUSB/usbdebug.h
  22. +560 −0 LPCUSB/usbhw_lpc.c
  23. +182 −0 LPCUSB/usbhw_lpc.h
  24. +82 −0 LPCUSB/usbinit.c
  25. +433 −0 LPCUSB/usbstdreq.c
  26. +120 −0 LPCUSB/usbstruct.h
  27. +516 −0 Main/Makefile
  28. +581 −0 Main/Startup.S
  29. BIN  Main/lpc21isp
  30. +1,323 −0 Main/main.c
  31. +158 −0 Main/main_memory_block.ld
  32. +399 −0 lib/LPC214x.h
  33. +383 −0 lib/LPC21xx.h
  34. +1,947 −0 lib/fat16.c
  35. +152 −0 lib/fat16.h
  36. +33 −0 lib/fat16_config.h
  37. +188 −0 lib/firmware.c
  38. +2 −0  lib/firmware.h
  39. +164 −0 lib/iap_flash.c
  40. +40 −0 lib/iap_flash.h
  41. +160 −0 lib/irq.c
  42. +127 −0 lib/irq.h
  43. +19 −0 lib/itoa.c
  44. +2 −0  lib/itoa.h
  45. +120 −0 lib/partition.c
  46. +161 −0 lib/partition.h
  47. +222 −0 lib/rootdir.c
  48. +21 −0 lib/rootdir.h
  49. +250 −0 lib/rprintf.c
  50. +7 −0 lib/rprintf.h
  51. +972 −0 lib/sd_raw.c
  52. +135 −0 lib/sd_raw.h
  53. +97 −0 lib/sd_raw_config.h
  54. +99 −0 lib/serial.c
  55. +13 −0 lib/serial.h
  56. +271 −0 lib/string_printf.c
  57. +4 −0 lib/string_printf.h
  58. +143 −0 lib/syscalls.c
  59. +44 −0 lib/target.h
  60. +32 −0 lib/type.h
  61. +162 −0 lib/uart.c
  62. +48 −0 lib/uart.h
BIN  FW.SFE
Binary file not shown
85 LPCUSB/armVIC.c
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ * $RCSfile$
+ * $Revision: 124 $
+ *
+ * This module provides the interface routines for setting up and
+ * controlling the various interrupt modes present on the ARM processor.
+ * Copyright 2004, R O SoftWare
+ * No guarantees, warrantees, or promises, implied or otherwise.
+ * May be used for hobby or commercial purposes provided copyright
+ * notice remains intact.
+ *
+ *****************************************************************************/
+#include "type.h"
+#include "armVIC.h"
+
+#define IRQ_MASK 0x00000080
+#define FIQ_MASK 0x00000040
+#define INT_MASK (IRQ_MASK | FIQ_MASK)
+
+static inline unsigned __get_cpsr(void)
+{
+ unsigned long retval;
+ asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
+ return retval;
+}
+
+static inline void __set_cpsr(unsigned val)
+{
+ asm volatile (" msr cpsr, %0" : /* no outputs */ : "r" (val) );
+}
+
+unsigned disableIRQ(void)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr(_cpsr | IRQ_MASK);
+ return _cpsr;
+}
+
+unsigned restoreIRQ(unsigned oldCPSR)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
+ return _cpsr;
+}
+
+unsigned enableIRQ(void)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr(_cpsr & ~IRQ_MASK);
+ return _cpsr;
+}
+
+unsigned disableFIQ(void)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr(_cpsr | FIQ_MASK);
+ return _cpsr;
+}
+
+unsigned restoreFIQ(unsigned oldCPSR)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr((_cpsr & ~FIQ_MASK) | (oldCPSR & FIQ_MASK));
+ return _cpsr;
+}
+
+unsigned enableFIQ(void)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+ __set_cpsr(_cpsr & ~FIQ_MASK);
+ return _cpsr;
+}
157 LPCUSB/armVIC.h
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * $RCSfile$
+ * $Revision: 124 $
+ *
+ * This module provides the interface definitions for setting up and
+ * controlling the various interrupt modes present on the ARM processor.
+ * Copyright 2004, R O SoftWare
+ * No guarantees, warrantees, or promises, implied or otherwise.
+ * May be used for hobby or commercial purposes provided copyright
+ * notice remains intact.
+ *
+ *****************************************************************************/
+#ifndef INC_ARM_VIC_H
+#define INC_ARM_VIC_H
+
+/******************************************************************************
+ *
+ * MACRO Name: ISR_ENTRY()
+ *
+ * Description:
+ * This MACRO is used upon entry to an ISR. The current version of
+ * the gcc compiler for ARM does not produce correct code for
+ * interrupt routines to operate properly with THUMB code. The MACRO
+ * performs the following steps:
+ *
+ * 1 - Adjust address at which execution should resume after servicing
+ * ISR to compensate for IRQ entry
+ * 2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
+ * 3 - Get the status of the interrupted program is in SPSR.
+ * 4 - Push it onto the IRQ stack as well.
+ *
+ *****************************************************************************/
+#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \
+ " stmfd sp!,{r0-r12,lr}\n" \
+ " mrs r1, spsr\n" \
+ " stmfd sp!,{r1}")
+
+/******************************************************************************
+ *
+ * MACRO Name: ISR_EXIT()
+ *
+ * Description:
+ * This MACRO is used to exit an ISR. The current version of the gcc
+ * compiler for ARM does not produce correct code for interrupt
+ * routines to operate properly with THUMB code. The MACRO performs
+ * the following steps:
+ *
+ * 1 - Recover SPSR value from stack
+ * 2 - and restore its value
+ * 3 - Pop the return address & the saved general registers from
+ * the IRQ stack & return
+ *
+ *****************************************************************************/
+#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \
+ " msr spsr_c,r1\n" \
+ " ldmfd sp!,{r0-r12,pc}^")
+
+/******************************************************************************
+ *
+ * Function Name: disableIRQ()
+ *
+ * Description:
+ * This function sets the IRQ disable bit in the status register
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned disableIRQ(void);
+
+/******************************************************************************
+ *
+ * Function Name: enableIRQ()
+ *
+ * Description:
+ * This function clears the IRQ disable bit in the status register
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned enableIRQ(void);
+
+/******************************************************************************
+ *
+ * Function Name: restoreIRQ()
+ *
+ * Description:
+ * This function restores the IRQ disable bit in the status register
+ * to the value contained within passed oldCPSR
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned restoreIRQ(unsigned oldCPSR);
+
+/******************************************************************************
+ *
+ * Function Name: disableFIQ()
+ *
+ * Description:
+ * This function sets the FIQ disable bit in the status register
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned disableFIQ(void);
+
+/******************************************************************************
+ *
+ * Function Name: enableFIQ()
+ *
+ * Description:
+ * This function clears the FIQ disable bit in the status register
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned enableFIQ(void);
+
+/******************************************************************************
+ *
+ * Function Name: restoreIRQ()
+ *
+ * Description:
+ * This function restores the FIQ disable bit in the status register
+ * to the value contained within passed oldCPSR
+ *
+ * Calling Sequence:
+ * void
+ *
+ * Returns:
+ * previous value of CPSR
+ *
+ *****************************************************************************/
+unsigned restoreFIQ(unsigned oldCPSR);
+
+#endif
10 LPCUSB/blockdev.h
@@ -0,0 +1,10 @@
+#include "type.h"
+
+
+int BlockDevInit(void);
+
+int BlockDevWrite(U32 dwAddress, U8* pbBuf);
+int BlockDevRead(U32 dwAddress, U8* pbBuf);
+
+int BlockDevGetSize(U32 *pdwDriveSize);
+int BlockDevGetStatus(void);
360 LPCUSB/blockdev_sd.c
@@ -0,0 +1,360 @@
+/*****************************************************************************\
+* efs - General purpose Embedded Filesystem library *
+* --------------------- ----------------------------------- *
+* *
+* Filename : sd.c *
+* Revision : Initial developement *
+* Description : This file contains the functions needed to use efs for *
+* accessing files on an SD-card. *
+* *
+* 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. *
+* *
+* (c)2005 Michael De Nil *
+* (c)2005 Lennart Yseboodt *
+\*****************************************************************************/
+
+/*
+ 2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+#include "type.h"
+
+#include <stdio.h>
+#include "rprintf.h"
+
+#include "blockdev.h"
+#include "spi.h"
+
+#define CMD_GOIDLESTATE 0
+#define CMD_SENDOPCOND 1
+#define CMD_READCSD 9
+#define CMD_READCID 10
+#define CMD_SENDSTATUS 13
+#define CMD_READSINGLEBLOCK 17
+#define CMD_WRITE 24
+#define CMD_WRITE_MULTIPLE 25
+
+static void Command(U8 cmd, U32 param)
+{
+ U8 abCmd[8];
+
+ // create buffer
+ abCmd[0] = 0xff;
+ abCmd[1] = 0x40 | cmd;
+ abCmd[2] = (U8)(param >> 24);
+ abCmd[3] = (U8)(param >> 16);
+ abCmd[4] = (U8)(param >> 8);
+ abCmd[5] = (U8)(param);
+ abCmd[6] = 0x95; /* Checksum (should be only valid for first command (0) */
+ abCmd[7] = 0xff; /* eat empty command - response */
+
+ SPISendN(abCmd, 8);
+}
+
+/*****************************************************************************/
+
+static U8 Resp8b(void)
+{
+ U8 i;
+ U8 resp;
+
+ /* Respone will come after 1 - 8 pings */
+ for (i = 0; i < 8; i++)
+ {
+ resp = SPISend(0xff);
+ if (resp != 0xff)
+ {
+ return resp;
+ }
+ }
+
+ return resp;
+}
+
+/*****************************************************************************/
+
+static void Resp8bError(U8 value)
+{
+ switch (value)
+ {
+ case 0x40: rprintf("Argument out of bounds.\n"); break;
+ case 0x20: rprintf("Address out of bounds.\n"); break;
+ case 0x10: rprintf("Error during erase sequence.\n"); break;
+ case 0x08: rprintf("CRC failed.\n"); break;
+ case 0x04: rprintf("Illegal command.\n"); break;
+ case 0x02: rprintf("Erase reset (see SanDisk docs p5-13).\n"); break;
+// case 0x01: rprintf("Card is initialising.\n"); break;
+ case 0x01: rprintf("."); break;
+ default:
+ rprintf("Unknown error 0x%x (see SanDisk docs p5-13).\n", value);
+ break;
+ }
+}
+
+
+/* ****************************************************************************
+ calculates size of card from CSD
+ (extension by Martin Thomas, inspired by code from Holger Klabunde)
+ */
+int BlockDevGetSize(U32 *pdwDriveSize)
+{
+ U8 cardresp, i, by;
+ U8 iob[16];
+ U16 c_size, c_size_mult, read_bl_len;
+
+ Command(CMD_READCSD, 0);
+ do
+ {
+ cardresp = Resp8b();
+ }
+ while (cardresp != 0xFE);
+
+ rprintf("CSD:");
+ for (i = 0; i < 16; i++)
+ {
+ iob[i] = SPISend(0xFF);
+ rprintf(" %02x", iob[i]);
+ }
+ rprintf("\n");
+
+ SPISend(0xff);
+ SPISend(0xff);
+
+ c_size = iob[6] & 0x03; // bits 1..0
+ c_size <<= 10;
+ c_size += (U16) iob[7] << 2;
+ c_size += iob[8] >> 6;
+
+ by = iob[5] & 0x0F;
+ read_bl_len = 1 << by;
+
+ by = iob[9] & 0x03;
+ by <<= 1;
+ by += iob[10] >> 7;
+
+ c_size_mult = 1 << (2 + by);
+
+ *pdwDriveSize = (U32) (c_size + 1) * (U32) c_size_mult *(U32) read_bl_len;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static U16 Resp16b(void)
+{
+ U16 resp;
+
+ resp = (Resp8b() << 8) & 0xff00;
+ resp |= SPISend(0xff);
+
+ return resp;
+}
+
+/*****************************************************************************/
+
+static int State(void)
+{
+ U16 value;
+
+ Command(CMD_SENDSTATUS, 0);
+ value = Resp16b();
+
+ switch (value)
+ {
+ case 0x0000: return 1;
+ case 0x0001: rprintf("Card is Locked.\n"); break;
+ case 0x0002: rprintf("WP Erase Skip, Lock/Unlock Cmd Failed.\n"); break;
+ case 0x0004: rprintf("General / Unknown error -- card broken?.\n"); break;
+ case 0x0008: rprintf("Internal card controller error.\n"); break;
+ case 0x0010: rprintf("Card internal ECC was applied, but failed to correct the data.\n"); break;
+ case 0x0020: rprintf("Write protect violation.\n"); break;
+ case 0x0040: rprintf("An invalid selection, sectors for erase.\n"); break;
+ case 0x0080: rprintf("Out of Range, CSD_Overwrite.\n"); break;
+ default:
+ if (value > 0x00FF)
+ {
+ Resp8bError((U8) (value >> 8));
+ }
+ else
+ {
+ rprintf("Unknown error: 0x%x (see SanDisk docs p5-14).\n", value);
+ }
+ break;
+ }
+ return -1;
+}
+
+/*****************************************************************************/
+
+
+int BlockDevInit(void)
+{
+ int i;
+ U8 resp;
+
+ SPIInit(); /* init at low speed */
+
+ /* Try to send reset command up to 100 times */
+ i = 100;
+ do
+ {
+ Command(CMD_GOIDLESTATE, 0);
+ resp = Resp8b();
+ }
+ while (resp != 1 && i--);
+
+ if (resp != 1)
+ {
+ if (resp == 0xff)
+ {
+ rprintf("resp=0xff\n");
+ return -1;
+ }
+ else
+ {
+ Resp8bError(resp);
+ rprintf("resp!=0xff\n");
+ return -2;
+ }
+ }
+
+ /* Wait till card is ready initialising (returns 0 on CMD_1) */
+ /* Try up to 32000 times. */
+ i = 32000;
+ do
+ {
+ Command(CMD_SENDOPCOND, 0);
+
+ resp = Resp8b();
+ if (resp != 0)
+ {
+ Resp8bError(resp);
+ }
+ }
+ while (resp == 1 && i--);
+
+ if (resp != 0)
+ {
+ Resp8bError(resp);
+ return -3;
+ }
+
+ /* increase speed after init */
+ SPISetSpeed(SPI_PRESCALE_MIN);
+
+ if (State() < 0)
+ {
+ rprintf("Card didn't return the ready state, breaking up...\n");
+ return -2;
+ }
+
+ rprintf("SD Init done...\n");
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+
+/* ****************************************************************************
+ * WAIT ?? -- FIXME
+ * CMD_WRITE
+ * WAIT
+ * CARD RESP
+ * WAIT
+ * DATA BLOCK OUT
+ * START BLOCK
+ * DATA
+ * CHKS (2B)
+ * BUSY...
+ */
+
+int BlockDevWrite(U32 dwAddress, U8 * pbBuf)
+{
+ U32 place;
+ U16 t = 0;
+
+ place = 512 * dwAddress;
+ Command(CMD_WRITE, place);
+
+ Resp8b(); /* Card response */
+
+ SPISend(0xfe); /* Start block */
+ SPISendN(pbBuf, 512);
+ SPISend(0xff); /* Checksum part 1 */
+ SPISend(0xff); /* Checksum part 2 */
+
+ SPISend(0xff);
+
+ while (SPISend(0xff) != 0xff)
+ {
+ t++;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/* ****************************************************************************
+ * WAIT ?? -- FIXME
+ * CMD_CMD_
+ * WAIT
+ * CARD RESP
+ * WAIT
+ * DATA BLOCK IN
+ * START BLOCK
+ * DATA
+ * CHKS (2B)
+ */
+
+int BlockDevRead(U32 dwAddress, U8 * pbBuf)
+{
+ U8 cardresp;
+ U8 firstblock;
+ U16 fb_timeout = 0xffff;
+ U32 place;
+
+ place = 512 * dwAddress;
+ Command(CMD_READSINGLEBLOCK, place);
+
+ cardresp = Resp8b(); /* Card response */
+
+ /* Wait for startblock */
+ do
+ {
+ firstblock = Resp8b();
+ }
+ while (firstblock == 0xff && fb_timeout--);
+
+ if (cardresp != 0x00 || firstblock != 0xfe)
+ {
+ Resp8bError(firstblock);
+ return -1;
+ }
+
+ SPIRecvN(pbBuf, 512);
+
+ /* Checksum (2 byte) - ignore for now */
+ SPISend(0xff);
+ SPISend(0xff);
+
+ return 0;
+}
+
+/*****************************************************************************/
149 LPCUSB/lpc2000_spi.c
@@ -0,0 +1,149 @@
+/*****************************************************************************\
+* efs - General purpose Embedded Filesystem library *
+* --------------------- ----------------------------------- *
+* *
+* Filename : lpc2000_spi.c *
+* Description : This contains the functions needed to use efs for *
+* accessing files on an SD-card connected to an LPC2xxx. *
+* *
+* 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. *
+* *
+* (c)2005 Martin Thomas *
+* *
+\*****************************************************************************/
+
+/*
+ 2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+
+/*****************************************************************************/
+#include "type.h"
+#include <stdio.h>
+#include "rprintf.h"
+#include "LPC214x.h"
+#include "spi.h"
+/*****************************************************************************/
+
+// SP0SPCR Bit-Definitions
+#define CPHA 3
+#define CPOL 4
+#define MSTR 5
+// SP0SPSR Bit-Definitions
+#define SPIF 7
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+// Utility-functions which does not toogle CS.
+// Only needed during card-init. During init
+// the automatic chip-select is disabled for SSP
+
+static U8 my_SPISend(U8 outgoing)
+{
+ S0SPDR = outgoing;
+ while (!(S0SPSR & (1 << SPIF)));
+ return S0SPDR;
+}
+
+/*****************************************************************************/
+
+void SPISetSpeed(U8 speed)
+{
+ speed &= 0xFE;
+ if (speed < SPI_PRESCALE_MIN)
+ {
+ speed = SPI_PRESCALE_MIN;
+ }
+ SPI_PRESCALE_REG = speed;
+}
+
+
+void SPIInit(void)
+{
+ U8 i;
+ //U32 j;
+
+ rprintf("spiInit for SPI(0)\n");
+
+ // setup GPIO
+ PINSEL2 = 0;
+
+ SPI_IODIR |= (1 << SPI_SCK_PIN) | (1 << SPI_MOSI_PIN);
+ SPI_SS_IODIR |= (1 << SPI_SS_PIN);
+ SPI_IODIR &= ~(1 << SPI_MISO_PIN);
+
+ // reset Pin-Functions
+ SPI_PINSEL &= ~((3 << SPI_SCK_FUNCBIT) | (3 << SPI_MISO_FUNCBIT) | (3 << SPI_MOSI_FUNCBIT));
+ SPI_PINSEL |= ((1 << SPI_SCK_FUNCBIT) | (1 << SPI_MISO_FUNCBIT) | (1 << SPI_MOSI_FUNCBIT));
+
+ // set Chip-Select high - unselect card
+ UNSELECT_CARD();
+
+ // enable SPI-Master
+ S0SPCR = (1 << MSTR) | (0 << CPOL); // TODO: check CPOL
+
+ // low speed during init
+ SPISetSpeed(254);
+
+ /* Send 20 spi commands with card not selected */
+ for (i = 0; i < 21; i++)
+ {
+ my_SPISend(0xff);
+ }
+}
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+U8 SPISend(U8 outgoing)
+{
+ U8 incoming;
+
+ SELECT_CARD();
+ S0SPDR = outgoing;
+ while (!(S0SPSR & (1 << SPIF)));
+ incoming = S0SPDR;
+ UNSELECT_CARD();
+
+ return incoming;
+}
+
+void SPISendN(U8 * pbBuf, int iLen)
+{
+ int i;
+
+ SELECT_CARD();
+ for (i = 0; i < iLen; i++)
+ {
+ S0SPDR = pbBuf[i];
+ while (!(S0SPSR & (1 << SPIF)));
+ }
+ UNSELECT_CARD();
+}
+
+void SPIRecvN(U8 * pbBuf, int iLen)
+{
+ int i;
+
+ SELECT_CARD();
+ for (i = 0; i < iLen; i++)
+ {
+ S0SPDR = 0xFF;
+ while (!(S0SPSR & (1 << SPIF)));
+ pbBuf[i] = S0SPDR;
+ }
+ UNSELECT_CARD();
+}
+
+/*****************************************************************************/
205 LPCUSB/main_msc.c
@@ -0,0 +1,205 @@
+/*
+ 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
+*/
+
+
+#include "main_msc.h"
+#include "type.h"
+
+#include <stdio.h>
+#include "rprintf.h"
+
+#include "LPC214x.h"
+#include "usbapi.h"
+#include "usbdebug.h"
+
+#include "msc_bot.h"
+#include "blockdev.h"
+
+#define BAUD_RATE 115200
+
+#define MAX_PACKET_SIZE 64
+
+#define LE_WORD(x) ((x)&0xFF),((x)>>8)
+
+static U8 abClassReqData[4];
+
+//static const U8 abDescriptors[] =
+static U8 abDescriptors[] =
+{
+
+ // device descriptor
+ 0x12,
+ DESC_DEVICE,
+ LE_WORD(0x0200), // bcdUSB
+ 0x00, // bDeviceClass
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ MAX_PACKET_SIZE0, // bMaxPacketSize
+ LE_WORD(0x1b4f), // idVendor
+ LE_WORD(0x0001), // idProduct
+ LE_WORD(0x0100), // bcdDevice
+ 0x01, // iManufacturer
+ 0x02, // iProduct
+ 0x03, // iSerialNumber
+ 0x01, // bNumConfigurations
+
+ // configuration descriptor
+ 0x09,
+ DESC_CONFIGURATION,
+ LE_WORD(32), // wTotalLength
+ 0x01, // bNumInterfaces
+ 0x01, // bConfigurationValue
+ 0x00, // iConfiguration
+ 0xC0, // bmAttributes
+ 0x32, // bMaxPower
+
+ // interface
+ 0x09,
+ DESC_INTERFACE,
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndPoints
+ 0x08, // bInterfaceClass = mass storage
+ 0x06, // bInterfaceSubClass = transparent SCSI
+ 0x50, // bInterfaceProtocol = BOT
+ 0x00, // iInterface
+ // EP
+ 0x07,
+ DESC_ENDPOINT,
+ MSC_BULK_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
+ 0x00, // bInterval
+ // EP
+ 0x07,
+ DESC_ENDPOINT,
+ MSC_BULK_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
+ 0x00, // bInterval
+
+ // string descriptors
+ 0x04,
+ DESC_STRING,
+ LE_WORD(0x0409),
+
+ 0x14,
+ DESC_STRING,
+ 'I', 0, 'N', 0, '2', 0, 'R', 0, 'o', 0, 'w', 0, 'i', 0, 'n', 0, 'g', 0,
+
+ 0x10,
+ DESC_STRING,
+ 'D', 0, 'a', 0, 't', 0, 'a', 0, 'L', 0, 'o', 0, 'g', 0,
+
+ 0x1A,
+ DESC_STRING,
+ '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0,
+
+ // terminating zero
+ 0
+};
+
+
+/*************************************************************************
+ HandleClassRequest
+ ==================
+ Handle mass storage class request
+
+**************************************************************************/
+static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ if (pSetup->wIndex != 0)
+ {
+ DBG("Invalid idx %X\n", pSetup->wIndex);
+ return FALSE;
+ }
+ if (pSetup->wValue != 0)
+ {
+ DBG("Invalid val %X\n", pSetup->wValue);
+ return FALSE;
+ }
+
+ switch (pSetup->bRequest)
+ {
+
+ // get max LUN
+ case 0xFE:
+ *ppbData[0] = 0; // No LUNs
+ *piLen = 1;
+ break;
+
+ // MSC reset
+ case 0xFF:
+ if (pSetup->wLength > 0)
+ {
+ return FALSE;
+ }
+ MSCBotReset();
+ break;
+
+ default:
+ DBG("Unhandled class\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*************************************************************************
+ msc_main
+ ====
+**************************************************************************/
+int main_msc(void)
+{
+ // initialise the SD card
+ BlockDevInit();
+
+ rprintf("Initialising USB stack\n");
+
+ // initialise stack
+ USBInit();
+
+ // enable bulk-in interrupts on NAKs
+ // these are required to get the BOT protocol going again after a STALL
+ USBHwNakIntEnable(INACK_BI);
+
+ // register descriptors
+ USBRegisterDescriptors(abDescriptors);
+
+ // register class request handler
+ USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
+
+ // register endpoint handlers
+ USBHwRegisterEPIntHandler(MSC_BULK_IN_EP, MSCBotBulkIn);
+ USBHwRegisterEPIntHandler(MSC_BULK_OUT_EP, MSCBotBulkOut);
+
+ rprintf("Starting USB communication\n");
+
+ // connect to bus
+ USBHwConnect(TRUE);
+
+ // call USB interrupt handler continuously
+ while (IOPIN0 & (1<<23))
+ {
+ USBHwISR();
+ }
+
+ return 0;
+}
+
1  LPCUSB/main_msc.h
@@ -0,0 +1 @@
+int main_msc(void);
467 LPCUSB/main_serial.c
@@ -0,0 +1,467 @@
+/*
+ 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.
+*/
+
+/*
+ Minimal implementation of a USB serial port, using the CDC class.
+ This example application simply echoes everything it receives right back
+ to the host.
+
+ Windows:
+ Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386
+ and store it somewhere (C:\temp is a good place) along with the usbser.inf
+ file. Then plug in the LPC214x and direct windows to the usbser driver.
+ Windows then creates an extra COMx port that you can open in a terminal
+ program, like hyperterminal.
+
+ Linux:
+ The device should be recognised automatically by the cdc_acm driver,
+ which creates a /dev/ttyACMx device file that acts just like a regular
+ serial port.
+
+*/
+
+
+#include "main_serial.h"
+#include "type.h"
+
+#include <stdio.h>
+#include "rprintf.h"
+
+#include "LPC214x.h"
+#include "usbapi.h"
+#include "usbdebug.h"
+
+//Used by VCOM
+#include "armVIC.h"
+#include "serial_fifo.h"
+
+//=========================
+#include <string.h> // memcpy
+
+//=========================
+
+
+#define BAUD_RATE 115200
+
+#define INT_IN_EP 0x81
+#define BULK_OUT_EP 0x05
+#define BULK_IN_EP 0x82
+
+#define MAX_PACKET_SIZE 64
+
+#define LE_WORD(x) ((x)&0xFF),((x)>>8)
+
+// CDC definitions
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+#define SET_LINE_CODING 0x20
+#define GET_LINE_CODING 0x21
+#define SET_CONTROL_LINE_STATE 0x22
+
+// interrupts
+//#define VICIntSelect *((volatile unsigned int *) 0xFFFFF00C)
+//#define VICIntEnable *((volatile unsigned int *) 0xFFFFF010)
+//#define VICVectAddr *((volatile unsigned int *) 0xFFFFF030)
+//#define VICVectAddr0 *((volatile unsigned int *) 0xFFFFF100)
+//#define VICVectCntl0 *((volatile unsigned int *) 0xFFFFF200)
+
+#define INT_VECT_NUM 0
+
+#define IRQ_MASK 0x00000080
+
+// data structure for GET_LINE_CODING / SET_LINE_CODING class requests
+typedef struct {
+ U32 dwDTERate;
+ U8 bCharFormat;
+ U8 bParityType;
+ U8 bDataBits;
+} TLineCoding;
+
+static TLineCoding LineCoding = {115200, 0, 0, 8};
+static U8 abBulkBuf[64];
+static U8 abClassReqData[8];
+
+static U8 txdata[VCOM_FIFO_SIZE];
+static U8 rxdata[VCOM_FIFO_SIZE];
+
+static fifo_t txfifo;
+static fifo_t rxfifo;
+
+// forward declaration of interrupt handler
+//static void USBIntHandler(void) __attribute__ ((interrupt("IRQ")));
+static void USBIntHandler(void);
+
+
+static const U8 abDescriptors[] = {
+
+// device descriptor
+ 0x12,
+ DESC_DEVICE,
+ LE_WORD(0x0101), // bcdUSB
+ 0x02, // bDeviceClass
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ MAX_PACKET_SIZE0, // bMaxPacketSize
+ LE_WORD(0xFFFF), // idVendor
+ LE_WORD(0x0005), // idProduct
+ LE_WORD(0x0100), // bcdDevice
+ 0x01, // iManufacturer
+ 0x02, // iProduct
+ 0x03, // iSerialNumber
+ 0x01, // bNumConfigurations
+
+// configuration descriptor
+ 0x09,
+ DESC_CONFIGURATION,
+ LE_WORD(67), // wTotalLength
+ 0x02, // bNumInterfaces
+ 0x01, // bConfigurationValue
+ 0x00, // iConfiguration
+ 0xC0, // bmAttributes
+ 0x32, // bMaxPower
+// control class interface
+ 0x09,
+ DESC_INTERFACE,
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x01, // bNumEndPoints
+ 0x02, // bInterfaceClass
+ 0x02, // bInterfaceSubClass
+ 0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
+ 0x00, // iInterface
+// header functional descriptor
+ 0x05,
+ CS_INTERFACE,
+ 0x00,
+ LE_WORD(0x0110),
+// call management functional descriptor
+ 0x05,
+ CS_INTERFACE,
+ 0x01,
+ 0x01, // bmCapabilities = device handles call management
+ 0x01, // bDataInterface
+// ACM functional descriptor
+ 0x04,
+ CS_INTERFACE,
+ 0x02,
+ 0x02, // bmCapabilities
+// union functional descriptor
+ 0x05,
+ CS_INTERFACE,
+ 0x06,
+ 0x00, // bMasterInterface
+ 0x01, // bSlaveInterface0
+// notification EP
+ 0x07,
+ DESC_ENDPOINT,
+ INT_IN_EP, // bEndpointAddress
+ 0x03, // bmAttributes = intr
+ LE_WORD(8), // wMaxPacketSize
+ 0x0A, // bInterval
+// data class interface descriptor
+ 0x09,
+ DESC_INTERFACE,
+ 0x01, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndPoints
+ 0x0A, // bInterfaceClass = data
+ 0x00, // bInterfaceSubClass
+ 0x00, // bInterfaceProtocol
+ 0x00, // iInterface
+// data EP OUT
+ 0x07,
+ DESC_ENDPOINT,
+ BULK_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+// data EP in
+ 0x07,
+ DESC_ENDPOINT,
+ BULK_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+
+ // string descriptors
+ 0x04,
+ DESC_STRING,
+ LE_WORD(0x0409),
+
+ 0x0E,
+ DESC_STRING,
+ 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+ 0x14,
+ DESC_STRING,
+ 'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
+
+ 0x12,
+ DESC_STRING,
+ 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
+
+// terminating zero
+ 0
+};
+
+
+/**
+ Local function to handle incoming bulk data
+
+ @param [in] bEP
+ @param [in] bEPStatus
+ */
+static void BulkOut(U8 bEP, U8 bEPStatus)
+{
+ int i, iLen;
+
+ if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) {
+ // may not fit into fifo
+ return;
+ }
+
+ // get data from USB into intermediate buffer
+ iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));
+ for (i = 0; i < iLen; i++) {
+ // put into FIFO
+ if (!fifo_put(&rxfifo, abBulkBuf[i])) {
+ // overflow... :(
+ ASSERT(FALSE);
+ break;
+ }
+ }
+}
+
+
+/**
+ Local function to handle outgoing bulk data
+
+ @param [in] bEP
+ @param [in] bEPStatus
+ */
+static void BulkIn(U8 bEP, U8 bEPStatus)
+{
+ int i, iLen;
+
+ if (fifo_avail(&txfifo) == 0) {
+ // no more data, disable further NAK interrupts until next USB frame
+ USBHwNakIntEnable(0);
+ return;
+ }
+
+ // get bytes from transmit FIFO into intermediate buffer
+ for (i = 0; i < MAX_PACKET_SIZE; i++) {
+ if (!fifo_get(&txfifo, &abBulkBuf[i])) {
+ break;
+ }
+ }
+ iLen = i;
+
+ // send over USB
+ if (iLen > 0) {
+ USBHwEPWrite(bEP, abBulkBuf, iLen);
+ }
+}
+
+
+/**
+ Local function to handle the USB-CDC class requests
+
+ @param [in] pSetup
+ @param [out] piLen
+ @param [out] ppbData
+ */
+static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ switch (pSetup->bRequest) {
+
+ // set line coding
+ case SET_LINE_CODING:
+DBG("SET_LINE_CODING\n");
+ memcpy((U8 *)&LineCoding, *ppbData, 7);
+ *piLen = 7;
+DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n",
+ LineCoding.dwDTERate,
+ LineCoding.bCharFormat,
+ LineCoding.bParityType,
+ LineCoding.bDataBits);
+ break;
+
+ // get line coding
+ case GET_LINE_CODING:
+DBG("GET_LINE_CODING\n");
+ *ppbData = (U8 *)&LineCoding;
+ *piLen = 7;
+ break;
+
+ // set control line state
+ case SET_CONTROL_LINE_STATE:
+ // bit0 = DTR, bit = RTS
+DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue);
+ break;
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ Initialises the VCOM port.
+ Call this function before using VCOM_putchar or VCOM_getchar
+ */
+void VCOM_init(void)
+{
+ fifo_init(&txfifo, txdata);
+ fifo_init(&rxfifo, rxdata);
+}
+
+
+/**
+ Writes one character to VCOM port
+
+ @param [in] c character to write
+ @returns character written, or EOF if character could not be written
+ */
+int VCOM_putchar(int c)
+{
+ return fifo_put(&txfifo, c) ? c : EOF;
+}
+
+
+/**
+ Reads one character from VCOM port
+
+ @returns character read, or EOF if character could not be read
+ */
+int VCOM_getchar(void)
+{
+ U8 c = 0;
+
+ return fifo_get(&rxfifo, &c) ? c : EOF;
+
+ /*
+ while(c != 0)
+ {
+ c = fifo_get(&rxfifo, &c);
+ }
+
+ return c;
+ */
+}
+
+
+/**
+ Interrupt handler
+
+ Simply calls the USB ISR, then signals end of interrupt to VIC
+ */
+static void USBIntHandler(void)
+{
+ USBHwISR();
+ VICVectAddr = 0x00; // dummy write to VIC to signal end of ISR
+}
+
+
+static void USBFrameHandler(U16 wFrame)
+{
+ if (fifo_avail(&txfifo) > 0) {
+ // data available, enable NAK interrupt on bulk in
+ USBHwNakIntEnable(INACK_BI);
+ }
+}
+
+/*************************************************************************
+ main_serial
+ ====
+**************************************************************************/
+int main_serial(void)
+{
+ int c;
+
+ // PLL and MAM
+ //Initialize();
+
+ // init DBG
+ //ConsoleInit(60000000 / (16 * BAUD_RATE));
+
+ DBG("Initialising USB stack\n");
+
+ // initialise stack
+ USBInit();
+
+ // register descriptors
+ USBRegisterDescriptors(abDescriptors);
+
+ // register class request handler
+ USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
+
+ // register endpoint handlers
+ USBHwRegisterEPIntHandler(INT_IN_EP, NULL);
+ USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn);
+ USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut);
+
+ // register frame handler
+ USBHwRegisterFrameHandler(USBFrameHandler);
+
+ // enable bulk-in interrupts on NAKs
+ USBHwNakIntEnable(INACK_BI);
+
+ // initialise VCOM
+ VCOM_init();
+
+ DBG("Starting USB communication\n");
+
+ // set up USB interrupt
+ VICIntSelect &= ~(1<<22); // select IRQ for USB
+ VICIntEnable |= (1<<22);
+
+ (*(&VICVectCntl0+INT_VECT_NUM)) = 0x20 | 22; // choose highest priority ISR slot
+ (*(&VICVectAddr0+INT_VECT_NUM)) = (int)USBIntHandler;
+
+ enableIRQ();
+
+ // connect to bus
+ USBHwConnect(TRUE);
+
+ // echo any character received (do USB stuff in interrupt)
+ while (1)
+ {
+ c = VCOM_getchar();
+ if (c != EOF)
+ {
+ VCOM_putchar(c);
+
+ if (c == '!') break; //Wait for user to press ! after VCOM is opened - to prevent buffer overrun
+ }
+ }
+
+ return 0;
+}
+
5 LPCUSB/main_serial.h
@@ -0,0 +1,5 @@
+void VCOM_init(void);
+int VCOM_putchar(int c);
+int VCOM_getchar(void);
+
+int main_serial(void);
418 LPCUSB/msc_bot.c
@@ -0,0 +1,418 @@
+/*
+ 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
+*/
+
+#include <string.h>
+
+#include "type.h"
+#include <stdio.h>
+#include "rprintf.h"
+
+#include "usbapi.h"
+#include "usbdebug.h"
+
+#include "msc_bot.h"
+#include "msc_scsi.h"
+
+#undef MIN
+#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */
+
+
+typedef struct
+{
+ U32 dwCBWSignature;
+ U32 dwCBWTag;
+ U32 dwCBWDataTransferLength;
+ U8 bmCBWFlags;
+ U8 bCBWLun;
+ U8 bCBWCBLength;
+ U8 CBWCB[16];
+}
+TCBW;
+
+typedef struct
+{
+ U32 dwCSWSignature;
+ U32 dwCSWTag;
+ U32 dwCSWDataResidue;
+ U8 bmCSWStatus;
+}
+TCSW;
+
+typedef enum
+{
+ eCBW,
+ eDataOut,
+ eDataIn,
+ eCSW,
+ eStalled
+}
+EBotState;
+
+
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+
+#define STATUS_PASSED 0x00
+#define STATUS_FAILED 0x01
+#define STATUS_PHASE_ERR 0x02
+
+static U32 dwTransferSize; // total size of data transfer
+static U32 dwOffset; // offset in current data transfer
+
+static TCBW CBW;
+static TCSW CSW;
+
+static EBotState eState;
+
+static U8 *pbData;
+
+
+
+void MSCBotReset(void)
+{
+ DBG("BOT reset in state %d\n", eState);
+ // reset BOT state
+ eState = eCBW;
+ // reset SCSI
+ SCSIReset();
+}
+
+
+static void SendCSW(U8 bStatus)
+{
+ int iResidue;
+
+ iResidue = CBW.dwCBWDataTransferLength - dwTransferSize;
+
+ // construct CSW
+ CSW.dwCSWSignature = CSW_SIGNATURE;
+ CSW.dwCSWTag = CBW.dwCBWTag;
+ CSW.dwCSWDataResidue = MAX(iResidue, 0);
+ CSW.bmCSWStatus = bStatus;
+
+ DBG("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue);
+
+ // next state
+ eState = eCSW;
+}
+
+
+/*************************************************************************
+ CheckCBW
+ ========
+ Checks if CBW is valid and meaningful
+
+ IN pCBW Command block wrapper
+ iLen Length of CBW
+
+ Returns TRUE if valid and meaningful
+**************************************************************************/
+static BOOL CheckCBW(TCBW *pCBW, int iLen)
+{
+ // CBW valid?
+ if (iLen != 31)
+ {
+ DBG("Invalid length (%d)\n", iLen);
+ return FALSE;
+ }
+ if (pCBW->dwCBWSignature != CBW_SIGNATURE)
+ {
+ DBG("Invalid signature %x\n", pCBW->dwCBWSignature);
+ return FALSE;
+ }
+
+ // CBW meaningful?
+ if (pCBW->bCBWLun != 0)
+ {
+ DBG("Invalid LUN %d\n", pCBW->bCBWLun);
+ return FALSE;
+ }
+ if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16))
+ {
+ DBG("Invalid CB len %d\n", pCBW->bCBWCBLength);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*************************************************************************
+ BOTStall
+ ========
+ Local function to stall ongoing transfer
+
+ Which endpoint to stall is determined by looking at the transfer
+ direction intended by the host.
+
+**************************************************************************/
+static void BOTStall(void)
+{
+ if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0))
+ {
+ // stall data-in or CSW
+ USBHwEPStall(MSC_BULK_IN_EP, TRUE);
+ }
+ else
+ {
+ // stall data-out
+ USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
+ }
+}
+
+
+/*************************************************************************
+ HandleDataIn
+ ============
+ Handles data from device-to-host
+
+**************************************************************************/
+static void HandleDataIn(void)
+{
+ int iChunk;
+
+ // process data for host in SCSI layer
+ pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+ if (pbData == NULL)
+ {
+ BOTStall();
+ SendCSW(STATUS_FAILED);
+ return;
+ }
+
+ // send data to host?
+ if (dwOffset < dwTransferSize)
+ {
+ iChunk = MIN(64, dwTransferSize - dwOffset);
+ USBHwEPWrite(MSC_BULK_IN_EP, pbData, iChunk);
+ dwOffset += iChunk;
+ }
+
+ // are we done now?
+ if (dwOffset == dwTransferSize)
+ {
+ if (dwOffset != CBW.dwCBWDataTransferLength)
+ {
+ // stall pipe
+ DBG("stalling DIN");
+ BOTStall();
+ }
+ // done
+ SendCSW(STATUS_PASSED);
+ }
+}
+
+
+/*************************************************************************
+ HandleDataOut
+ =============
+ Handles data from host-to-device
+
+**************************************************************************/
+static void HandleDataOut(void)
+{
+ int iChunk;
+
+ if (dwOffset < dwTransferSize)
+ {
+ // get data from host
+ iChunk = USBHwEPRead(MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset);
+ // process data in SCSI layer
+ pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+ if (pbData == NULL)
+ {
+ BOTStall();
+ SendCSW(STATUS_FAILED);
+ return;
+ }
+ dwOffset += iChunk;
+ }
+
+ // are we done now?
+ if (dwOffset == dwTransferSize)
+ {
+ if (dwOffset != CBW.dwCBWDataTransferLength)
+ {
+ // stall pipe
+ DBG("stalling DOUT");
+ BOTStall();
+ }
+ SendCSW(STATUS_PASSED);
+ }
+}
+
+
+/*************************************************************************
+ MSCBotBulkOut
+ ===============
+ Handles the BOT bulk OUT endpoint
+
+ IN bEP Endpoint number
+ bEPStatus Endpoint status (indicates NAK, STALL, etc)
+
+**************************************************************************/
+void MSCBotBulkOut(U8 bEP, U8 bEPStatus)
+{
+ int iLen, iChunk;
+ BOOL fHostIn, fDevIn;
+
+ // ignore events on stalled EP
+ if (bEPStatus & EP_STATUS_STALLED)
+ {
+ return;
+ }
+
+ switch (eState)
+ {
+
+ case eCBW:
+ iLen = USBHwEPRead(bEP, (U8 *)&CBW, sizeof(CBW));
+
+ // check if we got a good CBW
+ if (!CheckCBW(&CBW, iLen))
+ {
+ // see 6.6.1
+ USBHwEPStall(MSC_BULK_IN_EP, TRUE);
+ USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
+ eState = eStalled;
+ break;
+ }
+
+ DBG("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n",
+ CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength);
+
+ dwOffset = 0;
+ dwTransferSize = 0;
+ fHostIn = ((CBW.bmCBWFlags & 0x80) != 0);
+
+ // verify request
+ pbData = SCSIHandleCmd(CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn);
+ if (pbData == NULL)
+ {
+ // unknown command
+ BOTStall();
+ SendCSW(STATUS_FAILED);
+ break;
+ }
+
+ // rule: if device and host disagree on direction, send CSW with status 2
+ if ((iLen > 0) &&
+ ((fHostIn && !fDevIn) ||
+ (!fHostIn && fDevIn)))
+ {
+ DBG("Host and device disagree on direction\n");
+ BOTStall();
+ SendCSW(STATUS_PHASE_ERR);
+ break;
+ }
+
+ // rule: if D > H, send CSW with status 2
+ if (iLen > CBW.dwCBWDataTransferLength)
+ {
+ DBG("Negative residue\n");
+ BOTStall();
+ SendCSW(STATUS_PHASE_ERR);
+ break;
+ }
+
+ dwTransferSize = iLen;
+ if ((dwTransferSize == 0) || fDevIn)
+ {
+ // data from device-to-host
+ eState = eDataIn;
+ HandleDataIn();
+ }
+ else
+ {
+ // data from host-to-device
+ eState = eDataOut;
+ }
+ break;
+
+ case eDataOut:
+ HandleDataOut();
+ break;
+
+ case eDataIn:
+ case eCSW:
+ iChunk = USBHwEPRead(bEP, NULL, 0);
+ DBG("Phase error in state %d, %d bytes\n", eState, iChunk);
+ eState = eCBW;
+ break;
+
+ case eStalled:
+ // keep stalling
+ USBHwEPStall(MSC_BULK_OUT_EP, TRUE);
+ break;
+
+ default:
+ DBG("Invalid state %d\n", eState);
+// ASSERT(FALSE);
+ break;
+ }
+}
+
+
+/*************************************************************************
+ MSCBotBulkIn
+ ============
+ Handles the BOT bulk IN endpoint
+
+ IN bEP Endpoint number
+ bEPStatus Endpoint status (indicates NAK, STALL, etc)
+
+**************************************************************************/
+void MSCBotBulkIn(U8 bEP, U8 bEPStatus)
+{
+ // ignore events on stalled EP
+ if (bEPStatus & EP_STATUS_STALLED)
+ {
+ return;
+ }
+
+ switch (eState)
+ {
+
+ case eCBW:
+ case eDataOut:
+ // ignore possibly old ACKs
+ break;
+
+ case eDataIn:
+ HandleDataIn();
+ break;
+
+ case eCSW:
+ // wait for an IN token, then send the CSW
+ USBHwEPWrite(MSC_BULK_IN_EP, (U8 *)&CSW, 13);
+ eState = eCBW;
+ break;
+
+ case eStalled:
+ // keep stalling
+ USBHwEPStall(MSC_BULK_IN_EP, TRUE);
+ break;
+
+ default:
+ DBG("Invalid state %d\n", eState);
+// ASSERT(FALSE);
+ break;
+ }
+}
+
+
9 LPCUSB/msc_bot.h
@@ -0,0 +1,9 @@
+#include "type.h"
+
+#define MSC_BULK_OUT_EP 0x02
+#define MSC_BULK_IN_EP 0x85
+
+void MSCBotReset(void);
+void MSCBotBulkOut(U8 bEP, U8 bEPStatus);
+void MSCBotBulkIn(U8 bEP, U8 bEPStatus);
+
333 LPCUSB/msc_scsi.c
@@ -0,0 +1,333 @@
+/*
+ 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 the SCSI layer of the USB mass storage application example.
+ This layer depends directly on the blockdev layer.
+*/
+
+
+#include <string.h> // memcpy
+
+#include "type.h"
+#include "usbdebug.h"
+#include <stdio.h>
+#include "rprintf.h"
+
+#include "blockdev.h"
+#include "msc_scsi.h"
+
+#undef MIN
+#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */
+
+#define BLOCKSIZE 512
+
+// SCSI commands
+#define SCSI_CMD_TEST_UNIT_READY 0x00
+#define SCSI_CMD_REQUEST_SENSE 0x03
+#define SCSI_CMD_INQUIRY 0x12
+#define SCSI_CMD_READ_CAPACITY 0x25
+#define SCSI_CMD_READ_10 0x28
+#define SCSI_CMD_WRITE_10 0x2A
+
+// sense code
+#define WRITE_ERROR 0x030C00
+#define READ_ERROR 0x031100
+#define INVALID_CMD_OPCODE 0x052000
+#define INVALID_FIELD_IN_CDB 0x052400
+
+// Sense code, which is set on error conditions
+static U32 dwSense; // hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
+
+static const U8 abInquiry[] =
+{
+ 0x00, // PDT = direct-access device
+ 0x80, // removeable medium bit = set
+ 0x04, // version = complies to SPC2r20
+ 0x02, // response data format = SPC2r20
+ 0x1F, // additional length
+ 0x00,
+ 0x00,
+ 0x00,
+ 'L','P','C','U','S','B',' ',' ', // vendor
+ 'M','a','s','s',' ','s','t','o', // product
+ 'r','a','g','e',' ',' ',' ',' ',
+ '0','.','1',' ' // revision
+};
+
+// Data for "request sense" command. The 0xFF are filled in later
+static const U8 abSense[] =
+{
+ 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+ 0x00, 0x00
+};
+
+// Buffer for holding one block of disk data
+static U8 abBlockBuf[512];
+
+
+typedef struct
+{
+ U8 bOperationCode;
+ U8 abLBA[3];
+ U8 bLength;
+ U8 bControl;
+}
+TCDB6;
+
+
+/*************************************************************************
+ SCSIReset
+ =========
+ Resets any SCSI state
+
+**************************************************************************/
+void SCSIReset(void)
+{
+ dwSense = 0;
+}
+
+
+/*************************************************************************
+ SCSIHandleCmd
+ =============
+ Verifies a SCSI CDB and indicates the direction and amount of data
+ that the device wants to transfer.
+
+ If this call fails, a sense code is set in dwSense.
+
+ IN pbCDB Command data block
+ iCDBLen Command data block len
+ OUT *piRspLen Length of intended response data:
+ *pfDevIn TRUE if data is transferred from device-to-host
+
+ Returns a pointer to the data exchange buffer if successful,
+ return NULL otherwise.
+**************************************************************************/
+U8 * SCSIHandleCmd(U8 *pbCDB, int iCDBLen, int *piRspLen, BOOL *pfDevIn)
+{
+ int i;
+ TCDB6 *pCDB;
+ U32 dwLen, dwLBA;
+
+ //pCDB = (TCDB6 *)pbCDB;
+ //Compiler warning fix
+ TCDB6 cdb;
+ pCDB = &cdb;
+ memcpy(pCDB, pbCDB, sizeof(TCDB6));
+
+ // default direction is from device to host
+ *pfDevIn = TRUE;
+
+ switch (pCDB->bOperationCode)
+ {
+
+ // test unit ready (6)
+ case SCSI_CMD_TEST_UNIT_READY:
+ DBG("TEST UNIT READY\n");
+ *piRspLen = 0;
+ break;
+
+ // request sense (6)
+ case SCSI_CMD_REQUEST_SENSE:
+ DBG("REQUEST SENSE (%06X)\n", dwSense);
+ // check params
+ *piRspLen = MIN(18, pCDB->bLength);
+ break;
+
+ // inquiry (6)
+ case SCSI_CMD_INQUIRY:
+ DBG("INQUIRY\n");
+ // see SPC20r20, 4.3.4.6
+ *piRspLen = MIN(36, pCDB->bLength);
+ break;
+
+ // read capacity (10)
+ case SCSI_CMD_READ_CAPACITY:
+ DBG("READ CAPACITY\n");
+ *piRspLen = 8;
+ break;
+
+ // read (10)
+ case SCSI_CMD_READ_10:
+ if (iCDBLen != 10)
+ {
+ return NULL;
+ }
+ dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+ dwLen = (pbCDB[7] << 8) | pbCDB[8];
+ DBG("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
+ *piRspLen = dwLen * BLOCKSIZE;
+ break;
+
+ // write (10)
+ case SCSI_CMD_WRITE_10:
+ if (iCDBLen != 10)
+ {
+ return NULL;
+ }
+ dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+ dwLen = (pbCDB[7] << 8) | pbCDB[8];
+ DBG("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
+ *piRspLen = dwLen * BLOCKSIZE;
+ *pfDevIn = FALSE;
+ break;
+
+ default:
+ DBG("Unhandled SCSI: ");
+ for (i = 0; i < iCDBLen; i++)
+ {
+ DBG(" %02X", pbCDB[i]);
+ }
+ DBG("\n");
+ // unsupported command
+ dwSense = INVALID_CMD_OPCODE;
+ *piRspLen = 0;
+ return NULL;
+ }
+
+
+ return abBlockBuf;
+}
+
+
+/*************************************************************************
+ SCSIHandleData
+ ==============
+ Handles a block of SCSI data.
+
+ IN pbCDB Command data block
+ iCDBLen Command data block len
+ IN/OUT pbData Data buffer
+ IN dwOffset Offset in data
+
+ Returns a pointer to the next data to be exchanged if successful,
+ returns NULL otherwise.
+**************************************************************************/
+U8 * SCSIHandleData(U8 *pbCDB, int iCDBLen, U8 *pbData, U32 dwOffset)
+{
+ TCDB6 *pCDB;
+ U32 dwLBA;
+ U32 dwBufPos, dwBlockNr;
+ U32 dwNumBlocks, dwMaxBlock;
+
+ //pCDB = (TCDB6 *)pbCDB;
+ //Compiler warning fix
+ TCDB6 cdb;
+ pCDB = &cdb;
+ memcpy(pCDB, pbCDB, sizeof(TCDB6));
+
+ switch (pCDB->bOperationCode)
+ {
+
+ // test unit ready
+ case 0x00:
+ if (dwSense != 0)
+ {
+ return NULL;
+ }
+ break;
+
+ // request sense
+ case SCSI_CMD_REQUEST_SENSE:
+ memcpy(pbData, abSense, 18);
+ // fill in KEY/ASC/ASCQ
+ pbData[2] = (dwSense >> 16) & 0xFF;
+ pbData[12] = (dwSense >> 8) & 0xFF;
+ pbData[13] = (dwSense >> 0) & 0xFF;
+ // reset sense data
+ dwSense = 0;
+ break;
+
+ // inquiry
+ case SCSI_CMD_INQUIRY:
+ memcpy(pbData, abInquiry, sizeof(abInquiry));
+ break;
+
+ // read capacity
+ case SCSI_CMD_READ_CAPACITY:
+ // get size of drive (bytes)
+ BlockDevGetSize(&dwNumBlocks);
+ // calculate highest LBA
+ dwMaxBlock = (dwNumBlocks - 1) / 512;
+
+ pbData[0] = (dwMaxBlock >> 24) & 0xFF;
+ pbData[1] = (dwMaxBlock >> 16) & 0xFF;
+ pbData[2] = (dwMaxBlock >> 8) & 0xFF;
+ pbData[3] = (dwMaxBlock >> 0) & 0xFF;
+ pbData[4] = (BLOCKSIZE >> 24) & 0xFF;
+ pbData[5] = (BLOCKSIZE >> 16) & 0xFF;
+ pbData[6] = (BLOCKSIZE >> 8) & 0xFF;
+ pbData[7] = (BLOCKSIZE >> 0) & 0xFF;
+ break;
+
+ // read10
+ case SCSI_CMD_READ_10:
+ dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+
+ // copy data from block buffer
+ dwBufPos = (dwOffset & (BLOCKSIZE - 1));
+ if (dwBufPos == 0)
+ {
+ // read new block
+ dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+ DBG("R");
+ if (BlockDevRead(dwBlockNr, abBlockBuf) < 0)
+ {
+ dwSense = READ_ERROR;
+ DBG("BlockDevRead failed\n");
+ return NULL;
+ }
+ }
+ // return pointer to data
+ return abBlockBuf + dwBufPos;
+
+ // write10
+ case SCSI_CMD_WRITE_10:
+ dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+
+ // copy data to block buffer
+ dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
+ if (dwBufPos == 0)
+ {
+ // write new block
+ dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+ DBG("W");
+ if (BlockDevWrite(dwBlockNr, abBlockBuf) < 0)
+ {
+ dwSense = WRITE_ERROR;
+ DBG("BlockDevWrite failed\n");
+ return NULL;
+ }
+ }
+ // return pointer to next data
+ return abBlockBuf + dwBufPos;
+
+ default:
+ // unsupported command
+ dwSense = INVALID_CMD_OPCODE;
+ return NULL;
+ }
+
+ // default: return pointer to start of block buffer
+ return abBlockBuf;
+}
+
+
5 LPCUSB/msc_scsi.h
@@ -0,0 +1,5 @@
+#include "type.h"
+
+void SCSIReset(void);
+U8 * SCSIHandleCmd(U8 *pbCDB, int iCDBLen, int *piRspLen, BOOL *pfDevIn);
+U8 * SCSIHandleData(U8 *pbCDB, int iCDBLen, U8 *pbData, U32 dwOffset);
85 LPCUSB/serial_fifo.c
@@ -0,0 +1,85 @@
+/*
+ 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.
+*/
+
+#include "type.h"
+#include "serial_fifo.h"
+
+void fifo_init(fifo_t *fifo, U8 *buf)
+{
+ fifo->head = 0;
+ fifo->tail = 0;
+ fifo->buf = buf;
+}
+
+
+BOOL fifo_put(fifo_t *fifo, U8 c)
+{
+ int next;
+
+ // check if FIFO has room
+ next = (fifo->head + 1) % VCOM_FIFO_SIZE;
+ if (next == fifo->tail) {
+ // full
+ return FALSE;
+ }
+
+ fifo->buf[fifo->head] = c;
+ fifo->head = next;
+
+ return TRUE;
+}
+
+
+BOOL fifo_get(fifo_t *fifo, U8 *pc)
+{
+ int next;
+
+ // check if FIFO has data
+ if (fifo->head == fifo->tail) {
+ return FALSE;
+ }
+
+ next = (fifo->tail + 1) % VCOM_FIFO_SIZE;
+
+ *pc = fifo->buf[fifo->tail];
+ fifo->tail = next;
+
+ return TRUE;
+}
+
+
+int fifo_avail(fifo_t *fifo)
+{
+ return (VCOM_FIFO_SIZE + fifo->head - fifo->tail) % VCOM_FIFO_SIZE;
+}
+
+
+int fifo_free(fifo_t *fifo)
+{
+ return (VCOM_FIFO_SIZE - 1 - fifo_avail(fifo));
+}
+
42 LPCUSB/serial_fifo.h
@@ -0,0 +1,42 @@
+/*
+ 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.
+*/
+
+#include "type.h"
+
+#define VCOM_FIFO_SIZE 128
+
+typedef struct {
+ int head;
+ int tail;
+ U8 *buf;
+} fifo_t;
+
+void fifo_init(fifo_t *fifo, U8 *buf);
+BOOL fifo_put(fifo_t *fifo, U8 c);
+BOOL fifo_get(fifo_t *fifo, U8 *pc);
+int fifo_avail(fifo_t *fifo);
+int fifo_free(fifo_t *fifo);
44 LPCUSB/spi.h
@@ -0,0 +1,44 @@
+#include "type.h"
+
+#define SPI_PRESCALE_MIN 8
+
+void SPIInit(void);
+void SPISetSpeed(U8 speed);
+
+U8 SPISend(U8 outgoing);
+void SPISendN(U8 *pbBuf, int iLen);
+void SPIRecvN(U8 *pbBuf, int iLen);
+
+//#define SS_PORT_1
+//#define SPI_SS_PIN 24
+#define SS_PORT_0
+#define SPI_SS_PIN 7
+
+//SPI Chip Select Defines for SD Access
+#ifdef SS_PORT_1
+ #define SPI_SS_IODIR IODIR1
+ #define SPI_SS_IOCLR IOCLR1
+ #define SPI_SS_IOSET IOSET1
+#endif
+#ifdef SS_PORT_0
+ #define SPI_SS_IODIR IODIR0
+ #define SPI_SS_IOCLR IOCLR0
+ #define SPI_SS_IOSET IOSET0
+#endif
+
+//SPI Pin Location Definitions
+#define SPI_IODIR IODIR0
+#define SPI_SCK_PIN 4
+#define SPI_MISO_PIN 5
+#define SPI_MOSI_PIN 6
+
+
+#define SPI_PINSEL PINSEL0
+#define SPI_SCK_FUNCBIT 8
+#define SPI_MISO_FUNCBIT 10
+#define SPI_MOSI_FUNCBIT 12
+
+#define SPI_PRESCALE_REG S0SPCCR
+
+#define SELECT_CARD() SPI_SS_IOCLR |= (1 << SPI_SS_PIN)
+#define UNSELECT_CARD() SPI_SS_IOSET |= (1 << SPI_SS_PIN)
57 LPCUSB/type.h
@@ -0,0 +1,57 @@
+/*
+ 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
+ */
+
+
+#ifndef _TYPE_H_
+#define _TYPE_H_
+
+typedef unsigned char U8; /**< unsigned 8-bit */
+typedef unsigned short int U16; /**< unsigned 16-bit */
+typedef unsigned int U32; /**< unsigned 32-bit */
+
+typedef int BOOL; /**< #TRUE or #FALSE */
+
+#define TRUE 1 /**< TRUE */
+#define FALSE 0 /**< FALSE */
+
+#ifndef NULL
+#define NULL ((void*)0) /**< NULL pointer */
+#endif
+
+/* some other useful macros */
+//#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */
+#define MAX(x,y) ((x)>(y)?(x):(y)) /**< MAX */
+
+
+#endif /* _TYPE_H_ */
+
121 LPCUSB/usbapi.h
@@ -0,0 +1,121 @@
+/*
+ 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