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 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(const char * rootdir) : FATFileSystem(rootdir) 00033 { 00034 host = USBHost::getHostInst(); 00035 init(); 00036 } 00037 00038 void USBHostMSD::init() { 00039 dev_connected = false; 00040 dev = NULL; 00041 bulk_in = NULL; 00042 bulk_out = NULL; 00043 dev_connected = false; 00044 blockSize = 0; 00045 blockCount = 0; 00046 msd_intf = -1; 00047 msd_device_found = false; 00048 disk_init = false; 00049 dev_connected = false; 00050 nb_ep = 0; 00051 } 00052 00053 00054 bool USBHostMSD::connected() 00055 { 00056 return dev_connected; 00057 } 00058 00059 bool USBHostMSD::connect() 00060 { 00061 00062 if (dev_connected) { 00063 return true; 00064 } 00065 00066 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { 00067 if ((dev = host->getDevice(i)) != NULL) { 00068 00069 USB_DBG("Trying to connect MSD device\r\n"); 00070 00071 if(host->enumerate(dev, this)) 00072 break; 00073 00074 if (msd_device_found) { 00075 bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN); 00076 bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT); 00077 00078 if (!bulk_in || !bulk_out) 00079 continue; 00080 00081 USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf); 00082 dev->setName("MSD", msd_intf); 00083 host->registerDriver(dev, msd_intf, this, &USBHostMSD::init); 00084 00085 dev_connected = true; 00086 return true; 00087 } 00088 } //if() 00089 } //for() 00090 init(); 00091 return false; 00092 } 00093 00094 /*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid) 00095 { 00096 // we don't check VID/PID for MSD driver 00097 } 00098 00099 /*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 00100 { 00101 if ((msd_intf == -1) && 00102 (intf_class == MSD_CLASS) && 00103 (intf_subclass == 0x06) && 00104 (intf_protocol == 0x50)) { 00105 msd_intf = intf_nb; 00106 return true; 00107 } 00108 return false; 00109 } 00110 00111 /*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used 00112 { 00113 if (intf_nb == msd_intf) { 00114 if (type == BULK_ENDPOINT) { 00115 nb_ep++; 00116 if (nb_ep == 2) 00117 msd_device_found = true; 00118 return true; 00119 } 00120 } 00121 return false; 00122 } 00123 00124 00125 int USBHostMSD::testUnitReady() { 00126 USB_DBG("Test unit ready"); 00127 return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0); 00128 } 00129 00130 00131 int USBHostMSD::readCapacity() { 00132 USB_DBG("Read capacity"); 00133 uint8_t cmd [10] = {0x25,0,0,0,0,0,0,0,0,0}; 00134 uint8_t result[8]; 00135 int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8); 00136 if (status == 0) { 00137 blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]; 00138 blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7]; 00139 USB_INFO("MSD [dev: %p] - blockCount: %u, blockSize: %d, Capacity: %d\r\n", dev, blockCount, blockSize, blockCount*blockSize); 00140 } 00141 return status; 00142 } 00143 00144 00145 int USBHostMSD::SCSIRequestSense() { 00146 USB_DBG("Request sense"); 00147 uint8_t cmd[6] = {0x03,0,0,0,18,0}; 00148 uint8_t result[18]; 00149 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18); 00150 return status; 00151 } 00152 00153 00154 int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) { 00155 USB_DBG("Inquiry"); 00156 uint8_t evpd = (page_code == 0) ? 0 : 1; 00157 uint8_t cmd[6] = {0x12, uint8_t((lun << 5) | evpd), page_code, 0, 36, 0}; 00158 uint8_t result[36]; 00159 int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36); 00160 if (status == 0) { 00161 char vid_pid[17]; 00162 memcpy(vid_pid, &result[8], 8); 00163 vid_pid[8] = 0; 00164 USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid); 00165 00166 memcpy(vid_pid, &result[16], 16); 00167 vid_pid[16] = 0; 00168 USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid); 00169 00170 memcpy(vid_pid, &result[32], 4); 00171 vid_pid[4] = 0; 00172 USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid); 00173 } 00174 return status; 00175 } 00176 00177 int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) { 00178 // if ep stalled: send clear feature 00179 if (res == USB_TYPE_STALL_ERROR) { 00180 res = host->controlWrite( dev, 00181 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00182 CLEAR_FEATURE, 00183 0, ep->getAddress(), NULL, 0); 00184 // set state to IDLE if clear feature successful 00185 if (res == USB_TYPE_OK) { 00186 ep->setState(USB_TYPE_IDLE); 00187 } 00188 } 00189 00190 if (res != USB_TYPE_OK) 00191 return -1; 00192 00193 return 0; 00194 } 00195 00196 00197 int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) { 00198 00199 int res = 0; 00200 00201 cbw.Signature = CBW_SIGNATURE; 00202 cbw.Tag = 0; 00203 cbw.DataLength = transfer_len; 00204 cbw.Flags = flags; 00205 cbw.LUN = 0; 00206 cbw.CBLength = cmd_len; 00207 memset(cbw.CB,0,sizeof(cbw.CB)); 00208 if (cmd) { 00209 memcpy(cbw.CB,cmd,cmd_len); 00210 } 00211 00212 // send the cbw 00213 USB_DBG("Send CBW"); 00214 res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31); 00215 if (checkResult(res, bulk_out)) 00216 return -1; 00217 00218 // data stage if needed 00219 if (data) { 00220 USB_DBG("data stage"); 00221 if (flags == HOST_TO_DEVICE) { 00222 00223 res = host->bulkWrite(dev, bulk_out, data, transfer_len); 00224 if (checkResult(res, bulk_out)) 00225 return -1; 00226 00227 } else if (flags == DEVICE_TO_HOST) { 00228 00229 res = host->bulkRead(dev, bulk_in, data, transfer_len); 00230 if (checkResult(res, bulk_in)) 00231 return -1; 00232 } 00233 } 00234 00235 // status stage 00236 csw.Signature = 0; 00237 USB_DBG("Read CSW"); 00238 res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13); 00239 if (checkResult(res, bulk_in)) 00240 return -1; 00241 00242 if (csw.Signature != CSW_SIGNATURE) { 00243 return -1; 00244 } 00245 00246 USB_DBG("recv csw: status: %d", csw.Status); 00247 00248 // ModeSense? 00249 if ((csw.Status == 1) && (cmd[0] != 0x03)) { 00250 USB_DBG("request mode sense"); 00251 return SCSIRequestSense(); 00252 } 00253 00254 // perform reset recovery 00255 if ((csw.Status == 2) && (cmd[0] != 0x03)) { 00256 00257 // send Bulk-Only Mass Storage Reset request 00258 res = host->controlWrite( dev, 00259 USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS, 00260 BO_MASS_STORAGE_RESET, 00261 0, msd_intf, NULL, 0); 00262 00263 // unstall both endpoints 00264 res = host->controlWrite( dev, 00265 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00266 CLEAR_FEATURE, 00267 0, bulk_in->getAddress(), NULL, 0); 00268 00269 res = host->controlWrite( dev, 00270 USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD, 00271 CLEAR_FEATURE, 00272 0, bulk_out->getAddress(), NULL, 0); 00273 00274 } 00275 00276 return csw.Status; 00277 } 00278 00279 00280 int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) { 00281 uint8_t cmd[10]; 00282 memset(cmd,0,10); 00283 cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A; 00284 00285 cmd[2] = (block >> 24) & 0xff; 00286 cmd[3] = (block >> 16) & 0xff; 00287 cmd[4] = (block >> 8) & 0xff; 00288 cmd[5] = block & 0xff; 00289 00290 cmd[7] = (nbBlock >> 8) & 0xff; 00291 cmd[8] = nbBlock & 0xff; 00292 00293 return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock); 00294 } 00295 00296 int USBHostMSD::getMaxLun() { 00297 uint8_t buf[1], res; 00298 res = host->controlRead( dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, 00299 0xfe, 0, msd_intf, buf, 1); 00300 USB_DBG("max lun: %d", buf[0]); 00301 return res; 00302 } 00303 00304 int USBHostMSD::disk_initialize() { 00305 USB_DBG("FILESYSTEM: init"); 00306 uint16_t i, timeout = 10; 00307 00308 getMaxLun(); 00309 00310 for (i = 0; i < timeout; i++) { 00311 Thread::wait(100); 00312 if (!testUnitReady()) 00313 break; 00314 } 00315 00316 if (i == timeout) { 00317 disk_init = false; 00318 return -1; 00319 } 00320 00321 inquiry(0, 0); 00322 disk_init = 1; 00323 return readCapacity(); 00324 } 00325 00326 int USBHostMSD::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) { 00327 USB_DBG("FILESYSTEM: write block: %lld, count: %d", block_number, count); 00328 if (!disk_init) { 00329 disk_initialize(); 00330 } 00331 if (!disk_init) 00332 return -1; 00333 for (uint32_t b = block_number; b < block_number + count; b++) { 00334 if (dataTransfer((uint8_t*)buffer, b, 1, HOST_TO_DEVICE)) 00335 return -1; 00336 buffer += 512; 00337 } 00338 return 0; 00339 } 00340 00341 int USBHostMSD::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) { 00342 USB_DBG("FILESYSTEM: read block: %lld, count: %d", block_number, count); 00343 if (!disk_init) { 00344 disk_initialize(); 00345 } 00346 if (!disk_init) 00347 return -1; 00348 for (uint32_t b = block_number; b < block_number + count; b++) { 00349 if (dataTransfer((uint8_t*)buffer, b, 1, DEVICE_TO_HOST)) 00350 return -1; 00351 buffer += 512; 00352 } 00353 return 0; 00354 } 00355 00356 uint32_t USBHostMSD::disk_sectors() { 00357 USB_DBG("FILESYSTEM: sectors"); 00358 if (!disk_init) { 00359 disk_initialize(); 00360 } 00361 if (!disk_init) 00362 return 0; 00363 return blockCount; 00364 } 00365 00366 #endif
Generated on Tue Jul 12 2022 17:34:59 by
