/** * For driver use only. * * @return 0 if successful */ uint8_t BulkOnly::ResetRecovery() { Notify(PSTR("\r\nResetRecovery\r\n"), 0x80); Notify(PSTR("-----------------\r\n"), 0x80); delay(6); Reset(); delay(6); ClearEpHalt(epDataInIndex); delay(6); bLastUsbError = ClearEpHalt(epDataOutIndex); delay(6); return bLastUsbError; }
/** * For driver use only. * * @param error * @param index * @return */ uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) { uint8_t count = 3; bLastUsbError = error; //if (error) //ClearEpHalt(index); while (error && count) { if (error != hrSUCCESS) { ErrorMessage<uint8_t > (PSTR("USB Error"), error); ErrorMessage<uint8_t > (PSTR("Index"), index); } switch (error) { // case hrWRONGPID: case hrSUCCESS: return MASS_ERR_SUCCESS; case hrBUSY: // SIE is busy, just hang out and try again. return MASS_ERR_UNIT_BUSY; case hrTIMEOUT: case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED; case hrSTALL: if (index == 0) return MASS_ERR_STALL; ClearEpHalt(index); if (index != epDataInIndex) return MASS_ERR_WRITE_STALL; return MASS_ERR_STALL; case hrNAK: if (index == 0) return MASS_ERR_UNIT_BUSY; return MASS_ERR_UNIT_BUSY; case hrTOGERR: // 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, 0, bConfNum); if (error) break; } return MASS_ERR_SUCCESS; default: ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error); return MASS_ERR_GENERAL_USB_ERROR; } count--; } // while return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS); }
uint8_t BulkOnly::ResetRecovery() { bLastUsbError = Reset(); if (bLastUsbError) return bLastUsbError; delay(6); bLastUsbError = ClearEpHalt(epDataInIndex); if (bLastUsbError) return bLastUsbError; delay(6); bLastUsbError = ClearEpHalt(epDataOutIndex); delay(6); return bLastUsbError; }
uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) { uint8_t cnt = 3; bLastUsbError = pUsb->ctrlReq( bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL ); delay(10); //Serial.println(F("bLastUsbError: ")); //Serial.println(bLastUsbError); if (bLastUsbError == hrSTALL) { *plun = 0; bLastUsbError = ClearEpHalt(epDataInIndex); return MASS_ERR_SUCCESS; } if (bLastUsbError == hrJERR) return MASS_ERR_DEVICE_DISCONNECTED; else if (bLastUsbError) return MASS_ERR_GENERAL_USB_ERROR; return MASS_ERR_SUCCESS; }
uint8_t BulkOnly::HandleUsbError(uint8_t index) { uint8_t count = 3; while (bLastUsbError && count) { switch (bLastUsbError) { case hrSUCCESS: return MASS_ERR_SUCCESS; case hrJERR: bLastUsbError = hrSUCCESS; return MASS_ERR_DEVICE_DISCONNECTED; case hrSTALL: bLastUsbError = ClearEpHalt(index); break; default: return MASS_ERR_GENERAL_USB_ERROR; } count --; } // while return MASS_ERR_SUCCESS; }
/** * For driver use only. * * @param pcbw * @param buf_size * @param buf * @param flags * @return */ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf #if MS_WANT_PARSER , uint8_t flags #endif ) { #if MS_WANT_PARSER uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; printf("Transfersize %i\r\n", bytes); delay(1000); bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; #else uint16_t bytes = buf_size; #endif bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; uint8_t ret = 0; uint8_t usberr; 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 (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1); ret = HandleUsbError(usberr, epDataOutIndex); //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); if(ret) { ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret); } else { if(bytes) { if(!write) { #if MS_WANT_PARSER if(callback) { uint8_t rbuf[bytes]; while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1); if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); } else { #endif while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1); #if MS_WANT_PARSER } #endif ret = HandleUsbError(usberr, epDataInIndex); } else { while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1); ret = HandleUsbError(usberr, epDataOutIndex); } if(ret) { ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret); } } } { bytes = sizeof (CommandStatusWrapper); int tries = 2; while(tries--) { while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1); if(!usberr) break; ClearEpHalt(epDataInIndex); if(tries) ResetRecovery(); } 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 == hrSUCCESS) { 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); ResetRecovery(); //return MASS_ERR_SUCCESS; return MASS_ERR_INVALID_CSW; } } } return ret; }
uint8_t BulkOnly::Transaction(CommandBlockWrapper *cbw, uint16_t size, void *buf, uint8_t flags) { uint16_t read; { bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof(CommandBlockWrapper), (uint8_t*)cbw); uint8_t ret = HandleUsbError(epDataOutIndex); if (ret) { ErrorMessage<uint8_t>(PSTR("CBW"), ret); return ret; } } if (size && buf) { read = size; if (cbw->bmCBWFlags & MASS_CMD_DIR_IN) { if ((flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK) { const uint8_t bufSize = 64; uint16_t total = size; uint16_t count = 0; uint8_t rbuf[bufSize]; read = bufSize; while(count < total && ((bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)rbuf)) == hrSUCCESS) ) { ((USBReadParser*)buf)->Parse(read, rbuf, count); count += read; read = bufSize; } if (bLastUsbError == hrSTALL) bLastUsbError = ClearEpHalt(epDataInIndex); if (bLastUsbError) { ErrorMessage<uint8_t>(PSTR("RDR"), bLastUsbError); return MASS_ERR_GENERAL_USB_ERROR; } } // if ((flags & 1) == 1) else bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)buf); } // if (cbw->bmCBWFlags & MASS_CMD_DIR_IN) else if (cbw->bmCBWFlags & MASS_CMD_DIR_OUT) bLastUsbError = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, read, (uint8_t*)buf); } uint8_t ret = HandleUsbError((cbw->bmCBWFlags & MASS_CMD_DIR_IN) ? epDataInIndex : epDataOutIndex); if (ret) { ErrorMessage<uint8_t>(PSTR("RSP"), ret); return MASS_ERR_GENERAL_USB_ERROR; } { CommandStatusWrapper csw; read = sizeof(CommandStatusWrapper); bLastUsbError = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &read, (uint8_t*)&csw); uint8_t ret = HandleUsbError(epDataInIndex); if (ret) { ErrorMessage<uint8_t>(PSTR("CSW"), ret); return ret; } //if (csw.bCSWStatus == MASS_ERR_PHASE_ERROR) // bLastUsbError = ResetRecovery(); return csw.bCSWStatus; } //return MASS_ERR_SUCCESS; }