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 ep->setState(USB_TYPE_IDLE); 00199 } 00200 } 00201 00202 if (res != USB_TYPE_OK) 00203 return -1; 00204 00205 return 0; 00206 } 00207 00208 00209 int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) 00210 { 00211 00212 int res = 0; 00213 00214 cbw.Signature = CBW_SIGNATURE; 00215 cbw.Tag = 0; 00216 cbw.DataLength = transfer_len; 00217 cbw.Flags = flags; 00218 cbw.LUN = 0; 00219 cbw.CBLength = cmd_len; 00220 memset(cbw.CB,0,sizeof(cbw.CB)); 00221 if (cmd) { 00222 memcpy(cbw.CB,cmd,cmd_len); 00223 } 00224 00225 // send the cbw 00226 USB_DBG("Send CBW"); 00227 res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); 00228 if (checkResult(res, bulk_out)) 00229 return -1; 00230 00231 // data stage if needed 00232 if (data) { 00233 USB_DBG("data stage"); 00234 if (flags == HOST_TO_DEVICE) { 00235 00236 res = host->bulkWrite(dev, bulk_out, data, transfer_len); 00237 if (checkResult(res, bulk_out)) 00238 return -1; 00239 00240 } else if (flags == DEVICE_TO_HOST) { 00241 00242 res = host->bulkRead(dev, bulk_in, data, transfer_len); 00243 if (checkResult(res, bulk_in)) 00244 return -1; 00245 } 00246 } 00247 00248 // status stage 00249 csw.Signature = 0; 00250 USB_DBG("Read CSW"); 00251 res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); 00252 if (checkResult(res, bulk_in)) 00253 return -1; 00254 00255 if (csw.Signature != CSW_SIGNATURE) { 00256 return -1; 00257 } 00258 00259 USB_DBG("recv csw: status: %d", csw.Status); 00260 00261 // ModeSense? 00262 if ((csw.Status == 1) && (cmd[0] != 0x03)) { 00263 USB_DBG("request mode sense"); 00264 return SCSIRequestSense(); 00265 } 00266 00267 // perform reset recovery 00268 if ((csw.Status == 2) && (cmd[0] != 0x03)) { 00269 00270 // send Bulk-Only Mass Storage Reset request 00271 res = host->controlWrite( dev, 00272 USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, 00273 BO_MASS_STORAGE_RESET, 00274 0, msd_intf, NULL, 0); 00275 00276 // unstall both endpoints 00277 res = host->controlWrite( dev, 00278 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00279 CLEAR_FEATURE, 00280 0, bulk_in->getAddress(), NULL, 0); 00281 00282 res = host->controlWrite( dev, 00283 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00284 CLEAR_FEATURE, 00285 0, bulk_out->getAddress(), NULL, 0); 00286 00287 } 00288 00289 return csw.Status; 00290 } 00291 00292 00293 int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) 00294 { 00295 uint8_t cmd[10]; 00296 memset(cmd,0,10); 00297 cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; 00298 00299 cmd[2] = (block >> 24) & 0xff; 00300 cmd[3] = (block >> 16) & 0xff; 00301 cmd[4] = (block >> 8) & 0xff; 00302 cmd[5] = block & 0xff; 00303 00304 cmd[7] = (nbBlock >> 8) & 0xff; 00305 cmd[8] = nbBlock & 0xff; 00306 00307 return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); 00308 } 00309 00310 int USBHostMSD::getMaxLun() 00311 { 00312 uint8_t buf[1], res; 00313 res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, 00314 0xfe, 0, msd_intf, buf, 1); 00315 USB_DBG("max lun: %d", buf[0]); 00316 return res; 00317 } 00318 00319 int USBHostMSD::init() 00320 { 00321 USB_DBG("FILESYSTEM: init"); 00322 uint16_t i, timeout = 10, ret; 00323 getMaxLun(); 00324 for (i = 0; i < timeout; i++) { 00325 Thread::wait(100); 00326 if (!testUnitReady()) 00327 break; 00328 } 00329 00330 if (i == timeout) { 00331 disk_init = false; 00332 return -1; 00333 } 00334 00335 inquiry(0, 0); 00336 disk_init = 1; 00337 return readCapacity(); 00338 } 00339 00340 int USBHostMSD::program(const void *buffer, bd_addr_t addr, bd_size_t size) 00341 { 00342 uint32_t block_number, count; 00343 uint8_t *buf = (uint8_t *)buffer; 00344 if (!disk_init) { 00345 init(); 00346 } 00347 if (!disk_init) { 00348 return -1; 00349 } 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 } 00371 block_number = addr / blockSize; 00372 count = size / blockSize; 00373 00374 for (uint32_t b = block_number; b < block_number + count; b++) { 00375 if (dataTransfer(buf, b, 1, DEVICE_TO_HOST)) 00376 return -1; 00377 buf += blockSize; 00378 } 00379 return 0; 00380 } 00381 00382 int USBHostMSD::erase(bd_addr_t addr, bd_size_t size) 00383 { 00384 return 0; 00385 } 00386 00387 bd_size_t USBHostMSD::get_read_size() const 00388 { 00389 return (disk_init ? (bd_size_t)blockSize : -1); 00390 } 00391 00392 bd_size_t USBHostMSD::get_program_size() const 00393 { 00394 return (disk_init ? (bd_size_t)blockSize : -1); 00395 } 00396 bd_size_t USBHostMSD::get_erase_size() const 00397 { 00398 return (disk_init ? (bd_size_t)blockSize : -1); 00399 } 00400 00401 bd_size_t USBHostMSD::size() const 00402 { 00403 USB_DBG("FILESYSTEM: size "); 00404 return (disk_init ? (bd_size_t)blockSize : 0); 00405 } 00406 #endif
Generated on Tue Jul 12 2022 14:25:19 by
