12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205 |
- /* Copyright (C) 2015-2016 Andrew J. Kroll
- and
- Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- Contact information
- -------------------
-
- Circuits At Home, LTD
- Web : https://www.circuitsathome.com
- e-mail : support@circuitsathome.com
- */
-
- #if defined(LOAD_UHS_BULK_STORAGE) && defined(__UHS_BULK_STORAGE_H__) && !defined(UHS_BULK_STORAGE_LOADED)
- #define UHS_BULK_STORAGE_LOADED
-
- // uncomment to get 'printf' console debugging. NOT FOR UNO!
- //#define DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE
-
- #if DEBUG_PRINTF_EXTRA_HUGE
- #ifdef DEBUG_PRINTF_EXTRA_HUGE_UHS_BULK_STORAGE
- #define BS_HOST_DEBUG(...) printf(__VA_ARGS__)
- #else
- #define BS_HOST_DEBUG(...) VOID0
- #endif
- #else
- #define BS_HOST_DEBUG(...) VOID0
- #endif
-
- ////////////////////////////////////////////////////////////////////////////////
-
- // Interface code
-
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Get the capacity of the media
- *
- * @param lun Logical Unit Number
- * @return media capacity
- */
- uint32_t UHS_NI UHS_Bulk_Storage::GetCapacity(uint8_t lun) {
- uint32_t v = 0LU;
- pUsb->DisablePoll();
- if(LUNOk[lun])
- v = CurrentCapacity[lun];
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Get the sector (block) size used on the media
- *
- * @param lun Logical Unit Number
- * @return media sector size
- */
- uint16_t UHS_NI UHS_Bulk_Storage::GetSectorSize(uint8_t lun) {
- uint16_t v = 0U;
- pUsb->DisablePoll();
- if(LUNOk[lun])
- v = CurrentSectorSize[lun];
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Test if LUN is ready for use
- *
- * @param lun Logical Unit Number
- * @return true if LUN is ready for use
- */
- bool UHS_NI UHS_Bulk_Storage::LUNIsGood(uint8_t lun) {
- bool v;
- pUsb->DisablePoll();
- v = LUNOk[lun];
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Test if LUN is write protected
- *
- * @param lun Logical Unit Number
- * @return cached status of write protect switch
- */
- bool UHS_NI UHS_Bulk_Storage::WriteProtected(uint8_t lun) {
- bool v;
- pUsb->DisablePoll();
- v = WriteOk[lun];
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Wrap and execute a SCSI CDB with length of 6
- *
- * @param cdb CDB to execute
- * @param buf_size Size of expected transaction
- * @param buf Buffer
- * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::SCSITransaction6(SCSI_CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- pUsb->DisablePoll();
- // promote buf_size to 32bits.
- UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
-
- #if 0
- // Lets check the CBW here:
- printf("\r\n");
- printf("\r\n");
- uint8_t *dump = (uint8_t*)(&cbw);
-
- for(int i=0; i<(sizeof (UHS_BULK_CommandBlockWrapper)); i++) {
- printf("%02.2x ", *dump);
- dump++;
- }
- printf("\r\n");
- printf("\r\n");
- #endif
-
- uint8_t v = (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Wrap and execute a SCSI CDB with length of 10
- *
- * @param cdb CDB to execute
- * @param buf_size Size of expected transaction
- * @param buf Buffer
- * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::SCSITransaction10(SCSI_CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- pUsb->DisablePoll();
- // promote buf_size to 32bits.
- UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
- //SetCurLUN(cdb->LUN);
- uint8_t v = (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Lock or Unlock the tray or door on device.
- * Caution: Some devices with buggy firmware will lock up.
- *
- * @param lun Logical Unit Number
- * @param lock 1 to lock, 0 to unlock
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::LockMedia(uint8_t lun, uint8_t lock) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- pUsb->DisablePoll();
- Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
- Notify(PSTR("---------\r\n"), 0x80);
-
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
-
- uint8_t v = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)UHS_BULK_CMD_DIR_IN);
- pUsb->EnablePoll();
- return v;
- }
-
- /**
- * Media control, for spindle motor and media tray or door.
- * This includes CDROM, TAPE and anything with a media loader.
- *
- * @param lun Logical Unit Number
- * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
- * @return 0 on success
- */
- uint8_t UHS_NI UHS_Bulk_Storage::MediaCTL(uint8_t lun, uint8_t ctl) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- pUsb->DisablePoll();
- Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
- Notify(PSTR("-----------------\r\n"), 0x80);
-
- uint8_t rcode = UHS_BULK_ERR_UNIT_NOT_READY;
- if(bAddress) {
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
- rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)UHS_BULK_CMD_DIR_OUT);
- } else {
- SetCurLUN(lun);
- }
- pUsb->EnablePoll();
- return rcode;
- }
-
- /**
- * Read data from media
- *
- * @param lun Logical Unit Number
- * @param addr LBA address on media to read
- * @param bsize size of a block (we should probably use the cached size)
- * @param blocks how many blocks to read
- * @param buf memory that is able to hold the requested data
- * @return 0 on success
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
- if(!bAddress) return UHS_BULK_ERR_NO_MEDIA;
- uint8_t er = UHS_BULK_ERR_NO_MEDIA;
- pUsb->DisablePoll();
- if(LUNOk[lun]) {
- Notify(PSTR("\r\nRead LUN:\t"), 0x80);
- D_PrintHex<uint8_t > (lun, 0x90);
- Notify(PSTR("\r\nLBA:\t\t"), 0x90);
- D_PrintHex<uint32_t > (addr, 0x90);
- Notify(PSTR("\r\nblocks:\t\t"), 0x90);
- D_PrintHex<uint8_t > (blocks, 0x90);
- Notify(PSTR("\r\nblock size:\t"), 0x90);
- D_PrintHex<uint16_t > (bsize, 0x90);
- Notify(PSTR("\r\n---------\r\n"), 0x80);
- SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
-
- again:
- er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)UHS_BULK_CMD_DIR_IN);
-
- if(er == UHS_BULK_ERR_STALL) {
- MediaCTL(lun, 1);
-
- if(UHS_SLEEP_MS(150)) {
- if(!TestUnitReady(lun)) goto again;
- }
- }
- }
- qNextPollTime = millis() + 100;
- pUsb->EnablePoll();
-
- return er;
- }
-
- /**
- * Write data to media
- *
- * @param lun Logical Unit Number
- * @param addr LBA address on media to write
- * @param bsize size of a block (we should probably use the cached size)
- * @param blocks how many blocks to write
- * @param buf memory that contains the data to write
- * @return 0 on success
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
- if(!bAddress) return UHS_BULK_ERR_NO_MEDIA;
- uint8_t er = UHS_BULK_ERR_NO_MEDIA;
- pUsb->DisablePoll();
- if(LUNOk[lun]) {
- if(!WriteOk[lun]) {
- er = UHS_BULK_ERR_WRITE_PROTECTED;
- } else {
- Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
- D_PrintHex<uint8_t > (lun, 0x90);
- Notify(PSTR("\r\nLBA:\t\t"), 0x90);
- D_PrintHex<uint32_t > (addr, 0x90);
- Notify(PSTR("\r\nblocks:\t\t"), 0x90);
- D_PrintHex<uint8_t > (blocks, 0x90);
- Notify(PSTR("\r\nblock size:\t"), 0x90);
- D_PrintHex<uint16_t > (bsize, 0x90);
- Notify(PSTR("\r\n---------\r\n"), 0x80);
- SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
-
- again:
- er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)UHS_BULK_CMD_DIR_OUT);
-
- if(er == UHS_BULK_ERR_WRITE_STALL) {
- MediaCTL(lun, 1);
-
- if(UHS_SLEEP_MS(150)) {
- if(!TestUnitReady(lun)) goto again;
- }
- }
- }
- }
- qNextPollTime = millis() + 100;
- pUsb->EnablePoll();
-
- return er;
- }
-
- // End of user functions, the remaining code below is driver internals.
- // Only developer serviceable parts below!
-
- ////////////////////////////////////////////////////////////////////////////////
-
- // Main driver code
-
- ////////////////////////////////////////////////////////////////////////////////
-
- UHS_NI UHS_Bulk_Storage::UHS_Bulk_Storage(UHS_USB_HOST_BASE *p) {
- pUsb = p;
- dCBWTag = 0;
- if(pUsb) {
-
- DriverDefaults();
- pUsb->RegisterDeviceClass(this);
- // Serial.print("Bulk Register to USB Host @ 0x");
- // Serial.println((uint32_t)pUsb, HEX);
- // Serial.print("Bulk Register to USB Host Address Pool @ 0x");
- // Serial.println((uint32_t)pUsb->GetAddressPool(), HEX);
- }
- }
-
- /**
- * @param ei Enumeration information
- * @return true if this interface driver can handle this interface description
- */
- bool UHS_NI UHS_Bulk_Storage::OKtoEnumerate(ENUMERATION_INFO *ei) {
- BS_HOST_DEBUG("BulkOnly: checking numep %i, klass %2.2x, subklass %2.2x\r\n", ei->interface.numep, ei->klass, ei->subklass);
- BS_HOST_DEBUG("BulkOnly: checking protocol %2.2x, interface.klass %2.2x, interface.subklass %2.2x\r\n", ei->protocol, ei->interface.klass, ei->interface.subklass);
- BS_HOST_DEBUG("BulkOnly: checking interface.protocol %2.2x\r\n", ei->interface.protocol);
- //
- // TO-DO?
- // Check that we have 2 bulk endpoints, and one in each direction??
- // e.g. (ei->interface.numep > 1) && // two or more endpoints AND check types
- // This will work with proper hardware though.
- //
-
- return (
- ((ei->klass == UHS_USB_CLASS_MASS_STORAGE) || (ei->interface.klass == UHS_USB_CLASS_MASS_STORAGE)) && // mass storage class AND
- ((ei->subklass == UHS_BULK_SUBCLASS_SCSI) || (ei->interface.subklass == UHS_BULK_SUBCLASS_SCSI)) && // SCSI command set AND
- ((ei->protocol == UHS_STOR_PROTO_BBB) || (ei->interface.protocol == UHS_STOR_PROTO_BBB)) // Bulk Only transport
- );
- }
-
- /**
- * @param ei Enumeration information
- * @return 0 always
- */
- uint8_t UHS_NI UHS_Bulk_Storage::SetInterface(ENUMERATION_INFO *ei) {
- uint8_t index;
-
- bAddress = ei->address;
- BS_HOST_DEBUG("BS SetInterface\r\n");
- // Fill in the endpoint info structure
- for(uint8_t ep = 0; ep < ei->interface.numep; ep++) {
- BS_HOST_DEBUG("ep: 0x%2.2x bmAttributes: 0x%2.2x ", ep, ei->interface.epInfo[ep].bmAttributes);
- if(ei->interface.epInfo[ep].bmAttributes == USB_TRANSFER_TYPE_BULK) {
- index = ((ei->interface.epInfo[ep].bEndpointAddress & USB_TRANSFER_DIRECTION_IN) == USB_TRANSFER_DIRECTION_IN) ? epDataInIndex : epDataOutIndex;
- epInfo[index].epAddr = (ei->interface.epInfo[ep].bEndpointAddress & 0x0F);
- epInfo[index].maxPktSize = ei->interface.epInfo[ep].wMaxPacketSize;
- epInfo[index].epAttribs = 0;
- epInfo[index].bmNakPower = UHS_USB_NAK_MAX_POWER;
- epInfo[index].bmSndToggle = 0;
- epInfo[index].bmRcvToggle = 0;
- epInfo[index].bIface=ei->interface.bInterfaceNumber;
- BS_HOST_DEBUG("index: %i\r\n", index);
- }
- BS_HOST_DEBUG("\r\n");
- }
- bNumEP = 3;
- epInfo[0].epAddr = 0;
- epInfo[0].maxPktSize = ei->bMaxPacketSize0;
- epInfo[0].bmNakPower = UHS_USB_NAK_MAX_POWER;
- bIface = ei->interface.bInterfaceNumber;
-
- return 0;
- };
-
- /**
- * @return 0 for success
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Start() {
- uint8_t rcode;
- // Serial.print("Bulk Start from USB Host @ 0x");
- // Serial.println((uint32_t)pUsb, HEX);
- // Serial.print("Bulk Start USB Host Address Pool @ 0x");
- // Serial.println((uint32_t)pUsb->GetAddressPool(), HEX);
-
- BS_HOST_DEBUG("BS Start, speed: %i\r\n", pUsb->GetAddressPool()->GetUsbDevicePtr(bAddress)->speed);
- BS_HOST_DEBUG("BS Start\r\n");
- rcode = pUsb->setEpInfoEntry(bAddress, bIface, 3, epInfo);
- // Serial.println(rcode,HEX);
- if(rcode) goto FailOnInit;
-
- // Do a 1 second delay before LUN query
- if(!UHS_SLEEP_MS(1000)) goto FailUnPlug;
-
- rcode = GetMaxLUN(&bMaxLUN);
- BS_HOST_DEBUG("GetMaxLUN 0x%2.2x\r\n", rcode);
- if(rcode) {
- goto FailGetMaxLUN;
- }
- if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
- BS_HOST_DEBUG("MaxLUN %u\r\n", bMaxLUN);
- //ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
- if(!UHS_SLEEP_MS(150)) goto FailUnPlug; // Delay a bit for slow firmware. (again)
-
- for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
- if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
- SCSI_Inquiry_Response response;
- rcode = Inquiry(lun, sizeof (SCSI_Inquiry_Response), (uint8_t*) & response);
- BS_HOST_DEBUG("Inquiry 0x%2.2x 0x%2.2x\r\n", sizeof (SCSI_Inquiry_Response), rcode);
- if(rcode) {
- goto FailInquiry;
- #if 0
- } else {
- BS_HOST_DEBUG("LUN %i `", lun);
- uint8_t *buf = response.VendorID;
- for(int i = 0; i < 28; i++) BS_HOST_DEBUG("%c", buf[i]);
- BS_HOST_DEBUG("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
- BS_HOST_DEBUG("Device type %2.2X ", response.DeviceType);
- BS_HOST_DEBUG("RMB %1.1X ", response.Removable);
- BS_HOST_DEBUG("SSCS %1.1X ", response.SCCS);
- uint8_t sv = response.Version;
- BS_HOST_DEBUG("SCSI version %2.2X\r\nDevice conforms to ", sv);
- switch(sv) {
- case 0:
- BS_HOST_DEBUG("No specific");
- break;
- case 1:
- BS_HOST_DEBUG("ANSI X3.131-1986 (ANSI 1)");
- break;
- case 2:
- BS_HOST_DEBUG("ANSI X3.131-1994 (ANSI 2)");
- break;
- case 3:
- BS_HOST_DEBUG("ANSI INCITS 301-1997 (SPC)");
- break;
- case 4:
- BS_HOST_DEBUG("ANSI INCITS 351-2001 (SPC-2)");
- break;
- case 5:
- BS_HOST_DEBUG("ANSI INCITS 408-2005 (SPC-4)");
- break;
- case 6:
- BS_HOST_DEBUG("T10/1731-D (SPC-4)");
- break;
- default:
- BS_HOST_DEBUG("unknown");
- }
- BS_HOST_DEBUG(" standards.\r\n");
- #endif
- }
- }
-
- for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
- if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
- #ifndef USB_NO_TEST_UNIT_READY
- uint8_t tries = 0xF0;
- while((rcode = TestUnitReady(lun))) {
- BS_HOST_DEBUG("\r\nTry %2.2x TestUnitReady %2.2x\r\n", tries - 0xF0, rcode);
- if(rcode == 0x08) break; // break on no media, this is OK to do.
- if(rcode == UHS_BULK_ERR_DEVICE_DISCONNECTED) goto FailUnPlug;
- if(rcode == UHS_BULK_ERR_INVALID_CSW) goto Fail;
- if(rcode != UHS_BULK_ERR_MEDIA_CHANGED) goto Fail;
- if(!UHS_SLEEP_MS(2 * (tries + 1))) goto FailUnPlug;
- tries++;
- if(!tries) break;
- }
- #else
- // Don't wait for the LUN to become ready, as this will
- // trigger Marlin's watchdog timer
- rcode = -1;
- #endif
- if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
- LockMedia(lun, 1);
- if(rcode == 0x08) {
- if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
- if(MediaCTL(lun, 1) == UHS_BULK_ERR_DEVICE_DISCONNECTED) goto FailUnPlug; // I actually have a USB stick that needs this!
- }
- BS_HOST_DEBUG("\r\nTry %2.2x TestUnitReady %2.2x\r\n", tries - 0xF0, rcode);
- if(!rcode) {
- if(!UHS_SLEEP_MS(3)) goto FailUnPlug;
- BS_HOST_DEBUG("CheckLUN...\r\n");
- BS_HOST_DEBUG("%lu\r\n", millis()/1000);
- // Stalls on ***some*** devices, ***WHY***?! Device SAID it is READY!!
- LUNOk[lun] = CheckLUN(lun);
- BS_HOST_DEBUG("%lu\r\n", millis()/1000);
- if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
- if(!UHS_SLEEP_MS(1)) goto FailUnPlug;
- BS_HOST_DEBUG("Checked LUN...\r\n");
- } else {
- LUNOk[lun] = false;
- }
- }
-
- rcode = OnStart();
-
- if(rcode) goto FailOnInit;
-
- #ifdef DEBUG_USB_HOST
- USBTRACE("BS configured\r\n\r\n");
- #endif
- qNextPollTime = millis() + 100;
- bPollEnable = true;
-
- return 0;
- FailUnPlug:
- rcode = UHS_BULK_ERR_DEVICE_DISCONNECTED;
- goto Fail;
-
- FailOnInit:
- #ifdef DEBUG_USB_HOST
- USBTRACE("OnStart:");
- goto Fail;
- #endif
-
- FailGetMaxLUN:
- #ifdef DEBUG_USB_HOST
- USBTRACE("GetMaxLUN:");
- goto Fail;
- #endif
-
- FailInquiry:
- #ifdef DEBUG_USB_HOST
- USBTRACE("Inquiry:");
- #endif
-
- Fail:
- #ifdef DEBUG_USB_HOST
- NotifyFail(rcode);
- #endif
- Release();
-
- return rcode;
- }
-
- // Base class definition of Release() used. See UHS_USBInterface class definition for details
-
- /**
- * For driver use only.
- *
- * @return
- */
- //void UHS_NI UHS_Bulk_Storage::Release() {
- // pUsb->DisablePoll();
- // OnRelease();
- // DriverDefaults();
- // pUsb->EnablePoll();
- // return;
- //}
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @return true if LUN is ready for use.
- */
- bool UHS_NI UHS_Bulk_Storage::CheckLUN(uint8_t lun) {
- uint8_t rcode;
- SCSI_Capacity capacity;
- for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
-
- rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
- if(rcode) {
- BS_HOST_DEBUG(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
- return false;
- }
- #ifdef DEBUG_USB_HOST
- ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
- for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
- D_PrintHex<uint8_t > (capacity.data[i], 0x80);
- Notify(PSTR("\r\n\r\n"), 0x80);
- #endif
- // Only 512/1024/2048/4096 are valid values!
- uint32_t c = UHS_BYTES_TO_UINT32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
- if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) {
- return false;
- }
- // Store capacity information.
- CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
-
- CurrentCapacity[lun] = UHS_BYTES_TO_UINT32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
- if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) {
- // Buggy firmware will report 0xFFFFFFFF or 0 for no media
- #ifdef DEBUG_USB_HOST
- if(CurrentCapacity[lun])
- ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
- #endif
- return false;
- }
- if(!UHS_SLEEP_MS(20)) return false;
- #ifndef SKIP_PAGE3F
- Page3F(lun);
- #endif
- if(!TestUnitReady(lun)) return true;
-
- return false;
- }
-
- /**
- * For driver use only.
- *
- * Scan for media change on all LUNs
- */
- void UHS_NI UHS_Bulk_Storage::CheckMedia() {
- if(!bAddress) return;
- for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
- if(TestUnitReady(lun)) {
- LUNOk[lun] = false;
- continue;
- }
- if(!LUNOk[lun])
- LUNOk[lun] = CheckLUN(lun);
- }
- #if 0
- BS_HOST_DEBUG("}}}}}}}}}}}}}}}}STATUS ");
- for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
- if(LUNOk[lun])
- BS_HOST_DEBUG("#");
-
- else BS_HOST_DEBUG(".");
- }
- BS_HOST_DEBUG("\r\n");
- #endif
- OnPoll();
- qNextPollTime = millis() + 100;
- }
-
- /**
- * For driver use only.
- */
- void UHS_NI UHS_Bulk_Storage::Poll() {
- if((long)(millis() - qNextPollTime) >= 0L) {
-
- CheckMedia();
- }
-
- return;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
-
-
- // SCSI code
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * For driver use only.
- *
- * @param plun
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::GetMaxLUN(uint8_t *plun) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- uint8_t ret = pUsb->ctrlReq(bAddress, mkSETUP_PKT16(UHS_BULK_bmREQ_IN, UHS_BULK_REQ_GET_MAX_LUN, 0x0000U, bIface, 1), 1, plun);
-
- if(ret == UHS_HOST_ERROR_STALL) {
-
- *plun = 0;
- Notify(PSTR("\r\nGetMaxLUN Stalled\r\n"), 0x80);
- }
- return 0;
- }
-
- /**
- * For driver use only. Used during Driver Start
- *
- * @param lun Logical Unit Number
- * @param bsize
- * @param buf
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- Notify(PSTR("\r\nInquiry\r\n"), 0x80);
- Notify(PSTR("---------\r\n"), 0x80);
-
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
- uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)UHS_BULK_CMD_DIR_IN);
-
- return rc;
- }
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::TestUnitReady(uint8_t lun) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- //SetCurLUN(lun);
- if(!bAddress)
- return UHS_BULK_ERR_UNIT_NOT_READY;
-
- Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
- Notify(PSTR("-----------------\r\n"), 0x80);
-
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0);
-
- return SCSITransaction6(&cdb, 0, NULL, (uint8_t)UHS_BULK_CMD_DIR_IN);
-
- }
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @param pc
- * @param page
- * @param subpage
- * @param len
- * @param pbuf
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- Notify(PSTR("\r\rModeSense\r\n"), 0x80);
- Notify(PSTR("------------\r\n"), 0x80);
-
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_MODE_SENSE_6, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0);
-
- return SCSITransaction6(&cdb, len, pbuf, (uint8_t)UHS_BULK_CMD_DIR_IN);
- }
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @param bsize
- * @param buf
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::ReadCapacity10(uint8_t lun, uint8_t *buf) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
- Notify(PSTR("---------------\r\n"), 0x80);
-
- SCSI_CDB10_t cdb = SCSI_CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun);
-
- return SCSITransaction10(&cdb, 8, buf, (uint8_t)UHS_BULK_CMD_DIR_IN);
- }
-
- /**
- * For driver use only.
- *
- * Page 3F contains write protect status.
- *
- * @param lun Logical Unit Number to test.
- * @return Write protect switch status.
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Page3F(uint8_t lun) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- uint8_t buf[192];
- for(int i = 0; i < 192; i++) {
- buf[i] = 0x00;
- }
- WriteOk[lun] = true;
- uint8_t rc = ModeSense6(lun, 0, 0x3F, 0, 192, buf);
- if(!rc) {
- WriteOk[lun] = ((buf[2] & 0x80) == 0);
- #ifdef DEBUG_USB_HOST
- Notify(PSTR("Mode Sense: "), 0x80);
- for(int i = 0; i < 4; i++) {
-
- D_PrintHex<uint8_t > (buf[i], 0x80);
- Notify(PSTR(" "), 0x80);
- }
- Notify(PSTR("\r\n"), 0x80);
- #endif
- }
- return rc;
- }
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @param size
- * @param buf
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- pUsb->DisablePoll();
- Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
- Notify(PSTR("----------------\r\n"), 0x80);
-
- SCSI_CDB6_t cdb = SCSI_CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
- UHS_BULK_CommandBlockWrapper cbw = UHS_BULK_CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)UHS_BULK_CMD_DIR_IN);
- uint8_t v = Transaction(&cbw, size, buf);
- pUsb->EnablePoll();
-
- return v;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
-
- // USB code
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * For driver use only.
- *
- * @param index
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::ClearEpHalt(uint8_t index) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- uint8_t ret = 0;
- if(index != 0) {
- uint8_t ep = (index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr;
- do {
- ret = pUsb->EPClearHalt(bAddress, ep);
- if(!UHS_SLEEP_MS(6)) break;
- } while(ret == 0x01);
-
- if(ret) {
- ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
- ErrorMessage<uint8_t > (PSTR("EP"), ep);
- epInfo[index].bmSndToggle = 0;
- epInfo[index].bmRcvToggle = 0;
- return ret;
- } else {
-
- epInfo[index].bmSndToggle = 0;
- epInfo[index].bmRcvToggle = 0;
- }
- }
- return ret;
- }
-
- /**
- * For driver use only.
- */
- void UHS_NI UHS_Bulk_Storage::Reset() {
- if(!bAddress) return;
-
- while(pUsb->ctrlReq(bAddress, mkSETUP_PKT16(UHS_BULK_bmREQ_OUT, UHS_BULK_REQ_BOMSR, 0x0000U, bIface, 0), 0, NULL) == 0x01) {
- if(!UHS_SLEEP_MS(6)) break;
- }
-
- if(!bAddress) return;
-
- UHS_SLEEP_MS(2500);
- }
-
- /**
- * For driver use only.
- *
- * @return 0 if successful
- */
- uint8_t UHS_NI UHS_Bulk_Storage::ResetRecovery() {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- Notify(PSTR("\r\nResetRecovery\r\n"), 0x80);
- Notify(PSTR("-----------------\r\n"), 0x80);
- qNextPollTime = millis() + 90000;
- uint8_t bLastUsbError = UHS_HOST_ERROR_UNPLUGGED;
- if(UHS_SLEEP_MS(6)) {
- Reset();
- if(UHS_SLEEP_MS(6)) {
- bLastUsbError = ClearEpHalt(epDataInIndex);
- if(UHS_SLEEP_MS(6)) {
-
- bLastUsbError = ClearEpHalt(epDataOutIndex);
- UHS_SLEEP_MS(6);
- }
- }
- }
- return bLastUsbError;
- }
-
- /**
- * For driver use only.
- *
- * Clear all EP data and clear all LUN status
- */
- void UHS_NI UHS_Bulk_Storage::DriverDefaults() {
-
- pUsb->DeviceDefaults(MASS_MAX_ENDPOINTS, this);
-
- for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
-
- LUNOk[i] = false;
- WriteOk[i] = false;
- CurrentCapacity[i] = 0lu;
- CurrentSectorSize[i] = 0;
- }
-
- dCBWTag = 0;
- bMaxLUN = 0;
- bTheLUN = 0;
- }
-
- /**
- * For driver use only.
- *
- * @param pcsw
- * @param pcbw
- * @return
- */
- bool UHS_NI UHS_Bulk_Storage::IsValidCSW(UHS_BULK_CommandStatusWrapper *pcsw, UHS_BULK_CommandBlockWrapperBase *pcbw) {
- if(!bAddress) return false;
- if(pcsw->dCSWSignature != UHS_BULK_CSW_SIGNATURE) {
- Notify(PSTR("CSW:Sig error\r\n"), 0x80);
- return false;
- }
- if(pcsw->dCSWTag != pcbw->dCBWTag) {
- Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
- ErrorMessage<uint32_t > (PSTR("dCSWTag"), pcsw->dCSWTag);
- ErrorMessage<uint32_t > (PSTR("dCBWTag"), pcbw->dCBWTag);
-
- return false;
- }
- return true;
- }
-
- /**
- * For driver use only.
- *
- * @param error
- * @param index
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::HandleUsbError(uint8_t error, uint8_t index) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
-
- uint8_t count = 3;
- while(error && count) {
- if(error != UHS_HOST_ERROR_NONE) {
- ErrorMessage<uint8_t > (PSTR("USB Error"), error);
- ErrorMessage<uint8_t > (PSTR("Index"), index);
- }
- switch(error) {
- // case UHS_HOST_ERROR_WRONGPID:
- case UHS_HOST_ERROR_NONE:
- return UHS_BULK_ERR_SUCCESS;
- case UHS_HOST_ERROR_BUSY:
- // SIE is busy, just hang out and try again.
- return UHS_BULK_ERR_UNIT_BUSY;
- case UHS_HOST_ERROR_NAK:
- return UHS_BULK_ERR_UNIT_BUSY;
- case UHS_HOST_ERROR_UNPLUGGED:
- case UHS_HOST_ERROR_TIMEOUT:
- case UHS_HOST_ERROR_JERR:
- return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- case UHS_HOST_ERROR_STALL:
- if(index == 0) return UHS_BULK_ERR_STALL;
- ClearEpHalt(index);
- if(index != epDataInIndex) return UHS_BULK_ERR_WRITE_STALL;
- return UHS_BULK_ERR_STALL;
-
-
- case UHS_HOST_ERROR_TOGERR:
- // Handle a very super rare corner case, where toggles become de-synched.
- // I have only ran into one device that has this firmware bug, and this is
- // the only clean way to get back into sync with the buggy device firmware.
- // --AJK
- if(bAddress && bConfNum) {
- error = pUsb->setConf(bAddress, bConfNum);
-
- if(error) break;
- }
- return UHS_BULK_ERR_SUCCESS;
-
- default:
- ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error);
-
- return UHS_BULK_ERR_GENERAL_USB_ERROR;
- }
- count--;
- } // while
-
- return ((error && !count) ? UHS_BULK_ERR_GENERAL_USB_ERROR : UHS_BULK_ERR_SUCCESS);
- }
-
- /**
- * For driver use only.
- *
- * @param pcbw
- * @param buf_size
- * @param buf
- * @param flags
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::Transaction(UHS_BULK_CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
-
- uint16_t bytes = buf_size;
- bool write = (pcbw->bmCBWFlags & UHS_BULK_CMD_DIR_IN) != UHS_BULK_CMD_DIR_IN;
- uint8_t ret = 0;
- uint8_t usberr;
- UHS_BULK_CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
- SetCurLUN(pcbw->bmCBWLUN);
- ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);
-
- while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (UHS_BULK_CommandBlockWrapper), (uint8_t*)pcbw)) == UHS_HOST_ERROR_BUSY) {
- if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- }
- ret = HandleUsbError(usberr, epDataOutIndex);
- if(ret) {
- ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
- } else {
- if(bytes) {
- if(!write) {
- while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == UHS_HOST_ERROR_BUSY) {
- if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- }
- ret = HandleUsbError(usberr, epDataInIndex);
- } else {
- while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == UHS_HOST_ERROR_BUSY) {
- if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- }
- ret = HandleUsbError(usberr, epDataOutIndex);
- }
- if(ret) {
- ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
- }
- }
- }
-
- {
- bytes = sizeof (UHS_BULK_CommandStatusWrapper);
- int tries = 2;
- while(tries--) {
- while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == UHS_HOST_ERROR_BUSY) {
- if(!UHS_SLEEP_MS(1)) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- }
- if(!usberr) break;
- if(tries) {
- if(usberr == UHS_HOST_ERROR_STALL) {
- ResetRecovery();
- } else {
- ClearEpHalt(epDataInIndex);
- }
- }
- }
- if(!ret) {
- Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
- Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
- } else {
- // Throw away csw, IT IS NOT OF ANY USE.
- ResetRecovery();
- return ret;
- }
- ret = HandleUsbError(usberr, epDataInIndex);
- if(ret) {
- ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
- }
- if(usberr == UHS_HOST_ERROR_NONE) {
- if(IsValidCSW(&csw, pcbw)) {
- //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
- //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
- //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
- Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
- return csw.bCSWStatus;
- } else {
- // NOTE! Sometimes this is caused by the reported residue being wrong.
- // Get a different device. It isn't compliant, and should have never passed Q&A.
- // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
- // Other devices that exhibit this behavior exist in the wild too.
- // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
- Notify(PSTR("Invalid CSW\r\n"), 0x80);
- Reset();
- ResetRecovery();
-
- return UHS_BULK_ERR_INVALID_CSW;
- }
- }
- }
- return ret;
- }
-
- /**
- * For driver use only.
- *
- * @param lun Logical Unit Number
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::SetCurLUN(uint8_t lun) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- if(lun > bMaxLUN)
- return UHS_BULK_ERR_INVALID_LUN;
- bTheLUN = lun;
-
- return UHS_BULK_ERR_SUCCESS;
- };
-
- /**
- * For driver use only.
- *
- * @param status
- * @return
- */
- uint8_t UHS_NI UHS_Bulk_Storage::HandleSCSIError(uint8_t status) {
- if(!bAddress) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- uint8_t ret = 0;
- switch(status) {
- case 0: return UHS_BULK_ERR_SUCCESS;
-
- case 2:
- ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
- ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
- ResetRecovery();
- return UHS_BULK_ERR_GENERAL_SCSI_ERROR;
-
- case 1:
- ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
- ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
- SCSI_Request_Sense_Response rsp;
-
- ret = RequestSense(bTheLUN, sizeof (SCSI_Request_Sense_Response), (uint8_t*) & rsp);
-
- if(ret) {
- if(ret == UHS_BULK_ERR_DEVICE_DISCONNECTED) return UHS_BULK_ERR_DEVICE_DISCONNECTED;
- return UHS_BULK_ERR_GENERAL_SCSI_ERROR;
- }
- #if ENABLE_UHS_DEBUGGING
- ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode);
- if(rsp.bResponseCode & 0x80) {
- Notify(PSTR("Information field: "), 0x80);
- for(int i = 0; i < 4; i++) {
- D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80);
- Notify(PSTR(" "), 0x80);
- }
- Notify(PSTR("\r\n"), 0x80);
- }
- ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey);
- ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode);
- ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier);
- #endif
- // warning, this is not testing ASQ, only SK and ASC.
- switch(rsp.bmSenseKey) {
- case SCSI_S_UNIT_ATTENTION:
- switch(rsp.bAdditionalSenseCode) {
- case SCSI_ASC_MEDIA_CHANGED:
- return UHS_BULK_ERR_MEDIA_CHANGED;
- default:
- return UHS_BULK_ERR_UNIT_NOT_READY;
- }
- case SCSI_S_NOT_READY:
- switch(rsp.bAdditionalSenseCode) {
- case SCSI_ASC_MEDIUM_NOT_PRESENT:
- return UHS_BULK_ERR_NO_MEDIA;
- default:
- return UHS_BULK_ERR_UNIT_NOT_READY;
- }
- case SCSI_S_ILLEGAL_REQUEST:
- switch(rsp.bAdditionalSenseCode) {
- case SCSI_ASC_LBA_OUT_OF_RANGE:
- return UHS_BULK_ERR_BAD_LBA;
- default:
- return UHS_BULK_ERR_CMD_NOT_SUPPORTED;
- }
- default:
- return UHS_BULK_ERR_GENERAL_SCSI_ERROR;
- }
-
- // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
- // case 0x05/0x14: we stalled out
- // case 0x15/0x16: we naked out.
- default:
- ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status);
- ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
-
- return status;
- } // switch
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
-
- // Debugging code
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * @param ep_ptr
- */
- void UHS_NI UHS_Bulk_Storage::PrintEndpointDescriptor(const USB_FD_ENDPOINT_DESCRIPTOR * ep_ptr) {
- Notify(PSTR("Endpoint descriptor:"), 0x80);
- Notify(PSTR("\r\nLength:\t\t"), 0x80);
- D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
- Notify(PSTR("\r\nType:\t\t"), 0x80);
- D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
- Notify(PSTR("\r\nAddress:\t"), 0x80);
- D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
- Notify(PSTR("\r\nAttributes:\t"), 0x80);
- D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
- Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
- D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
- Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
- D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
- Notify(PSTR("\r\n"), 0x80);
- }
-
- #else
- #error "Never include UHS_BULK_STORAGE_INLINE.h, include UHS_host.h instead"
- #endif
|