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.
Fork of gr-peach-opencv-project by
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 msd_init(); 00036 } 00037 00038 USBHostMSD::~USBHostMSD() 00039 { 00040 if (_is_initialized) { 00041 deinit(); 00042 } 00043 } 00044 00045 void USBHostMSD::msd_init() { 00046 dev_connected = false; 00047 dev = NULL; 00048 bulk_in = NULL; 00049 bulk_out = NULL; 00050 dev_connected = false; 00051 blockSize = 0; 00052 blockCount = 0; 00053 msd_intf = -1; 00054 msd_device_found = false; 00055 _is_initialized = false; 00056 dev_connected = false; 00057 nb_ep = 0; 00058 } 00059 00060 00061 bool USBHostMSD::connected() 00062 { 00063 return dev_connected; 00064 } 00065 00066 bool USBHostMSD::connect() 00067 { 00068 00069 if (dev_connected) { 00070 return true; 00071 } 00072 00073 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00074 if ((dev = host->getDevice(i)) != NULL) { 00075 00076 USB_DBG("Trying to connect MSD device\r\n"); 00077 00078 if(host->enumerate(dev, this)) 00079 break; 00080 00081 if (msd_device_found) { 00082 bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN); 00083 bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT); 00084 00085 if (!bulk_in || !bulk_out) 00086 continue; 00087 00088 USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf); 00089 dev->setName("MSD", msd_intf); 00090 host->registerDriver(dev, msd_intf, this, &USBHostMSD::msd_init); 00091 00092 dev_connected = true; 00093 return true; 00094 } 00095 } //if() 00096 } //for() 00097 msd_init(); 00098 return false; 00099 } 00100 00101 /*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid) 00102 { 00103 // we don't check VID/PID for MSD driver 00104 } 00105 00106 /*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 00107 { 00108 if ((msd_intf == -1) && 00109 (intf_class == MSD_CLASS) && 00110 (intf_subclass == 0x06) && 00111 (intf_protocol == 0x50)) { 00112 msd_intf = intf_nb; 00113 return true; 00114 } 00115 return false; 00116 } 00117 00118 /*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used 00119 { 00120 if (intf_nb == msd_intf) { 00121 if (type == BULK_ENDPOINT) { 00122 nb_ep++; 00123 if (nb_ep == 2) 00124 msd_device_found = true; 00125 return true; 00126 } 00127 } 00128 return false; 00129 } 00130 00131 00132 int USBHostMSD::testUnitReady() { 00133 USB_DBG("Test unit ready"); 00134 return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0); 00135 } 00136 00137 00138 int USBHostMSD::readCapacity() { 00139 USB_DBG("Read capacity"); 00140 uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0}; 00141 uint8_t result[8]; 00142 int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8); 00143 if (status == 0) { 00144 blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]; 00145 blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7]; 00146 USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize); 00147 } 00148 return status; 00149 } 00150 00151 00152 int USBHostMSD::SCSIRequestSense() { 00153 USB_DBG("Request sense"); 00154 uint8_t cmd[6] = {0x03,0,0,0,18,0}; 00155 uint8_t result[18]; 00156 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); 00157 return status; 00158 } 00159 00160 00161 int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) { 00162 USB_DBG("Inquiry"); 00163 uint8_t evpd = (page_code == 0) ? 0 : 1; 00164 uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0}; 00165 uint8_t result[36]; 00166 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); 00167 if (status == 0) { 00168 char vid_pid[17]; 00169 memcpy(vid_pid, &result[8], 8); 00170 vid_pid[8] = 0; 00171 USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid); 00172 00173 memcpy(vid_pid, &result[16], 16); 00174 vid_pid[16] = 0; 00175 USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid); 00176 00177 memcpy(vid_pid, &result[32], 4); 00178 vid_pid[4] = 0; 00179 USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid); 00180 } 00181 return status; 00182 } 00183 00184 int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) { 00185 // if ep stalled: send clear feature 00186 if (res == USB_TYPE_STALL_ERROR) { 00187 res = host->controlWrite( dev, 00188 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00189 CLEAR_FEATURE, 00190 0, ep->getAddress(), NULL, 0); 00191 // set state to IDLE if clear feature successful 00192 if (res == USB_TYPE_OK) { 00193 ep->setState(USB_TYPE_IDLE); 00194 } 00195 } 00196 00197 if (res != USB_TYPE_OK) 00198 return -1; 00199 00200 return 0; 00201 } 00202 00203 00204 int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) { 00205 00206 int res = 0; 00207 00208 cbw.Signature = CBW_SIGNATURE; 00209 cbw.Tag = 0; 00210 cbw.DataLength = transfer_len; 00211 cbw.Flags = flags; 00212 cbw.LUN = 0; 00213 cbw.CBLength = cmd_len; 00214 memset(cbw.CB,0,sizeof(cbw.CB)); 00215 if (cmd) { 00216 memcpy(cbw.CB,cmd,cmd_len); 00217 } 00218 00219 // send the cbw 00220 USB_DBG("Send CBW"); 00221 res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); 00222 if (checkResult(res, bulk_out)) 00223 return -1; 00224 00225 // data stage if needed 00226 if (data) { 00227 USB_DBG("data stage"); 00228 if (flags == HOST_TO_DEVICE) { 00229 00230 res = host->bulkWrite(dev, bulk_out, data, transfer_len); 00231 if (checkResult(res, bulk_out)) 00232 return -1; 00233 00234 } else if (flags == DEVICE_TO_HOST) { 00235 00236 res = host->bulkRead(dev, bulk_in, data, transfer_len); 00237 if (checkResult(res, bulk_in)) 00238 return -1; 00239 } 00240 } 00241 00242 // status stage 00243 csw.Signature = 0; 00244 USB_DBG("Read CSW"); 00245 res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); 00246 if (checkResult(res, bulk_in)) 00247 return -1; 00248 00249 if (csw.Signature != CSW_SIGNATURE) { 00250 return -1; 00251 } 00252 00253 USB_DBG("recv csw: status: %d", csw.Status); 00254 00255 // ModeSense? 00256 if ((csw.Status == 1) && (cmd[0] != 0x03)) { 00257 USB_DBG("request mode sense"); 00258 return SCSIRequestSense(); 00259 } 00260 00261 // perform reset recovery 00262 if ((csw.Status == 2) && (cmd[0] != 0x03)) { 00263 00264 // send Bulk-Only Mass Storage Reset request 00265 res = host->controlWrite( dev, 00266 USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, 00267 BO_MASS_STORAGE_RESET, 00268 0, msd_intf, NULL, 0); 00269 00270 // unstall both endpoints 00271 res = host->controlWrite( dev, 00272 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00273 CLEAR_FEATURE, 00274 0, bulk_in->getAddress(), NULL, 0); 00275 00276 res = host->controlWrite( dev, 00277 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00278 CLEAR_FEATURE, 00279 0, bulk_out->getAddress(), NULL, 0); 00280 00281 } 00282 00283 return csw.Status; 00284 } 00285 00286 00287 int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) { 00288 uint8_t cmd[10]; 00289 memset(cmd,0,10); 00290 cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; 00291 00292 cmd[2] = (block >> 24) & 0xff; 00293 cmd[3] = (block >> 16) & 0xff; 00294 cmd[4] = (block >> 8) & 0xff; 00295 cmd[5] = block & 0xff; 00296 00297 cmd[7] = (nbBlock >> 8) & 0xff; 00298 cmd[8] = nbBlock & 0xff; 00299 00300 return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); 00301 } 00302 00303 int USBHostMSD::getMaxLun() { 00304 uint8_t buf[1], res; 00305 res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, 00306 0xfe, 0, msd_intf, buf, 1); 00307 USB_DBG("max lun: %d", buf[0]); 00308 return res; 00309 } 00310 00311 #define USB_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ 00312 #define USB_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ 00313 #define USB_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ 00314 #define USB_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ 00315 #define USB_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ 00316 #define USB_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ 00317 00318 int USBHostMSD::init() { 00319 uint16_t i, timeout = 10; 00320 00321 _lock.lock(); 00322 getMaxLun(); 00323 00324 for (i = 0; i < timeout; i++) { 00325 Thread::wait(100); 00326 if (!testUnitReady()) 00327 break; 00328 } 00329 00330 if (i == timeout) { 00331 return BD_ERROR_DEVICE_ERROR; 00332 } 00333 00334 inquiry(0, 0); 00335 if (readCapacity() != 0) { 00336 _lock.unlock(); 00337 return BD_ERROR_DEVICE_ERROR; 00338 } 00339 _is_initialized = true; 00340 _lock.unlock(); 00341 00342 return BD_ERROR_OK; 00343 } 00344 00345 int USBHostMSD::deinit() { 00346 return 0; 00347 } 00348 00349 int USBHostMSD::program(const void *b, bd_addr_t addr, bd_size_t size) 00350 { 00351 if (!is_valid_program(addr, size)) { 00352 return USB_BLOCK_DEVICE_ERROR_PARAMETER; 00353 } 00354 00355 _lock.lock(); 00356 if (!_is_initialized) { 00357 _lock.unlock(); 00358 return USB_BLOCK_DEVICE_ERROR_NO_INIT; 00359 } 00360 00361 const uint8_t *buffer = static_cast<const uint8_t*>(b); 00362 while (size > 0) { 00363 bd_addr_t block = addr / 512; 00364 00365 // send the data block 00366 if (dataTransfer((uint8_t*)buffer, block, 1, HOST_TO_DEVICE)) { 00367 _lock.unlock(); 00368 return BD_ERROR_DEVICE_ERROR; 00369 } 00370 00371 buffer += 512; 00372 addr += 512; 00373 size -= 512; 00374 } 00375 _lock.unlock(); 00376 return 0; 00377 } 00378 00379 int USBHostMSD::read(void *b, bd_addr_t addr, bd_size_t size) 00380 { 00381 if (!is_valid_read(addr, size)) { 00382 return USB_BLOCK_DEVICE_ERROR_PARAMETER; 00383 } 00384 00385 _lock.lock(); 00386 if (!_is_initialized) { 00387 _lock.unlock(); 00388 return USB_BLOCK_DEVICE_ERROR_PARAMETER; 00389 } 00390 00391 uint8_t *buffer = static_cast<uint8_t *>(b); 00392 while (size > 0) { 00393 bd_addr_t block = addr / 512; 00394 00395 // receive the data 00396 if (dataTransfer((uint8_t*)buffer, block, 1, DEVICE_TO_HOST)) { 00397 _lock.unlock(); 00398 return BD_ERROR_DEVICE_ERROR; 00399 } 00400 buffer += 512; 00401 addr += 512; 00402 size -= 512; 00403 } 00404 _lock.unlock(); 00405 return 0; 00406 } 00407 00408 int USBHostMSD::erase(bd_addr_t addr, bd_size_t size) 00409 { 00410 return 0; 00411 } 00412 00413 bd_size_t USBHostMSD::get_read_size() const 00414 { 00415 return 512; 00416 } 00417 00418 bd_size_t USBHostMSD::get_program_size() const 00419 { 00420 return 512; 00421 } 00422 00423 bd_size_t USBHostMSD::get_erase_size() const 00424 { 00425 return 512; 00426 } 00427 00428 bd_size_t USBHostMSD::size() const 00429 { 00430 bd_size_t sectors = 0; 00431 if(_is_initialized) { 00432 sectors = blockCount; 00433 } 00434 return 512*sectors; 00435 } 00436 00437 void USBHostMSD::debug(bool dbg) 00438 { 00439 // _dbg = dbg; 00440 } 00441 00442 #endif 00443
Generated on Tue Jul 12 2022 15:17:32 by
1.7.2
