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.
Dependents: UsbHostMAX3421E_Hello
masstorage.cpp
00001 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00016 00017 Contact information 00018 ------------------- 00019 00020 Circuits At Home, LTD 00021 Web : http://www.circuitsathome.com 00022 e-mail : support@circuitsathome.com 00023 */ 00024 00025 #include "masstorage.h" 00026 00027 const uint8_t BulkOnly::epDataInIndex = 1; 00028 const uint8_t BulkOnly::epDataOutIndex = 2; 00029 const uint8_t BulkOnly::epInterruptInIndex = 3; 00030 00031 //////////////////////////////////////////////////////////////////////////////// 00032 00033 // Interface code 00034 00035 //////////////////////////////////////////////////////////////////////////////// 00036 00037 /** 00038 * Get the capacity of the media 00039 * 00040 * @param lun Logical Unit Number 00041 * @return media capacity 00042 */ 00043 uint32_t BulkOnly::GetCapacity(uint8_t lun) { 00044 if(LUNOk[lun]) 00045 return CurrentCapacity[lun]; 00046 return 0LU; 00047 } 00048 00049 /** 00050 * Get the sector (block) size used on the media 00051 * 00052 * @param lun Logical Unit Number 00053 * @return media sector size 00054 */ 00055 uint16_t BulkOnly::GetSectorSize(uint8_t lun) { 00056 if(LUNOk[lun]) 00057 return CurrentSectorSize[lun]; 00058 return 0U; 00059 } 00060 00061 /** 00062 * Test if LUN is ready for use 00063 * 00064 * @param lun Logical Unit Number 00065 * @return true if LUN is ready for use 00066 */ 00067 bool BulkOnly::LUNIsGood(uint8_t lun) { 00068 return LUNOk[lun]; 00069 } 00070 00071 /** 00072 * Test if LUN is write protected 00073 * 00074 * @param lun Logical Unit Number 00075 * @return cached status of write protect switch 00076 */ 00077 bool BulkOnly::WriteProtected(uint8_t lun) { 00078 return WriteOk[lun]; 00079 } 00080 00081 /** 00082 * Wrap and execute a SCSI CDB with length of 6 00083 * 00084 * @param cdb CDB to execute 00085 * @param buf_size Size of expected transaction 00086 * @param buf Buffer 00087 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT 00088 * @return 00089 */ 00090 uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { 00091 // promote buf_size to 32bits. 00092 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); 00093 //SetCurLUN(cdb->LUN); 00094 return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); 00095 } 00096 00097 /** 00098 * Wrap and execute a SCSI CDB with length of 10 00099 * 00100 * @param cdb CDB to execute 00101 * @param buf_size Size of expected transaction 00102 * @param buf Buffer 00103 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT 00104 * @return 00105 */ 00106 uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { 00107 // promote buf_size to 32bits. 00108 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); 00109 //SetCurLUN(cdb->LUN); 00110 return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); 00111 } 00112 00113 /** 00114 * Lock or Unlock the tray or door on device. 00115 * Caution: Some devices with buggy firmware will lock up. 00116 * 00117 * @param lun Logical Unit Number 00118 * @param lock 1 to lock, 0 to unlock 00119 * @return 00120 */ 00121 uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) { 00122 Notify(PSTR("\r\nLockMedia\r\n"), 0x80); 00123 Notify(PSTR("---------\r\n"), 0x80); 00124 00125 CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock); 00126 return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN); 00127 } 00128 00129 /** 00130 * Media control, for spindle motor and media tray or door. 00131 * This includes CDROM, TAPE and anything with a media loader. 00132 * 00133 * @param lun Logical Unit Number 00134 * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media 00135 * @return 0 on success 00136 */ 00137 uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { 00138 Notify(PSTR("\r\nMediaCTL\r\n"), 0x80); 00139 Notify(PSTR("-----------------\r\n"), 0x80); 00140 00141 uint8_t rcode = MASS_ERR_UNIT_NOT_READY; 00142 if(bAddress) { 00143 CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0); 00144 rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT); 00145 } else { 00146 SetCurLUN(lun); 00147 } 00148 return rcode; 00149 } 00150 00151 /** 00152 * Read data from media 00153 * 00154 * @param lun Logical Unit Number 00155 * @param addr LBA address on media to read 00156 * @param bsize size of a block (we should probably use the cached size) 00157 * @param blocks how many blocks to read 00158 * @param buf memory that is able to hold the requested data 00159 * @return 0 on success 00160 */ 00161 uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) { 00162 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; 00163 Notify(PSTR("\r\nRead LUN:\t"), 0x80); 00164 D_PrintHex<uint8_t > (lun, 0x90); 00165 Notify(PSTR("\r\nLBA:\t\t"), 0x90); 00166 D_PrintHex<uint32_t > (addr, 0x90); 00167 Notify(PSTR("\r\nblocks:\t\t"), 0x90); 00168 D_PrintHex<uint8_t > (blocks, 0x90); 00169 Notify(PSTR("\r\nblock size:\t"), 0x90); 00170 D_PrintHex<uint16_t > (bsize, 0x90); 00171 Notify(PSTR("\r\n---------\r\n"), 0x80); 00172 CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr); 00173 00174 again: 00175 uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN); 00176 00177 if(er == MASS_ERR_STALL) { 00178 MediaCTL(lun, 1); 00179 wait_ms(150); 00180 if(!TestUnitReady(lun)) goto again; 00181 } 00182 return er; 00183 } 00184 00185 /** 00186 * Write data to media 00187 * 00188 * @param lun Logical Unit Number 00189 * @param addr LBA address on media to write 00190 * @param bsize size of a block (we should probably use the cached size) 00191 * @param blocks how many blocks to write 00192 * @param buf memory that contains the data to write 00193 * @return 0 on success 00194 */ 00195 uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) { 00196 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; 00197 if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED; 00198 Notify(PSTR("\r\nWrite LUN:\t"), 0x80); 00199 D_PrintHex<uint8_t > (lun, 0x90); 00200 Notify(PSTR("\r\nLBA:\t\t"), 0x90); 00201 D_PrintHex<uint32_t > (addr, 0x90); 00202 Notify(PSTR("\r\nblocks:\t\t"), 0x90); 00203 D_PrintHex<uint8_t > (blocks, 0x90); 00204 Notify(PSTR("\r\nblock size:\t"), 0x90); 00205 D_PrintHex<uint16_t > (bsize, 0x90); 00206 Notify(PSTR("\r\n---------\r\n"), 0x80); 00207 CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr); 00208 00209 again: 00210 uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT); 00211 00212 if(er == MASS_ERR_WRITE_STALL) { 00213 MediaCTL(lun, 1); 00214 wait_ms(150); 00215 if(!TestUnitReady(lun)) goto again; 00216 } 00217 return er; 00218 } 00219 00220 // End of user functions, the remaining code below is driver internals. 00221 // Only developer serviceable parts below! 00222 00223 //////////////////////////////////////////////////////////////////////////////// 00224 00225 // Main driver code 00226 00227 //////////////////////////////////////////////////////////////////////////////// 00228 00229 BulkOnly::BulkOnly(Usb *p) : 00230 pUsb(p), 00231 bAddress(0), 00232 bIface(0), 00233 bNumEP(1), 00234 qNextPollTime(0), 00235 bPollEnable(false), 00236 //dCBWTag(0), 00237 bLastUsbError(0) { 00238 ClearAllEP(); 00239 dCBWTag = 0; 00240 if(pUsb) 00241 pUsb->RegisterDeviceClass(this); 00242 } 00243 00244 /** 00245 * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success 00246 * We need to standardize either the rcode, or change the API to return values 00247 * so a signal that additional actions are required can be produced. 00248 * Some of these codes do exist already. 00249 * 00250 * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance. 00251 * Doing so would save some program memory when using multiple drivers. 00252 * 00253 * @param parent USB address of parent 00254 * @param port address of port on parent 00255 * @param lowspeed true if device is low speed 00256 * @return 00257 */ 00258 uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { 00259 00260 const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); 00261 00262 uint8_t buf[constBufSize]; 00263 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00264 uint8_t rcode; 00265 UsbDevice *p = NULL; 00266 EpInfo *oldep_ptr = NULL; 00267 USBTRACE("MS ConfigureDevice\r\n"); 00268 ClearAllEP(); 00269 AddressPool &addrPool = pUsb->GetAddressPool(); 00270 00271 00272 if(bAddress) 00273 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00274 00275 // <TECHNICAL> 00276 // Get pointer to pseudo device with address 0 assigned 00277 p = addrPool.GetUsbDevicePtr(0); 00278 if(!p) { 00279 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00280 } 00281 00282 if(!p->epinfo) { 00283 USBTRACE("epinfo\r\n"); 00284 return USB_ERROR_EPINFO_IS_NULL; 00285 } 00286 00287 // Save old pointer to EP_RECORD of address 0 00288 oldep_ptr = p->epinfo; 00289 00290 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00291 p->epinfo = epInfo; 00292 00293 p->lowspeed = lowspeed; 00294 // Get device descriptor 00295 rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); 00296 00297 // Restore p->epinfo 00298 p->epinfo = oldep_ptr; 00299 00300 if(rcode) { 00301 goto FailGetDevDescr; 00302 } 00303 // Allocate new address according to device class 00304 bAddress = addrPool.AllocAddress(parent, false, port); 00305 00306 if(!bAddress) 00307 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00308 00309 // Extract Max Packet Size from the device descriptor 00310 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00311 // Steal and abuse from epInfo structure to save on memory. 00312 epInfo[1].epAddr = udd->bNumConfigurations; 00313 // </TECHNICAL> 00314 return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; 00315 00316 FailGetDevDescr: 00317 #ifdef DEBUG_USB_HOST 00318 NotifyFailGetDevDescr(rcode); 00319 #endif 00320 rcode = USB_ERROR_FailGetDevDescr; 00321 00322 Release(); 00323 return rcode; 00324 }; 00325 00326 /** 00327 * 00328 * @param parent (not used) 00329 * @param port (not used) 00330 * @param lowspeed true if device is low speed 00331 * @return 0 for success 00332 */ 00333 uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) { 00334 uint8_t rcode; 00335 uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations 00336 epInfo[1].epAddr = 0; 00337 USBTRACE("MS Init\r\n"); 00338 00339 AddressPool &addrPool = pUsb->GetAddressPool(); 00340 UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); 00341 00342 if(!p) 00343 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00344 00345 // Assign new address to the device 00346 wait_ms(2000); 00347 rcode = pUsb->setAddr(0, 0, bAddress); 00348 00349 if(rcode) { 00350 p->lowspeed = false; 00351 addrPool.FreeAddress(bAddress); 00352 bAddress = 0; 00353 USBTRACE2("setAddr:", rcode); 00354 return rcode; 00355 } 00356 00357 USBTRACE2("Addr:", bAddress); 00358 00359 p->lowspeed = false; 00360 00361 p = addrPool.GetUsbDevicePtr(bAddress); 00362 00363 if(!p) 00364 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00365 00366 p->lowspeed = lowspeed; 00367 00368 // Assign epInfo to epinfo pointer 00369 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00370 00371 if(rcode) 00372 goto FailSetDevTblEntry; 00373 00374 USBTRACE2("NC:", num_of_conf); 00375 00376 for(uint8_t i = 0; i < num_of_conf; i++) { 00377 ConfigDescParser< USB_CLASS_MASS_STORAGE, 00378 MASS_SUBCLASS_SCSI, 00379 MASS_PROTO_BBB, 00380 CP_MASK_COMPARE_CLASS | 00381 CP_MASK_COMPARE_SUBCLASS | 00382 CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this); 00383 00384 rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); 00385 00386 if(rcode) 00387 goto FailGetConfDescr; 00388 00389 if(bNumEP > 1) 00390 break; 00391 } 00392 00393 if(bNumEP < 3) 00394 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00395 00396 // Assign epInfo to epinfo pointer 00397 pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); 00398 00399 USBTRACE2("Conf:", bConfNum); 00400 00401 // Set Configuration Value 00402 rcode = pUsb->setConf(bAddress, 0, bConfNum); 00403 00404 if(rcode) 00405 goto FailSetConfDescr; 00406 00407 //Linux does a 1sec delay after this. 00408 wait_ms(1000); 00409 00410 rcode = GetMaxLUN(&bMaxLUN); 00411 if(rcode) 00412 goto FailGetMaxLUN; 00413 00414 if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1; 00415 ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN); 00416 00417 wait_ms(1000); // Delay a bit for slow firmware. 00418 00419 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { 00420 InquiryResponse response; 00421 rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); 00422 if(rcode) { 00423 ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode); 00424 } else { 00425 #if 0 00426 printf("LUN %i `", lun); 00427 uint8_t *buf = response.VendorID; 00428 for(int i = 0; i < 28; i++) printf("%c", buf[i]); 00429 printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier); 00430 printf("Device type %2.2X ", response.DeviceType); 00431 printf("RMB %1.1X ", response.Removable); 00432 printf("SSCS %1.1X ", response.SCCS); 00433 uint8_t sv = response.Version; 00434 printf("SCSI version %2.2X\r\nDevice conforms to ", sv); 00435 switch(sv) { 00436 case 0: 00437 printf("No specific"); 00438 break; 00439 case 1: 00440 printf("ANSI X3.131-1986 (ANSI 1)"); 00441 break; 00442 case 2: 00443 printf("ANSI X3.131-1994 (ANSI 2)"); 00444 break; 00445 case 3: 00446 printf("ANSI INCITS 301-1997 (SPC)"); 00447 break; 00448 case 4: 00449 printf("ANSI INCITS 351-2001 (SPC-2)"); 00450 break; 00451 case 5: 00452 printf("ANSI INCITS 408-2005 (SPC-4)"); 00453 break; 00454 case 6: 00455 printf("T10/1731-D (SPC-4)"); 00456 break; 00457 default: 00458 printf("unknown"); 00459 } 00460 printf(" standards.\r\n"); 00461 #endif 00462 uint8_t tries = 0xf0; 00463 while((rcode = TestUnitReady(lun))) { 00464 if(rcode == 0x08) break; // break on no media, this is OK to do. 00465 // try to lock media and spin up 00466 if(tries < 14) { 00467 LockMedia(lun, 1); 00468 MediaCTL(lun, 1); // I actually have a USB stick that needs this! 00469 } else wait_ms(2 * (tries + 1)); 00470 tries++; 00471 if(!tries) break; 00472 } 00473 if(!rcode) { 00474 wait_ms(1000); 00475 LUNOk[lun] = CheckLUN(lun); 00476 if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun); 00477 } 00478 } 00479 } 00480 00481 00482 CheckMedia(); 00483 00484 rcode = OnInit(); 00485 00486 if(rcode) 00487 goto FailOnInit; 00488 00489 #ifdef DEBUG_USB_HOST 00490 USBTRACE("MS configured\r\n\r\n"); 00491 #endif 00492 00493 bPollEnable = true; 00494 00495 //USBTRACE("Poll enabled\r\n"); 00496 return 0; 00497 00498 FailSetConfDescr: 00499 #ifdef DEBUG_USB_HOST 00500 NotifyFailSetConfDescr(); 00501 goto Fail; 00502 #endif 00503 00504 FailOnInit: 00505 #ifdef DEBUG_USB_HOST 00506 USBTRACE("OnInit:"); 00507 goto Fail; 00508 #endif 00509 00510 FailGetMaxLUN: 00511 #ifdef DEBUG_USB_HOST 00512 USBTRACE("GetMaxLUN:"); 00513 goto Fail; 00514 #endif 00515 00516 //#ifdef DEBUG_USB_HOST 00517 //FailInvalidSectorSize: 00518 // USBTRACE("Sector Size is NOT VALID: "); 00519 // goto Fail; 00520 //#endif 00521 00522 FailSetDevTblEntry: 00523 #ifdef DEBUG_USB_HOST 00524 NotifyFailSetDevTblEntry(); 00525 goto Fail; 00526 #endif 00527 00528 FailGetConfDescr: 00529 #ifdef DEBUG_USB_HOST 00530 NotifyFailGetConfDescr(); 00531 #endif 00532 00533 #ifdef DEBUG_USB_HOST 00534 Fail: 00535 NotifyFail(rcode); 00536 #endif 00537 Release(); 00538 return rcode; 00539 } 00540 00541 /** 00542 * For driver use only. 00543 * 00544 * @param conf 00545 * @param iface 00546 * @param alt 00547 * @param proto 00548 * @param pep 00549 */ 00550 void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR * pep) { 00551 ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf); 00552 ErrorMessage<uint8_t > (PSTR("Iface Num"), iface); 00553 ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt); 00554 00555 bConfNum = conf; 00556 00557 uint8_t index; 00558 00559 #if 1 00560 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) { 00561 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; 00562 // Fill in the endpoint info structure 00563 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); 00564 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; 00565 epInfo[index].bmSndToggle = 0; 00566 epInfo[index].bmRcvToggle = 0; 00567 00568 bNumEP++; 00569 00570 PrintEndpointDescriptor(pep); 00571 00572 } 00573 #else 00574 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) 00575 index = epInterruptInIndex; 00576 else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) 00577 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; 00578 else 00579 return; 00580 00581 // Fill in the endpoint info structure 00582 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); 00583 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; 00584 epInfo[index].bmSndToggle = 0; 00585 epInfo[index].bmRcvToggle = 0; 00586 00587 bNumEP++; 00588 00589 PrintEndpointDescriptor(pep); 00590 #endif 00591 } 00592 00593 /** 00594 * For driver use only. 00595 * 00596 * @return 00597 */ 00598 uint8_t BulkOnly::Release() { 00599 ClearAllEP(); 00600 pUsb->GetAddressPool().FreeAddress(bAddress); 00601 return 0; 00602 } 00603 00604 /** 00605 * For driver use only. 00606 * 00607 * @param lun Logical Unit Number 00608 * @return true if LUN is ready for use. 00609 */ 00610 bool BulkOnly::CheckLUN(uint8_t lun) { 00611 uint8_t rcode; 00612 Capacity capacity; 00613 for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0; 00614 00615 rcode = ReadCapacity10(lun, (uint8_t*)capacity.data); 00616 if(rcode) { 00617 //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode); 00618 return false; 00619 } 00620 ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun); 00621 for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++) 00622 D_PrintHex<uint8_t > (capacity.data[i], 0x80); 00623 Notify(PSTR("\r\n\r\n"), 0x80); 00624 // Only 512/1024/2048/4096 are valid values! 00625 uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]); 00626 if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) { 00627 return false; 00628 } 00629 // Store capacity information. 00630 CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF); 00631 00632 CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1; 00633 if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) { 00634 // Buggy firmware will report 0xffffffff or 0 for no media 00635 if(CurrentCapacity[lun]) 00636 ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun); 00637 return false; 00638 } 00639 wait_ms(20); 00640 Page3F(lun); 00641 if(!TestUnitReady(lun)) return true; 00642 return false; 00643 } 00644 00645 /** 00646 * For driver use only. 00647 * 00648 * Scan for media change on all LUNs 00649 */ 00650 void BulkOnly::CheckMedia() { 00651 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { 00652 if(TestUnitReady(lun)) { 00653 LUNOk[lun] = false; 00654 continue; 00655 } 00656 if(!LUNOk[lun]) 00657 LUNOk[lun] = CheckLUN(lun); 00658 } 00659 #if 0 00660 printf("}}}}}}}}}}}}}}}}STATUS "); 00661 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) { 00662 if(LUNOk[lun]) 00663 printf("#"); 00664 else printf("."); 00665 } 00666 printf("\r\n"); 00667 #endif 00668 qNextPollTime = (uint32_t)millis() + 2000; 00669 } 00670 00671 /** 00672 * For driver use only. 00673 * 00674 * @return 00675 */ 00676 uint8_t BulkOnly::Poll() { 00677 //uint8_t rcode = 0; 00678 00679 if(!bPollEnable) 00680 return 0; 00681 00682 if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { 00683 CheckMedia(); 00684 } 00685 //rcode = 0; 00686 00687 return 0; 00688 } 00689 00690 //////////////////////////////////////////////////////////////////////////////// 00691 00692 00693 // SCSI code 00694 00695 00696 //////////////////////////////////////////////////////////////////////////////// 00697 00698 /** 00699 * For driver use only. 00700 * 00701 * @param plun 00702 * @return 00703 */ 00704 uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) { 00705 uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL); 00706 00707 if(ret == hrSTALL) 00708 *plun = 0; 00709 00710 return 0; 00711 } 00712 00713 /** 00714 * For driver use only. Used during Driver Init 00715 * 00716 * @param lun Logical Unit Number 00717 * @param bsize 00718 * @param buf 00719 * @return 00720 */ 00721 uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { 00722 Notify(PSTR("\r\nInquiry\r\n"), 0x80); 00723 Notify(PSTR("---------\r\n"), 0x80); 00724 00725 CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0); 00726 uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN); 00727 00728 return rc; 00729 } 00730 00731 /** 00732 * For driver use only. 00733 * 00734 * @param lun Logical Unit Number 00735 * @return 00736 */ 00737 uint8_t BulkOnly::TestUnitReady(uint8_t lun) { 00738 //SetCurLUN(lun); 00739 if(!bAddress) 00740 return MASS_ERR_UNIT_NOT_READY; 00741 00742 Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80); 00743 Notify(PSTR("-----------------\r\n"), 0x80); 00744 00745 CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0); 00746 return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN); 00747 00748 } 00749 00750 /** 00751 * For driver use only. 00752 * 00753 * @param lun Logical Unit Number 00754 * @param pc 00755 * @param page 00756 * @param subpage 00757 * @param len 00758 * @param pbuf 00759 * @return 00760 */ 00761 uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) { 00762 Notify(PSTR("\r\rModeSense\r\n"), 0x80); 00763 Notify(PSTR("------------\r\n"), 0x80); 00764 00765 CDB6_t cdb = CDB6_t(SCSI_CMD_MODE_SENSE_6, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0); 00766 return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN); 00767 } 00768 00769 /** 00770 * For driver use only. 00771 * 00772 * @param lun Logical Unit Number 00773 * @param bsize 00774 * @param buf 00775 * @return 00776 */ 00777 uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) { 00778 Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); 00779 Notify(PSTR("---------------\r\n"), 0x80); 00780 00781 CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun); 00782 return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN); 00783 } 00784 00785 /** 00786 * For driver use only. 00787 * 00788 * Page 3F contains write protect status. 00789 * 00790 * @param lun Logical Unit Number to test. 00791 * @return Write protect switch status. 00792 */ 00793 uint8_t BulkOnly::Page3F(uint8_t lun) { 00794 uint8_t buf[192]; 00795 for(int i = 0; i < 192; i++) { 00796 buf[i] = 0x00; 00797 } 00798 WriteOk[lun] = true; 00799 uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf); 00800 if(!rc) { 00801 WriteOk[lun] = ((buf[2] & 0x80) == 0); 00802 Notify(PSTR("Mode Sense: "), 0x80); 00803 for(int i = 0; i < 4; i++) { 00804 D_PrintHex<uint8_t > (buf[i], 0x80); 00805 Notify(PSTR(" "), 0x80); 00806 } 00807 Notify(PSTR("\r\n"), 0x80); 00808 } 00809 return rc; 00810 } 00811 00812 /** 00813 * For driver use only. 00814 * 00815 * @param lun Logical Unit Number 00816 * @param size 00817 * @param buf 00818 * @return 00819 */ 00820 uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) { 00821 Notify(PSTR("\r\nRequestSense\r\n"), 0x80); 00822 Notify(PSTR("----------------\r\n"), 0x80); 00823 00824 CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0); 00825 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN); 00826 //SetCurLUN(lun); 00827 return Transaction(&cbw, size, buf); 00828 } 00829 00830 00831 //////////////////////////////////////////////////////////////////////////////// 00832 00833 00834 // USB code 00835 00836 00837 //////////////////////////////////////////////////////////////////////////////// 00838 00839 /** 00840 * For driver use only. 00841 * 00842 * @param index 00843 * @return 00844 */ 00845 uint8_t BulkOnly::ClearEpHalt(uint8_t index) { 00846 if(index == 0) 00847 return 0; 00848 00849 uint8_t ret = 0; 00850 00851 while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01)) 00852 wait_ms(6); 00853 00854 if(ret) { 00855 ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret); 00856 ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr)); 00857 return ret; 00858 } 00859 epInfo[index].bmSndToggle = 0; 00860 epInfo[index].bmRcvToggle = 0; 00861 return 0; 00862 } 00863 00864 /** 00865 * For driver use only. 00866 * 00867 */ 00868 void BulkOnly::Reset() { 00869 while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) wait_ms(6); 00870 } 00871 00872 /** 00873 * For driver use only. 00874 * 00875 * @return 0 if successful 00876 */ 00877 uint8_t BulkOnly::ResetRecovery() { 00878 Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); 00879 Notify(PSTR("-----------------\r\n"), 0x80); 00880 00881 wait_ms(6); 00882 Reset(); 00883 wait_ms(6); 00884 ClearEpHalt(epDataInIndex); 00885 wait_ms(6); 00886 bLastUsbError = ClearEpHalt(epDataOutIndex); 00887 wait_ms(6); 00888 return bLastUsbError; 00889 } 00890 00891 /** 00892 * For driver use only. 00893 * 00894 * Clear all EP data and clear all LUN status 00895 */ 00896 void BulkOnly::ClearAllEP() { 00897 for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) { 00898 epInfo[i].epAddr = 0; 00899 epInfo[i].maxPktSize = (i) ? 0 : 8; 00900 epInfo[i].bmSndToggle = 0; 00901 epInfo[i].bmRcvToggle = 0; 00902 epInfo[i].bmNakPower = USB_NAK_DEFAULT; 00903 } 00904 00905 for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) { 00906 LUNOk[i] = false; 00907 WriteOk[i] = false; 00908 CurrentCapacity[i] = 0lu; 00909 CurrentSectorSize[i] = 0; 00910 } 00911 00912 bIface = 0; 00913 bNumEP = 1; 00914 bAddress = 0; 00915 qNextPollTime = 0; 00916 bPollEnable = false; 00917 bLastUsbError = 0; 00918 bMaxLUN = 0; 00919 bTheLUN = 0; 00920 } 00921 00922 /** 00923 * For driver use only. 00924 * 00925 * @param pcsw 00926 * @param pcbw 00927 * @return 00928 */ 00929 bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) { 00930 if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) { 00931 Notify(PSTR("CSW:Sig error\r\n"), 0x80); 00932 return false; 00933 } 00934 if(pcsw->dCSWTag != pcbw->dCBWTag) { 00935 Notify(PSTR("CSW:Wrong tag\r\n"), 0x80); 00936 return false; 00937 } 00938 return true; 00939 } 00940 00941 /** 00942 * For driver use only. 00943 * 00944 * @param error 00945 * @param index 00946 * @return 00947 */ 00948 uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { 00949 uint8_t count = 3; 00950 00951 bLastUsbError = error; 00952 //if (error) 00953 //ClearEpHalt(index); 00954 while(error && count) { 00955 if(error != hrSUCCESS) { 00956 ErrorMessage<uint8_t > (PSTR("USB Error"), error); 00957 ErrorMessage<uint8_t > (PSTR("Index"), index); 00958 } 00959 switch(error) { 00960 // case hrWRONGPID: 00961 case hrSUCCESS: 00962 return MASS_ERR_SUCCESS; 00963 case hrBUSY: 00964 // SIE is busy, just hang out and try again. 00965 return MASS_ERR_UNIT_BUSY; 00966 case hrTIMEOUT: 00967 case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; 00968 case hrSTALL: 00969 if(index == 0) 00970 return MASS_ERR_STALL; 00971 ClearEpHalt(index); 00972 if(index != epDataInIndex) 00973 return MASS_ERR_WRITE_STALL; 00974 return MASS_ERR_STALL; 00975 00976 case hrNAK: 00977 if(index == 0) 00978 return MASS_ERR_UNIT_BUSY; 00979 return MASS_ERR_UNIT_BUSY; 00980 00981 case hrTOGERR: 00982 // Handle a very super rare corner case, where toggles become de-synched. 00983 // I have only ran into one device that has this firmware bug, and this is 00984 // the only clean way to get back into sync with the buggy device firmware. 00985 // --AJK 00986 if(bAddress && bConfNum) { 00987 error = pUsb->setConf(bAddress, 0, bConfNum); 00988 00989 if(error) 00990 break; 00991 } 00992 return MASS_ERR_SUCCESS; 00993 default: 00994 ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error); 00995 return MASS_ERR_GENERAL_USB_ERROR; 00996 } 00997 count--; 00998 } // while 00999 01000 return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); 01001 } 01002 01003 #if MS_WANT_PARSER 01004 01005 uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) { 01006 return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0); 01007 } 01008 #endif 01009 01010 /** 01011 * For driver use only. 01012 * 01013 * @param pcbw 01014 * @param buf_size 01015 * @param buf 01016 * @param flags 01017 * @return 01018 */ 01019 uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf 01020 #if MS_WANT_PARSER 01021 , uint8_t flags 01022 #endif 01023 ) { 01024 01025 #if MS_WANT_PARSER 01026 uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; 01027 printf("Transfersize %i\r\n", bytes); 01028 wait_ms(1000); 01029 01030 bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; 01031 #else 01032 uint16_t bytes = buf_size; 01033 #endif 01034 bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; 01035 uint8_t ret = 0; 01036 uint8_t usberr; 01037 CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles. 01038 SetCurLUN(pcbw->bmCBWLUN); 01039 ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); 01040 01041 while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) wait_ms(1); 01042 01043 ret = HandleUsbError(usberr, epDataOutIndex); 01044 //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); 01045 if(ret) { 01046 ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret); 01047 } else { 01048 if(bytes) { 01049 if(!write) { 01050 #if MS_WANT_PARSER 01051 if(callback) { 01052 uint8_t rbuf[bytes]; 01053 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) wait_ms(1); 01054 if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); 01055 } else { 01056 #endif 01057 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) wait_ms(1); 01058 #if MS_WANT_PARSER 01059 01060 } 01061 #endif 01062 ret = HandleUsbError(usberr, epDataInIndex); 01063 } else { 01064 while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) wait_ms(1); 01065 ret = HandleUsbError(usberr, epDataOutIndex); 01066 } 01067 if(ret) { 01068 ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret); 01069 } 01070 } 01071 } 01072 01073 { 01074 bytes = sizeof (CommandStatusWrapper); 01075 int tries = 2; 01076 while(tries--) { 01077 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) wait_ms(1); 01078 if(!usberr) break; 01079 ClearEpHalt(epDataInIndex); 01080 if(tries) ResetRecovery(); 01081 } 01082 if(!ret) { 01083 Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); 01084 Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); 01085 } else { 01086 // Throw away csw, IT IS NOT OF ANY USE. 01087 ResetRecovery(); 01088 return ret; 01089 } 01090 ret = HandleUsbError(usberr, epDataInIndex); 01091 if(ret) { 01092 ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret); 01093 } 01094 if(usberr == hrSUCCESS) { 01095 if(IsValidCSW(&csw, pcbw)) { 01096 //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag); 01097 //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus); 01098 //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue); 01099 Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); 01100 return csw.bCSWStatus; 01101 } else { 01102 // NOTE! Sometimes this is caused by the reported residue being wrong. 01103 // Get a different device. It isn't compliant, and should have never passed Q&A. 01104 // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter. 01105 // Other devices that exhibit this behavior exist in the wild too. 01106 // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk 01107 Notify(PSTR("Invalid CSW\r\n"), 0x80); 01108 ResetRecovery(); 01109 //return MASS_ERR_SUCCESS; 01110 return MASS_ERR_INVALID_CSW; 01111 } 01112 } 01113 } 01114 return ret; 01115 } 01116 01117 /** 01118 * For driver use only. 01119 * 01120 * @param lun Logical Unit Number 01121 * @return 01122 */ 01123 uint8_t BulkOnly::SetCurLUN(uint8_t lun) { 01124 if(lun > bMaxLUN) 01125 return MASS_ERR_INVALID_LUN; 01126 bTheLUN = lun; 01127 return MASS_ERR_SUCCESS; 01128 }; 01129 01130 /** 01131 * For driver use only. 01132 * 01133 * @param status 01134 * @return 01135 */ 01136 uint8_t BulkOnly::HandleSCSIError(uint8_t status) { 01137 uint8_t ret = 0; 01138 01139 switch(status) { 01140 case 0: return MASS_ERR_SUCCESS; 01141 01142 case 2: 01143 ErrorMessage<uint8_t > (PSTR("Phase Error"), status); 01144 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); 01145 ResetRecovery(); 01146 return MASS_ERR_GENERAL_SCSI_ERROR; 01147 01148 case 1: 01149 ErrorMessage<uint8_t > (PSTR("SCSI Error"), status); 01150 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); 01151 RequestSenseResponce rsp; 01152 01153 ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); 01154 01155 if(ret) { 01156 return MASS_ERR_GENERAL_SCSI_ERROR; 01157 } 01158 ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode); 01159 if(rsp.bResponseCode & 0x80) { 01160 Notify(PSTR("Information field: "), 0x80); 01161 for(int i = 0; i < 4; i++) { 01162 D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80); 01163 Notify(PSTR(" "), 0x80); 01164 } 01165 Notify(PSTR("\r\n"), 0x80); 01166 } 01167 ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey); 01168 ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); 01169 ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); 01170 // warning, this is not testing ASQ, only SK and ASC. 01171 switch(rsp.bmSenseKey) { 01172 case SCSI_S_UNIT_ATTENTION: 01173 switch(rsp.bAdditionalSenseCode) { 01174 case SCSI_ASC_MEDIA_CHANGED: 01175 return MASS_ERR_MEDIA_CHANGED; 01176 default: 01177 return MASS_ERR_UNIT_NOT_READY; 01178 } 01179 case SCSI_S_NOT_READY: 01180 switch(rsp.bAdditionalSenseCode) { 01181 case SCSI_ASC_MEDIUM_NOT_PRESENT: 01182 return MASS_ERR_NO_MEDIA; 01183 default: 01184 return MASS_ERR_UNIT_NOT_READY; 01185 } 01186 case SCSI_S_ILLEGAL_REQUEST: 01187 switch(rsp.bAdditionalSenseCode) { 01188 case SCSI_ASC_LBA_OUT_OF_RANGE: 01189 return MASS_ERR_BAD_LBA; 01190 default: 01191 return MASS_ERR_CMD_NOT_SUPPORTED; 01192 } 01193 default: 01194 return MASS_ERR_GENERAL_SCSI_ERROR; 01195 } 01196 01197 // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later. 01198 // case 0x05/0x14: we stalled out 01199 // case 0x15/0x16: we naked out. 01200 default: 01201 ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status); 01202 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); 01203 return status; 01204 } // switch 01205 } 01206 01207 01208 //////////////////////////////////////////////////////////////////////////////// 01209 01210 01211 // Debugging code 01212 01213 01214 //////////////////////////////////////////////////////////////////////////////// 01215 01216 /** 01217 * 01218 * @param ep_ptr 01219 */ 01220 void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) { 01221 Notify(PSTR("Endpoint descriptor:"), 0x80); 01222 Notify(PSTR("\r\nLength:\t\t"), 0x80); 01223 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); 01224 Notify(PSTR("\r\nType:\t\t"), 0x80); 01225 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); 01226 Notify(PSTR("\r\nAddress:\t"), 0x80); 01227 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); 01228 Notify(PSTR("\r\nAttributes:\t"), 0x80); 01229 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); 01230 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); 01231 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); 01232 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); 01233 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); 01234 Notify(PSTR("\r\n"), 0x80); 01235 } 01236 01237 01238 //////////////////////////////////////////////////////////////////////////////// 01239 01240 01241 // misc/to kill/to-do 01242 01243 01244 //////////////////////////////////////////////////////////////////////////////// 01245 01246 /* We won't be needing this... */ 01247 uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attribute__((unused)), uint16_t bsize __attribute__((unused)), uint8_t blocks __attribute__((unused)), USBReadParser * prs __attribute__((unused))) { 01248 #if MS_WANT_PARSER 01249 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; 01250 Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); 01251 Notify(PSTR("---------\r\n"), 0x80); 01252 01253 CommandBlockWrapper cbw = CommandBlockWrapper(); 01254 01255 cbw.dCBWSignature = MASS_CBW_SIGNATURE; 01256 cbw.dCBWTag = ++dCBWTag; 01257 cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); 01258 cbw.bmCBWFlags = MASS_CMD_DIR_IN, 01259 cbw.bmCBWLUN = lun; 01260 cbw.bmCBWCBLength = 10; 01261 01262 cbw.CBWCB[0] = SCSI_CMD_READ_10; 01263 cbw.CBWCB[8] = blocks; 01264 cbw.CBWCB[2] = ((addr >> 24) & 0xff); 01265 cbw.CBWCB[3] = ((addr >> 16) & 0xff); 01266 cbw.CBWCB[4] = ((addr >> 8) & 0xff); 01267 cbw.CBWCB[5] = (addr & 0xff); 01268 01269 return HandleSCSIError(Transaction(&cbw, bsize, prs, 1)); 01270 #else 01271 return MASS_ERR_NOT_IMPLEMENTED; 01272 #endif 01273 }
Generated on Tue Jul 12 2022 18:12:04 by
1.7.2