TERES/SOFTWARE/A64-TERES/u-boot_new/usb_sunxi/usb_mass.c
Dimitar Gamishev 093685c7d8 u-boot
2017-10-13 14:02:55 +03:00

979 lines
26 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (C) Copyright 2007-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Jerry Wang <wangflord@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
#include "usb_base.h"
#include <scsi.h>
#include <asm/arch/dma.h>
#include <sys_partition.h>
#include "usb_mass.h"
static int sunxi_usb_mass_write_enable = 0;
static int sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
#if defined(SUNXI_USB_30)
static int sunxi_usb_mass_status_enable = 1;
#endif
static mass_trans_set_t trans_data;
/*
*******************************************************************************
* do_usb_req_set_interface
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_set_interface(struct usb_device_request *req)
{
sunxi_usb_dbg("set interface\n");
/* Only support interface 0, alternate 0 */
if((0 == req->wIndex) && (0 == req->wValue))
{
sunxi_udc_ep_reset();
}
else
{
printf("err: invalid wIndex and wValue, (0, %d), (0, %d)\n", req->wIndex, req->wValue);
return SUNXI_USB_REQ_OP_ERR;
}
return SUNXI_USB_REQ_SUCCESSED;
}
/*
*******************************************************************************
* do_usb_req_set_address
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_set_address(struct usb_device_request *req)
{
uchar address;
address = req->wValue & 0x7f;
printf("set address 0x%x\n", address);
sunxi_udc_set_address(address);
return SUNXI_USB_REQ_SUCCESSED;
}
/*
*******************************************************************************
* do_usb_req_set_configuration
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_set_configuration(struct usb_device_request *req)
{
sunxi_usb_dbg("set configuration\n");
/* Only support 1 configuration so nak anything else */
if (1 == req->wValue)
{
sunxi_udc_ep_reset();
}
else
{
printf("err: invalid wValue, (0, %d)\n", req->wValue);
return SUNXI_USB_REQ_OP_ERR;
}
sunxi_udc_set_configuration(req->wValue);
return SUNXI_USB_REQ_SUCCESSED;
}
/*
*******************************************************************************
* do_usb_req_get_descriptor
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer)
{
int ret = SUNXI_USB_REQ_SUCCESSED;
//获取描述符
switch(req->wValue >> 8)
{
case USB_DT_DEVICE: //设备描述符
{
struct usb_device_descriptor *dev_dscrptr;
sunxi_usb_dbg("get device descriptor\n");
dev_dscrptr = (struct usb_device_descriptor *)buffer;
memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor));
dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor));
dev_dscrptr->bDescriptorType = USB_DT_DEVICE;
#ifdef CONFIG_USB_1_1_DEVICE
dev_dscrptr->bcdUSB = 0x110;
#else
dev_dscrptr->bcdUSB = 0x200;
#endif
dev_dscrptr->bDeviceClass = 0; //设备类:大容量存储
dev_dscrptr->bDeviceSubClass = 0;
dev_dscrptr->bDeviceProtocol = 0;
dev_dscrptr->bMaxPacketSize0 = 0x40;
dev_dscrptr->idVendor = 0xBB4;
dev_dscrptr->idProduct = 0xfff;
dev_dscrptr->bcdDevice = 0x200;
dev_dscrptr->iManufacturer = SUNXI_USB_STRING_IMANUFACTURER;
dev_dscrptr->iProduct = SUNXI_USB_STRING_IPRODUCT;
dev_dscrptr->iSerialNumber = SUNXI_USB_STRING_ISERIALNUMBER;
dev_dscrptr->bNumConfigurations = 1;
sunxi_udc_send_setup(dev_dscrptr->bLength, buffer);
}
break;
case USB_DT_CONFIG: //配置描述符
{
struct usb_configuration_descriptor *config_dscrptr;
struct usb_interface_descriptor *inter_dscrptr;
struct usb_endpoint_descriptor *ep_in, *ep_out;
unsigned char bytes_remaining = req->wLength;
unsigned char bytes_total = 0;
sunxi_usb_dbg("get config descriptor\n");
bytes_total = sizeof (struct usb_configuration_descriptor) + \
sizeof (struct usb_interface_descriptor) + \
sizeof (struct usb_endpoint_descriptor) + \
sizeof (struct usb_endpoint_descriptor);
memset(buffer, 0, bytes_total);
config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0);
inter_dscrptr = (struct usb_interface_descriptor *)(buffer + \
sizeof(struct usb_configuration_descriptor));
ep_in = (struct usb_endpoint_descriptor *)(buffer + \
sizeof(struct usb_configuration_descriptor) + \
sizeof(struct usb_interface_descriptor));
ep_out = (struct usb_endpoint_descriptor *)(buffer + \
sizeof(struct usb_configuration_descriptor) + \
sizeof(struct usb_interface_descriptor) + \
sizeof(struct usb_endpoint_descriptor));
/* configuration */
config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor));
config_dscrptr->bDescriptorType = USB_DT_CONFIG;
config_dscrptr->wTotalLength = bytes_total;
config_dscrptr->bNumInterfaces = 1;
config_dscrptr->bConfigurationValue = 1;
config_dscrptr->iConfiguration = 0;
config_dscrptr->bmAttributes = 0xc0;
config_dscrptr->bMaxPower = 0xFA; //最大电流500ms(0xfa * 2)
bytes_remaining -= config_dscrptr->bLength;
/* interface */
inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor));
inter_dscrptr->bDescriptorType = USB_DT_INTERFACE;
inter_dscrptr->bInterfaceNumber = 0x00;
inter_dscrptr->bAlternateSetting = 0x00;
inter_dscrptr->bNumEndpoints = 0x02;
inter_dscrptr->bInterfaceClass = USB_CLASS_MASS_STORAGE; //mass storage
inter_dscrptr->bInterfaceSubClass = US_SC_SCSI;
inter_dscrptr->bInterfaceProtocol = US_PR_BULK;
inter_dscrptr->iInterface = 1;
bytes_remaining -= inter_dscrptr->bLength;
/* ep_in */
ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
ep_in->bDescriptorType = USB_DT_ENDPOINT;
ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */
ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK;
ep_in->wMaxPacketSize = sunxi_udc_get_ep_max();
ep_in->bInterval = 0x00;
bytes_remaining -= ep_in->bLength;
/* ep_out */
ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor));
ep_out->bDescriptorType = USB_DT_ENDPOINT;
ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type(); /* OUT */
ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK;
ep_out->wMaxPacketSize = sunxi_udc_get_ep_max();
ep_out->bInterval = 0x00;
bytes_remaining -= ep_out->bLength;
sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer);
}
break;
case USB_DT_STRING:
{
unsigned char bLength = 0;
unsigned char string_index = req->wValue & 0xff;
sunxi_usb_dbg("get string descriptor\n");
/* Language ID */
if(string_index == 0)
{
bLength = MIN(4, req->wLength);
sunxi_udc_send_setup(bLength, (void *)sunxi_usb_mass_dev[0]);
}
else if(string_index < SUNXI_USB_MASS_DEV_MAX)
{
/* Size of string in chars */
unsigned char i = 0;
unsigned char str_length = strlen ((const char *)sunxi_usb_mass_dev[string_index]);
unsigned char bLength = 2 + (2 * str_length);
buffer[0] = bLength; /* length */
buffer[1] = USB_DT_STRING; /* descriptor = string */
/* Copy device string to fifo, expand to simple unicode */
for(i = 0; i < str_length; i++)
{
buffer[2+ 2*i + 0] = sunxi_usb_mass_dev[string_index][i];
buffer[2+ 2*i + 1] = 0;
}
bLength = MIN(bLength, req->wLength);
sunxi_udc_send_setup(bLength, buffer);
}
else
{
printf("sunxi usb err: string line %d is not supported\n", string_index);
}
}
break;
case USB_DT_DEVICE_QUALIFIER:
{
#ifdef CONFIG_USB_1_1_DEVICE
/* This is an invalid request for usb 1.1, nak it */
USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0);
#else
struct usb_qualifier_descriptor *qua_dscrpt;
sunxi_usb_dbg("get qualifier descriptor\n");
qua_dscrpt = (struct usb_qualifier_descriptor *)buffer;
memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor));
qua_dscrpt->bLength = MIN(req->wLength, sizeof(sizeof(struct usb_qualifier_descriptor)));
qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
qua_dscrpt->bcdUSB = 0x200;
qua_dscrpt->bDeviceClass = 0xff;
qua_dscrpt->bDeviceSubClass = 0xff;
qua_dscrpt->bDeviceProtocol = 0xff;
qua_dscrpt->bMaxPacketSize0 = 0x40;
qua_dscrpt->bNumConfigurations = 1;
qua_dscrpt->breserved = 0;
sunxi_udc_send_setup(qua_dscrpt->bLength, buffer);
#endif
}
break;
default:
printf("err: unkown wValue(%d)\n", req->wValue);
ret = SUNXI_USB_REQ_OP_ERR;
}
return ret;
}
/*
*******************************************************************************
* do_usb_req_get_status
*
* Description:
* void
*
* Parameters:
* void
*
* Return value:
* void
*
* note:
* void
*
*******************************************************************************
*/
static int __usb_get_status(struct usb_device_request *req, uchar *buffer)
{
unsigned char bLength = 0;
sunxi_usb_dbg("get status\n");
if(0 == req->wLength)
{
/* sent zero packet */
sunxi_udc_send_setup(0, NULL);
return SUNXI_USB_REQ_OP_ERR;
}
bLength = MIN(req->wValue, 2);
buffer[0] = 1;
buffer[1] = 0;
sunxi_udc_send_setup(bLength, buffer);
return SUNXI_USB_REQ_SUCCESSED;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int __sunxi_mass_send_status(void *buffer, unsigned int buffer_size)
{
return sunxi_udc_send_data((uchar *)buffer, buffer_size);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_mass_init(void)
{
sunxi_usb_dbg("sunxi_mass_init\n");
memset(&trans_data, 0, sizeof(mass_trans_set_t));
sunxi_usb_mass_write_enable = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
trans_data.base_recv_buffer = (u8 *)malloc(SUNXI_MASS_RECV_MEM_SIZE);
if(!trans_data.base_recv_buffer)
{
printf("sunxi usb mass err: unable to malloc memory for mass receive\n");
return -1;
}
trans_data.base_send_buffer = (u8 *)malloc(SUNXI_MASS_SEND_MEM_SIZE);
if(!trans_data.base_send_buffer)
{
printf("sunxi usb mass err: unable to malloc memory for mass send\n");
free(trans_data.base_recv_buffer);
return -1;
}
sunxi_usb_dbg("recv addr 0x%x\n", (uint)trans_data.base_recv_buffer);
sunxi_usb_dbg("send addr 0x%x\n", (uint)trans_data.base_send_buffer);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_mass_exit(void)
{
sunxi_usb_dbg("sunxi_mass_exit\n");
if(trans_data.base_recv_buffer)
{
free(trans_data.base_recv_buffer);
}
if(trans_data.base_send_buffer)
{
free(trans_data.base_send_buffer);
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_mass_reset(void)
{
sunxi_usb_mass_write_enable = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_mass_usb_rx_dma_isr(void *p_arg)
{
sunxi_usb_dbg("dma int for usb rx occur\n");
//通知主循环,可以写入数据
sunxi_usb_mass_write_enable = 1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void sunxi_mass_usb_tx_dma_isr(void *p_arg)
{
sunxi_usb_dbg("dma int for usb tx occur\n");
#if defined(SUNXI_USB_30)
sunxi_usb_mass_status_enable = 1;
#endif
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_mass_standard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer)
{
int ret = SUNXI_USB_REQ_OP_ERR;
switch(cmd)
{
case USB_REQ_GET_STATUS:
{
ret = __usb_get_status(req, buffer);
break;
}
//case USB_REQ_CLEAR_FEATURE:
//case USB_REQ_SET_FEATURE:
case USB_REQ_SET_ADDRESS:
{
ret = __usb_set_address(req);
break;
}
case USB_REQ_GET_DESCRIPTOR:
//case USB_REQ_SET_DESCRIPTOR:
case USB_REQ_GET_CONFIGURATION:
{
ret = __usb_get_descriptor(req, buffer);
break;
}
case USB_REQ_SET_CONFIGURATION:
{
ret = __usb_set_configuration(req);
break;
}
//case USB_REQ_GET_INTERFACE:
case USB_REQ_SET_INTERFACE:
{
ret = __usb_set_interface(req);
break;
}
//case USB_REQ_SYNCH_FRAME:
default:
{
printf("sunxi mass error: standard req is not supported\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
break;
}
}
return ret;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_mass_nonstandard_req_op(uint cmd, struct usb_device_request *req, uchar *buffer, uint data_status)
{
int ret = SUNXI_USB_REQ_SUCCESSED;
switch(req->bmRequestType) //MASS 特有请求
{
case 161:
if(req->bRequest == 0xFE)
{
sunxi_usb_dbg("mass ask for max lun\n");
buffer[0] = 0;
sunxi_udc_send_setup(1, buffer);
}
else
{
printf("sunxi usb err: unknown ep0 req in mass\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
}
break;
default:
printf("sunxi usb err: unknown non standard ep0 req\n");
ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED;
break;
}
return ret;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int sunxi_mass_state_loop(void *buffer)
{
static struct umass_bbb_cbw_t *cbw;
static struct umass_bbb_csw_t csw;
static uint mass_flash_start = 0;
static uint mass_flash_sectors = 0;
int ret;
sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer;
switch(sunxi_usb_mass_status)
{
case SUNXI_USB_MASS_IDLE:
if(sunxi_ubuf->rx_ready_for_data == 1)
{
sunxi_usb_mass_status = SUNXI_USB_MASS_SETUP;
}
break;
case SUNXI_USB_MASS_SETUP:
sunxi_usb_dbg("SUNXI_USB_MASS_SETUP\n");
if(sunxi_ubuf->rx_req_length != sizeof(struct umass_bbb_cbw_t))
{
printf("sunxi usb error: received bytes 0x%x is not equal cbw struct size 0x%lx\n", sunxi_ubuf->rx_req_length, (long)sizeof(struct umass_bbb_cbw_t));
sunxi_ubuf->rx_ready_for_data = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
break;
}
cbw = (struct umass_bbb_cbw_t *)sunxi_ubuf->rx_req_buffer;
if(CBWSIGNATURE != cbw->dCBWSignature)
{
printf("sunxi usb error: the cbw signature 0x%x is bad, need 0x%x\n", cbw->dCBWSignature, CBWSIGNATURE);
sunxi_ubuf->rx_ready_for_data = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
break;
}
csw.dCSWSignature = CSWSIGNATURE;
csw.dCSWTag = cbw->dCBWTag;
sunxi_usb_dbg("usb cbw command = 0x%x\n", cbw->CBWCDB[0]);
#if defined(SUNXI_USB_30)
sunxi_usb_mass_status_enable = 1;
#endif
switch(cbw->CBWCDB[0])
{
case SCSI_TST_U_RDY:
sunxi_usb_dbg("SCSI_TST_U_RDY\n");
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
break;
case SCSI_REQ_SENSE:
sunxi_usb_dbg("SCSI_REQ_SENSE\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
trans_data.send_size = min(cbw->dCBWDataTransferLength, 18);
trans_data.act_send_buffer = (uchar *)RequestSense;
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
break;
case SCSI_VERIFY:
sunxi_usb_dbg("SCSI_VERIFY\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
break;
case SCSI_INQUIRY:
sunxi_usb_dbg("SCSI_INQUIRY\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
trans_data.send_size = min(cbw->dCBWDataTransferLength, 36);
trans_data.act_send_buffer = (uchar *)InquiryData;
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
break;
case SCSI_MODE_SEN6:
sunxi_usb_dbg("SCSI_MODE_SEN6\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
{
trans_data.base_send_buffer[0] = 3;
trans_data.base_send_buffer[1] = 0; //介质类型为0
trans_data.base_send_buffer[2] = 0; //设备标识参数, 为0
trans_data.base_send_buffer[3] = 0; //块描述符长度可以为0
trans_data.act_send_buffer = trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, 4);
}
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
break;
case SCSI_RD_CAPAC:
sunxi_usb_dbg("SCSI_RD_CAPAC\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
{
memset(trans_data.base_send_buffer, 0, 8);
uint size = sunxi_flash_size() - CONFIG_MMC_LOGICAL_OFFSET - 1;
trans_data.base_send_buffer[0] = (size >> 24) & 0xFF;
trans_data.base_send_buffer[1] = (size >> 16) & 0xFF;
trans_data.base_send_buffer[2] = (size >> 8) & 0xFF;
trans_data.base_send_buffer[3] = (size >> 0) & 0xFF;
size = 512;
trans_data.base_send_buffer[4] = (size >> 24) & 0xFF;
trans_data.base_send_buffer[5] = (size >> 16) & 0xFF;
trans_data.base_send_buffer[6] = (size >> 8) & 0xFF;
trans_data.base_send_buffer[7] = (size >> 0) & 0xFF;
trans_data.act_send_buffer = trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, 8);
}
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
break;
case SCSI_RD_FMT_CAPAC:
sunxi_usb_dbg("SCSI_RD_FMT_CAPAC\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
{
memset(trans_data.base_send_buffer, 0, 12);
trans_data.base_send_buffer[2] = 0x80;
trans_data.base_send_buffer[6] = 2;
trans_data.base_send_buffer[8] = 2;
trans_data.base_send_buffer[10] = 2;
trans_data.act_send_buffer = trans_data.base_send_buffer;
trans_data.send_size = min(cbw->dCBWDataTransferLength, 12);
}
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
break;
case SCSI_MED_REMOVL:
sunxi_usb_dbg("SCSI_MED_REMOVL\n");
csw.bCSWStatus = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
break;
case SCSI_READ6:
case SCSI_READ10: //HOST READ, not this device read
sunxi_usb_dbg("SCSI_READ\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
{
uint start, sectors;
start = (cbw->CBWCDB[2]<<24) | cbw->CBWCDB[3]<<16 | cbw->CBWCDB[4]<<8 | cbw->CBWCDB[5]<<0;
sectors = (cbw->CBWCDB[7]<<8) | cbw->CBWCDB[8];
sunxi_usb_dbg("read start: 0x%x, sectors 0x%x\n", start, sectors);
trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512);
trans_data.act_send_buffer = trans_data.base_send_buffer;
ret = sunxi_flash_read(start, sectors, trans_data.base_send_buffer);
if(!ret)
{
printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors);
csw.bCSWStatus = 1;
}
else
{
csw.bCSWStatus = 0;
}
sunxi_usb_mass_status = SUNXI_USB_MASS_SEND_DATA;
}
break;
case SCSI_WRITE6:
case SCSI_WRITE10: //HOST WRITE, not this device write
sunxi_usb_dbg("SCSI_WRITE\n");
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
mass_flash_start = (cbw->CBWCDB[2]<<24) | cbw->CBWCDB[3]<<16 | cbw->CBWCDB[4]<<8 | cbw->CBWCDB[5]<<0;
mass_flash_sectors = (cbw->CBWCDB[7]<<8) | cbw->CBWCDB[8];
sunxi_usb_dbg("command write start: 0x%x, sectors 0x%x\n", mass_flash_start, mass_flash_sectors);
trans_data.recv_size = min(cbw->dCBWDataTransferLength, mass_flash_sectors * 512);
trans_data.act_recv_buffer = trans_data.base_recv_buffer;
sunxi_usb_dbg("try to receive data 0x%x\n", trans_data.recv_size);
sunxi_usb_mass_write_enable = 0;
sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, trans_data.recv_size); //start dma to receive data
sunxi_usb_mass_status = SUNXI_USB_MASS_RECEIVE_DATA;
break;
default:
sunxi_usb_dbg("not supported command 0x%x now\n", cbw->CBWCDB[0]);
sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength);
csw.bCSWStatus = 1;
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
break;
}
break;
case SUNXI_USB_MASS_SEND_DATA:
sunxi_usb_dbg("SUNXI_USB_SEND_DATA\n");
#if defined(SUNXI_USB_30)
sunxi_usb_mass_status_enable = 0;
#endif
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size);
break;
case SUNXI_USB_MASS_RECEIVE_DATA:
sunxi_usb_dbg("SUNXI_USB_RECEIVE_DATA\n");
if(sunxi_usb_mass_write_enable == 1)
{
sunxi_usb_dbg("write flash, start 0x%x, sectors 0x%x\n", mass_flash_start, trans_data.recv_size/512);
ret = sunxi_flash_write(mass_flash_start, trans_data.recv_size/512, (void *)trans_data.act_recv_buffer);
if(!ret)
{
printf("sunxi flash write err: start,0x%x sectors 0x%x\n", mass_flash_start, trans_data.recv_size/512);
csw.bCSWStatus = 1;
}
else
{
csw.bCSWStatus = 0;
}
sunxi_usb_mass_write_enable = 0;
sunxi_usb_mass_status = SUNXI_USB_MASS_STATUS;
}
break;
case SUNXI_USB_MASS_STATUS:
sunxi_usb_dbg("SUNXI_USB_MASS_STATUS\n");
#if defined(SUNXI_USB_30)
if(sunxi_usb_mass_status_enable)
#endif
{
sunxi_usb_mass_status = SUNXI_USB_MASS_IDLE;
sunxi_ubuf->rx_ready_for_data = 0;
__sunxi_mass_send_status(&csw, sizeof(struct umass_bbb_csw_t));
}
break;
default:
break;
}
return 0;
}
sunxi_usb_module_init(SUNXI_USB_DEVICE_MASS, \
sunxi_mass_init, \
sunxi_mass_exit, \
sunxi_mass_reset, \
sunxi_mass_standard_req_op, \
sunxi_mass_nonstandard_req_op, \
sunxi_mass_state_loop, \
sunxi_mass_usb_rx_dma_isr, \
sunxi_mass_usb_tx_dma_isr \
);