usb mass storage class
This commit is contained in:
@@ -28,7 +28,7 @@
|
|||||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
|
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
|
||||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
|
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
|
||||||
|
|
||||||
#define VIRTUAL_COM_PORT_DATA_SIZE 64
|
#define VIRTUAL_COM_PORT_DATA_SIZE 16
|
||||||
#define VIRTUAL_COM_PORT_INT_SIZE 8
|
#define VIRTUAL_COM_PORT_INT_SIZE 8
|
||||||
|
|
||||||
#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18
|
#define VIRTUAL_COM_PORT_SIZ_DEVICE_DESC 18
|
||||||
|
|||||||
@@ -439,6 +439,13 @@ main (int argc, char **argv)
|
|||||||
"Hello world\r\n\r\n", 35+21+15);
|
"Hello world\r\n\r\n", 35+21+15);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (msc_recv_cbw () == 0)
|
||||||
|
{
|
||||||
|
int r = msc_handle_cbw ();
|
||||||
|
|
||||||
|
if (r != 1)
|
||||||
|
msc_handle_err (r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -28,9 +28,14 @@
|
|||||||
/* EP3 */
|
/* EP3 */
|
||||||
#define ENDP3_TXADDR (0x140)
|
#define ENDP3_TXADDR (0x140)
|
||||||
/* EP4 */
|
/* EP4 */
|
||||||
#define ENDP4_TXADDR (0x180)
|
#define ENDP4_TXADDR (0x150)
|
||||||
/* EP5 */
|
/* EP5 */
|
||||||
#define ENDP5_RXADDR (0x190)
|
#define ENDP5_RXADDR (0x160)
|
||||||
|
|
||||||
|
/* EP6 */
|
||||||
|
#define ENDP6_TXADDR (0x180)
|
||||||
|
/* EP7 */
|
||||||
|
#define ENDP7_RXADDR (0x1c0)
|
||||||
|
|
||||||
#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )
|
#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )
|
||||||
|
|
||||||
|
|||||||
@@ -29,14 +29,29 @@ static const uint8_t gnukDeviceDescriptor[] = {
|
|||||||
0x01 /* bNumConfigurations */
|
0x01 /* bNumConfigurations */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ICC_TOTAL_LENGTH (9+9+54+7+7)
|
||||||
|
#define ICC_NUM_INTERFACES 1
|
||||||
|
|
||||||
#ifdef ENABLE_VIRTUAL_COM_PORT
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||||
#define W_TOTAL_LENGTH (9+9+54+7+7+9+5+5+4+5+7+9+7+7)
|
#define VCOM_TOTAL_LENGTH (9+5+5+4+5+7+9+7+7)
|
||||||
#define NUM_INTERFACES 3 /* two for CDC, one for GPG */
|
#define VCOM_NUM_INTERFACES 2
|
||||||
#else
|
#else
|
||||||
#define W_TOTAL_LENGTH (9+9+54+7+7)
|
#define VCOM_TOTAL_LENGTH 0
|
||||||
#define NUM_INTERFACES 1 /* GPG only */
|
#define VCOM_NUM_INTERFACES 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PINPAD_DND_SUPPORT
|
||||||
|
#define MSC_TOTAL_LENGTH (9+7+7)
|
||||||
|
#define MSC_NUM_INTERFACES 1
|
||||||
|
#else
|
||||||
|
#define MSC_TOTAL_LENGTH 0
|
||||||
|
#define MSC_NUM_INTERFACES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define W_TOTAL_LENGTH (ICC_TOTAL_LENGTH+VCOM_TOTAL_LENGTH+MSC_TOTAL_LENGTH)
|
||||||
|
#define NUM_INTERFACES (ICC_NUM_INTERFACES+VCOM_NUM_INTERFACES+MSC_NUM_INTERFACES)
|
||||||
|
|
||||||
|
|
||||||
/* Configuation Descriptor */
|
/* Configuation Descriptor */
|
||||||
static const uint8_t gnukConfigDescriptor[] = {
|
static const uint8_t gnukConfigDescriptor[] = {
|
||||||
9, /* bLength: Configuation Descriptor size */
|
9, /* bLength: Configuation Descriptor size */
|
||||||
@@ -105,7 +120,7 @@ static const uint8_t gnukConfigDescriptor[] = {
|
|||||||
0xff, /* bClassEnvelope: */
|
0xff, /* bClassEnvelope: */
|
||||||
0, 0, /* wLCDLayout: FIXED VALUE */
|
0, 0, /* wLCDLayout: FIXED VALUE */
|
||||||
#if defined(PINPAD_SUPPORT)
|
#if defined(PINPAD_SUPPORT)
|
||||||
#if defined(PINPAD_CIR_SUPPORT)
|
#if defined(PINPAD_CIR_SUPPORT) || defined(PINPAD_DND_SUPPORT)
|
||||||
1, /* bPinSupport: with PIN pad (verify) */
|
1, /* bPinSupport: with PIN pad (verify) */
|
||||||
#elif defined(PINPAD_DIAL_SUPPORT)
|
#elif defined(PINPAD_DIAL_SUPPORT)
|
||||||
3, /* bPinSupport: with PIN pad (verify, modify) */
|
3, /* bPinSupport: with PIN pad (verify, modify) */
|
||||||
@@ -193,7 +208,40 @@ static const uint8_t gnukConfigDescriptor[] = {
|
|||||||
0x83, /* bEndpointAddress: (IN3) */
|
0x83, /* bEndpointAddress: (IN3) */
|
||||||
0x02, /* bmAttributes: Bulk */
|
0x02, /* bmAttributes: Bulk */
|
||||||
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
VIRTUAL_COM_PORT_DATA_SIZE, 0x00, /* wMaxPacketSize: */
|
||||||
0x00 /* bInterval */
|
0x00, /* bInterval */
|
||||||
|
#endif
|
||||||
|
#ifdef PINPAD_DND_SUPPORT
|
||||||
|
/* Interface Descriptor.*/
|
||||||
|
9, /* bLength: Interface Descriptor size */
|
||||||
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
|
||||||
|
#ifdef ENABLE_VIRTUAL_COM_PORT
|
||||||
|
0x03, /* bInterfaceNumber. */
|
||||||
|
#else
|
||||||
|
0x01, /* bInterfaceNumber. */
|
||||||
|
#endif
|
||||||
|
0x00, /* bAlternateSetting. */
|
||||||
|
0x02, /* bNumEndpoints. */
|
||||||
|
0x08, /* bInterfaceClass (Mass Stprage). */
|
||||||
|
0x06, /* bInterfaceSubClass (SCSI
|
||||||
|
transparent command set, MSCO
|
||||||
|
chapter 2). */
|
||||||
|
0x50, /* bInterfaceProtocol (Bulk-Only
|
||||||
|
Mass Storage, MSCO chapter 3). */
|
||||||
|
0x00, /* iInterface. */
|
||||||
|
/* Endpoint Descriptor.*/
|
||||||
|
7, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||||
|
0x86, /* bEndpointAddress: (IN6) */
|
||||||
|
0x02, /* bmAttributes (Bulk). */
|
||||||
|
0x40, 0x00, /* wMaxPacketSize. */
|
||||||
|
0x00, /* bInterval (ignored for bulk). */
|
||||||
|
/* Endpoint Descriptor.*/
|
||||||
|
7, /* bLength: Endpoint Descriptor size */
|
||||||
|
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
|
||||||
|
0x07, /* bEndpointAddress: (OUT7) */
|
||||||
|
0x02, /* bmAttributes (Bulk). */
|
||||||
|
0x40, 0x00, /* wMaxPacketSize. */
|
||||||
|
0x00, /* bInterval (ignored for bulk). */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
491
src/usb_msc.c
Normal file
491
src/usb_msc.c
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
#include "usb_lib.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "ch.h"
|
||||||
|
#include "gnuk.h"
|
||||||
|
#include "usb_msc.h"
|
||||||
|
|
||||||
|
struct usb_endp_in {
|
||||||
|
const uint8_t *txbuf; /* Pointer to the transmission buffer. */
|
||||||
|
size_t txsize; /* Transmit transfer size remained. */
|
||||||
|
size_t txcnt; /* Transmitted bytes so far. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usb_endp_out {
|
||||||
|
uint8_t *rxbuf; /* Pointer to the receive buffer. */
|
||||||
|
size_t rxsize; /* Requested receive transfer size. */
|
||||||
|
size_t rxcnt; /* Received bytes so far. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct usb_endp_in ep6_in;
|
||||||
|
static struct usb_endp_out ep7_out;
|
||||||
|
|
||||||
|
static Thread *the_thread;
|
||||||
|
|
||||||
|
#define ENDP_MAX_SIZE 64
|
||||||
|
|
||||||
|
static uint8_t msc_state;
|
||||||
|
|
||||||
|
|
||||||
|
static void usb_stall_transmit (void)
|
||||||
|
{
|
||||||
|
SetEPTxStatus (ENDP6, EP_TX_STALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_start_transmit (const uint8_t *p, size_t n)
|
||||||
|
{
|
||||||
|
size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
|
||||||
|
|
||||||
|
ep6_in.txbuf = p;
|
||||||
|
ep6_in.txsize = n;
|
||||||
|
ep6_in.txcnt = 0;
|
||||||
|
|
||||||
|
USB_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, pkt_len);
|
||||||
|
SetEPTxValid (ENDP6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Data Transmitted" callback */
|
||||||
|
void EP6_IN_Callback (void)
|
||||||
|
{
|
||||||
|
size_t n = (size_t)GetEPTxCount (ENDP6);
|
||||||
|
|
||||||
|
ep6_in.txbuf += n;
|
||||||
|
ep6_in.txcnt += n;
|
||||||
|
ep6_in.txsize -= n;
|
||||||
|
|
||||||
|
if (ep6_in.txsize > 0) /* More data to be sent */
|
||||||
|
{
|
||||||
|
if (ep6_in.txsize > ENDP_MAX_SIZE)
|
||||||
|
n = ENDP_MAX_SIZE;
|
||||||
|
else
|
||||||
|
n = ep6_in.txsize;
|
||||||
|
USB_SIL_Write (EP6_IN, (uint8_t *)ep6_in.txbuf, n);
|
||||||
|
SetEPTxValid (ENDP6);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transmit has been completed, notify the waiting thread */
|
||||||
|
switch (msc_state)
|
||||||
|
{
|
||||||
|
case MSC_SENDING_CSW:
|
||||||
|
case MSC_DATA_IN:
|
||||||
|
if (the_thread != NULL) {
|
||||||
|
Thread *tp;
|
||||||
|
chSysLockFromIsr ();
|
||||||
|
tp = the_thread;
|
||||||
|
the_thread = NULL;
|
||||||
|
tp->p_u.rdymsg = RDY_OK;
|
||||||
|
chSchReadyI (tp);
|
||||||
|
chSysUnlockFromIsr ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void usb_stall_receive (void)
|
||||||
|
{
|
||||||
|
SetEPRxStatus (ENDP7, EP_RX_STALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_start_receive (uint8_t *p, size_t n)
|
||||||
|
{
|
||||||
|
ep7_out.rxbuf = p;
|
||||||
|
ep7_out.rxsize = n;
|
||||||
|
ep7_out.rxcnt = 0;
|
||||||
|
SetEPRxValid (ENDP7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Data Received" call back */
|
||||||
|
void EP7_OUT_Callback (void)
|
||||||
|
{
|
||||||
|
size_t n = (size_t)GetEPRxCount (ENDP7);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (n > ep7_out.rxsize)
|
||||||
|
{ /* buffer overflow */
|
||||||
|
err = 1;
|
||||||
|
SetEPRxCount (ENDP7, ep7_out.rxsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = USB_SIL_Read (EP7_OUT, ep7_out.rxbuf);
|
||||||
|
ep7_out.rxbuf += n;
|
||||||
|
ep7_out.rxcnt += n;
|
||||||
|
ep7_out.rxsize -= n;
|
||||||
|
|
||||||
|
if (n == ENDP_MAX_SIZE && ep7_out.rxsize != 0)
|
||||||
|
{ /* More data to be received */
|
||||||
|
SetEPRxValid (ENDP7);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receiving has been completed, notify the waiting thread */
|
||||||
|
switch (msc_state)
|
||||||
|
{
|
||||||
|
case MSC_IDLE:
|
||||||
|
case MSC_DATA_OUT:
|
||||||
|
if (the_thread != NULL) {
|
||||||
|
Thread *tp;
|
||||||
|
chSysLockFromIsr ();
|
||||||
|
tp = the_thread;
|
||||||
|
the_thread = NULL;
|
||||||
|
tp->p_u.rdymsg = err? RDY_OK : RDY_RESET;
|
||||||
|
chSchReadyI (tp);
|
||||||
|
chSysUnlockFromIsr ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t lun_buf[4] = {0, 0, 0, 0}; /* One drives: 0 */
|
||||||
|
|
||||||
|
static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
static const uint8_t scsi_inquiry_data[] = {
|
||||||
|
0x00, /* Direct Access Device. */
|
||||||
|
0x80, /* RMB = 1: Removable Medium. */
|
||||||
|
0x05, /* Version: SPC-3. */
|
||||||
|
0x02, /* Response format: SPC-3. */
|
||||||
|
36 - 4, /* Additional Length. */
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
/* Vendor Identification */
|
||||||
|
'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ',
|
||||||
|
/* Product Identification */
|
||||||
|
'V', 'i', 'r', 't', 'u', 'a', 'l', ' ',
|
||||||
|
'D', 'i', 's', 'k', ' ', ' ', ' ', ' ',
|
||||||
|
/* Product Revision Level */
|
||||||
|
'1', '.', '0', ' '
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t scsi_sense_data_desc[] = {
|
||||||
|
0x72, /* Response Code: descriptor, current */
|
||||||
|
0x02, /* Sense Key */
|
||||||
|
0x3a, /* ASC (additional sense code) */
|
||||||
|
0x00, /* ASCQ (additional sense code qualifier) */
|
||||||
|
0x00, 0x00, 0x00,
|
||||||
|
0x00, /* Additional Sense Length */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t scsi_sense_data_fixed[] = {
|
||||||
|
0x70, /* Response Code: fixed, current */
|
||||||
|
0x00,
|
||||||
|
0x02, /* Sense Key */
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x0a, /* Additional Sense Length */
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x3a, /* ASC (additional sense code) */
|
||||||
|
0x00, /* ASCQ (additional sense code qualifier) */
|
||||||
|
0x00,
|
||||||
|
0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc) {
|
||||||
|
scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key;
|
||||||
|
scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t buf[512];
|
||||||
|
|
||||||
|
static uint8_t media_available;
|
||||||
|
static uint8_t media_changed;
|
||||||
|
|
||||||
|
void msc_media_insert_change (int available)
|
||||||
|
{
|
||||||
|
media_available = available;
|
||||||
|
media_changed = 1;
|
||||||
|
if (available)
|
||||||
|
set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */
|
||||||
|
else
|
||||||
|
set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t scsi_read_format_capacities (uint32_t *nblocks,
|
||||||
|
uint32_t *secsize)
|
||||||
|
{
|
||||||
|
*nblocks = 68;
|
||||||
|
*secsize = 512;
|
||||||
|
if (media_available)
|
||||||
|
return 2; /* Formatted Media.*/
|
||||||
|
else
|
||||||
|
return 3; /* No Media.*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct CBW CBW;
|
||||||
|
|
||||||
|
static struct CSW CSW;
|
||||||
|
|
||||||
|
int msc_recv_cbw (void)
|
||||||
|
{
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msc_state = MSC_IDLE;
|
||||||
|
the_thread = chThdSelf ();
|
||||||
|
usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
|
||||||
|
chSchGoSleepTimeoutS (THD_STATE_SUSPENDED, MS2ST (1000));
|
||||||
|
msg = chThdSelf ()->p_u.rdymsg;
|
||||||
|
chSysUnlock ();
|
||||||
|
if (msg == RDY_OK)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msc_recv_data (void)
|
||||||
|
{
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock ();
|
||||||
|
msc_state = MSC_DATA_OUT;
|
||||||
|
the_thread = chThdSelf ();
|
||||||
|
usb_start_receive (buf, 512);
|
||||||
|
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||||
|
msg = chThdSelf ()->p_u.rdymsg;
|
||||||
|
chSysUnlock ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msc_send_data (const uint8_t *p, size_t n)
|
||||||
|
{
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock ();
|
||||||
|
msc_state = MSC_DATA_IN;
|
||||||
|
the_thread = chThdSelf ();
|
||||||
|
usb_start_transmit (p, n);
|
||||||
|
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||||
|
msg = chThdSelf ()->p_u.rdymsg;
|
||||||
|
CSW.dCSWDataResidue -= (uint32_t)n;
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msc_send_result (const uint8_t *p, size_t n)
|
||||||
|
{
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
if (n > CBW.dCBWDataTransferLength)
|
||||||
|
n = CBW.dCBWDataTransferLength;
|
||||||
|
|
||||||
|
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||||
|
msc_send_data (p, n);
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
chSysLock ();
|
||||||
|
msc_state = MSC_SENDING_CSW;
|
||||||
|
the_thread = chThdSelf ();
|
||||||
|
usb_start_transmit ((uint8_t *)&CSW, sizeof CSW);
|
||||||
|
chSchGoSleepS (THD_STATE_SUSPENDED);
|
||||||
|
msg = chThdSelf ()->p_u.rdymsg;
|
||||||
|
chSysUnlock ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void msc_handle_err (int err)
|
||||||
|
{
|
||||||
|
if (err == 0)
|
||||||
|
{
|
||||||
|
msc_state = MSC_ERROR;
|
||||||
|
chSysLock ();
|
||||||
|
usb_stall_receive ();
|
||||||
|
chSysUnlock ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msc_state = MSC_ERROR;
|
||||||
|
chSysLock ();
|
||||||
|
usb_stall_transmit ();
|
||||||
|
usb_stall_receive ();
|
||||||
|
chSysUnlock ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int msc_handle_cbw (void)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
uint32_t nblocks, secsize;
|
||||||
|
uint8_t lun;
|
||||||
|
uint32_t lba;
|
||||||
|
|
||||||
|
n = ep7_out.rxcnt;
|
||||||
|
|
||||||
|
if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CSW.dCSWTag = CBW.dCBWTag;
|
||||||
|
switch (CBW.CBWCB[0]) {
|
||||||
|
case SCSI_REQUEST_SENSE:
|
||||||
|
if (CBW.CBWCB[1] & 0x01) /* DESC */
|
||||||
|
msc_send_result ((uint8_t *)&scsi_sense_data_desc,
|
||||||
|
sizeof scsi_sense_data_desc);
|
||||||
|
else
|
||||||
|
msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
|
||||||
|
sizeof scsi_sense_data_fixed);
|
||||||
|
if (media_changed && media_available)
|
||||||
|
{
|
||||||
|
media_changed = 0;
|
||||||
|
set_scsi_sense_data (0x00, 0x00);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
case SCSI_INQUIRY:
|
||||||
|
if (CBW.CBWCB[1] & 0x01) /* EVPD */
|
||||||
|
/* assume page 00 */
|
||||||
|
msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
|
||||||
|
sizeof scsi_inquiry_data_00);
|
||||||
|
else
|
||||||
|
msc_send_result ((uint8_t *)&scsi_inquiry_data,
|
||||||
|
sizeof scsi_inquiry_data);
|
||||||
|
return 1;
|
||||||
|
case SCSI_READ_FORMAT_CAPACITIES:
|
||||||
|
buf[8] = scsi_read_format_capacities (&nblocks, &secsize);
|
||||||
|
buf[0] = buf[1] = buf[2] = 0;
|
||||||
|
buf[3] = 8;
|
||||||
|
buf[4] = (uint8_t)(nblocks >> 24);
|
||||||
|
buf[5] = (uint8_t)(nblocks >> 16);
|
||||||
|
buf[6] = (uint8_t)(nblocks >> 8);
|
||||||
|
buf[7] = (uint8_t)(nblocks >> 0);
|
||||||
|
buf[9] = (uint8_t)(secsize >> 16);
|
||||||
|
buf[10] = (uint8_t)(secsize >> 8);
|
||||||
|
buf[11] = (uint8_t)(secsize >> 0);
|
||||||
|
msc_send_result (buf, 12);
|
||||||
|
return 1;
|
||||||
|
case SCSI_TEST_UNIT_READY:
|
||||||
|
if (media_available == 0 || media_changed)
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||||
|
CSW.dCSWDataResidue = 0;
|
||||||
|
msc_send_result (NULL, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case SCSI_SYNCHRONIZE_CACHE:
|
||||||
|
case SCSI_VERIFY10:
|
||||||
|
case SCSI_START_STOP_UNIT:
|
||||||
|
case SCSI_ALLOW_MEDIUM_REMOVAL:
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||||
|
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||||
|
msc_send_result (NULL, 0);
|
||||||
|
return 1;
|
||||||
|
case SCSI_MODE_SENSE6:
|
||||||
|
buf[0] = 0x03;
|
||||||
|
buf[1] = buf[2] = buf[3] = 0;
|
||||||
|
msc_send_result (buf, 4);
|
||||||
|
return 1;
|
||||||
|
case SCSI_READ_CAPACITY10:
|
||||||
|
scsi_read_format_capacities (&nblocks, &secsize);
|
||||||
|
buf[0] = (uint8_t)((nblocks - 1) >> 24);
|
||||||
|
buf[1] = (uint8_t)((nblocks - 1) >> 16);
|
||||||
|
buf[2] = (uint8_t)((nblocks - 1) >> 8);
|
||||||
|
buf[3] = (uint8_t)((nblocks - 1) >> 0);
|
||||||
|
buf[4] = (uint8_t)(secsize >> 24);
|
||||||
|
buf[5] = (uint8_t)(secsize >> 16);
|
||||||
|
buf[6] = (uint8_t)(secsize >> 8);
|
||||||
|
buf[7] = (uint8_t)(secsize >> 0);
|
||||||
|
msc_send_result (buf, 8);
|
||||||
|
return 1;
|
||||||
|
case SCSI_READ10:
|
||||||
|
case SCSI_WRITE10:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (CBW.dCBWDataTransferLength == 0)
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||||
|
CSW.dCSWDataResidue = 0;
|
||||||
|
msc_send_result (NULL, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lun = CBW.bCBWLUN;
|
||||||
|
lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
|
||||||
|
| (CBW.CBWCB[4] << 8) | CBW.CBWCB[5];
|
||||||
|
|
||||||
|
/* Transfer direction.*/
|
||||||
|
if (CBW.bmCBWFlags & 0x80)
|
||||||
|
{
|
||||||
|
/* IN, Device to Host.*/
|
||||||
|
msc_state = MSC_DATA_IN;
|
||||||
|
if (CBW.CBWCB[0] == SCSI_READ10)
|
||||||
|
{
|
||||||
|
const uint8_t *p;
|
||||||
|
|
||||||
|
CSW.dCSWDataResidue = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((p = msc_scsi_read (lun, lba)))
|
||||||
|
{
|
||||||
|
msc_send_data (p, 512);
|
||||||
|
if (++CBW.CBWCB[5] == 0)
|
||||||
|
if (++CBW.CBWCB[4] == 0)
|
||||||
|
if (++CBW.CBWCB[3] == 0)
|
||||||
|
++CBW.CBWCB[2];
|
||||||
|
if (CBW.CBWCB[8]-- == 0)
|
||||||
|
CBW.CBWCB[7]--;
|
||||||
|
CSW.dCSWDataResidue += 512;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msc_send_result (NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* OUT, Host to Device.*/
|
||||||
|
if (CBW.CBWCB[0] == SCSI_WRITE10)
|
||||||
|
{
|
||||||
|
CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
msc_recv_data ();
|
||||||
|
if (msc_scsi_write (lun, lba, buf, 512))
|
||||||
|
{
|
||||||
|
if (++CBW.CBWCB[5] == 0)
|
||||||
|
if (++CBW.CBWCB[4] == 0)
|
||||||
|
if (++CBW.CBWCB[3] == 0)
|
||||||
|
++CBW.CBWCB[2];
|
||||||
|
if (CBW.CBWCB[8]-- == 0)
|
||||||
|
CBW.CBWCB[7]--;
|
||||||
|
CSW.dCSWDataResidue -= 512;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msc_send_result (NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
45
src/usb_msc.h
Normal file
45
src/usb_msc.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#define MSC_CBW_SIGNATURE 0x43425355
|
||||||
|
#define MSC_CSW_SIGNATURE 0x53425355
|
||||||
|
|
||||||
|
#define MSC_GET_MAX_LUN_COMMAND 0xFE
|
||||||
|
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
|
||||||
|
|
||||||
|
#define MSC_CSW_STATUS_PASSED 0
|
||||||
|
#define MSC_CSW_STATUS_FAILED 1
|
||||||
|
|
||||||
|
#define SCSI_INQUIRY 0x12
|
||||||
|
#define SCSI_MODE_SENSE6 0x1A
|
||||||
|
#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||||
|
#define SCSI_READ10 0x28
|
||||||
|
#define SCSI_READ_CAPACITY10 0x25
|
||||||
|
#define SCSI_REQUEST_SENSE 0x03
|
||||||
|
#define SCSI_START_STOP_UNIT 0x1B
|
||||||
|
#define SCSI_TEST_UNIT_READY 0x00
|
||||||
|
#define SCSI_WRITE10 0x2A
|
||||||
|
#define SCSI_VERIFY10 0x2F
|
||||||
|
#define SCSI_READ_FORMAT_CAPACITIES 0x23
|
||||||
|
|
||||||
|
#define SCSI_SYNCHRONIZE_CACHE 0x35
|
||||||
|
|
||||||
|
#define MSC_IDLE 0
|
||||||
|
#define MSC_DATA_OUT 1
|
||||||
|
#define MSC_DATA_IN 2
|
||||||
|
#define MSC_SENDING_CSW 3
|
||||||
|
#define MSC_ERROR 4
|
||||||
|
|
||||||
|
struct CBW {
|
||||||
|
uint32_t dCBWSignature;
|
||||||
|
uint32_t dCBWTag;
|
||||||
|
uint32_t dCBWDataTransferLength;
|
||||||
|
uint8_t bmCBWFlags;
|
||||||
|
uint8_t bCBWLUN;
|
||||||
|
uint8_t bCBWCBLength;
|
||||||
|
uint8_t CBWCB[16];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct CSW {
|
||||||
|
uint32_t dCSWSignature;
|
||||||
|
uint32_t dCSWTag;
|
||||||
|
uint32_t dCSWDataResidue;
|
||||||
|
uint8_t bCSWStatus;
|
||||||
|
} __attribute__((packed));
|
||||||
271
src/virtual_block_device.c
Normal file
271
src/virtual_block_device.c
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "ch.h"
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
extern Thread *main_thread;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
blk=0: master boot record sector
|
||||||
|
blk=1: fat0
|
||||||
|
blk=2: fat1
|
||||||
|
blk=3: root directory
|
||||||
|
blk=4: fat cluster #2
|
||||||
|
...
|
||||||
|
blk=4+63: fat cluster #2+63
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const uint8_t d0_0_sector[512] = {
|
||||||
|
0xeb, 0x3c, /* Jump instruction */
|
||||||
|
0x90, /* NOP */
|
||||||
|
|
||||||
|
0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x20, /* "mkdosfs " */
|
||||||
|
|
||||||
|
0x00, 0x02, /* Bytes per sector: 512 */
|
||||||
|
|
||||||
|
0x01, /* sectors per cluster: 1 */
|
||||||
|
0x01, 0x00, /* reserved sector count: 1 */
|
||||||
|
0x02, /* Number of FATs: 2 */
|
||||||
|
0x10, 0x00, /* Max. root directory entries: 16 (1 sector) */
|
||||||
|
0x44, 0x00, /* total sectors: 68 */
|
||||||
|
0xf8, /* media descriptor: fixed disk */
|
||||||
|
0x01, 0x00, /* sectors per FAT: 1 */
|
||||||
|
0x04, 0x00, /* sectors per track: 4 */
|
||||||
|
0x01, 0x00, /* number of heads: 1 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, /* hidden sectors: 0 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, /* total sectors (long) */
|
||||||
|
0x00, /* drive number */
|
||||||
|
0x00, /* reserved */
|
||||||
|
0x29, /* extended boot signature */
|
||||||
|
0xbf, 0x86, 0x75, 0xea, /* Volume ID (serial number) (Little endian) */
|
||||||
|
|
||||||
|
/* Volume label */
|
||||||
|
'G', 'O', 'N', 'E', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
|
||||||
|
0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, /* FAT12 */
|
||||||
|
|
||||||
|
0x0e, 0x1f,
|
||||||
|
0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
|
||||||
|
0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10,
|
||||||
|
0x5e, 0xeb, 0xf0, 0x32, 0xe4, 0xcd, 0x16, 0xcd,
|
||||||
|
0x19,
|
||||||
|
0xeb, 0xfe, /* loop: jmp loop */
|
||||||
|
|
||||||
|
/* "Thisis not a bootable disk... \r\n" */
|
||||||
|
0x54, 0x68, 0x69, 0x73, 0x20,
|
||||||
|
0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61,
|
||||||
|
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||||
|
0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20,
|
||||||
|
0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20,
|
||||||
|
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61,
|
||||||
|
0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
|
||||||
|
0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
|
||||||
|
0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72,
|
||||||
|
0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20,
|
||||||
|
0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74,
|
||||||
|
0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e,
|
||||||
|
0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t d0_fat0_sector[512] = {
|
||||||
|
0xf8, 0xff, 0xff, /* Media descriptor: fixed disk */ /* EOC */
|
||||||
|
0xff, 0xff, 0xff, /* cluster 2: used */ /* cluster 3: used */
|
||||||
|
0xff, 0xff, 0xff, /* cluster 4: used */ /* cluster 5: used */
|
||||||
|
0xff, 0xff, 0xff, /* cluster 6: used */ /* cluster 7: used */
|
||||||
|
0xff, 0x0f, 0x00, /* cluster 8: used */ /* cluster 9: free */
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t zero_sector[512] = {
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t the_sector[512];
|
||||||
|
|
||||||
|
struct folder {
|
||||||
|
uint8_t parent;
|
||||||
|
uint8_t children[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct folder folders[8] = { { 0, { 1, 2, 3, 4, 5, 6, 7 } }, };
|
||||||
|
#define FOLDER_INDEX_TO_CLUSTER_NO(i) (i+1)
|
||||||
|
#define CLUSTER_NO_TO_FOLDER_INDEX(n) (n-1)
|
||||||
|
#define FOLDER_INDEX_TO_LBA(i) (i+3)
|
||||||
|
#define LBA_TO_FOLDER_INDEX(lba) (lba-3)
|
||||||
|
#define FOLDER_INDEX_TO_DIRCHAR(i) ('A'+i-1)
|
||||||
|
#define DIRCHAR_TO_FOLDER_INDEX(c) (c - 'A' + 1)
|
||||||
|
|
||||||
|
static uint8_t *fill_file_entry (uint8_t *p, const uint8_t *filename,
|
||||||
|
uint16_t cluster_no)
|
||||||
|
{
|
||||||
|
memcpy (p, filename, 8+3);
|
||||||
|
p += 11;
|
||||||
|
*p++ = 0x10; /* directory */
|
||||||
|
*p++ = 0x00; /* reserved */
|
||||||
|
memcpy (p, "\x64\x3b\xa7\x61\x3f", 5); /* create time */
|
||||||
|
p += 5;
|
||||||
|
memcpy (p, "\x61\x3f", 2); /* last access */
|
||||||
|
p += 2;
|
||||||
|
*p++ = 0x00; *p++ = 0x00; /* ea-index */
|
||||||
|
memcpy (p, "\x3b\xa7\x61\x3f", 4); /* last modified */
|
||||||
|
p += 4;
|
||||||
|
memcpy (p, &cluster_no, 2); /* cluster # */
|
||||||
|
p += 2;
|
||||||
|
*p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; /* file size */
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t *build_directory_sector (uint8_t *p, uint8_t index)
|
||||||
|
{
|
||||||
|
uint16_t cluster_no = FOLDER_INDEX_TO_CLUSTER_NO (index);
|
||||||
|
int i;
|
||||||
|
uint8_t filename[11] = { 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20 };
|
||||||
|
uint8_t child;
|
||||||
|
uint8_t *p_orig = p;
|
||||||
|
|
||||||
|
memset (p, 0, 512);
|
||||||
|
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
p = fill_file_entry (p, filename, cluster_no);
|
||||||
|
filename[1] = 0x2e;
|
||||||
|
p = fill_file_entry (p, filename, 0);
|
||||||
|
filename[1] = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
if ((child = folders[index].children[i]) != 0)
|
||||||
|
{
|
||||||
|
filename[0] = FOLDER_INDEX_TO_DIRCHAR (child);
|
||||||
|
p = fill_file_entry (p, filename, FOLDER_INDEX_TO_CLUSTER_NO (child));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
return p_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *
|
||||||
|
msc_scsi_read (uint8_t lun, uint32_t lba)
|
||||||
|
{
|
||||||
|
switch (lba)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return d0_0_sector;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return d0_fat0_sector;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
return build_directory_sector (the_sector, LBA_TO_FOLDER_INDEX (lba));
|
||||||
|
default:
|
||||||
|
return zero_sector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t datetime_string[29];
|
||||||
|
static uint8_t *dts = datetime_string;
|
||||||
|
|
||||||
|
static void parse_directory_sector (const uint8_t *p, uint8_t index)
|
||||||
|
{
|
||||||
|
uint16_t cluster_no = FOLDER_INDEX_TO_CLUSTER_NO (index);
|
||||||
|
int i;
|
||||||
|
uint8_t filename[11] = { 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x20 };
|
||||||
|
uint8_t child;
|
||||||
|
uint8_t *p_orig = p;
|
||||||
|
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
uint16_t cluster_no;
|
||||||
|
uint8_t dest_index;
|
||||||
|
|
||||||
|
p += 32; /* skip "." */
|
||||||
|
|
||||||
|
/* ".." */
|
||||||
|
cluster_no = p[26] | (p[27] << 8);
|
||||||
|
dest_index = CLUSTER_NO_TO_FOLDER_INDEX (cluster_no);
|
||||||
|
|
||||||
|
if (dest_index >= 1 && dest_index <= 7)
|
||||||
|
dts += sprintf (dts, "%c%c ", FOLDER_INDEX_TO_DIRCHAR (index),
|
||||||
|
FOLDER_INDEX_TO_DIRCHAR (dest_index));
|
||||||
|
else
|
||||||
|
; /* can be 255 : root_dir */
|
||||||
|
|
||||||
|
p += 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 7; i++)
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
child = DIRCHAR_TO_FOLDER_INDEX (*p);
|
||||||
|
folders[index].children[i] = child;
|
||||||
|
p += 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
msc_scsi_write (uint8_t lun, uint32_t lba, const uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
if (lba <= 2)
|
||||||
|
return 1; /* error */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t index = LBA_TO_FOLDER_INDEX (lba);
|
||||||
|
|
||||||
|
parse_directory_sector (buf, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user