KT24-1110_65E-HA-651B/apps/common/usb/device/msd.c

1099 lines
34 KiB
C
Raw Permalink Normal View History

2024-11-10 10:44:17 +00:00
#include "system/includes.h"
#include "usb/device/usb_stack.h"
#include "usb/device/msd.h"
#include "usb/scsi.h"
#include "usb_config.h"
#include "device/device.h"
#include "app_config.h"
#if TCFG_DEV_MANAGER_ENABLE
#include "dev_manager.h"
#endif
#if TCFG_USB_APPLE_DOCK_EN
#include "apple_dock/iAP.h"
#endif
#if TCFG_USB_SLAVE_MSD_ENABLE
#define LOG_TAG_CONST USB
#define LOG_TAG "[USB]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
// *INDENT-OFF*
#define USB_MSD_BULK_DEV_USE_ASYNC 1
// Mass Storage Class
/*********************************************************/
static const u8 sMassDescriptor[] = { //<Interface & Endpoint Descriptor
///Interface
USB_DT_INTERFACE_SIZE, //Length
USB_DT_INTERFACE, //DescriptorType:Inerface
0x00, //InterfaceNum:0
0x00, //AlternateSetting:0
0x02, //NumEndpoint:0
USB_CLASS_MASS_STORAGE, //InterfaceClass:MSD
0x06, //InterfaceSubClass SCSI transparent command set Allocated by USB-IF for SCSI. SCSI standards are defined outside of USB.
0x50, //InterfaceProtocol BBB USB Mass Storage Class Bulk-Only (BBB) Transport
0x00, //Interface String
///Endpoint IN
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
USB_DIR_IN | MSD_BULK_EP_IN,
USB_ENDPOINT_XFER_BULK,
LOBYTE(MAXP_SIZE_BULKIN), HIBYTE(MAXP_SIZE_BULKIN),
0x01,
///Endpoint OUT
USB_DT_ENDPOINT_SIZE,
USB_DT_ENDPOINT,
MSD_BULK_EP_OUT,
USB_ENDPOINT_XFER_BULK,
LOBYTE(MAXP_SIZE_BULKOUT), HIBYTE(MAXP_SIZE_BULKOUT),
0x01,
};
#if defined(CONFIG_CPU_BR23)
#define CPU_NAME 'B','R','2','3'
#elif defined(CONFIG_CPU_BR25)
#define CPU_NAME 'B','R','2','5'
#elif defined(CONFIG_CPU_BD29)
#define CPU_NAME 'B','D','2','9'
#elif defined(CONFIG_CPU_BR30)
#define CPU_NAME 'B','R','3','0'
#elif defined(CONFIG_CPU_BD19)
#define CPU_NAME 'B','D','1','9'
#elif defined(CONFIG_CPU_BR36)
#define CPU_NAME 'B','R','3','6'
#else
#define CPU_NAME 'U','K','N','W'
/* #error "not define cpu name" */
#endif
// *INDENT-ON*
static const u8 SCSIInquiryData[] = {
0x00,// // Peripheral Device Type: direct access devices 0x05,//
0x80, // Removable: UFD is removable
0x02, // iso ecma ANSI version
0x02, // Response Data Format: compliance with UFI
0x20, // Additional Length (Number of UINT8s following this one): 31, totally 36 UINT8s
0x00, 0x00, 0x00, // reserved
CPU_NAME, //-- Vender information start
' ',
' ',
' ',
' ', //" " -- Vend Information end
'U', //-- Production Identification start
'D',
'I',
'S',
'K',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ', //" " -- Production Identification end
0x31, //"1" -- Production Revision Level start
0x2e, //"."
0x30, //"0"
0x30 //"0" -- Production Revision Level end
};
#define MSD_BLOCK_SIZE 1
#define MSD_BUFFER_SIZE (MSD_BLOCK_SIZE * 512)
struct usb_msd_handle {
struct usb_scsi_cbw cbw;
struct usb_scsi_csw csw;
struct msd_info info;
u8 *msd_buf;
u8 *ep_out_dmabuffer;
/* u8 *ep_in_dmabuffer; */
};
struct usb_msd_handle *msd_handle;
#if USB_MALLOC_ENABLE
#else
#if USB_MSD_BULK_DEV_USE_ASYNC
static u8 msd_buf[MSD_BUFFER_SIZE * 2] SEC(.mass_storage) __attribute__((aligned(64)));
#else
static u8 msd_buf[MSD_BUFFER_SIZE] SEC(.mass_storage) __attribute__((aligned(64)));
#endif
static struct usb_msd_handle _msd_handle SEC(.mass_storage);
#endif
inline static u8 __get_max_msd_dev()
{
u8 cnt = 0;
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD0_ENABLE)\
||(TCFG_SD0_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 0)
//没有复用时候判断 sd开关
//复用时候判断是否参与复用
cnt++;
#endif
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD1_ENABLE)\
||(TCFG_SD1_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 1)
//没有复用时候判断 sd开关
//复用时候判断是否参与复用
cnt++;
#endif
#if defined(TCFG_NORFLASH_DEV_ENABLE) && TCFG_NORFLASH_DEV_ENABLE
cnt++;
#endif
#if TCFG_VIR_UDISK_ENABLE
cnt++;
#endif
if (!cnt) {
cnt = 1;
} else if (cnt >= MAX_MSD_DEV) {
cnt = MAX_MSD_DEV;
}
return cnt;
}
u32 msd_set_wakeup_handle(void (*handle)(struct usb_device_t *usb_device))
{
if (msd_handle) {
msd_handle->info.msd_wakeup_handle = handle;
return 1;
}
return 0;
}
static void msd_wakeup(struct usb_device_t *usb_device, u32 ep)
{
if ((msd_handle) && (msd_handle->info.msd_wakeup_handle)) {
msd_handle->info.msd_wakeup_handle(usb_device);
}
}
static u8 get_cardreader_popup(u32 lun)
{
return msd_handle->info.bDisk_popup[lun];//弹出
}
static void set_cardreader_popup(u32 lun, u8 status)
{
if (msd_handle->info.dev_handle[lun] != NULL) {
msd_handle->info.bDisk_popup[lun] = status;//弹出
}
}
static void recover_set_cardreader_popup(u32 lun)
{
if (msd_handle->info.dev_handle[lun] != NULL) {
msd_handle->info.bDisk_popup[lun] = 0;//未弹出
}
}
static void msd_endpoint_init(struct usb_device_t *usb_device, u32 itf)
{
const usb_dev usb_id = usb_device2id(usb_device);
usb_g_ep_config(usb_id, MSD_BULK_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, msd_handle->ep_out_dmabuffer, MAXP_SIZE_BULKIN);
usb_g_ep_config(usb_id, MSD_BULK_EP_OUT, USB_ENDPOINT_XFER_BULK, 1, msd_handle->ep_out_dmabuffer, MAXP_SIZE_BULKOUT);
usb_g_set_intr_hander(usb_id, MSD_BULK_EP_OUT, msd_wakeup);
usb_enable_ep(usb_id, MSD_BULK_EP_IN);
}
static void msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
{
const usb_dev usb_id = usb_device2id(usb_device);
if (msd_handle && msd_handle->info.msd_reset_wakeup_handle) {
msd_handle->info.msd_reset_wakeup_handle(usb_device, itf_num);
}
}
void msd_set_reset_wakeup_handle(void (*handle)(struct usb_device_t *usb_device, u32 itf_num))
{
if (msd_handle) {
msd_handle->info.msd_reset_wakeup_handle = handle;
}
}
void msd_reset(struct usb_device_t *usb_device, u32 itf_num)
{
const usb_dev usb_id = usb_device2id(usb_device);
log_debug("%s", __func__);
#if USB_ROOT2
usb_disable_ep(usb_id, MSD_BULK_EP_OUT);
#else
msd_endpoint_init(usb_device, itf_num);
#endif
}
static void *check_disk_status(u8 cur_lun)
{
u32 ret;
u32 online_status;
void *dev_fd = msd_handle->info.dev_handle[cur_lun] ;
const char *dev_name = msd_handle->info.dev_name[cur_lun];
#if TCFG_DEV_MANAGER_ENABLE
if (dev_manager_list_check_by_logo((char *)dev_name)) {
if (dev_fd == NULL) {
msd_handle->info.dev_handle[cur_lun] = dev_open(dev_name, NULL);
} else {
//FIXME:need add device state check??
u32 dev_online = 0;
ret = dev_ioctl(dev_fd, IOCTL_GET_STATUS, (u32)&dev_online);
if (ret || !dev_online) {
goto __dev_offline;
}
}
if (get_cardreader_popup(cur_lun)) {
return NULL;
}
} else {
if (dev_fd) {
goto __dev_offline;
}
}
#else
if (dev_fd == NULL) {
msd_handle->info.dev_handle[cur_lun] = dev_open(dev_name, NULL);
} else {
u32 dev_online = 0;
ret = dev_ioctl(dev_fd, IOCTL_GET_STATUS, (u32)&dev_online);
if (ret || !dev_online) {
goto __dev_offline;
}
}
#endif
return msd_handle->info.dev_handle[cur_lun];
__dev_offline:
dev_close(dev_fd);
recover_set_cardreader_popup(cur_lun);
msd_handle->info.dev_handle[cur_lun] = NULL;
return NULL;
}
static u32 msd_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
{
u32 tx_len;
u8 *tx_payload = usb_get_setup_buffer(usb_device);
u32 bRequestType = setup->bRequestType & USB_TYPE_MASK;
switch (bRequestType) {
case USB_TYPE_STANDARD:
switch (setup->bRequest) {
case USB_REQ_GET_STATUS:
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
break;
case USB_REQ_GET_INTERFACE:
tx_len = 1;
u8 i = 0;
usb_set_data_payload(usb_device, setup, &i, tx_len);
break;
case USB_REQ_SET_INTERFACE:
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
break;
default:
break;
}
break;
case USB_TYPE_CLASS:
switch (setup->bRequest) {
case USB_MSD_MAX_LUN:
msd_endpoint_init(usb_device, -1);
tx_len = 1;
tx_payload[0] = __get_max_msd_dev() - 1;
usb_set_data_payload(usb_device, setup, tx_payload, tx_len);
break;
case USB_MSD_RESET :
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
break;
default:
break;
}
break;
default:
break;
}
return 0;
}
u32 msd_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
{
log_debug("%s() %d", __func__, *cur_itf_num);
memcpy(ptr, sMassDescriptor, sizeof(sMassDescriptor));
ptr[2] = *cur_itf_num;
#if TCFG_USB_APPLE_DOCK_EN
if (apple_mfi_chip_online_lib()) {
ptr[5] = 0xff; //bInterfaceClass:Vendor-Specific
ptr[6] = 0xf0; //bInterfaceSubClass:MFi Accessory
ptr[7] = 0x00; //bInterfaceProtocol */
ptr[8] = MSD_STR_INDEX; //bInterfaceString*/
}
#endif
if (usb_set_interface_hander(usb_id, *cur_itf_num, msd_itf_hander) != *cur_itf_num) {
}
if (usb_set_reset_hander(usb_id, *cur_itf_num, msd_reset_wakeup) != *cur_itf_num) {
}
*cur_itf_num = *cur_itf_num + 1;
return sizeof(sMassDescriptor);
}
u32 msd_usb2mcu(const struct usb_device_t *usb_device, u8 *buffer, u32 len)
{
usb_dev usb_id = usb_device2id(usb_device);
return usb_g_bulk_read(usb_id, MSD_BULK_EP_OUT, buffer, len, 1);
}
u32 msd_mcu2usb(const struct usb_device_t *usb_device, const u8 *buffer, u32 len)
{
usb_dev usb_id = usb_device2id(usb_device);
return usb_g_bulk_write(usb_id, MSD_BULK_EP_IN, buffer, len);
}
static u32 msd_usb2mcu_64byte_fast(const struct usb_device_t *usb_device, u8 *buffer, u32 len)
{
usb_dev usb_id = usb_device2id(usb_device);
return usb_g_bulk_read64byte_fast(usb_id, MSD_BULK_EP_OUT, buffer, len);
}
static u32 get_cbw(const struct usb_device_t *usb_device)
{
msd_handle->cbw.dCBWSignature = 0;
memset((u8 *)(&(msd_handle->cbw)), 0, sizeof(struct usb_scsi_cbw));
u32 rx_len = msd_usb2mcu(usb_device, (u8 *)(&(msd_handle->cbw)), sizeof(struct usb_scsi_cbw));
if (rx_len == 0) {
return 1;
}
if (msd_handle->cbw.dCBWSignature ^ CBW_SIGNATURE) {
if ((msd_handle->cbw.dCBWSignature ^ CBW_SIGNATURE) != CBW_SIGNATURE) {
}
return 1;
}
msd_handle->csw.dCSWTag = msd_handle->cbw.dCBWTag;
msd_handle->csw.uCSWDataResidue = msd_handle->cbw.dCBWDataTransferLength;
return 0;
}
static void inquiry(const struct usb_device_t *usb_device)
{
u32 err;
u32 len = min(msd_handle->csw.uCSWDataResidue, sizeof(SCSIInquiryData));
u32 scsiinquirydata[sizeof(SCSIInquiryData) / 4]; //usb dma 不能访问code区域
memcpy(scsiinquirydata, SCSIInquiryData, sizeof(SCSIInquiryData));
err = msd_mcu2usb(usb_device, scsiinquirydata, len);
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
msd_handle->csw.uCSWDataResidue -= len;
msd_handle->csw.bCSWStatus = 0;
}
static void send_csw(const struct usb_device_t *usb_device)
{
u32 err;
msd_handle->csw.dCSWSignature = CSW_SIGNATURE;
err = msd_mcu2usb(usb_device, (u8 *) & (msd_handle->csw), sizeof(struct usb_scsi_csw));
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
}
static void stall_inep(const struct usb_device_t *usb_device)
{
const usb_dev usb_id = usb_device2id(usb_device);
usb_write_txcsr(usb_id, MSD_BULK_EP_IN, TXCSRP_SendStall);
u32 ot = 2000;
while (1) {
if (ot-- == 0) {
break;
}
if (usb_otg_online(usb_id) == DISCONN_MODE) {
break;
}
if ((usb_read_txcsr(usb_id, MSD_BULK_EP_IN) & TXCSRP_SendStall) == 0) {
break;
}
}
}
static void stall_outep(const struct usb_device_t *usb_device)
{
const usb_dev usb_id = usb_device2id(usb_device);
usb_write_rxcsr(usb_id, MSD_BULK_EP_OUT, RXCSRP_SendStall);
u32 ot = 2000;
while (1) {
if (ot-- == 0) {
break;
}
if (usb_otg_online(usb_id) == DISCONN_MODE) {
break;
}
if ((usb_read_rxcsr(usb_id, MSD_BULK_EP_OUT) & RXCSRP_SendStall) == 0) {
break;
}
}
}
static void unknow(const struct usb_device_t *usb_device, u8 rw)
{
if (rw) {
stall_outep(usb_device);
} else {
stall_inep(usb_device);
}
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0x01;
msd_handle->info.bError = 0x1;
/* msd_handle->info.bError = 0x2; */
}
static void stall_error(const struct usb_device_t *usb_device, u8 rw, u8 error)
{
msd_handle->csw.bCSWStatus = 0x01;
unknow(usb_device, rw);
msd_handle->info.bError = error;
}
static void test_unit_ready(const struct usb_device_t *usb_device)
{
int err;
u8 cur_lun = msd_handle->cbw.bCBWLUN;
if (NULL == check_disk_status(cur_lun)) {
msd_handle->csw.bCSWStatus = 0x1;
msd_handle->info.bError = 0x0f;
} else {
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0x0;
}
}
static void allow_medium_removal(const struct usb_device_t *usb_device)
{
msd_handle->csw.bCSWStatus = 0x0;
if (msd_handle->cbw.lba[2]) {
msd_handle->info.bError = 0x02;
msd_handle->csw.bCSWStatus = 0x01;
}
msd_handle->csw.uCSWDataResidue = 0;
}
static void request_sense(const struct usb_device_t *usb_device)
{
u32 err;
u32 len;
u8 sense_data[0x12];
len = min(msd_handle->csw.uCSWDataResidue, 0x12);
if (msd_handle->csw.uCSWDataResidue == 0) {
stall_inep(usb_device);
msd_handle->info.bError = NOT_READY;
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0x01;
return;
} else {
memset(sense_data, 0x0, sizeof(sense_data));
sense_data[2] = msd_handle->info.bSenseKey;
sense_data[12] = msd_handle->info.bAdditionalSenseCode;
sense_data[13] = msd_handle->info.bAddiSenseCodeQualifier;
sense_data[0] = 0x70;
sense_data[7] = 0x0a;
err = msd_mcu2usb(usb_device, sense_data, len);
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
}
msd_handle->csw.uCSWDataResidue -= len;
msd_handle->csw.bCSWStatus = 0;
}
static u8 const scsi_mode_sense[4] = {
0x03, 0x00, 0x00, 0x00
};
static void mode_sense(const struct usb_device_t *usb_device)
{
u32 err;
u32 sense;
err = msd_mcu2usb(usb_device, (u8 *)scsi_mode_sense, sizeof(scsi_mode_sense));
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0;
}
static void verify(const struct usb_device_t *usb_device)
{
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0;
}
#if USB_MSD_BULK_DEV_USE_ASYNC
static void msd_write_10_async(const struct usb_device_t *usb_device, u8 cur_lun, u32 lba, u16 lba_num)
{
u32 err = 0;
u16 num = 0;
u8 buf_idx = 0;
u32 have_send_stall = FALSE;
void *dev_fd = NULL;
while (lba_num) {
wdt_clear();
num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
if (msd_handle->csw.uCSWDataResidue == 0) {
msd_handle->csw.bCSWStatus = 1;
break;
}
if (msd_handle->csw.uCSWDataResidue >= num * 0x200) {
msd_handle->csw.uCSWDataResidue -= num * 0x200;
}
err = msd_usb2mcu_64byte_fast(usb_device, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, num * 0x200);
if (err != num * 0x200) {
log_error("read usb_err %d, dev = %s",
__LINE__, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 1, MEDIUM_ERROR);
have_send_stall = TRUE;
break;
}
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
err = dev_bulk_write(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
if (err != num) {
log_error("write_10 write fail, %d, dev = %s",
err, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 1, MEDIUM_ERROR);
have_send_stall = TRUE;
break;
}
} else {
log_error("write_10 disk offline, dev = %s",
msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 1, MEDIUM_ERROR);
have_send_stall = TRUE;
break;
}
buf_idx = !buf_idx;
lba_num -= num;
lba += num;
}
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
//async mode last block flush
dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
} else {
if (have_send_stall == FALSE) {
log_error("write_10 disk offline while sync, dev = %s",
msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 1, MEDIUM_ERROR);
}
}
}
static void msd_read_10_async(const struct usb_device_t *usb_device, u8 cur_lun, u32 lba, u16 lba_num)
{
u32 err = 0;
u16 num = 0;
u8 buf_idx = 0;
u32 last_lba = 0, last_num = 0;
void *dev_fd = NULL;
if (lba_num == 0) {
log_error("lba_num == 0\n");
stall_error(usb_device, 0, 0x02);
return;
}
num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
err = dev_bulk_read(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
if (err != num) {
log_error("read disk error0 = %d, dev = %s\n", err, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
return;
}
} else {
log_error("read_10 disk offline, dev = %s\n", msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
return;
}
while (lba_num) {
wdt_clear();
last_num = num;
last_lba = lba;
buf_idx = !buf_idx;
lba += num;
lba_num -= num;
num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
if (msd_handle->csw.uCSWDataResidue == 0) {
msd_handle->csw.bCSWStatus = 1;
break;
}
if (msd_handle->csw.uCSWDataResidue >= last_num * 0x200) {
msd_handle->csw.uCSWDataResidue -= last_num * 0x200;
}
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
if (num) {
dev_ioctl(dev_fd, IOCTL_SET_ASYNC_MODE, 0);
err = dev_bulk_read(dev_fd, msd_handle->msd_buf + buf_idx * MSD_BUFFER_SIZE, lba, num);
if (err != num) {
log_error("read disk error1 = %d, dev = %s",
err, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
break;
}
} else {
//async mode last block flush
dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
}
} else {
log_error("read_10 disk offline, dev = %s",
msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
break;
}
err = msd_mcu2usb(usb_device, msd_handle->msd_buf + !buf_idx * MSD_BUFFER_SIZE, last_num * 0x200);
if (err != last_num * 0x200) {
log_error("read_10 data transfer err %d, dev = %s",
__LINE__, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, 0x05);
if (num) {
dev_ioctl(dev_fd, IOCTL_FLUSH, 0);
}
break;
}
}
}
#endif
static u32 read_32(u8 *p)
{
return ((u32)(p[0]) << 24) | ((u32)(p[1]) << 16) | ((u32)(p[2]) << 8) | (p[3]);
}
static void write_10(const struct usb_device_t *usb_device)
{
u32 err = 0 ;
u32 lba;
u16 lba_num;
u16 num = 0;
lba = read_32(msd_handle->cbw.lba);
lba_num = ((u16)(msd_handle->cbw.LengthH) << 8) | (msd_handle->cbw.LengthL);
u8 cur_lun = msd_handle->cbw.bCBWLUN;
void *dev_fd = msd_handle->info.dev_handle[cur_lun];
/* app_status_handler(APP_STATUS_PC_COPY); */
#if USB_MSD_BULK_DEV_USE_ASYNC
/* u32 old_speed; */
/* dev_fd = check_disk_status(cur_lun); */
/* if (dev_fd) { */
/* dev_ioctl(dev_fd, IOCTL_GET_SPEED, (u32)&old_speed); */
/* dev_ioctl(dev_fd, IOCTL_SET_SPEED, 48000000); */
/* } */
msd_write_10_async(usb_device, cur_lun, lba, lba_num);
/* if (dev_fd) { */
/* dev_ioctl(dev_fd, IOCTL_SET_SPEED, old_speed); */
/* } */
#else
while (lba_num) {
wdt_clear();
num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
if (msd_handle->csw.uCSWDataResidue == 0) {
msd_handle->csw.bCSWStatus = 0x1;
break;
}
if (msd_handle->csw.uCSWDataResidue >= (num * 0x200)) {
msd_handle->csw.uCSWDataResidue -= (num * 0x200);
}
err = msd_usb2mcu_64byte_fast(usb_device, msd_handle->msd_buf, num * 0x200);
if (err == 0) {
stall_error(usb_device, 1, MEDIUM_ERROR);
log_error("read usb, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
break;
}
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
dev_ioctl(dev_fd, IOCTL_CMD_RESUME, 0);
err = dev_bulk_write(dev_fd, msd_handle->msd_buf, lba, num);
dev_ioctl(dev_fd, IOCTL_CMD_SUSPEND, 0);
if (err != num) {
stall_error(usb_device, 1, MEDIUM_ERROR);
log_error("write disk error =%d, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
break;
} else {
break;
}
lba += num;
lba_num -= num;
} else {
log_error("write disk offline, dev = %s", msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 1, MEDIUM_ERROR);
break;
}
}
#endif
}
static void read_10(const struct usb_device_t *usb_device)
{
u32 err = 0;
u32 lba;
u16 lba_num;
u16 num = 0;
lba = read_32(msd_handle->cbw.lba);
lba_num = ((u16)(msd_handle->cbw.LengthH) << 8) | (msd_handle->cbw.LengthL);
u8 cur_lun = msd_handle->cbw.bCBWLUN;
void *dev_fd = msd_handle->info.dev_handle[cur_lun];
#if USB_MSD_BULK_DEV_USE_ASYNC
msd_read_10_async(usb_device, cur_lun, lba, lba_num);
#else
while (lba_num) {
wdt_clear();
num = lba_num > MSD_BLOCK_SIZE ? MSD_BLOCK_SIZE : lba_num;
if (msd_handle->csw.uCSWDataResidue == 0) {
msd_handle->csw.bCSWStatus = 0x1;
break;
}
if (msd_handle->csw.uCSWDataResidue >= (num * 0x200)) {
msd_handle->csw.uCSWDataResidue -= (num * 0x200);
}
dev_fd = check_disk_status(cur_lun);
if (dev_fd) {
dev_ioctl(dev_fd, IOCTL_CMD_RESUME, 0);
err = dev_bulk_read(dev_fd, msd_handle->msd_buf, lba, num);
dev_ioctl(dev_fd, IOCTL_CMD_SUSPEND, 0);
if (err != num) {
log_error("read disk error =%d, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
break;
}
} else {
log_error("read disk offline, dev = %s", err, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
break;
}
err = msd_mcu2usb(usb_device, msd_handle->msd_buf, num * 0x200);
if (err == 0) {
log_error("write usb err %d, dev = %s", __LINE__, msd_handle->info.dev_name[cur_lun]);
stall_error(usb_device, 0, MEDIUM_ERROR);
break;
}
lba += num;
lba_num -= num;
}
#endif
}
static void read_capacity(const struct usb_device_t *usb_device)
{
u32 err;
u32 capacity_temp;
u8 capacity[8] = {0};
u8 cur_lun = msd_handle->cbw.bCBWLUN;
void *dev_fd = check_disk_status(cur_lun);
if (!dev_fd) {
stall_error(usb_device, 0, 0x0f);
return;
}
dev_ioctl(dev_fd, IOCTL_GET_CAPACITY, (u32)&capacity_temp);
capacity_temp = cpu_to_be32(capacity_temp - 1);
memcpy(capacity, &capacity_temp, 4);
dev_ioctl(dev_fd, IOCTL_GET_BLOCK_SIZE, (u32)&capacity_temp);
/* r_printf(">>>[test]:capacity_temp2 = %d\n", capacity_temp); */
capacity_temp = cpu_to_be32(capacity_temp);
memcpy(&capacity[4], &capacity_temp, 4);
err = msd_mcu2usb(usb_device, capacity, 8);
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0;
}
static void read_format_capacity(const struct usb_device_t *usb_device)
{
u32 err;
u8 capacity[12] = {0};
u32 capacity_temp;
u8 cur_lun = msd_handle->cbw.bCBWLUN;
void *dev_fd = check_disk_status(cur_lun);
if (!dev_fd) {
stall_error(usb_device, 0, 0x0f);
return;
}
dev_ioctl(dev_fd, IOCTL_GET_CAPACITY, (u32)&capacity_temp);
capacity_temp = cpu_to_be32(capacity_temp);
memcpy(&capacity[4], &capacity_temp, 4);
dev_ioctl(dev_fd, IOCTL_GET_BLOCK_SIZE, (u32)&capacity_temp);
capacity_temp = cpu_to_be32(capacity_temp);
memcpy(&capacity[8], &capacity_temp, 4);
capacity[3] = 0x08;
capacity[8] = 0x02;
err = msd_mcu2usb(usb_device, capacity, 12);
if (err == 0) {
log_error("write usb err %d", __LINE__);
}
msd_handle->csw.uCSWDataResidue -= 12;
msd_handle->csw.bCSWStatus = 0;
}
static void stop_start()
{
int i;
u8 loej, start;
/* set_cardreader_popup(0, !(msd_handle->cbw.lba[2])); */
loej = msd_handle->cbw.lba[2] & BIT(1);
start = msd_handle->cbw.lba[2] & BIT(0);
for (i = 0; i < __get_max_msd_dev(); i++) {
if (loej && !start) {
set_cardreader_popup(i, 1);
} else if (loej && start) {
set_cardreader_popup(i, 0);
}
}
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0x0;
}
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
void USB_MassStorage(const struct usb_device_t *usb_device)
{
const usb_dev usb_id = usb_device2id(usb_device);
usb_clr_intr_rxe(usb_id, MSD_BULK_EP_OUT);
if (get_cbw(usb_device)) {
usb_set_intr_rxe(usb_id, MSD_BULK_EP_OUT);
return;
}
/* log_debug("opcode %x", msd_handle->cbw.operationCode); */
if (private_scsi_cmd(usb_device, &(msd_handle->cbw))) {
msd_handle->info.bError = 0;
msd_handle->csw.uCSWDataResidue = 0;
msd_handle->csw.bCSWStatus = 0x0;
} else {
wdt_clear();
switch (msd_handle->cbw.operationCode) {
case INQUIRY://0x12
inquiry(usb_device);
break;
case TEST_UNIT_READY://0x00
test_unit_ready(usb_device);
break;
case VERIFY://0x2f
verify(usb_device);
break;
case ALLOW_MEDIUM_REMOVAL://0x1e
allow_medium_removal(usb_device);
break;
case REQUEST_SENSE://0x03
request_sense(usb_device);
break;
case MODE_SENSE://0x1a
mode_sense(usb_device);
break;
case READ_10://0x28
read_10(usb_device);
break;
case WRITE_10://0x2a
write_10(usb_device);
break;
case READ_CAPACITY://0x25
read_capacity(usb_device);
break;
case READ_FORMAT_CAPACITIES://0x23
read_format_capacity(usb_device);
break;
case START_STOP://0x1b
stop_start();
break;
default:
log_error("opcode %x", msd_handle->cbw.operationCode);
stall_error(usb_device, 0, !(msd_handle->cbw.bmCBWFlags & 0x80));
break;
}
}
switch (msd_handle->info.bError) {
case 0x00:
msd_handle->info.bSenseKey = NO_SENSE;
msd_handle->info.bAdditionalSenseCode = ASC_NO_ADDITIONAL_SENSE_INFORMATION;
msd_handle->info.bAddiSenseCodeQualifier = ASCQ_NO_ADDITIONAL_SENSE_INFORMATION;
break;
case 0x02:
msd_handle->info.bSenseKey = ILLEGAL_REQUEST;
msd_handle->info.bAdditionalSenseCode = ASC_INVALID_FIELD_IN_COMMAND_PACKET;
msd_handle->info.bAddiSenseCodeQualifier = ASCQ_INVALID_FIELD_IN_COMMAND_PACKET;
break;
case MEDIUM_ERROR:
msd_handle->info.bSenseKey = MEDIUM_ERROR;
msd_handle->info.bAdditionalSenseCode = ASC_WRITE_FAULT;
msd_handle->info.bAddiSenseCodeQualifier = ASCQ_WRITE_FAULT;
break;
case 0x0f:
case 0x05:
msd_handle->info.bSenseKey = NOT_READY;
msd_handle->info.bAdditionalSenseCode = ASC_MEDIUM_PRESENT;
msd_handle->info.bAddiSenseCodeQualifier = ASCQ_MEDIUM_PRESENT;
break;
case 0x06:
msd_handle->info.bSenseKey = ABORTED_COMMAND;
msd_handle->info.bAdditionalSenseCode = ASC_INVALID_COMMAND_OPERATION_CODE;
msd_handle->info.bAddiSenseCodeQualifier = ASCQ_INVALID_COMMAND_OPERATION_CODE;
break;
}
usb_set_intr_rxe(usb_id, MSD_BULK_EP_OUT);
send_csw(usb_device);
}
u32 msd_register_disk(const char *name, void *arg)
{
int i;
u32 len, ret = -1;
if (msd_handle) {
for (i = 0; i < __get_max_msd_dev(); i++) {
if (msd_handle->info.dev_name[i][0] == 0) {
ASSERT(strlen(name) <= MSD_DEV_NAME_LEN, "MSD_DEV_NAME_LEN too small");
strcpy(msd_handle->info.dev_name[i], name);
msd_handle->info.dev_handle[i] = NULL;
break;
}
}
if (i == __get_max_msd_dev()) {
ret = -3;
}
}
return ret;
}
u32 msd_unregister_disk(const char *name)
{
u32 err;
int i;
if (msd_handle) {
for (i = 0; i < __get_max_msd_dev(); i++) {
if (!strcmp(msd_handle->info.dev_name[i], name)) {
msd_handle->info.dev_name[i][0] = 0;
return 0;
}
}
}
return -1;
}
u32 msd_unregister_all()
{
u32 err;
int i;
if (msd_handle) {
for (i = 0; i < __get_max_msd_dev(); i++) {
if (msd_handle->info.dev_handle[i]) {
err = dev_close(msd_handle->info.dev_handle[i]);
msd_handle->info.dev_handle[i] = NULL;
/* memset(msd_handle->info.dev_name[i], 0, MSD_DEV_NAME_LEN); */
}
}
}
return 0;
}
u32 msd_register(const usb_dev usb_id)
{
if (msd_handle == NULL) {
#if USB_MALLOC_ENABLE
msd_handle = (struct usb_msd_handle *)zalloc(sizeof(struct usb_msd_handle));
if (msd_handle == NULL) {
log_error("msd_register err");
return -1;
}
#if USB_MSD_BULK_DEV_USE_ASYNC
msd_handle->msd_buf = (u8 *)malloc(MSD_BUFFER_SIZE * 2);
#else
msd_handle->msd_buf = (u8 *)malloc(MSD_BUFFER_SIZE);
#endif
if (msd_handle->msd_buf == NULL) {
log_error("msd_register err");
return -1;
}
#else
memset(&_msd_handle, 0, sizeof(struct usb_msd_handle));
_msd_handle.msd_buf = msd_buf;
msd_handle = &_msd_handle;
#endif
log_info("msd_handle = %x", msd_handle);
msd_handle->ep_out_dmabuffer = usb_alloc_ep_dmabuffer(usb_id, MSD_BULK_EP_OUT, MAXP_SIZE_BULKIN + MAXP_SIZE_BULKOUT);
}
return 0;
}
u32 msd_release()
{
if (msd_handle) {
for (int i = 0; i < __get_max_msd_dev(); i++) {
void *dev_fd = msd_handle->info.dev_handle[i] ;
if (dev_fd) {
dev_close(dev_fd);
msd_handle->info.dev_handle[i] = NULL;
}
}
#if USB_MALLOC_ENABLE
if (msd_handle->msd_buf) {
free(msd_handle->msd_buf);
msd_handle->msd_buf = NULL;
}
free(msd_handle);
#endif
msd_handle = NULL;
}
return 0;
}
#if TCFG_USB_APPLE_DOCK_EN
int usb_g_ep_read_check(const usb_dev id, u32 ep, u32 rx_len)
{
if (apple_mfi_chip_online_lib()) {
if (ep != MSD_BULK_EP_OUT) {
return 0;
}
u32 dma_size = usb_get_dma_size(id, ep);
/* printf("dma:%d, rl:%d, ep:%d \n", dma_size, rx_len, ep); */
if (rx_len < dma_size) {
return -1;
}
}
return 0;
}
void apple_usb_msd_wakeup(struct usb_device_t *usb_device)
{
msd_wakeup(usb_device, MSD_BULK_EP_IN);
}
u8 MCU_SRAMToUSB_app(void *hdl, u8 *pBuf, u16 uCount)
{
return msd_mcu2usb(hdl, pBuf, uCount);
}
u8 MCU_USBToSRAM_app(void *hdl, u8 *pBuf, u16 uCount)
{
/* return msd_usb2mcu(hdl, pBuf, uCount); */
usb_dev usb_id = usb_device2id(hdl);
int ret;
int cnt = 10000;
while (cnt--) {
ret = usb_g_bulk_read(usb_id, MSD_BULK_EP_OUT, pBuf, uCount, 0);
if (ret) {
break;
}
}
// printf("%s,%d, ret:%d, cnt:%d \n", __func__, __LINE__, ret, cnt);
// put_buf(pBuf, ret);
return ret;
}
#endif
#endif