⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_storage.c

📁 基于s3c2440的U盘读写程序
💻 C
📖 第 1 页 / 共 3 页
字号:
static int usb_stor_CB_reset(struct us_data *us)
{
    unsigned char cmd[12];
    int result;
    USB_STOR_PRINTF("CB_reset\n");
    memset(cmd, 0xFF, sizeof(cmd));
    cmd[0] = SCSI_SEND_DIAG;
    cmd[1] = 4;
    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, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5);
    /* long wait for reset */
    wait_ms(1500);
    USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status);
    usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
    usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
    USB_STOR_PRINTF("CB_reset done\n");
    return 0;
}


/*
 * Set up the command for a BBB device. Note that the actual SCSI
 * command is copied into cbw.CBWCDB.
 */
int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
{
    int result;
    int actlen;
    int dir_in;
    unsigned int pipe;
    umass_bbb_cbw_t cbw;
    dir_in = US_DIRECTION(srb->cmd[0]);
    #ifdef BBB_COMDAT_TRACE
    USB_STOR_PRINTF("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata);
    if (srb->cmdlen) 
    {
        for(result = 0;result < srb->cmdlen;result++)
        USB_STOR_PRINTF("cmd[%d] %#x ", result, srb->cmd[result]);
        USB_STOR_PRINTF("\n");
    }
    #endif
    /* sanity checks */
    if (!(srb->cmdlen <= CBWCDBLENGTH)) 
    {
        USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n");
        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);
    if (result < 0)
    USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n");
    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--) 
    {
        USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);
        usb_show_srb(srb);
        /* 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);
        USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status);
        /* check the return code for the command */
        if (result < 0) 
        {
            if(us->pusb_dev->status & USB_ST_STALLED) 
            {
                status=us->pusb_dev->status;
                USB_STOR_PRINTF(" stall during command found, clear pipe\n");
                usb_clear_halt(us->pusb_dev,  usb_sndctrlpipe(us->pusb_dev,0));
                us->pusb_dev->status=status;
            }
            USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status);
            return result;
        }
        /* transfer the data payload for this command, if one exists*/
        USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen);
        if (srb->datalen) 
        {
            result = us_one_transfer(us, pipe, (char *)srb->pdata,srb->datalen);
            USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len);
            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;
        wait_ms (10);
    }
    if (us->ip_wanted) 
    {
        USB_STOR_PRINTF("	Did not get interrupt on CBI\n");
        us->ip_wanted = 0;
        return USB_STOR_TRANSPORT_ERROR;
    }
    USB_STOR_PRINTF
    ("Got interrupt data 0x%x, transfered %d status 0x%lX\n",
    us->ip_data, us->pusb_dev->irq_act_len,
    us->pusb_dev->irq_status);
    /* 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;
    }
    /* switch */
    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, U8 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;
    #ifdef BBB_XPORT_TRACE
    unsigned char *ptr;
    int index;
    #endif
    dir_in = US_DIRECTION(srb->cmd[0]);
    /* COMMAND phase */
    USB_STOR_PRINTF("COMMAND phase\n");
    result = usb_stor_BBB_comdat(srb, us);
    if (result < 0) 
    {
        USB_STOR_PRINTF("failed to send CBW status %ld\n",
        us->pusb_dev->status);
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    }
    wait_ms(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;
    USB_STOR_PRINTF("DATA phase\n");
    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)) 
    {
        USB_STOR_PRINTF("DATA:stall\n");
        /* 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_PRINTF("usb_bulk_msg error status %ld\n",
        us->pusb_dev->status);
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    }
    #ifdef BBB_XPORT_TRACE
    for (index = 0; index < data_actlen; index++)
    USB_STOR_PRINTF("pdata[%d] %#x ", index, srb->pdata[index]);
    USB_STOR_PRINTF("\n");
    #endif
    /* STATUS phase + error handling */
st:
    retry = 0;
again:
    USB_STOR_PRINTF("STATUS phase\n");
    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)) 
    {
        USB_STOR_PRINTF("STATUS:stall\n");
        /* 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_STOR_PRINTF("usb_bulk_msg error status %ld\n",
        us->pusb_dev->status);
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    }
    #ifdef BBB_XPORT_TRACE
    ptr = (unsigned char *)&csw;
    for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
    USB_STOR_PRINTF("ptr[%d] %#x ", index, ptr[index]);
    USB_STOR_PRINTF("\n");
    #endif
    /* 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_PRINTF("!CSWSIGNATURE\n");
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    } 
    else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) 
    {
        USB_STOR_PRINTF("!Tag\n");
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    } 
    else if (csw.bCSWStatus > CSWSTATUS_PHASE) 
    {
        USB_STOR_PRINTF(">PHASE\n");
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    } 
    else if (csw.bCSWStatus == CSWSTATUS_PHASE) 
    {
        USB_STOR_PRINTF("=PHASE\n");
        usb_stor_BBB_reset(us);
        return USB_STOR_TRANSPORT_FAILED;
    } 
    else if (data_actlen > srb->datalen) 
    {
        USB_STOR_PRINTF("transferred %dB instead of %dB\n",
        data_actlen, srb->datalen);
        return USB_STOR_TRANSPORT_FAILED;
    } 
    else if (csw.bCSWStatus == CSWSTATUS_FAILED) 
    {
        USB_STOR_PRINTF("FAILED\n");
        return USB_STOR_TRANSPORT_FAILED;
    }
    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);
    USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status);
    /* 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) 
        {
            USB_STOR_PRINTF(" USB CBI Command Error\n");
            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) 
            {
                USB_STOR_PRINTF(" USB CBI Command Good\n");
                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)) 
    {
        USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status);
        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 */
        USB_STOR_PRINTF("No auto request and good\n");
        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);
    USB_STOR_PRINTF("auto request returned %d\n",result);
    /* 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)) 
    {
        USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status);
        return USB_STOR_TRANSPORT_ERROR;
    }
    USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
    /* 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;
        break;
    case 0x02: 
        /* Not Ready */
        if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) 
        {
            USB_STOR_PRINTF("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n",
            srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
            return USB_STOR_TRANSPORT_FAILED;
        } 
        else 
        {
            wait_ms(100);
            goto do_retry;
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -