test public

Dependencies:   HttpServer_snapshot_mbed-os

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHostMSD.cpp Source File

USBHostMSD.cpp

00001 /* mbed USBHost Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "USBHostMSD.h"
00018 
00019 #if USBHOST_MSD
00020 
00021 #include "dbg.h"
00022 
00023 #define CBW_SIGNATURE   0x43425355
00024 #define CSW_SIGNATURE   0x53425355
00025 
00026 #define DEVICE_TO_HOST  0x80
00027 #define HOST_TO_DEVICE  0x00
00028 
00029 #define GET_MAX_LUN             (0xFE)
00030 #define BO_MASS_STORAGE_RESET   (0xFF)
00031 
00032 USBHostMSD::USBHostMSD()
00033 {
00034     host = USBHost::getHostInst();
00035 #if defined(TARGET_RZ_A2XX)
00036     trans_buf = (uint8_t *)AllocNonCacheMem(512);
00037     result    = (uint8_t *)AllocNonCacheMem(36);
00038     p_cbw     = (CBW *)AllocNonCacheMem(sizeof(CBW));
00039     p_csw     = (CSW *)AllocNonCacheMem(sizeof(CSW));
00040 #endif
00041     msd_init();
00042 }
00043 
00044 USBHostMSD::~USBHostMSD()
00045 {
00046     if (_is_initialized) {
00047         deinit();
00048     }
00049 #if defined(TARGET_RZ_A2XX)
00050     FreeNonCacheMem(trans_buf);
00051     FreeNonCacheMem(p_cbw);
00052     FreeNonCacheMem(p_csw);
00053 #endif
00054 }
00055 
00056 void USBHostMSD::msd_init() {
00057     dev_connected = false;
00058     dev = NULL;
00059     bulk_in = NULL;
00060     bulk_out = NULL;
00061     dev_connected = false;
00062     blockSize = 0;
00063     blockCount = 0;
00064     msd_intf = -1;
00065     msd_device_found = false;
00066     _is_initialized = false;
00067     dev_connected = false;
00068     nb_ep = 0;
00069 }
00070 
00071 
00072 bool USBHostMSD::connected()
00073 {
00074     return dev_connected;
00075 }
00076 
00077 bool USBHostMSD::connect()
00078 {
00079 
00080     if (dev_connected) {
00081         return true;
00082     }
00083 
00084     for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
00085         if ((dev = host->getDevice(i)) != NULL) {
00086 
00087             USB_DBG("Trying to connect MSD device\r\n");
00088 
00089             if(host->enumerate(dev, this))
00090                 break;
00091 
00092             if (msd_device_found) {
00093                 bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
00094                 bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
00095 
00096                 if (!bulk_in || !bulk_out)
00097                     continue;
00098 
00099                 USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
00100                 dev->setName("MSD", msd_intf);
00101                 host->registerDriver(dev, msd_intf, this, &USBHostMSD::msd_init);
00102 
00103                 dev_connected = true;
00104                 return true;
00105             }
00106         } //if()
00107     } //for()
00108     msd_init();
00109     return false;
00110 }
00111 
00112 /*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
00113 {
00114     // we don't check VID/PID for MSD driver
00115 }
00116 
00117 /*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
00118 {
00119     if ((msd_intf == -1) &&
00120         (intf_class == MSD_CLASS) &&
00121         (intf_subclass == 0x06) &&
00122         (intf_protocol == 0x50)) {
00123         msd_intf = intf_nb;
00124         return true;
00125     }
00126     return false;
00127 }
00128 
00129 /*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
00130 {
00131     if (intf_nb == msd_intf) {
00132         if (type == BULK_ENDPOINT) {
00133             nb_ep++;
00134             if (nb_ep == 2)
00135                 msd_device_found = true;
00136             return true;
00137         }
00138     }
00139     return false;
00140 }
00141 
00142 
00143 int USBHostMSD::testUnitReady() {
00144     USB_DBG("Test unit ready");
00145     return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
00146 }
00147 
00148 
00149 int USBHostMSD::readCapacity() {
00150     USB_DBG("Read capacity");
00151     uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
00152 #if defined(TARGET_RZ_A2XX)
00153 #else
00154     uint8_t result[8];
00155 #endif
00156     int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
00157     if (status == 0) {
00158         blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
00159         blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
00160         USB_INFO("MSD [dev: %p] - blockCount: %ld, blockSize: %d, Capacity: %ld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
00161     }
00162     return status;
00163 }
00164 
00165 
00166 int USBHostMSD::SCSIRequestSense() {
00167     USB_DBG("Request sense");
00168     uint8_t cmd[6] = {0x03,0,0,0,18,0};
00169 #if defined(TARGET_RZ_A2XX)
00170 #else
00171     uint8_t result[18];
00172 #endif
00173     int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
00174     return status;
00175 }
00176 
00177 
00178 int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
00179     USB_DBG("Inquiry");
00180     uint8_t evpd = (page_code == 0) ? 0 : 1;
00181     uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0};
00182 #if defined(TARGET_RZ_A2XX)
00183 #else
00184     uint8_t result[36];
00185 #endif
00186     int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
00187     if (status == 0) {
00188         char vid_pid[17];
00189         memcpy(vid_pid, &result[8], 8);
00190         vid_pid[8] = 0;
00191         USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
00192 
00193         memcpy(vid_pid, &result[16], 16);
00194         vid_pid[16] = 0;
00195         USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
00196 
00197         memcpy(vid_pid, &result[32], 4);
00198         vid_pid[4] = 0;
00199         USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
00200     }
00201     return status;
00202 }
00203 
00204 int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
00205     // if ep stalled: send clear feature
00206     if (res == USB_TYPE_STALL_ERROR) {
00207         res = host->controlWrite(   dev,
00208                                     USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
00209                                     CLEAR_FEATURE,
00210                                     0, ep->getAddress(), NULL, 0);
00211         // set state to IDLE if clear feature successful
00212         if (res == USB_TYPE_OK) {
00213             ep->setState(USB_TYPE_IDLE);
00214         }
00215     }
00216 
00217     if (res != USB_TYPE_OK)
00218         return -1;
00219 
00220     return 0;
00221 }
00222 
00223 
00224 int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
00225 
00226     int res = 0;
00227 
00228 #if defined(TARGET_RZ_A2XX)
00229     p_cbw->Signature = CBW_SIGNATURE;
00230     p_cbw->Tag = 0;
00231     p_cbw->DataLength = transfer_len;
00232     p_cbw->Flags = flags;
00233     p_cbw->LUN = 0;
00234     p_cbw->CBLength = cmd_len;
00235     memset(p_cbw->CB,0,sizeof(p_cbw->CB));
00236     if (cmd) {
00237         memcpy(p_cbw->CB,cmd,cmd_len);
00238     }
00239 
00240     // send the cbw
00241     USB_DBG("Send CBW");
00242     res = host->bulkWrite(dev, bulk_out,(uint8_t *)p_cbw, 31);
00243 #else
00244     cbw.Signature = CBW_SIGNATURE;
00245     cbw.Tag = 0;
00246     cbw.DataLength = transfer_len;
00247     cbw.Flags = flags;
00248     cbw.LUN = 0;
00249     cbw.CBLength = cmd_len;
00250     memset(cbw.CB,0,sizeof(cbw.CB));
00251     if (cmd) {
00252         memcpy(cbw.CB,cmd,cmd_len);
00253     }
00254 
00255     // send the cbw
00256     USB_DBG("Send CBW");
00257     res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
00258 #endif
00259     if (checkResult(res, bulk_out))
00260         return -1;
00261 
00262     // data stage if needed
00263     if (data) {
00264         USB_DBG("data stage");
00265         if (flags == HOST_TO_DEVICE) {
00266 
00267             res = host->bulkWrite(dev, bulk_out, data, transfer_len);
00268             if (checkResult(res, bulk_out))
00269                 return -1;
00270 
00271         } else if (flags == DEVICE_TO_HOST) {
00272 
00273             res = host->bulkRead(dev, bulk_in, data, transfer_len);
00274             if (checkResult(res, bulk_in))
00275                 return -1;
00276         }
00277     }
00278 
00279     // status stage
00280     uint8_t wk_cmd0 = 0;
00281     if (cmd) {
00282         wk_cmd0 = cmd[0];
00283     }
00284 #if defined(TARGET_RZ_A2XX)
00285     p_csw->Signature = 0;
00286     USB_DBG("Read CSW");
00287     res = host->bulkRead(dev, bulk_in,(uint8_t *)p_csw, 13);
00288     if (checkResult(res, bulk_in))
00289         return -1;
00290 
00291     if (p_csw->Signature != CSW_SIGNATURE) {
00292         return -1;
00293     }
00294 
00295     USB_DBG("recv csw: status: %d", p_csw->Status);
00296 
00297     // ModeSense?
00298     if ((p_csw->Status == 1) && (wk_cmd0 != 0x03)) {
00299         USB_DBG("request mode sense");
00300         return SCSIRequestSense();
00301     }
00302 
00303     // perform reset recovery
00304     if ((p_csw->Status == 2) && (wk_cmd0 != 0x03)) {
00305 
00306         // send Bulk-Only Mass Storage Reset request
00307         res = host->controlWrite(   dev,
00308                                     USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
00309                                     BO_MASS_STORAGE_RESET,
00310                                     0, msd_intf, NULL, 0);
00311 
00312         // unstall both endpoints
00313         res = host->controlWrite(   dev,
00314                                     USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
00315                                     CLEAR_FEATURE,
00316                                     0, bulk_in->getAddress(), NULL, 0);
00317 
00318         res = host->controlWrite(   dev,
00319                                     USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
00320                                     CLEAR_FEATURE,
00321                                     0, bulk_out->getAddress(), NULL, 0);
00322 
00323     }
00324 
00325     return p_csw->Status;
00326 #else
00327     csw.Signature = 0;
00328     USB_DBG("Read CSW");
00329     res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
00330     if (checkResult(res, bulk_in))
00331         return -1;
00332 
00333     if (csw.Signature != CSW_SIGNATURE) {
00334         return -1;
00335     }
00336 
00337     USB_DBG("recv csw: status: %d", csw.Status);
00338 
00339     // ModeSense?
00340     if ((csw.Status == 1) && (wk_cmd0 != 0x03)) {
00341         USB_DBG("request mode sense");
00342         return SCSIRequestSense();
00343     }
00344 
00345     // perform reset recovery
00346     if ((csw.Status == 2) && (wk_cmd0 != 0x03)) {
00347 
00348         // send Bulk-Only Mass Storage Reset request
00349         res = host->controlWrite(   dev,
00350                                     USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
00351                                     BO_MASS_STORAGE_RESET,
00352                                     0, msd_intf, NULL, 0);
00353 
00354         // unstall both endpoints
00355         res = host->controlWrite(   dev,
00356                                     USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
00357                                     CLEAR_FEATURE,
00358                                     0, bulk_in->getAddress(), NULL, 0);
00359 
00360         res = host->controlWrite(   dev,
00361                                     USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
00362                                     CLEAR_FEATURE,
00363                                     0, bulk_out->getAddress(), NULL, 0);
00364 
00365     }
00366 
00367     return csw.Status;
00368 #endif
00369 }
00370 
00371 
00372 int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
00373     uint8_t cmd[10];
00374     memset(cmd,0,10);
00375     cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
00376 
00377     cmd[2] = (block >> 24) & 0xff;
00378     cmd[3] = (block >> 16) & 0xff;
00379     cmd[4] = (block >> 8) & 0xff;
00380     cmd[5] =  block & 0xff;
00381 
00382     cmd[7] = (nbBlock >> 8) & 0xff;
00383     cmd[8] = nbBlock & 0xff;
00384 
00385     return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
00386 }
00387 
00388 int USBHostMSD::getMaxLun() {
00389 #if defined(TARGET_RZ_A2XX)
00390     uint8_t res;
00391     res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
00392                                 0xfe, 0, msd_intf, trans_buf, 1);
00393     USB_DBG("max lun: %d", trans_buf[0]);
00394 #else
00395     uint8_t buf[1], res;
00396     res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
00397                                 0xfe, 0, msd_intf, buf, 1);
00398     USB_DBG("max lun: %d", buf[0]);
00399 #endif
00400     return res;
00401 }
00402 
00403 #define USB_BLOCK_DEVICE_ERROR_WOULD_BLOCK        -5001 /*!< operation would block */
00404 #define USB_BLOCK_DEVICE_ERROR_UNSUPPORTED        -5002 /*!< unsupported operation */
00405 #define USB_BLOCK_DEVICE_ERROR_PARAMETER          -5003 /*!< invalid parameter */
00406 #define USB_BLOCK_DEVICE_ERROR_NO_INIT            -5004 /*!< uninitialized */
00407 #define USB_BLOCK_DEVICE_ERROR_NO_DEVICE          -5005 /*!< device is missing or not connected */
00408 #define USB_BLOCK_DEVICE_ERROR_WRITE_PROTECTED    -5006 /*!< write protected */
00409 
00410 int USBHostMSD::init() {
00411     uint16_t i, timeout = 10;
00412 
00413     _lock.lock();
00414     getMaxLun();
00415 
00416     for (i = 0; i < timeout; i++) {
00417         ThisThread::sleep_for(100);
00418         if (!testUnitReady())
00419             break;
00420     }
00421 
00422     if (i == timeout) {
00423         return BD_ERROR_DEVICE_ERROR;
00424     }
00425 
00426     inquiry(0, 0);
00427     if (readCapacity() != 0) {
00428         _lock.unlock();
00429         return BD_ERROR_DEVICE_ERROR;
00430     }
00431     _is_initialized = true;
00432     _lock.unlock();
00433 
00434     return BD_ERROR_OK;
00435 }
00436 
00437 int USBHostMSD::deinit() {
00438     return 0;
00439 }
00440 
00441 int USBHostMSD::program(const void *b, bd_addr_t addr, bd_size_t size)
00442 {
00443     if (!is_valid_program(addr, size)) {
00444         return USB_BLOCK_DEVICE_ERROR_PARAMETER;
00445     }
00446 
00447     _lock.lock();
00448     if (!_is_initialized) {
00449         _lock.unlock();
00450         return USB_BLOCK_DEVICE_ERROR_NO_INIT;
00451     }
00452 
00453     const uint8_t *buffer = static_cast<const uint8_t*>(b);
00454     while (size > 0) {
00455         bd_addr_t block = addr / 512;
00456 
00457         // send the data block
00458 #if defined(TARGET_RZ_A2XX)
00459         (void)memcpy(trans_buf, buffer, 512);
00460         if (dataTransfer((uint8_t*)trans_buf, block, 1, HOST_TO_DEVICE)) {
00461 #else
00462         if (dataTransfer((uint8_t*)buffer, block, 1, HOST_TO_DEVICE)) {
00463 #endif
00464             _lock.unlock();
00465             return BD_ERROR_DEVICE_ERROR;
00466         }
00467 
00468         buffer += 512;
00469         addr += 512;
00470         size -= 512;
00471     }
00472     _lock.unlock();
00473     return 0;
00474 }
00475 
00476 int USBHostMSD::read(void *b, bd_addr_t addr, bd_size_t size)
00477 {
00478     if (!is_valid_read(addr, size)) {
00479         return USB_BLOCK_DEVICE_ERROR_PARAMETER;
00480     }
00481 
00482     _lock.lock();
00483     if (!_is_initialized) {
00484         _lock.unlock();
00485         return USB_BLOCK_DEVICE_ERROR_PARAMETER;
00486     }
00487 
00488     uint8_t *buffer = static_cast<uint8_t *>(b);
00489     while (size > 0) {
00490         bd_addr_t block = addr / 512;
00491 
00492         // receive the data
00493 #if defined(TARGET_RZ_A2XX)
00494         if (dataTransfer((uint8_t*)trans_buf, block, 1, DEVICE_TO_HOST)) {
00495             _lock.unlock();
00496             return BD_ERROR_DEVICE_ERROR;
00497         }
00498         (void)memcpy(buffer, trans_buf, 512);
00499 #else
00500         if (dataTransfer((uint8_t*)buffer, block, 1, DEVICE_TO_HOST)) {
00501             _lock.unlock();
00502             return BD_ERROR_DEVICE_ERROR;
00503         }
00504 #endif
00505         buffer += 512;
00506         addr += 512;
00507         size -= 512;
00508     }
00509     _lock.unlock();
00510     return 0;
00511 }
00512 
00513 int USBHostMSD::erase(bd_addr_t addr, bd_size_t size)
00514 {
00515     return 0;
00516 }
00517 
00518 bd_size_t USBHostMSD::get_read_size() const
00519 {
00520     return 512;
00521 }
00522 
00523 bd_size_t USBHostMSD::get_program_size() const
00524 {
00525     return 512;
00526 }
00527 
00528 bd_size_t USBHostMSD::get_erase_size() const
00529 {
00530     return 512;
00531 }
00532 
00533 bd_size_t USBHostMSD::size() const
00534 {
00535     bd_size_t sectors = 0;
00536     if(_is_initialized) {
00537         sectors = blockCount;
00538     }
00539     return 512*sectors;
00540 }
00541 
00542 const char *USBHostMSD::get_type() const
00543 {
00544     return "MSD";
00545 }
00546 
00547 void USBHostMSD::debug(bool dbg)
00548 {
00549 //    _dbg = dbg;
00550 }
00551 
00552 #endif
00553