USB Device ROM Stack API example program

Dependencies:   mbed

LPC1549のROM APIを使ったRAMディスクです。PCからはUSBメモリとして見えます。

参考:
http://docs.lpcware.com/usbromlib/v1.0/

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Fri Mar 14 09:14:16 2014 +0000
Commit message:
first commit

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
rl_usb.h Show annotated file Show diff for this revision Revisions of this file
usb.c Show annotated file Show diff for this revision Revisions of this file
usb.h Show annotated file Show diff for this revision Revisions of this file
usbd_LPC1549.c Show annotated file Show diff for this revision Revisions of this file
usbd_user_msc.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,16 @@
+#if defined(TARGET_LPC1549)
+#include "mbed.h"
+#include <rl_usb.h>
+
+DigitalOut led1(LED1);
+
+int main() {
+    usbd_init(); 
+    usbd_connect(1);    
+    while(1) {
+        led1 = !led1;
+        wait_ms(500);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/8e73be2a2ac1
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rl_usb.h	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,41 @@
+/* CMSIS-DAP Interface Firmware
+ * Copyright (c) 2009-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __RL_USB_H__
+#define __RL_USB_H__
+
+#ifdef __cplusplus
+extern "C"  {
+#endif
+
+#include <stdint.h>
+#include "usb.h"
+
+/*****************  Functions *************************************************/
+
+/* USB Device functions exported from USB Device Core module                  */
+extern void  usbd_init                  (void);
+extern void  usbd_connect               (uint8_t con);
+    
+/* USB Device user functions imported to USB Mass Storage Class module        */
+extern void  usbd_msc_init              (void);
+extern void  usbd_msc_read_sect         (uint32_t block, uint8_t *buf, uint32_t num_of_blocks);
+extern void  usbd_msc_write_sect        (uint32_t block, uint8_t *buf, uint32_t num_of_blocks);    
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __RL_USB_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb.c	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,226 @@
+#if defined(TARGET_LPC1549)
+#include "LPC15xx.h"
+#define ROM_API_ADDR (0x03000200)
+#else
+#error "target error"
+#endif
+#include <rl_usb.h>
+#include <string.h>
+
+USBD_API_T* pUsbApi;
+USBD_HANDLE_T hUsb;
+
+uint32_t USBD_MSC_MemorySize;
+uint32_t USBD_MSC_BlockSize;
+uint32_t USBD_MSC_BlockGroup;
+uint32_t USBD_MSC_BlockCount;
+uint8_t* USBD_MSC_BlockBuf;
+uint8_t USBD_MSC_MediaReady;
+
+extern void USBD_Init(void); // interface/*/usbd_*.c
+extern void USBD_Connect(uint8_t con);
+
+static USBD_API_INIT_PARAM_T usb_param;
+static USB_CORE_DESCS_T desc;
+static USBD_MSC_INIT_PARAM_T msc_param;
+
+static uint8_t usbmem[2048] __attribute__ ((aligned(2048)));
+static uint8_t* mem_base;
+static uint32_t mem_size;
+
+#define WBVAL(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
+
+/* USB Standard Device Descriptor */
+static const uint8_t USB_DeviceDescriptor[] = {
+  18,               /* bLength */
+  1,                /* USB_DEVICE_DESCRIPTOR_TYPE, bDescriptorType */
+  WBVAL(0x0200),    /* 2.00  bcdUSB */
+  0x00,             /* bDeviceClass */
+  0x00,             /* bDeviceSubClass */
+  0x00,             /* bDeviceProtocol */
+  64,               /* USB_MAX_PACKET0, bMaxPacketSize0 */
+  WBVAL(0x0d28),    /* idVendor */
+  WBVAL(0x0204),    /* idProduct */
+  WBVAL(0x0001),    /* bcdDevice */
+  1,                /* iManufacturer */
+  2,                /* iProduct */
+  3,                /* iSerialNumber */
+  1                 /* bNumConfigurations */
+};
+
+/* USB FSConfiguration Descriptor */
+/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
+static const uint8_t USB_FsConfigDescriptor[] = {
+/* Configuration 1 */
+  9,                /* USB_CONFIGUARTION_DESC_SIZE, bLength */
+  2,                /* USB_CONFIGURATION_DESCRIPTOR_TYPE, bDescriptorType */
+  WBVAL(9 + 9 + 7 * 2),/* wTotalLength */
+  0x01,             /* bNumInterfaces */
+  0x01,             /* bConfigurationValue */
+  0x00,             /* iConfiguration */
+  0xc0,             /* USB_CONFIG_SELF_POWERED, bmAttributes */
+  50,               /* USB_CONFIG_POWER_MA(100), bMaxPower */
+/* Interface 0, Alternate Setting 0, MSC Class */
+  9,                /* USB_INTERFACE_DESC_SIZE, bLength */
+  4,                /* USB_INTERFACE_DESCRIPTOR_TYPE, bDescriptorType */
+  0,                /* bInterfaceNumber */
+  0,                /* bAlternateSetting */
+  2,                /* bNumEndpoints */
+  0x08,             /* USB_DEVICE_CLASS_STORAGE, bInterfaceClass */
+  0x06,             /* MSC_SUBCLASS_SCSI, bInterfaceSubClass */
+  0x50,             /* MSC_PROTOCOL_BULK_ONLY, bInterfaceProtocol */
+  0x05,             /* iInterface */
+/* Bulk In Endpoint */
+  7,                /* USB_ENDPOINT_DESC_SIZE, bLength */
+  5,                /* USB_ENDPOINT_DESCRIPTOR_TYPE, bDescriptorType */
+  0x01,             /* MSC_EP_IN, bEndpointAddress */
+  0x02,             /* USB_ENDPOINT_TYPE_BULK, bmAttributes */
+  WBVAL(64),        /* WBVAL(USB_FS_MAX_BULK_PACKET), wMaxPacketSize */
+  0,                /* bInterval */
+/* Bulk Out Endpoint */
+  7,                /* USB_ENDPOINT_DESC_SIZE, bLength */
+  5,                /* USB_ENDPOINT_DESCRIPTOR_TYPE bDescriptorType */
+  0x81,             /* MSC_EP_OUT bEndpointAddress */
+  0x02,             /* USB_ENDPOINT_TYPE_BULK bmAttributes */
+  WBVAL(64),        /* WBVAL(USB_FS_MAX_BULK_PACKET) wMaxPacketSize */
+  0,                /* bInterval */
+/* Terminator */
+  0                 /* bLength */
+};
+
+/* USB String Descriptor (optional) */
+static const uint8_t USB_StringDescriptor[] = {
+  /* Index 0x00: LANGID Codes */
+  4,            /* bLength */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  WBVAL(0x0409),/* US English wLANGID */
+  /* Index 0x01: Manufacturer */
+  (8*2 + 2),   /* bLength (8 Char + Type + lenght) */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  'm', 0, 'b', 0, 'e', 0, 'd', 0, '.', 0, 'o', 0, 'r', 0, 'g', 0, /* mbed.org */
+  /* Index 0x02: Product */
+  (14*2 + 2),   /* bLength (14 Char + Type + lenght) */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  'M', 0, 'B', 0, 'E', 0, ' ', 0, 'D', 0,                                 /* MBED_ */
+  'C', 0, 'M', 0, 'S', 0, 'I', 0, 'S', 0, '-', 0, 'D', 0, 'A', 0, 'P', 0, /* CMSIS-DAP */
+  /* Index 0x03: Serial Number */
+  (10*2 + 2),   /* bLength (10 Char + Type + lenght) */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0,
+  /* Index 0x04: Interface 0, Alternate Setting 0 */
+  (3*2 + 2),    /* bLength (3 Char + Type + lenght) */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  'M', 0, 'S', 0, 'D', 0,
+  /* Index 0x05: Interface 1, Alternate Setting 0 */
+  (3*2 + 2),    /* bLength (3 Char + Type + lenght) */
+  3,            /* USB_STRING_DESCRIPTOR_TYPE, bDescriptorType */
+  'U', 0, 'S', 0, 'B', 0,
+};
+
+static const uint8_t InquiryStr[28] = {
+    'M', 'B', 'E', 'D', '.', 'O', 'R', 'G', 'M', 'B', 
+    'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 
+    'K', ' ', ' ', ' ', '1', '.', '0', ' '
+};
+
+
+static uint8_t MSC_buf[512];                           
+static void MSC_Read(uint32_t offset, uint8_t** buff_adr, uint32_t length, uint32_t high_offset)
+{
+    int i, j;
+    if (offset % 512 == 0) { /* head chunk ? */
+        usbd_msc_read_sect(offset / 512, MSC_buf, 1);
+    }
+    j = offset % 512;
+    for (i = 0; i < length; i++, j++) {
+      (*buff_adr)[i] = MSC_buf[j];
+   }
+}
+
+static void MSC_Write(uint32_t offset, uint8_t** buff_adr, uint32_t length, uint32_t high_offset)
+{
+    int i, j;
+    j = offset % 512;
+    for(i = 0; i < length; i++, j++) {
+        MSC_buf[j] = (*buff_adr)[i];
+    }
+    if ((offset % 512) + length == 512) { /* tail chunk ? */
+        usbd_msc_write_sect(offset / 512, MSC_buf, 1);
+    }
+}
+
+static ErrorCode_t MSC_Verify(uint32_t offset, uint8_t* src, uint32_t length, uint32_t high_offset)
+{
+    return LPC_OK;
+}
+                           
+static void USBD_MSC_Init(void) {
+    ErrorCode_t ret;
+    
+    usbd_msc_init();
+    memset((void*)&msc_param, 0, sizeof(msc_param));
+    msc_param.mem_base = mem_base;
+    msc_param.mem_size = mem_size;
+
+    /* mass storage paramas */
+    msc_param.InquiryStr = InquiryStr; 
+    msc_param.BlockCount = USBD_MSC_BlockCount;
+    msc_param.BlockSize = USBD_MSC_BlockSize;
+    msc_param.MemorySize = USBD_MSC_MemorySize;
+    msc_param.intf_desc = USB_FsConfigDescriptor + 9;
+
+    /* user defined functions */
+    msc_param.MSC_Write = MSC_Write; 
+    msc_param.MSC_Read = MSC_Read;
+    msc_param.MSC_Verify = MSC_Verify;   
+
+    ret = pUsbApi->msc->init(hUsb, &msc_param);
+    if (ret == LPC_OK) {
+        /* update memory variables */
+        mem_base = msc_param.mem_base;
+        mem_size = msc_param.mem_size;
+    }
+}
+
+void usbd_init(void)
+{
+    ErrorCode_t ret;
+
+    USBD_Init();
+    
+    /* get USB API table pointer */
+    pUsbApi = (USBD_API_T*)((*(ROM **)ROM_API_ADDR)->pUSBD);
+
+    mem_base = usbmem;
+    mem_size = sizeof(usbmem);
+
+    /* initilize call back structures */
+    memset((void*)&usb_param, 0, sizeof(usb_param));
+    usb_param.usb_reg_base = LPC_USB_BASE;
+    usb_param.mem_base = mem_base;
+    usb_param.mem_size = mem_size;
+    usb_param.max_num_ep = 2;
+
+    /* Initialize Descriptor pointers */
+    memset((void*)&desc, 0, sizeof(desc));
+    desc.device_desc = USB_DeviceDescriptor;
+    desc.string_desc = USB_StringDescriptor;
+    desc.full_speed_desc = USB_FsConfigDescriptor;
+    desc.high_speed_desc = USB_FsConfigDescriptor;
+
+    /* USB Initialization */
+    ret = pUsbApi->hw->Init(&hUsb, &desc, &usb_param);  
+    if (ret == LPC_OK) {
+        mem_base = usb_param.mem_base;
+        mem_size = usb_param.mem_size;
+        USBD_MSC_Init();    
+    }
+}
+
+void usbd_connect(uint8_t con)
+{
+    USBD_Connect(con);
+    if (con) {
+        pUsbApi->hw->Connect(hUsb, 1);
+    }        
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usb.h	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,108 @@
+#ifndef _USB_H_
+#define _USB_H_
+
+typedef enum {
+    LPC_OK=0,
+} ErrorCode_t;
+
+typedef uint32_t USBD_HANDLE_T;
+typedef void* USB_CB_T;
+typedef void* USB_PARAM_CB_T;
+
+typedef struct _USB_CORE_DESCS_T {
+    const uint8_t *device_desc;
+    const uint8_t *string_desc;
+    const uint8_t *full_speed_desc;
+    const uint8_t *high_speed_desc;
+    const uint8_t *device_qualifier;
+} USB_CORE_DESCS_T;
+
+typedef struct USBD_API_INIT_PARAM {
+    uint32_t usb_reg_base; 
+    uint8_t* mem_base;
+    uint32_t mem_size;
+    uint8_t max_num_ep;
+    uint8_t pad0[3];
+    USB_CB_T USB_Reset_Event;
+    USB_CB_T USB_Suspend_Event;
+    USB_CB_T USB_Resume_Event;
+    USB_CB_T reserved_sbz;
+    USB_CB_T USB_SOF_Event;
+    USB_PARAM_CB_T USB_WakeUpCfg;
+    USB_PARAM_CB_T USB_Power_Event;
+    USB_PARAM_CB_T USB_Error_Event;
+    USB_CB_T USB_Configure_Event;
+    USB_CB_T USB_Interface_Event;
+    USB_CB_T USB_Feature_Event;
+    uint32_t (* virt_to_phys)(void* vaddr);
+    void (* cache_flush)(uint32_t* start_adr, uint32_t* end_adr);
+} USBD_API_INIT_PARAM_T;
+
+typedef struct USBD_HW_API {
+    uint32_t (*GetMemSize)(USBD_API_INIT_PARAM_T* param);
+    ErrorCode_t (*Init)(USBD_HANDLE_T* phUsb, USB_CORE_DESCS_T* pDesc, USBD_API_INIT_PARAM_T* param);
+    void (*Connect)(USBD_HANDLE_T hUsb, uint32_t con);
+    void (*ISR)(USBD_HANDLE_T hUsb);
+} USBD_HW_API_T;
+
+typedef struct USBD_CORE_API {
+    void* dummy;
+    //TODO
+} USBD_CORE_API_T;
+
+typedef struct USBD_MSC_INIT_PARAM {
+    uint8_t* mem_base;
+    uint32_t mem_size;
+    const uint8_t* InquiryStr;
+    uint32_t BlockCount;
+    uint32_t BlockSize;
+    uint32_t MemorySize;
+    const uint8_t* intf_desc;
+    void (*MSC_Write)(uint32_t offset, uint8_t** src, uint32_t length, uint32_t high_offset);
+    void (*MSC_Read)(uint32_t offset, uint8_t** dst, uint32_t length, uint32_t high_offset);
+    ErrorCode_t (*MSC_Verify)(uint32_t offset, uint8_t buf[], uint32_t length, uint32_t high_offset);
+    void (*MSC_GetWriteBuf)(uint32_t offset, uint8_t** buff_adr, uint32_t length, uint32_t high_offset);
+    ErrorCode_t (*MSC_Ep0_Hdlr)(USBD_HANDLE_T hUsb, void* data, uint32_t event);
+    uint64_t  MemorySize64;
+} USBD_MSC_INIT_PARAM_T;
+
+typedef struct USBD_MSC_API {
+    uint32_t (*GetMemSize)(USBD_MSC_INIT_PARAM_T* param);
+    ErrorCode_t (*init)(USBD_HANDLE_T hUsb, USBD_MSC_INIT_PARAM_T* param);
+} USBD_MSC_API_T;
+
+typedef struct USBD_HID_API {
+    void* dummy;
+    // TODO
+} USBD_HID_API_T;
+typedef struct USBD_CDC_API {
+    void* dummy;
+    // TODO
+} USBD_CDC_API_T;
+
+typedef struct USBD_API {
+  const USBD_HW_API_T* hw;
+  const USBD_CORE_API_T* core;
+  const USBD_MSC_API_T* msc;
+  const void* dfu;
+  const USBD_HID_API_T* hid;
+  const USBD_CDC_API_T* cdc;
+  const uint32_t* reserved6;
+  uint32_t version;
+} USBD_API_T;
+
+typedef struct _ROM {
+   const USBD_API_T * pUSBD;
+} ROM;
+
+extern USBD_API_T* pUsbApi;
+extern USBD_HANDLE_T hUsb;
+
+extern uint32_t USBD_MSC_MemorySize;
+extern uint32_t USBD_MSC_BlockSize;
+extern uint32_t USBD_MSC_BlockGroup;
+extern uint32_t USBD_MSC_BlockCount;
+extern uint8_t* USBD_MSC_BlockBuf;
+extern uint8_t USBD_MSC_MediaReady;
+
+#endif // _USB_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbd_LPC1549.c	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,59 @@
+#include <rl_usb.h>
+#include <LPC15xx.h>
+
+/*
+ *  USB Device Initialize Function
+ *   Called by the User to initialize USB Device
+ *    Return Value:    None
+ */
+
+void USBD_Init (void)
+{
+	/* Set USB PLL input to main oscillator */
+    LPC_SYSCON->USBPLLCLKSEL = 0x01;
+    /* Setup USB PLL  (FCLKIN = 12MHz) * 4 = 48MHz
+	   MSEL = 3 (this is pre-decremented), PSEL = 1 (for P = 2)
+	   FCLKOUT = FCLKIN * (MSEL + 1) = 12MHz * 4 = 48MHz
+	   FCCO = FCLKOUT * 2 * P = 48MHz * 2 * 2 = 192MHz (within FCCO range) */
+    LPC_SYSCON->USBPLLCTRL = 3|(1<<6);
+
+	/* Powerup USB PLL */  
+    LPC_SYSCON->PDRUNCFG &= ~(1<<23);
+
+    /* Wait for PLL to lock */
+    while(!(LPC_SYSCON->USBPLLSTAT&0x01));
+
+    /* enable USB main clock */
+    LPC_SYSCON->USBCLKSEL = 0x02;
+    LPC_SYSCON->USBCLKDIV = 1;
+    /* Enable AHB clock to the USB block. */
+    LPC_SYSCON->SYSAHBCLKCTRL1 |= (1<<23);
+    /* power UP USB Phy */
+    LPC_SYSCON->PDRUNCFG &= ~(1<<9);
+    /* Reset USB block */
+    LPC_SYSCON->PRESETCTRL1 |= (1<23);
+}
+
+/*
+ *  USB Device Connect Function
+ *   Called by the User to Connect/Disconnect USB Device
+ *    Parameters:      con:   Connect/Disconnect
+ *    Return Value:    None
+ */
+
+void USBD_Connect(uint8_t con)
+{
+    if (con) {
+        NVIC_EnableIRQ(USB_IRQ_IRQn);
+    } else {
+        NVIC_DisableIRQ(USB_IRQ_IRQn);
+    }
+}
+
+/*
+ *  USB Device Interrupt Service Routine
+ */
+
+void USB_IRQ_IRQHandler(void) {
+  pUsbApi->hw->ISR(hUsb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbd_user_msc.c	Fri Mar 14 09:14:16 2014 +0000
@@ -0,0 +1,160 @@
+#include <rl_usb.h>
+
+// from USBMSD_Ram.cpp http://mbed.org/users/samux/code/RAM_DISK/
+//5 sectors
+const uint8_t disk_image_0[] = {
+    //sector 0: boot sector
+    0xEB,0x3C,0x90,0x4D,0x53,0x44,0x4F,0x53,0x35,0x2E,0x30,    0x00,0x02,/*bytes per sector: 512*/   0x08, /*sectors per cluster*/ 0x01,0x00,/*number of reserved sector*/
+    0x01, /* number of FATs*/ 0x10,0x00, /*Maximum number of root directory entries: 16*/ 0x20,0x00, /*Total sector count: 32*/ 0xF0,  0x02,0x00,/*sectors per FAT: 2*/  0x01,0x00,/*Sectors per track*/  0x01,0x00, /*Number of heads*/  0x00,0x00,0x00,0x00,
+    0x00,0x01,0x00,0x00,0x00,0x00,  0x29, /*boot signature*/ 0x74,0x19,0x02,0x27, /*volume ID*/ 'M','b','e','d',' ',
+    'U','S','B',' ',' ',' ', /*volume label: Mbed USB*/     0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x33,0xC9,
+    0x8E,0xD1,0xBC,0xF0,0x7B,0x8E,0xD9,0xB8,0x00,0x20,0x8E,0xC0,0xFC,0xBD,0x00,0x7C,
+    0x38,0x4E,0x24,0x7D,0x24,0x8B,0xC1,0x99,0xE8,0x3C,0x01,0x72,0x1C,0x83,0xEB,0x3A,
+    0x66,0xA1,0x1C,0x7C,0x26,0x66,0x3B,0x07,0x26,0x8A,0x57,0xFC,0x75,0x06,0x80,0xCA,
+    0x02,0x88,0x56,0x02,0x80,0xC3,0x10,0x73,0xEB,0x33,0xC9,0x8A,0x46,0x10,0x98,0xF7,
+    0x66,0x16,0x03,0x46,0x1C,0x13,0x56,0x1E,0x03,0x46,0x0E,0x13,0xD1,0x8B,0x76,0x11,
+    0x60,0x89,0x46,0xFC,0x89,0x56,0xFE,0xB8,0x20,0x00,0xF7,0xE6,0x8B,0x5E,0x0B,0x03,
+    0xC3,0x48,0xF7,0xF3,0x01,0x46,0xFC,0x11,0x4E,0xFE,0x61,0xBF,0x00,0x00,0xE8,0xE6,
+    0x00,0x72,0x39,0x26,0x38,0x2D,0x74,0x17,0x60,0xB1,0x0B,0xBE,0xA1,0x7D,0xF3,0xA6,
+    0x61,0x74,0x32,0x4E,0x74,0x09,0x83,0xC7,0x20,0x3B,0xFB,0x72,0xE6,0xEB,0xDC,0xA0,
+    0xFB,0x7D,0xB4,0x7D,0x8B,0xF0,0xAC,0x98,0x40,0x74,0x0C,0x48,0x74,0x13,0xB4,0x0E,
+    0xBB,0x07,0x00,0xCD,0x10,0xEB,0xEF,0xA0,0xFD,0x7D,0xEB,0xE6,0xA0,0xFC,0x7D,0xEB,
+    0xE1,0xCD,0x16,0xCD,0x19,0x26,0x8B,0x55,0x1A,0x52,0xB0,0x01,0xBB,0x00,0x00,0xE8,
+    0x3B,0x00,0x72,0xE8,0x5B,0x8A,0x56,0x24,0xBE,0x0B,0x7C,0x8B,0xFC,0xC7,0x46,0xF0,
+    0x3D,0x7D,0xC7,0x46,0xF4,0x29,0x7D,0x8C,0xD9,0x89,0x4E,0xF2,0x89,0x4E,0xF6,0xC6,
+    0x06,0x96,0x7D,0xCB,0xEA,0x03,0x00,0x00,0x20,0x0F,0xB6,0xC8,0x66,0x8B,0x46,0xF8,
+    0x66,0x03,0x46,0x1C,0x66,0x8B,0xD0,0x66,0xC1,0xEA,0x10,0xEB,0x5E,0x0F,0xB6,0xC8,
+    0x4A,0x4A,0x8A,0x46,0x0D,0x32,0xE4,0xF7,0xE2,0x03,0x46,0xFC,0x13,0x56,0xFE,0xEB,
+    0x4A,0x52,0x50,0x06,0x53,0x6A,0x01,0x6A,0x10,0x91,0x8B,0x46,0x18,0x96,0x92,0x33,
+    0xD2,0xF7,0xF6,0x91,0xF7,0xF6,0x42,0x87,0xCA,0xF7,0x76,0x1A,0x8A,0xF2,0x8A,0xE8,
+    0xC0,0xCC,0x02,0x0A,0xCC,0xB8,0x01,0x02,0x80,0x7E,0x02,0x0E,0x75,0x04,0xB4,0x42,
+    0x8B,0xF4,0x8A,0x56,0x24,0xCD,0x13,0x61,0x61,0x72,0x0B,0x40,0x75,0x01,0x42,0x03,
+    0x5E,0x0B,0x49,0x75,0x06,0xF8,0xC3,0x41,0xBB,0x00,0x00,0x60,0x66,0x6A,0x00,0xEB,
+    0xB0,0x4E,0x54,0x4C,0x44,0x52,0x20,0x20,0x20,0x20,0x20,0x20,0x0D,0x0A,0x52,0x65,
+    0x6D,0x6F,0x76,0x65,0x20,0x64,0x69,0x73,0x6B,0x73,0x20,0x6F,0x72,0x20,0x6F,0x74,
+    0x68,0x65,0x72,0x20,0x6D,0x65,0x64,0x69,0x61,0x2E,0xFF,0x0D,0x0A,0x44,0x69,0x73,
+    0x6B,0x20,0x65,0x72,0x72,0x6F,0x72,0xFF,0x0D,0x0A,0x50,0x72,0x65,0x73,0x73,0x20,
+    0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,0x6F,0x20,0x72,0x65,0x73,0x74,0x61,
+    0x72,0x74,0x0D,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAC,0xCB,0xD8,0x55,0xAA,
+};
+
+const uint8_t disk_image_1[] = {
+    //sector 1: FAT 1
+    0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,
+};
+
+const uint8_t disk_image_2[] = {    
+    //sector 2: FAT1: two sectors per FAT
+};
+
+const uint8_t disk_image_3[] = {     
+    //sector 3: root directory
+    //entry 1
+    'M','b','e','d',' ','U','S','B',' ',' ',' ',   0x28,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    //entry 2
+    0x52,0x45,0x41,0x44,0x4D,0x45,0x20,0x20,0x54,0x58,0x54, /*readme.txt*/ 0x20,0x00,0x00,0x00,0x00,
+    0x21,0x00,0xBB,0x32,0x00,0x00,   0xDC,0x83,/*hour/min/doublesec*/  0x6A,0x3F,/*year/month/day*/  0x02,0x00, /*starting cluster*/ 0x1e,0x00,0x00,0x00, /*size*/
+};
+    
+const uint8_t disk_image_4[] = {    
+    //sector 4: data
+    'H','e','l','l','o',' ','f','r','o','m',' ','M','b','e','d','!',
+    '\r','\n','U','S','B',' ','M','S','D',' ','d','e','m','o',
+};
+
+#define SLOT_SIZE 48
+static int slot[SLOT_SIZE];
+static uint8_t image[SLOT_SIZE][512];
+
+static int index_block(int block) {
+    int i;
+    for(i = 0; i < SLOT_SIZE; i++) {
+        if (slot[i] == block) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static int block_len(uint8_t* buf) {
+    int i;
+    for(i = 512-1; i >= 0; i--) {
+        if (buf[i] != 0x00) {
+            return i+1;
+        }
+    }
+    return 0;
+}
+
+static void mem_cpy(uint8_t* dst, const uint8_t* src, int size)
+{
+    while(size-- > 0) {
+        *dst++ = *src++;
+    }
+}
+
+static void mem_set(uint8_t* dst, uint8_t dat, int size)
+{
+    while(size-- > 0) {
+        *dst++ = dat;
+    }
+}
+   
+void usbd_msc_read_sect(uint32_t block, uint8_t *buf, uint32_t num_of_blocks)
+{
+    int i;
+    i = index_block(block);
+    if (i != (-1)) {
+        mem_cpy(buf, image[i], 512);
+    } else {
+        mem_set(buf, 0x00, 512);
+    }
+}
+
+void usbd_msc_write_sect(uint32_t block, uint8_t *buf, uint32_t num_of_blocks)
+{
+    int i, len;
+    len = block_len(buf);
+    i = index_block(block);
+    if (i != -1) {
+        if (len == 0) {
+            slot[i] = -1;
+        } else {
+            mem_cpy(image[i], buf, 512);
+        }
+    } else {
+        if (len != 0) {
+            for(i = 0; i < SLOT_SIZE; i++) {
+                if (slot[i] == (-1)) {
+                    slot[i] = block;
+                    mem_cpy(image[i], buf, 512);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void usbd_msc_init () {
+    int i;
+    for(i = 0; i < SLOT_SIZE; i++) {
+        slot[i] = -1;
+        mem_set(image[i], 0, 512);
+    }
+    for(i = 0; i < 5; i++) {
+        slot[i] = i;
+    }
+    mem_cpy(image[0], disk_image_0, sizeof(disk_image_0));
+    mem_cpy(image[1], disk_image_1, sizeof(disk_image_1));
+    mem_cpy(image[2], disk_image_2, sizeof(disk_image_2));
+    mem_cpy(image[3], disk_image_3, sizeof(disk_image_3));
+    mem_cpy(image[4], disk_image_4, sizeof(disk_image_4));
+    
+    USBD_MSC_MemorySize = 65536;
+    USBD_MSC_BlockSize  = 512;
+    USBD_MSC_BlockGroup = 1;
+    USBD_MSC_BlockCount = USBD_MSC_MemorySize / USBD_MSC_BlockSize;
+    //USBD_MSC_BlockBuf   = (uint8_t *)usb_buffer;
+    //USBD_MSC_MediaReady = __TRUE;
+}