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.
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 #include "dbg.h" 00021 00022 #define CBW_SIGNATURE 0x43425355 00023 #define CSW_SIGNATURE 0x53425355 00024 00025 #define DEVICE_TO_HOST 0x80 00026 #define HOST_TO_DEVICE 0x00 00027 00028 #define GET_MAX_LUN (0xFE) 00029 #define BO_MASS_STORAGE_RESET (0xFF) 00030 00031 USBHostMSD::USBHostMSD() 00032 { 00033 host = USBHost::getHostInst(); 00034 /* register an object in FAT */ 00035 00036 init_usb(); 00037 } 00038 00039 void USBHostMSD::init_usb() 00040 { 00041 dev_connected = false; 00042 dev = NULL; 00043 bulk_in = NULL; 00044 bulk_out = NULL; 00045 dev_connected = false; 00046 blockSize = 0; 00047 blockCount = 0; 00048 msd_intf = -1; 00049 msd_device_found = false; 00050 disk_init = false; 00051 dev_connected = false; 00052 nb_ep = 0; 00053 } 00054 00055 00056 bool USBHostMSD::connected() 00057 { 00058 return dev_connected; 00059 } 00060 00061 bool USBHostMSD::connect() 00062 { 00063 00064 if (dev_connected) { 00065 return true; 00066 } 00067 00068 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00069 if ((dev = host->getDevice(i)) != NULL) { 00070 00071 USB_DBG("Trying to connect MSD device\r\n"); 00072 00073 if(host->enumerate(dev, this)) 00074 break; 00075 00076 if (msd_device_found) { 00077 /* As this is done in a specific thread 00078 * this lock is taken to avoid to process a disconnection in 00079 * usb process during the device registering */ 00080 USBHost::Lock Lock(host); 00081 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::init_usb); 00091 00092 dev_connected = true; 00093 return true; 00094 } 00095 } //if() 00096 } //for() 00097 init_usb(); 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 { 00134 USB_DBG("Test unit ready"); 00135 return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0); 00136 } 00137 00138 00139 int USBHostMSD::readCapacity() 00140 { 00141 USB_DBG("Read capacity"); 00142 uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0}; 00143 uint8_t result[8]; 00144 int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8); 00145 if (status == 0) { 00146 blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]; 00147 blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7]; 00148 USB_INFO("MSD [dev: %p] - blockCount: %u, blockSize: %d, Capacity: %d\r\n", dev, blockCount, blockSize, blockCount*blockSize); 00149 } 00150 return status; 00151 } 00152 00153 00154 int USBHostMSD::SCSIRequestSense() 00155 { 00156 USB_DBG("Request sense"); 00157 uint8_t cmd[6] = {0x03,0,0,0,18,0}; 00158 uint8_t result[18]; 00159 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); 00160 return status; 00161 } 00162 00163 00164 int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) 00165 { 00166 USB_DBG("Inquiry"); 00167 uint8_t evpd = (page_code == 0) ? 0 : 1; 00168 uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0}; 00169 uint8_t result[36]; 00170 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); 00171 if (status == 0) { 00172 char vid_pid[17]; 00173 memcpy(vid_pid, &result[8], 8); 00174 vid_pid[8] = 0; 00175 USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid); 00176 00177 memcpy(vid_pid, &result[16], 16); 00178 vid_pid[16] = 0; 00179 USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid); 00180 00181 memcpy(vid_pid, &result[32], 4); 00182 vid_pid[4] = 0; 00183 USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid); 00184 } 00185 return status; 00186 } 00187 00188 int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) 00189 { 00190 // if ep stalled: send clear feature 00191 if (res == USB_TYPE_STALL_ERROR) { 00192 res = host->controlWrite( dev, 00193 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00194 CLEAR_FEATURE, 00195 0, ep->getAddress(), NULL, 0); 00196 // set state to IDLE if clear feature successful 00197 if (res == USB_TYPE_OK) { 00198 USBHost::Lock Lock(host); 00199 ep->setState(USB_TYPE_IDLE); 00200 } 00201 } 00202 00203 if (res != USB_TYPE_OK) 00204 return -1; 00205 00206 return 0; 00207 } 00208 00209 00210 int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) 00211 { 00212 00213 int res = 0; 00214 00215 cbw.Signature = CBW_SIGNATURE; 00216 cbw.Tag = 0; 00217 cbw.DataLength = transfer_len; 00218 cbw.Flags = flags; 00219 cbw.LUN = 0; 00220 cbw.CBLength = cmd_len; 00221 memset(cbw.CB,0,sizeof(cbw.CB)); 00222 if (cmd) { 00223 memcpy(cbw.CB,cmd,cmd_len); 00224 } 00225 00226 // send the cbw 00227 USB_DBG("Send CBW"); 00228 res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); 00229 if (checkResult(res, bulk_out)) 00230 return -1; 00231 00232 // data stage if needed 00233 if (data) { 00234 USB_DBG("data stage"); 00235 if (flags == HOST_TO_DEVICE) { 00236 00237 res = host->bulkWrite(dev, bulk_out, data, transfer_len); 00238 if (checkResult(res, bulk_out)) 00239 return -1; 00240 00241 } else if (flags == DEVICE_TO_HOST) { 00242 00243 res = host->bulkRead(dev, bulk_in, data, transfer_len); 00244 if (checkResult(res, bulk_in)) 00245 return -1; 00246 } 00247 } 00248 00249 // status stage 00250 csw.Signature = 0; 00251 USB_DBG("Read CSW"); 00252 res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); 00253 if (checkResult(res, bulk_in)) 00254 return -1; 00255 00256 if (csw.Signature != CSW_SIGNATURE) { 00257 return -1; 00258 } 00259 00260 USB_DBG("recv csw: status: %d", csw.Status); 00261 00262 // ModeSense? 00263 if ((csw.Status == 1) && (cmd[0] != 0x03)) { 00264 USB_DBG("request mode sense"); 00265 return SCSIRequestSense(); 00266 } 00267 00268 // perform reset recovery 00269 if ((csw.Status == 2) && (cmd[0] != 0x03)) { 00270 00271 // send Bulk-Only Mass Storage Reset request 00272 res = host->controlWrite( dev, 00273 USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, 00274 BO_MASS_STORAGE_RESET, 00275 0, msd_intf, NULL, 0); 00276 00277 // unstall both endpoints 00278 res = host->controlWrite( dev, 00279 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00280 CLEAR_FEATURE, 00281 0, bulk_in->getAddress(), NULL, 0); 00282 00283 res = host->controlWrite( dev, 00284 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00285 CLEAR_FEATURE, 00286 0, bulk_out->getAddress(), NULL, 0); 00287 00288 } 00289 00290 return csw.Status; 00291 } 00292 00293 00294 int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) 00295 { 00296 uint8_t cmd[10]; 00297 memset(cmd,0,10); 00298 cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; 00299 00300 cmd[2] = (block >> 24) & 0xff; 00301 cmd[3] = (block >> 16) & 0xff; 00302 cmd[4] = (block >> 8) & 0xff; 00303 cmd[5] = block & 0xff; 00304 00305 cmd[7] = (nbBlock >> 8) & 0xff; 00306 cmd[8] = nbBlock & 0xff; 00307 00308 return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); 00309 } 00310 00311 int USBHostMSD::getMaxLun() 00312 { 00313 uint8_t buf[1], res; 00314 res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, 00315 0xfe, 0, msd_intf, buf, 1); 00316 USB_DBG("max lun: %d", buf[0]); 00317 return res; 00318 } 00319 00320 int USBHostMSD::init() 00321 { 00322 USB_DBG("FILESYSTEM: init"); 00323 uint16_t i, timeout = 10, ret; 00324 getMaxLun(); 00325 for (i = 0; i < timeout; i++) { 00326 Thread::wait(100); 00327 if (!testUnitReady()) 00328 break; 00329 } 00330 00331 if (i == timeout) { 00332 disk_init = false; 00333 return -1; 00334 } 00335 00336 inquiry(0, 0); 00337 disk_init = 1; 00338 return readCapacity(); 00339 } 00340 00341 int USBHostMSD::program(const void *buffer, bd_addr_t addr, bd_size_t size) 00342 { 00343 uint32_t block_number, count; 00344 uint8_t *buf = (uint8_t *)buffer; 00345 if (!disk_init) { 00346 init(); 00347 } 00348 if (!disk_init) 00349 return -1; 00350 block_number = addr / blockSize; 00351 count = size /blockSize; 00352 00353 for (uint32_t b = block_number; b < block_number + count; b++) { 00354 if (dataTransfer(buf, b, 1, HOST_TO_DEVICE)) 00355 return -1; 00356 buf += blockSize; 00357 } 00358 return 0; 00359 } 00360 00361 int USBHostMSD::read(void *buffer, bd_addr_t addr, bd_size_t size) 00362 { 00363 uint32_t block_number, count; 00364 uint8_t *buf = (uint8_t *)buffer; 00365 if (!disk_init) { 00366 init(); 00367 } 00368 if (!disk_init) 00369 return -1; 00370 block_number = addr / blockSize; 00371 count = size /blockSize; 00372 00373 for (uint32_t b = block_number; b < block_number + count; b++) { 00374 if (dataTransfer((uint8_t*)buf, b, 1, DEVICE_TO_HOST)) 00375 return -1; 00376 buf += blockSize; 00377 } 00378 return 0; 00379 } 00380 00381 int USBHostMSD::erase(bd_addr_t addr, bd_size_t size) 00382 { 00383 return 0; 00384 } 00385 00386 bd_size_t USBHostMSD::get_read_size() const 00387 { 00388 if (!disk_init) 00389 return -1; 00390 return (bd_size_t)blockSize; 00391 } 00392 00393 bd_size_t USBHostMSD::get_program_size() const 00394 { 00395 if (!disk_init) 00396 return -1; 00397 return (bd_size_t)blockSize; 00398 } 00399 bd_size_t USBHostMSD::get_erase_size() const 00400 { 00401 if (!disk_init) 00402 return -1; 00403 return (bd_size_t)blockSize; 00404 } 00405 00406 bd_size_t USBHostMSD::size() const 00407 { 00408 USB_DBG("FILESYSTEM: size "); 00409 if (!disk_init) 00410 return 0; 00411 return (bd_size_t)blockCount*(bd_size_t)blockSize; 00412 } 00413 #endif
Generated on Thu Jul 14 2022 01:07:34 by
1.7.2