📄 usb_storage.c
字号:
{ return -1; /* usb_stor_BBB_comdat:cmdlen too large\n"); */
}
cbw = (umass_bbb_cbw_t *)malloc(sizeof(umass_bbb_cbw_t));
if(cbw == NULL) return -1;
/* always OUT to the ep */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
cbw->dCBWSignature = swap_32(CBWSIGNATURE);
cbw->dCBWTag = swap_32(CBWTag++);
cbw->dCBWDataTransferLength = swap_32(srb->datalen);
cbw->bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT);
cbw->bCBWLUN = srb->lun;
cbw->bCDBLength = srb->cmdlen;
/* copy the command data into the CBW command data buffer */
/* DST SRC LEN!!! */
memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5);
free(cbw);
return result;
}
/* FIXME: we also need a CBI_command which sets up the completion
* interrupt, and waits for it
*/
int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
{
int result = 0;
int dir_in,retry;
unsigned int pipe;
unsigned long status;
retry = 5;
dir_in = US_DIRECTION(srb->cmd[0]);
if(dir_in)
{ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); }
else
{ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); }
while(retry--)
{
/* let's send the command via the control pipe */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum,
srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5);
/* check the return code for the command */
if (result < 0)
{
if(us->pusb_dev->status & USB_ST_STALLED)
{
status = us->pusb_dev->status;
usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0));
us->pusb_dev->status = status;
}
return result;
}
/* transfer the data payload for this command, if one exists*/
if (srb->datalen)
{
result = us_one_transfer(us, pipe, (char *)srb->pdata, srb->datalen);
if(!(us->pusb_dev->status & USB_ST_NAK_REC))
{ break; }
}
/* if (srb->datalen) */
else
{ break; }
}
/* return result */
return result;
}
int usb_stor_CBI_get_status (ccb * srb, struct us_data *us)
{
int timeout;
us->ip_wanted = 1;
submit_int_msg (us->pusb_dev, us->irqpipe, (void *) &us->ip_data, us->irqmaxp, us->irqinterval);
timeout = 1000;
while (timeout--)
{
if ((volatile int *) us->ip_wanted == 0)
{ break; }
os_dly_wait (1);
}
if (us->ip_wanted)
{ /* Did not get interrupt on CBI\n"); */
us->ip_wanted = 0;
return USB_STOR_TRANSPORT_ERROR;
}
/* UFI gives us ASC and ASCQ, like a request sense */
if (us->subclass == US_SC_UFI)
{
if((srb->cmd[0] == SCSI_REQ_SENSE) ||
(srb->cmd[0] == SCSI_INQUIRY))
{ return USB_STOR_TRANSPORT_GOOD; }/* Good */
else if (us->ip_data)
{ return USB_STOR_TRANSPORT_FAILED; }
else
{ return USB_STOR_TRANSPORT_GOOD; }
}
/* otherwise, we interpret the data normally */
switch (us->ip_data) {
case 0x0001:
return USB_STOR_TRANSPORT_GOOD;
case 0x0002:
return USB_STOR_TRANSPORT_FAILED;
default:
return USB_STOR_TRANSPORT_ERROR;
}
}
#define USB_TRANSPORT_UNKNOWN_RETRY 5
#define USB_TRANSPORT_NOT_READY_RETRY 10
/* clear a stall on an endpoint - special for BBB devices */
int usb_stor_BBB_clear_endpt_stall(struct us_data *us, unsigned char endpt)
{
int result;
/* ENDPOINT_HALT = 0, so set value to 0 */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
0, endpt, 0, 0, USB_CNTL_TIMEOUT*5);
return result;
}
int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
{
int result, retry;
int dir_in;
int actlen, data_actlen;
unsigned int pipe, pipein, pipeout;
umass_bbb_csw_t *csw;
dir_in = US_DIRECTION(srb->cmd[0]);
/* COMMAND phase */
result = usb_stor_BBB_comdat(srb, us);
if(result < 0)
{ /* failed to send CBW status %ld\n", us->pusb_dev->status); */
usb_stor_BBB_reset(us);
return USB_STOR_TRANSPORT_FAILED;
}
os_dly_wait(1); //os_dly_waitms(5);
pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
/* DATA phase + error handling */
data_actlen = 0;
/* no data, go immediately to the STATUS phase */
if(srb->datalen == 0)
{ goto st; }
if (dir_in)
{ pipe = pipein; }
else
{ pipe = pipeout; }
result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5);
/* special handling of STALL in DATA phase */
if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED))
{
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out);
if (result >= 0)
/* continue on to STATUS phase */
{ goto st; }
}
if (result < 0)
{
usb_stor_BBB_reset(us); /* usb_bulk_msg error status %ld\n", us->pusb_dev->status); */
return USB_STOR_TRANSPORT_FAILED;
}
/* STATUS phase + error handling */
st:
retry = 0;
csw = (umass_bbb_csw_t *)malloc(sizeof(umass_bbb_csw_t));
if(csw == NULL) return -1;
again:
result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5);
/* special handling of STALL in STATUS phase */
if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED))
{
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
if (result >= 0 && (retry++ < 1))
{ /* do a retry */
goto again;
}
}
if (result < 0)
{
/* usb_bulk_msg error status %ld\n", us->pusb_dev->status); */
usb_stor_BBB_reset(us);
free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
/* misuse pipe to get the residue */
pipe = swap_32(csw->dCSWDataResidue);
if((pipe == 0) && (srb->datalen != 0) && (srb->datalen - data_actlen != 0))
{ pipe = srb->datalen - data_actlen; }
if (CSWSIGNATURE != swap_32(csw->dCSWSignature))
{
usb_stor_BBB_reset(us);
free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
else if ((CBWTag - 1) != swap_32(csw->dCSWTag))
{
usb_stor_BBB_reset(us);
free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
else if (csw->bCSWStatus > CSWSTATUS_PHASE)
{
usb_stor_BBB_reset(us);
free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
else if (csw->bCSWStatus == CSWSTATUS_PHASE)
{
usb_stor_BBB_reset(us);
free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
else if (data_actlen > srb->datalen)
{ free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
else if (csw->bCSWStatus == CSWSTATUS_FAILED)
{ free(csw);
return USB_STOR_TRANSPORT_FAILED;
}
free(csw);
return result;
}
int usb_stor_CB_transport(ccb *srb, struct us_data *us)
{
int result,status;
ccb *psrb;
ccb reqsrb;
int retry,notready;
psrb = &reqsrb;
status = USB_STOR_TRANSPORT_GOOD;
retry = 0;
notready = 0;
/* issue the command */
do_retry:
result = usb_stor_CB_comdat(srb, us);
/* if this is an CBI Protocol, get IRQ */
if(us->protocol == US_PR_CBI)
{
status = usb_stor_CBI_get_status(srb,us);
/* if the status is error, report it */
if(status == USB_STOR_TRANSPORT_ERROR)
{ return status;
}
srb->sense_buf[12] = (unsigned char)(us->ip_data>>8);
srb->sense_buf[13] = (unsigned char)(us->ip_data&0xff);
if(!us->ip_data)
{
/* if the status is good, report it */
if(status == USB_STOR_TRANSPORT_GOOD)
{
return status;
}
}
}
/* do we have to issue an auto request? */
/* HERE we have to check the result */
if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED))
{
us->transport_reset(us);
return USB_STOR_TRANSPORT_ERROR;
}
if((us->protocol == US_PR_CBI) &&
((srb->cmd[0] == SCSI_REQ_SENSE) || (srb->cmd[0] == SCSI_INQUIRY)))
{
/* do not issue an autorequest after request sense */
return USB_STOR_TRANSPORT_GOOD;
}
/* issue an request_sense */
memset(&psrb->cmd[0], 0, 12);
psrb->cmd[0] = SCSI_REQ_SENSE;
psrb->cmd[1] = srb->lun<<5;
psrb->cmd[4] = 18;
psrb->datalen = 18;
psrb->pdata = &srb->sense_buf[0];
psrb->cmdlen = 12;
/* issue the command */
result = usb_stor_CB_comdat(psrb, us);
/* if this is an CBI Protocol, get IRQ */
if(us->protocol == US_PR_CBI)
{
status = usb_stor_CBI_get_status(psrb,us);
}
if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED))
{
return USB_STOR_TRANSPORT_ERROR;
}
/* Check the auto request result */
if((srb->sense_buf[2]==0) &&
(srb->sense_buf[12]==0) &&
(srb->sense_buf[13]==0)) /* ok, no sense */
{ return USB_STOR_TRANSPORT_GOOD; }
/* Check the auto request result */
switch(srb->sense_buf[2]) {
case 0x01:
/* Recovered Error */
return USB_STOR_TRANSPORT_GOOD;
case 0x02:
/* Not Ready */
if(notready++ > USB_TRANSPORT_NOT_READY_RETRY)
{
return USB_STOR_TRANSPORT_FAILED;
}
else
{ os_dly_wait(10);
goto do_retry;
}
default:
if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY)
{
return USB_STOR_TRANSPORT_FAILED;
}
else
{ goto do_retry;
}
}
}
static int usb_inquiry(ccb *srb, struct us_data *ss)
{
int retry,i;
retry = 5;
do {
memset(&srb->cmd[0],0,12);
srb->cmd[0] = SCSI_INQUIRY;
srb->cmd[1] = srb->lun<<5;
srb->cmd[4] = 36;
srb->datalen = 36;
srb->cmdlen = 12;
i = ss->transport(srb, ss);
if(i == 0) break;
} while(retry--) ;
if(!retry)
{ return -1;
}
return 0;
}
static int usb_request_sense(ccb *srb, struct us_data *ss)
{
char *ptr;
ptr = (char *)srb->pdata;
memset(&srb->cmd[0],0,12);
srb->cmd[0] = SCSI_REQ_SENSE;
srb->cmd[1] = srb->lun<<5;
srb->cmd[4] = 18;
srb->datalen = 18;
srb->pdata = &srb->sense_buf[0];
srb->cmdlen = 12;
ss->transport(srb,ss);
srb->pdata = (unsigned char *)ptr;
return 0;
}
static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
{
int retries = 10;
do {
memset(&srb->cmd[0],0,12);
srb->cmd[0] = SCSI_TST_U_RDY;
srb->cmd[1] = srb->lun<<5;
srb->datalen = 0;
srb->cmdlen = 12;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -