Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers masstorage.cpp Source File

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 }