#include "masstorage.h"
const uint8_t BulkOnly::epDataInIndex = 1;
const uint8_t BulkOnly::epDataOutIndex = 2;
const uint8_t BulkOnly::epInterruptInIndex = 3;
uint32_t BulkOnly::GetCapacity(uint8_t lun) {
if(LUNOk[lun])
return CurrentCapacity[lun];
return 0LU;
}
uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
if(LUNOk[lun])
return CurrentSectorSize[lun];
return 0U;
}
bool BulkOnly::LUNIsGood(uint8_t lun) {
return LUNOk[lun];
}
bool BulkOnly::WriteProtected(uint8_t lun) {
return WriteOk[lun];
}
uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
}
uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
}
uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN);
}
uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
Notify(PSTR("-----------------\r\n"), 0x80);
uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
if(bAddress) {
CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
} else {
SetCurLUN(lun);
}
return rcode;
}
uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
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);
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
again:
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN);
if(er == MASS_ERR_STALL) {
MediaCTL(lun, 1);
delay(150);
if(!TestUnitReady(lun)) goto again;
}
return er;
}
uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
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);
CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
again:
uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT);
if(er == MASS_ERR_WRITE_STALL) {
MediaCTL(lun, 1);
delay(150);
if(!TestUnitReady(lun)) goto again;
}
return er;
}
BulkOnly::BulkOnly(USB *p) :
pUsb(p),
bAddress(0),
bIface(0),
bNumEP(1),
qNextPollTime(0),
bPollEnable(false),
bLastUsbError(0) {
ClearAllEP();
dCBWTag = 0;
if(pUsb)
pUsb->RegisterDeviceClass(this);
}
uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
uint8_t buf[constBufSize];
USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
uint8_t rcode;
UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL;
USBTRACE("MS ConfigureDevice\r\n");
ClearAllEP();
AddressPool &addrPool = pUsb->GetAddressPool();
if(bAddress)
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
p = addrPool.GetUsbDevicePtr(0);
if(!p) {
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
if(!p->epinfo) {
USBTRACE("epinfo\r\n");
return USB_ERROR_EPINFO_IS_NULL;
}
oldep_ptr = p->epinfo;
p->epinfo = epInfo;
p->lowspeed = lowspeed;
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
p->epinfo = oldep_ptr;
if(rcode) {
goto FailGetDevDescr;
}
bAddress = addrPool.AllocAddress(parent, false, port);
if(!bAddress)
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
epInfo[0].maxPktSize = udd->bMaxPacketSize0;
epInfo[1].epAddr = udd->bNumConfigurations;
return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
FailGetDevDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetDevDescr(rcode);
#endif
rcode = USB_ERROR_FailGetDevDescr;
Release();
return rcode;
};
uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t rcode;
uint8_t num_of_conf = epInfo[1].epAddr; epInfo[1].epAddr = 0;
USBTRACE("MS Init\r\n");
AddressPool &addrPool = pUsb->GetAddressPool();
UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
delay(2000);
rcode = pUsb->setAddr(0, 0, bAddress);
if(rcode) {
p->lowspeed = false;
addrPool.FreeAddress(bAddress);
bAddress = 0;
USBTRACE2("setAddr:", rcode);
return rcode;
}
USBTRACE2("Addr:", bAddress);
p->lowspeed = false;
p = addrPool.GetUsbDevicePtr(bAddress);
if(!p)
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
p->lowspeed = lowspeed;
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if(rcode)
goto FailSetDevTblEntry;
USBTRACE2("NC:", num_of_conf);
for(uint8_t i = 0; i < num_of_conf; i++) {
ConfigDescParser< USB_CLASS_MASS_STORAGE,
MASS_SUBCLASS_SCSI,
MASS_PROTO_BBB,
CP_MASK_COMPARE_CLASS |
CP_MASK_COMPARE_SUBCLASS |
CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 1)
break;
}
if(bNumEP < 3)
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
USBTRACE2("Conf:", bConfNum);
rcode = pUsb->setConf(bAddress, 0, bConfNum);
if(rcode)
goto FailSetConfDescr;
delay(1000);
rcode = GetMaxLUN(&bMaxLUN);
if(rcode)
goto FailGetMaxLUN;
if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
delay(1000);
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
InquiryResponse response;
rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
if(rcode) {
ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
} else {
#if 0#endif
uint8_t tries = 0xf0;
while((rcode = TestUnitReady(lun))) {
if(rcode == 0x08) break; if(tries < 14) {
LockMedia(lun, 1);
MediaCTL(lun, 1); } else delay(2 * (tries + 1));
tries++;
if(!tries) break;
}
if(!rcode) {
delay(1000);
LUNOk[lun] = CheckLUN(lun);
if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
}
}
}
CheckMedia();
rcode = OnInit();
if(rcode)
goto FailOnInit;
#ifdef DEBUG_USB_HOST
USBTRACE("MS configured\r\n\r\n");
#endif
bPollEnable = true;
return 0;
FailSetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailSetConfDescr();
goto Fail;
#endif
FailOnInit:
#ifdef DEBUG_USB_HOST
USBTRACE("OnInit:");
goto Fail;
#endif
FailGetMaxLUN:
#ifdef DEBUG_USB_HOST
USBTRACE("GetMaxLUN:");
goto Fail;
#endif
FailSetDevTblEntry:
#ifdef DEBUG_USB_HOST
NotifyFailSetDevTblEntry();
goto Fail;
#endif
FailGetConfDescr:
#ifdef DEBUG_USB_HOST
NotifyFailGetConfDescr();
#endif
#ifdef DEBUG_USB_HOST
Fail:
NotifyFail(rcode);
#endif
Release();
return rcode;
}
void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR * pep) {
ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
bConfNum = conf;
uint8_t index;
#if 1
if((pep->bmAttributes & 0x02) == 2) {
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
epInfo[index].epAttribs = 0;
bNumEP++;
PrintEndpointDescriptor(pep);
}
#else#endif
}
uint8_t BulkOnly::Release() {
ClearAllEP();
pUsb->GetAddressPool().FreeAddress(bAddress);
return 0;
}
bool BulkOnly::CheckLUN(uint8_t lun) {
uint8_t rcode;
Capacity capacity;
for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
if(rcode) {
return false;
}
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
for(uint8_t i = 0; i < 8 ; i++)
D_PrintHex<uint8_t > (capacity.data[i], 0x80);
Notify(PSTR("\r\n\r\n"), 0x80);
uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) {
return false;
}
CurrentSectorSize[lun] = (uint16_t)(c);
CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
if(CurrentCapacity[lun] == 0x01LU || CurrentCapacity[lun] == 0x00LU) {
if(CurrentCapacity[lun])
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
return false;
}
delay(20);
Page3F(lun);
if(!TestUnitReady(lun)) return true;
return false;
}
void BulkOnly::CheckMedia() {
for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
if(TestUnitReady(lun)) {
LUNOk[lun] = false;
continue;
}
if(!LUNOk[lun])
LUNOk[lun] = CheckLUN(lun);
}
#if 0#endif
qNextPollTime = millis() + 2000;
}
uint8_t BulkOnly::Poll() {
if(!bPollEnable)
return 0;
if((long)(millis() - qNextPollTime) >= 0L) {
CheckMedia();
}
return 0;
}
uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) {
uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL);
if(ret == hrSTALL)
*plun = 0;
return 0;
}
uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
Notify(PSTR("\r\nInquiry\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN);
return rc;
}
uint8_t BulkOnly::TestUnitReady(uint8_t lun) {
if(!bAddress)
return MASS_ERR_UNIT_NOT_READY;
Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
Notify(PSTR("-----------------\r\n"), 0x80);
CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0);
return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN);
}
uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) {
Notify(PSTR("\r\rModeSense\r\n"), 0x80);
Notify(PSTR("------------\r\n"), 0x80);
CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0);
return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN);
}
uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) {
Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
Notify(PSTR("---------------\r\n"), 0x80);
CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun);
return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN);
}
uint8_t BulkOnly::Page3F(uint8_t lun) {
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);
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);
}
return rc;
}
uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
Notify(PSTR("----------------\r\n"), 0x80);
CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN);
return Transaction(&cbw, size, buf);
}
uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
if(index == 0)
return 0;
uint8_t ret = 0;
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))
delay(6);
if(ret) {
ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
return ret;
}
epInfo[index].bmSndToggle = 0;
epInfo[index].bmRcvToggle = 0;
return 0;
}
void BulkOnly::Reset() {
while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) delay(6);
}
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;
}
void BulkOnly::ClearAllEP() {
for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
}
for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
LUNOk[i] = false;
WriteOk[i] = false;
CurrentCapacity[i] = 0lu;
CurrentSectorSize[i] = 0;
}
bIface = 0;
bNumEP = 1;
bAddress = 0;
qNextPollTime = 0;
bPollEnable = false;
bLastUsbError = 0;
bMaxLUN = 0;
bTheLUN = 0;
}
bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
if(pcsw->dCSWSignature != MASS_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);
return false;
}
return true;
}
uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
uint8_t count = 3;
bLastUsbError = error;
while(error && count) {
if(error != hrSUCCESS) {
ErrorMessage<uint8_t > (PSTR("USB Error"), error);
ErrorMessage<uint8_t > (PSTR("Index"), index);
}
switch(error) {
case hrSUCCESS:
return MASS_ERR_SUCCESS;
case hrBUSY:
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:
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--;
}
return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
}
#if MS_WANT_PARSER
uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
}
#endif
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; 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);
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 {
ResetRecovery();
return ret;
}
ret = HandleUsbError(usberr, epDataInIndex);
if(ret) {
ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
}
if(usberr == hrSUCCESS) {
if(IsValidCSW(&csw, pcbw)) {
Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
return csw.bCSWStatus;
} else {
Notify(PSTR("Invalid CSW\r\n"), 0x80);
ResetRecovery();
return MASS_ERR_INVALID_CSW;
}
}
}
return ret;
}
uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
if(lun > bMaxLUN)
return MASS_ERR_INVALID_LUN;
bTheLUN = lun;
return MASS_ERR_SUCCESS;
};
uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
uint8_t ret = 0;
switch(status) {
case 0: return MASS_ERR_SUCCESS;
case 2:
ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
ResetRecovery();
return MASS_ERR_GENERAL_SCSI_ERROR;
case 1:
ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
RequestSenseResponce rsp;
ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
if(ret) {
return MASS_ERR_GENERAL_SCSI_ERROR;
}
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);
switch(rsp.bmSenseKey) {
case SCSI_S_UNIT_ATTENTION:
switch(rsp.bAdditionalSenseCode) {
case SCSI_ASC_MEDIA_CHANGED:
return MASS_ERR_MEDIA_CHANGED;
default:
return MASS_ERR_UNIT_NOT_READY;
}
case SCSI_S_NOT_READY:
switch(rsp.bAdditionalSenseCode) {
case SCSI_ASC_MEDIUM_NOT_PRESENT:
return MASS_ERR_NO_MEDIA;
default:
return MASS_ERR_UNIT_NOT_READY;
}
case SCSI_S_ILLEGAL_REQUEST:
switch(rsp.bAdditionalSenseCode) {
case SCSI_ASC_LBA_OUT_OF_RANGE:
return MASS_ERR_BAD_LBA;
default:
return MASS_ERR_CMD_NOT_SUPPORTED;
}
default:
return MASS_ERR_GENERAL_SCSI_ERROR;
}
default:
ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status);
ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
return status;
} }
void BulkOnly::PrintEndpointDescriptor(const USB_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);
}
uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser * prs) {
#if MS_WANT_PARSER
if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
Notify(PSTR("---------\r\n"), 0x80);
CommandBlockWrapper cbw = CommandBlockWrapper();
cbw.dCBWSignature = MASS_CBW_SIGNATURE;
cbw.dCBWTag = ++dCBWTag;
cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
cbw.bmCBWFlags = MASS_CMD_DIR_IN,
cbw.bmCBWLUN = lun;
cbw.bmCBWCBLength = 10;
cbw.CBWCB[0] = SCSI_CMD_READ_10;
cbw.CBWCB[8] = blocks;
cbw.CBWCB[2] = ((addr >> 24) & 0xff);
cbw.CBWCB[3] = ((addr >> 16) & 0xff);
cbw.CBWCB[4] = ((addr >> 8) & 0xff);
cbw.CBWCB[5] = (addr & 0xff);
return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
#else
return MASS_ERR_NOT_IMPLEMENTED;
#endif
}