Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FatFileSystem TB6612FNG2 mbed
Diff: msc/msc.cpp
- Revision:
- 0:de03cbbcd0ff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/msc/msc.cpp Mon Nov 30 09:32:15 2015 +0000
@@ -0,0 +1,390 @@
+#include "msc.h"
+//#define __DEBUG
+#include "mydbg.h"
+#include "Utils.h"
+
+//#define WRITE_PROTECT
+
+msc::msc(const char* name, int drive): FATFileSystem(name)
+{
+ DBG("drive=%d\n", drive);
+ m_name = name;
+ m_drive = drive;
+ DBG_ASSERT(sizeof(CBW) == 31);
+ DBG_ASSERT(sizeof(CSW) == 13);
+ m_numBlocks = 0;
+ m_BlockSize = 0;
+ m_lun = 0;
+ m_interface = 0;
+ m_pDev = NULL;
+ m_pEpBulkIn = NULL;
+ m_pEpBulkOut = NULL;
+}
+
+int msc::disk_initialize()
+{
+ DBG("m_BlockSize=%d\n", m_BlockSize);
+ if (m_BlockSize != 512) {
+ return 1;
+ }
+ return 0;
+}
+
+int msc::disk_write(const char *buffer, int block_number)
+{
+ DBG("buffer=%p block_number=%d\n", buffer, block_number);
+ int ret = MS_BulkSend(block_number, 1, (uint8_t*)buffer);
+ if (ret >= 0) {
+ return 0;
+ }
+ return 1;
+}
+
+int msc::disk_read(char *buffer, int block_number)
+{
+ DBG("buffer=%p block_number=%d\n", buffer, block_number);
+ int ret = MS_BulkRecv(block_number, 1, (uint8_t*)buffer);
+ if (ret >= 0) {
+ return 0;
+ }
+ return 1;
+}
+
+int msc::disk_status()
+{
+ DBG("\n");
+ return 0;
+}
+
+int msc::disk_sync()
+{
+ DBG("\n");
+ return 0;
+}
+
+int msc::disk_sectors()
+{
+ DBG("m_numBlocks=%d\n", m_numBlocks);
+ return m_numBlocks;
+}
+
+int msc::setup(int timeout)
+{
+ for(int i = 0; i < 2; i++) {
+ m_pDev = m_pHost->getDeviceByClass(0x08, m_drive); // USB Mass Storage Class
+ if (m_pDev || i > 0) {
+ break;
+ }
+ UsbErr rc = Usb_poll();
+ if (rc == USBERR_PROCESSING) {
+ VERBOSE("%p USBERR_PROCESSING\n", this);
+ return -1;
+ }
+ }
+ DBG("m_pDev=%p\n", m_pDev);
+ if (m_pDev == NULL) {
+ VERBOSE("%p MSC DISK(%d) NOT FOUND\n", this, m_drive);
+ return -1;
+ }
+ DBG_ASSERT(m_pDev);
+
+ ParseConfiguration();
+
+ GetMaxLUN();
+
+ int retry = 0;
+ Timer t;
+ t.start();
+ t.reset();
+ while(t.read_ms() < timeout) {
+ DBG("retry=%d t=%d\n", retry, t.read_ms());
+ if (retry > 80) {
+ return -1;
+ }
+ int rc = TestUnitReady();
+ DBG("TestUnitReady(): %d\n", rc);
+ if (rc == USBERR_OK) {
+ DBG("m_CSW.bCSWStatus: %02X\n", m_CSW.bCSWStatus);
+ if (m_CSW.bCSWStatus == 0x00) {
+ break;
+ }
+ }
+ GetSenseInfo();
+ retry++;
+ wait_ms(50);
+ }
+ if (t.read_ms() >= timeout) {
+ return -1;
+ }
+ ReadCapacity();
+ Inquire();
+ return 0;
+}
+void msc::_test()
+{
+ ReadCapacity();
+
+ char buf[512];
+ for(int block = 0; block < m_numBlocks; block++) {
+ DBG("block=%d\n", block);
+ disk_read(buf, block);
+ }
+ exit(1);
+}
+
+int msc::ParseConfiguration()
+{
+ UsbErr rc;
+ uint8_t ConfigDesc[9];
+ int index = 0;
+ DBG_ASSERT(m_pDev);
+ rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, ConfigDesc, sizeof(ConfigDesc));
+ DBG_ASSERT(rc == USBERR_OK);
+ DBG_BYTES("ConfigDescriptor 9bytes", ConfigDesc, sizeof(ConfigDesc));
+ DBG_ASSERT(ConfigDesc[0] == 9);
+ DBG_ASSERT(ConfigDesc[1] == 0x02);
+ int wTotalLength = *((uint16_t*)&ConfigDesc[2]);
+ DBG("TotalLength: %d\n", wTotalLength);
+ int bConfigValue = ConfigDesc[5];
+ DBG_ASSERT(bConfigValue == 1);
+ DBG("ConfigValue: %d\n", bConfigValue);
+ DBG("MaxPower: %d mA\n", ConfigDesc[8]*2);
+
+ uint8_t* buf = new uint8_t[wTotalLength];
+ DBG_ASSERT(buf);
+ rc = m_pDev->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, wTotalLength);
+ DBG_ASSERT(rc == USBERR_OK);
+ DBG_ASSERT(ConfigDesc[1] == 0x02);
+ for (int pos = 0; pos < wTotalLength; pos += buf[pos]) {
+ DBG_BYTES("CFG", buf+pos, buf[pos]);
+ int type = buf[pos+1];
+ if (USB_DESCRIPTOR_TYPE_INTERFACE == type) { // 0x04
+ DBG("InterfaceNumber: %d\n", buf[pos+2]);
+ DBG("AlternateSetting: %d\n", buf[pos+3]);
+ DBG("NumEndpoint: %d\n", buf[pos+4]);
+ DBG("InterfaceClass: %02X\n", buf[pos+5]);
+ DBG("InterfaceSubClass: %02X\n", buf[pos+6]);
+ DBG("InterfaceProtocol: %02X\n", buf[pos+7]);
+ DBG_ASSERT(buf[pos+6] == 0x06); // SCSI
+ DBG_ASSERT(buf[pos+7] == 0x50); // bulk only
+ }
+ if (USB_DESCRIPTOR_TYPE_ENDPOINT == type) {
+ DBG_ASSERT(buf[pos] == 7);
+ uint8_t att = buf[pos+3];
+ if (att == 2) { // bulk
+ uint8_t ep = buf[pos+2];
+ bool dir = ep & 0x80; // true=IN
+ uint16_t size = LE16(buf+pos+4);
+ DBG("EndpointAddress: %02X\n", ep);
+ DBG("Attribute: %02X\n", att);
+ DBG("MaxPacketSize: %d\n", size);
+ UsbEndpoint* pEp = new UsbEndpoint(m_pDev, ep, dir, USB_BULK, size);
+ DBG_ASSERT(pEp);
+ if (dir) {
+ m_pEpBulkIn = pEp;
+ } else {
+ m_pEpBulkOut = pEp;
+ }
+ }
+ }
+ }
+ delete[] buf;
+ DBG_ASSERT(m_pEpBulkIn);
+ DBG_ASSERT(m_pEpBulkOut);
+ return 0;
+}
+
+int msc::BulkOnlyMassStorageReset()
+{
+ DBG_ASSERT(m_pDev);
+ UsbErr rc = m_pDev->controlReceive(0x21, 0xff, 0x0000, m_interface, NULL, 0);
+ DBG_ASSERT(rc == USBERR_OK);
+ return rc;
+}
+
+int msc::GetMaxLUN()
+{
+ DBG_ASSERT(m_interface == 0);
+ uint8_t temp[1];
+ DBG_ASSERT(m_pDev);
+ UsbErr rc = m_pDev->controlReceive(0xa1, 0xfe, 0x0000, m_interface, temp, sizeof(temp));
+ DBG_ASSERT(rc == USBERR_OK);
+ DBG_BYTES("GetMaxLUN", temp, sizeof(temp));
+ m_MaxLUN = temp[0];
+ DBG_ASSERT(m_MaxLUN <= 15);
+ return rc;
+}
+
+
+int msc::TestUnitReady()
+{
+ const uint8_t cdb[6] = {SCSI_CMD_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00};
+ m_CBW.dCBWDataTraansferLength = 0;
+ m_CBW.bmCBWFlags = 0x00;
+ CommandTransport(cdb, sizeof(cdb));
+ StatusTransport();
+ return 0;
+}
+
+int msc::GetSenseInfo()
+{
+ const uint8_t cdb[6] = {SCSI_CMD_REQUEST_SENSE, 0x00, 0x00, 0x00, 18, 0x00};
+ m_CBW.dCBWDataTraansferLength = 18;
+ m_CBW.bmCBWFlags = 0x80; // data In
+ CommandTransport(cdb, sizeof(cdb));
+
+ uint8_t buf[18];
+ _bulkRecv(buf, sizeof(buf));
+ DBG_HEX(buf, sizeof(buf));
+
+ StatusTransport();
+ DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+ return 0;
+}
+
+int msc::ReadCapacity()
+{
+ const uint8_t cdb[10] = {SCSI_CMD_READ_CAPACITY, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00};
+ m_CBW.dCBWDataTraansferLength = 8;
+ m_CBW.bmCBWFlags = 0x80; // data In
+ CommandTransport(cdb, sizeof(cdb));
+
+ uint8_t buf[8];
+ int rc = _bulkRecv(buf, sizeof(buf));
+ DBG_ASSERT(rc >= 0);
+ DBG_HEX(buf, sizeof(buf));
+
+ StatusTransport();
+ DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+
+ m_numBlocks = BE32(buf);
+ m_BlockSize = BE32(buf+4);
+ DBG("m_numBlocks=%d m_BlockSize=%d\n", m_numBlocks, m_BlockSize);
+ DBG_ASSERT(m_BlockSize == 512);
+ DBG_ASSERT(m_numBlocks > 0);
+ return 0;
+}
+
+int msc::Inquire()
+{
+ const uint8_t cdb[6] = {SCSI_CMD_INQUIRY, 0x00, 0x00, 0x00, 36, 0x00};
+ m_CBW.dCBWDataTraansferLength = 36;
+ m_CBW.bmCBWFlags = 0x80; // data In
+ CommandTransport(cdb, sizeof(cdb));
+
+ uint8_t buf[36];
+ _bulkRecv(buf, sizeof(buf));
+ DBG_HEX(buf, sizeof(buf));
+
+ StatusTransport();
+ return 0;
+}
+
+int msc::MS_BulkRecv(uint32_t block_number, int num_blocks, uint8_t* user_buffer)
+{
+ DBG_ASSERT(m_BlockSize == 512);
+ DBG_ASSERT(num_blocks == 1);
+ DBG_ASSERT(user_buffer);
+ uint8_t cdb[10] = {SCSI_CMD_READ_10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00};
+ BE32(block_number, cdb+2);
+ BE16(num_blocks, cdb+7);
+ uint32_t len = m_BlockSize * num_blocks;
+ DBG_ASSERT(len <= 512);
+ m_CBW.dCBWDataTraansferLength = len;
+ m_CBW.bmCBWFlags = 0x80; // data In
+ CommandTransport(cdb, sizeof(cdb));
+
+ int ret = _bulkRecv(user_buffer, len);
+ //DBG_HEX(user_buffer, len);
+
+ StatusTransport();
+ DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+ return ret;
+}
+
+int msc::MS_BulkSend(uint32_t block_number, int num_blocks, uint8_t* user_buffer)
+{
+#ifdef WRITE_PROTECT
+ return 0;
+#else
+ DBG_ASSERT(num_blocks == 1);
+ DBG_ASSERT(user_buffer);
+ uint8_t cdb[10] = {SCSI_CMD_WRITE_10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00};
+ BE32(block_number, cdb+2);
+ BE16(num_blocks, cdb+7);
+ uint32_t len = m_BlockSize * num_blocks;
+ DBG_ASSERT(len <= 512);
+ m_CBW.dCBWDataTraansferLength = len;
+ m_CBW.bmCBWFlags = 0x00; // data Out
+ CommandTransport(cdb, sizeof(cdb));
+
+ int ret = _bulkSend(user_buffer, len);
+ //DBG_HEX(user_buffer, len);
+
+ StatusTransport();
+ DBG_ASSERT(m_CSW.bCSWStatus == 0x00);
+ return ret;
+#endif //WRITE_PROTECT
+}
+
+int msc::CommandTransport(const uint8_t* cdb, int size)
+{
+ DBG_ASSERT(cdb);
+ DBG_ASSERT(size >= 6);
+ DBG_ASSERT(size <= 16);
+ m_CBW.bCBWLUN = m_lun;
+ m_CBW.bCBWCBLength = size;
+ memcpy(m_CBW.CBWCB, cdb, size);
+
+ m_CBW.dCBWSignature = 0x43425355;
+ m_CBW.dCBWTag = m_tag++;
+ m_CBW.bCBWLUN = 0;
+ //DBG_HEX((uint8_t*)&m_CBW, sizeof(CBW));
+ int rc = _bulkSend((uint8_t*)&m_CBW, sizeof(CBW));
+ return rc;
+}
+
+int msc::StatusTransport()
+{
+ DBG_ASSERT(sizeof(CSW) == 13);
+ int rc = _bulkRecv((uint8_t*)&m_CSW, sizeof(CSW));
+ //DBG_HEX((uint8_t*)&m_CSW, sizeof(CSW));
+ DBG_ASSERT(m_CSW.dCSWSignature == 0x53425355);
+ DBG_ASSERT(m_CSW.dCSWTag == m_CBW.dCBWTag);
+ DBG_ASSERT(m_CSW.dCSWDataResidue == 0);
+ return rc;
+}
+
+int msc::_bulkRecv(uint8_t* buf, int size)
+{
+ UsbErr rc = m_pEpBulkIn->transfer(buf, size);
+ DBG_ASSERT(rc == USBERR_PROCESSING);
+ while(m_pEpBulkIn->status() == USBERR_PROCESSING){
+ wait_us(1);
+ }
+ int ret = m_pEpBulkIn->status();
+ if (ret >= 0) {
+ return ret;
+ }
+ DBG("buf=%p size=%d ret=%d\n", buf, size, ret);
+ return ret;
+}
+
+int msc::_bulkSend(uint8_t* buf, int size)
+{
+ DBG_ASSERT(m_pEpBulkOut);
+ UsbErr rc = m_pEpBulkOut->transfer(buf, size);
+ DBG_ASSERT(rc == USBERR_PROCESSING);
+ while(m_pEpBulkOut->status() == USBERR_PROCESSING){
+ wait_us(1);
+ }
+ int ret = m_pEpBulkOut->status();
+ if (ret >= 0) {
+ return ret;
+ }
+ DBG("buf=%p size=%d ret=%d\n", buf, size, ret);
+ return ret;
+}