doubao_chat/apps/common/usb/host/usb_storage.c

2532 lines
77 KiB
C
Raw Permalink 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.

/** * @file usb_storage.c
* @brief
* @author chenrixin@zh-jieli.com
* @version 1.00
* @date 2017-02-09
*/
#include "asm/includes.h"
#include "system/timer.h"
#include "device/ioctl_cmds.h"
#include "usb/host/usb_host.h"
#include "usb_ctrl_transfer.h"
#include "usb_bulk_transfer.h"
#include "device_drive.h"
#include "usb_storage.h"
#include "usb_config.h"
#include "app_config.h"
#if TCFG_UDISK_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"
static int set_stor_power(struct usb_host_device *host_dev, u32 value);
static int get_stor_power(struct usb_host_device *host_dev, u32 value);
static const struct interface_ctrl udisk_ops = {
.interface_class = USB_CLASS_MASS_STORAGE,
.set_power = set_stor_power,
.get_power = get_stor_power,
.ioctl = NULL,
};
static struct mass_storage mass_stor[USB_MAX_HW_NUM];//SEC(.usb_h_udisk);
static const struct usb_interface_info udisk_inf[USB_MAX_HW_NUM] = {
{
.ctrl = (struct interface_ctrl *) &udisk_ops,
.dev.disk = &mass_stor[0],
},
{
.ctrl = (struct interface_ctrl *) &udisk_ops,
.dev.disk = &mass_stor[1],
},
};
static struct device udisk_device[USB_MAX_HW_NUM];//SEC(.usb_h_udisk);
#define host_device2disk(host_dev) (udisk_inf[host_device2id(host_dev)].dev.disk)
/**
* @brief usb_stor_force_reset
*
* @param device
*
* @return
*/
static int usb_stor_force_reset(const usb_dev usb_id)
{
/* struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev); */
log_error("============usb_stor_force_reset===============\n");
return usb_host_force_reset(usb_id);
}
static void usb_stor_set_curlun(struct mass_storage *disk, u32 i)
{
disk->curlun = i;
}
static int usb_stor_get_curlun(struct mass_storage *disk)
{
return disk->curlun;
}
static int usb_stor_txmaxp(struct mass_storage *disk)
{
#if HUSB_MODE
if (disk == &mass_stor[0]) {
return 0x40;
} else {
return disk->udisk_ep.txmaxp;
}
#else
return 0x40;
#endif
}
static int usb_stor_rxmaxp(struct mass_storage *disk)
{
#if HUSB_MODE
if (disk == &mass_stor[0]) {
return 0x40;
} else {
return disk->udisk_ep.rxmaxp;
}
#else
return 0x40;
#endif
}
#define UDISK_MUTEX_TIMEOUT 5000/10 //5s
static int usb_h_mutex_pend(struct usb_host_device *host_dev)
{
struct mass_storage *disk = host_device2disk(host_dev);
/* putchar('{'); */
/* putchar('^'); */
/* putchar('['); */
int r = os_mutex_pend(&disk->mutex, UDISK_MUTEX_TIMEOUT);
if (r) {
log_error("-----------------%d -------------------", r);
}
if (r == OS_TIMEOUT) {
return OS_TIMEOUT;
}
return r;
}
static int usb_h_mutex_post(struct usb_host_device *host_dev)
{
struct mass_storage *disk = host_device2disk(host_dev);
/* putchar(']'); */
/* putchar('^'); */
/* putchar('}'); */
int r = os_mutex_post(&disk->mutex);
return r;
}
static int set_stor_power(struct usb_host_device *host_dev, u32 value)
{
struct mass_storage *disk = host_device2disk(host_dev);
log_debug("%s() %d ", __func__, disk->dev_status);
if (disk) {
disk->online = !!value;
}
if (disk == NULL || disk->dev_status == DEV_IDLE) {
return 0;
}
int r = usb_h_mutex_pend(host_dev);
if (disk->dev_status == DEV_READ || disk->dev_status == DEV_WRITE) {
if (value == -1) {
log_error("%s disk busy", __func__);
}
}
disk->dev_status = DEV_CLOSE;
log_debug("%s() %d ", __func__, disk->dev_status);
if (r == OS_TIMEOUT) {
return OS_TIMEOUT;
}
usb_h_mutex_post(host_dev);
return DEV_ERR_NONE;
}
static int get_stor_power(struct usb_host_device *host_dev, u32 value)
{
struct mass_storage *disk = host_device2disk(host_dev);
if (disk) {
return disk->online;
}
return DEV_ERR_NONE;
}
/**
* @brief usb_init_cbw
*
* @param device
*/
static void usb_init_cbw(struct device *device, u32 dir, u32 opcode, u32 length)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
memset(&disk->cbw, 0x00, sizeof(struct usb_scsi_cbw));
u32 curlun = usb_stor_get_curlun(disk);
disk->cbw.dCBWSignature = CBW_SIGNATURE;
disk->cbw.dCBWTag = rand32();
disk->cbw.bCBWLUN = curlun;
disk->cbw.lun = curlun << 5;
disk->cbw.bmCBWFlags = dir;
disk->cbw.operationCode = opcode;
disk->cbw.dCBWDataTransferLength = cpu_to_le32(length);
}
static int usb_stor_check_status(struct usb_host_device *host_dev)
{
struct mass_storage *disk = host_device2disk(host_dev);
if (!host_dev) {
return -DEV_ERR_NOT_MOUNT;
}
if (!disk) {
return -DEV_ERR_NOT_MOUNT;
}
if (disk->dev_status == DEV_IDLE) {
return -DEV_ERR_NOT_MOUNT;
} else if (disk->dev_status == DEV_CLOSE) {
return -DEV_ERR_NOT_MOUNT;
}
return 0;
}
static int usb_stor_reset(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
int ret = DEV_ERR_NONE;
if (disk == NULL) {
return -DEV_ERR_NOT_MOUNT;
}
//mass storage reset request
ret = set_msd_reset(host_dev);
return ret;
}
static int usb_stor_resume(struct device *device)
{
struct usb_device_descriptor device_desc;
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
u8 devnum = host_dev->private_data.devnum;
int ret = DEV_ERR_NONE;
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
usb_h_resume(usb_id);
ret = usb_get_device_descriptor(host_dev, &device_desc);
if (ret == 0) {
return ret;
}
usb_host_force_reset(usb_id);
ret = set_address(host_dev, devnum);
if (ret) {
log_error("%s() @ %d %x\n", __func__, __LINE__, ret);
usb_sie_close(usb_id);
return -ret;
}
ret = usb_get_device_descriptor(host_dev, &device_desc);
if (ret) {
log_error("%s() @ %d %x\n", __func__, __LINE__, ret);
usb_sie_close(usb_id);
return -ret;
}
return ret;
}
/**
* @brief usb_stor_inquiry
*
* @param device
*
* @return
*/
static int _usb_stor_inquiry(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = DEV_ERR_NONE;
struct inquiry_data inquiry;
log_info("usb_stor_inquiry disk =%x", (u32)disk);
u32 total_lun = disk->lun;
u32 init_lun = 0;
for (int i = 0; i <= total_lun; i ++) {
usb_stor_set_curlun(disk, i);
usb_init_cbw(device, USB_DIR_IN, INQUIRY, sizeof(struct inquiry_data));
disk->cbw.bCBWLength = 0x06;
disk->cbw.lba[2] = sizeof(struct inquiry_data);
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&inquiry,
sizeof(struct inquiry_data));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct inquiry_data)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
/* printf_buf(&inquiry, sizeof(struct inquiry_data)); */
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
if (inquiry.PeripheralDeviceType) {
if (init_lun == i) {
if (init_lun < total_lun) {
init_lun++;
} else {
init_lun = 0;
}
}
}
}
usb_stor_set_curlun(disk, init_lun);
return DEV_ERR_NONE;
__exit:
log_error("%s---%d\n", __func__, __LINE__);
return ret;
}
static int usb_stor_inquiry(struct device *device)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_inquiry(device);
usb_h_mutex_post(host_dev);
return ret;
}
/**
* @brief usb_stor_test_unit_ready
*
* @param device
*
* @return
*/
static int _usb_stor_test_unit_ready(struct device *device)
{
int ret = DEV_ERR_NONE;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
usb_init_cbw(device, 0, TEST_UNIT_READY, 0);
disk->cbw.bCBWLength = 6;
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
return DEV_ERR_NONE;
__exit:
log_error("%s---%d\n", __func__, __LINE__);
return ret;
}
static int usb_stor_test_unit_ready(struct device *device)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_test_unit_ready(device);
usb_h_mutex_post(host_dev);
return ret;
}
/**
* @brief usb_stor_mode_sense6
*
* @param device
*
* @return
*
* @brief disk write protect inquiry
*/
static int _usb_stor_mode_sense6(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
u8 *cdb;
int ret = DEV_ERR_NONE;
u8 data_buf[4];
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
usb_init_cbw(device, USB_DIR_IN, MODE_SENSE, 4);
disk->cbw.bCBWLUN = 6;
cdb = (u8 *)&disk->cbw.operationCode;
cdb[1] = 0; // PC | DBD
cdb[2] = 0x1c; //page code
cdb[3] = 0; //subpage code
cdb[4] = 192; //allocation length
cdb[5] = 0; //control;
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp, disk->udisk_ep.target_epin,
data_buf,
sizeof(data_buf));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->read_only = data_buf[2] == 0x80 ? 1 : 0; //write protect
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_NONE;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
return DEV_ERR_NONE;
__exit:
log_error("%s---%d\n", __func__, __LINE__);
return ret;
}
static int usb_stor_mode_sense6(struct device *device)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_mode_sense6(device);
usb_h_mutex_post(host_dev);
return ret;
}
/**
* @brief usb_stor_request_sense
*
* @param device
*
* @return
*/
static int _usb_stor_request_sense(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
int ret = DEV_ERR_NONE;
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
usb_init_cbw(device, USB_DIR_IN, REQUEST_SENSE, sizeof(struct request_sense_data));
disk->cbw.bCBWLength = 0xC;
disk->cbw.lba[2] = sizeof(struct request_sense_data);
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->sense,
sizeof(struct request_sense_data));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct request_sense_data)) {
ret = -DEV_ERR_NONE;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
/* printf_buf(&private_data->dev.disk->sense, sizeof(struct REQUEST_SENSE_DATA)); */
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
return DEV_ERR_NONE;
__exit:
log_error("%s---%d\n", __func__, __LINE__);
return ret;
}
static int usb_stor_request_sense(struct device *device)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_request_sense(device);
usb_h_mutex_post(host_dev);
return ret;
}
/**
* @brief usb_stor_read_capacity
*
* @param device
*
* @return
*/
static int _usb_stor_read_capacity(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
int ret = DEV_ERR_NONE;
if (disk == NULL) {
return -DEV_ERR_NOT_MOUNT;
}
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
u32 curlun = usb_stor_get_curlun(disk);
usb_init_cbw(device, USB_DIR_IN, READ_CAPACITY, 8);
disk->cbw.bCBWLength = 0xA;
disk->cbw.bmCBWFlags = USB_DIR_IN;
disk->cbw.operationCode = READ_CAPACITY;
disk->capacity[curlun].block_size = 0;
disk->capacity[curlun].block_num = 0;
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->capacity[curlun],
sizeof(struct read_capacity_data));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct read_capacity_data)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->capacity[curlun].block_size = be32_to_cpu(disk->capacity[curlun].block_size);
disk->capacity[curlun].block_num = be32_to_cpu(disk->capacity[curlun].block_num) + 1;
log_info("block_size=%d", disk->capacity[curlun].block_size);
log_info("block_num=%d", disk->capacity[curlun].block_num);
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
return DEV_ERR_NONE;
__exit:
log_error("%s---%d\n", __func__, __LINE__);
return ret;
}
static int usb_stor_read_capacity(struct device *device)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_read_capacity(device);
usb_h_mutex_post(host_dev);
return ret;
}
static int _usb_stro_read_cbw_request(struct device *device, u32 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
u32 cur_lba = lba;
int ret = 0;
disk->dev_status = DEV_READ;
disk->suspend_cnt = 0;
usb_init_cbw(device, USB_DIR_IN, READ_10, rx_len);
disk->cbw.bCBWLength = 0xA;
cur_lba = cpu_to_be32(cur_lba);
memcpy(disk->cbw.lba, &cur_lba, sizeof(cur_lba));
disk->cbw.LengthH = HIBYTE(num_lba);
disk->cbw.LengthL = LOBYTE(num_lba);
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d", __func__, __LINE__);
return ret;
}
return num_lba;
}
static int _usb_stro_read_csw(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = 0;
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d ret:%d\n", __func__, __LINE__, ret);
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
}
return ret;
}
static int _usb_stor_read_block_finish(struct device *device, u32 remain_len, u8 num_lba, void *pBuf)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = 0;
int len = num_lba * 512;
while (remain_len) {
//读完剩余的包,再开始下一次请求
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
len);
remain_len -= len;
if (remain_len == 0) {
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
}
}
return 0;
}
static int _usb_stor_read_big_block(struct device *device, u32 disk_block_size, void *pBuf, u8 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = 0;
u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
u8 num_block = disk_block_size / 512; //8
u8 req_offset = lba % num_block; //计算block数据偏移量
u8 send_cbw = 0;
if ((req_offset == 0) || (lba <= disk->prev_lba) || ((lba - disk->prev_lba) > num_block) || (disk->remain_len == 0)) {
//sector 4k地址;或地址不连续时(地址小于上一次地址; 地址和上一次地址不属于同一个sector)
send_cbw = 1;
} else {
//地址连续
send_cbw = 0;
}
/* y_printf("lba===%d prev_lba=%d req_offset===%d cbw:%d %d %d\n", */
/* lba, disk->prev_lba, req_offset, send_cbw, disk_block_size,disk->remain_len); */
disk->prev_lba = lba;
lba = lba / num_block;
if (send_cbw) {
_usb_stor_read_block_finish(device, disk->remain_len, num_lba, pBuf); //确保读完剩余包 */
disk->remain_len = 0;
disk->dev_status = DEV_READ;
disk->suspend_cnt = 0;
usb_init_cbw(device, USB_DIR_IN, READ_10, disk_block_size / 512 * 512);
disk->cbw.bCBWLength = 0xA;
lba = cpu_to_be32(lba);
memcpy(disk->cbw.lba, &lba, sizeof(lba));
disk->cbw.LengthH = HIBYTE(num_lba);
disk->cbw.LengthL = LOBYTE(num_lba);
//cbw
//请求disk_block_size 大小数据
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len = disk_block_size;
} else {
req_offset = 0; //地址连续时,读一次data
}
//data
do {
//循环读取,直到读取到偏移量所在的数据为止
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= rx_len;
} while (req_offset--);
if (!disk->remain_len) { //读完data,需要读csw
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
}
disk->dev_status = DEV_OPEN;
return num_lba;
__exit:
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d", __func__, __LINE__);
return 0;
}
int _usb_stor_async_wait_sem(struct usb_host_device *host_dev)
{
int ret = 0;
#if UDISK_READ_512_ASYNC_ENABLE
const usb_dev usb_id = host_device2id(host_dev);
if (get_async_mode(usb_id) == BULK_ASYNC_MODE_SEM_PEND) {
set_async_mode(usb_id, BULK_ASYNC_MODE_EXIT);
ret = usb_sem_pend(host_dev, 100);
if (ret) {
r_printf("usb async ret timeout %d", ret);
return -DEV_ERR_TIMEOUT;
}
}
#endif
return ret;
}
#if UDISK_READ_BIGBLOCK_ASYNC_ENABLE
static int _usb_stro_read_async(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = 0;
u8 read_block_num = UDISK_READ_ASYNC_BLOCK_NUM;
u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
/* r_printf("read lba : %d %d\n",lba,disk->remain_len); */
if ((lba != disk->async_prev_lba + 1) || disk->remain_len == 0) {
//这里要确保上次cbw 请求的数据读取完毕
//data
while (disk->remain_len) {
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
NULL,
rx_len);
disk->remain_len -= rx_len;
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
disk->remain_len = 0; //data 接收错误直接发csw
}
if (disk->remain_len == 0) {
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
}
break;
}
}
_usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
disk->remain_len = read_block_num * 512;
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= rx_len;
} else {
//地址连续,直接读取预读的数据
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= rx_len;
if (disk->remain_len == 0) {
//预读数据读完,发csw
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
}
}
disk->async_prev_lba = lba;
disk->dev_status = DEV_OPEN;
return num_lba;
__exit:
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d", __func__, __LINE__);
return 0;
}
#endif
#if UDISK_READ_512_ASYNC_ENABLE
static int _usb_stro_read_async(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
int ret = 0;
u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
u8 read_block_num = UDISK_READ_ASYNC_BLOCK_NUM;
/* r_printf("lba : %d %d\n",lba,disk->remain_len); */
if (_usb_stor_async_wait_sem(host_dev)) {
goto __exit;
}
if ((lba != disk->async_prev_lba + 1)) {
if (disk->remain_len == 0) {
if (disk->need_send_csw) {
//已取完data,需要发csw
ret = _usb_stro_read_csw(device);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d %d\n", __func__, __LINE__, ret);
goto __exit;
}
disk->need_send_csw = 0;
}
}
//这里要确保上次cbw 请求的数据读取完毕
//data
while (disk->remain_len) {
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
NULL,
rx_len);
disk->remain_len -= rx_len;
if (ret != rx_len) {
log_error("%s:%d %d\n", __func__, __LINE__, ret);
disk->remain_len = 0; //data 接收错误直接发csw
goto __exit;
}
if (disk->remain_len == 0) {
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
break;
}
}
ret = _usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len = read_block_num * 512;
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= rx_len;
if (disk->remain_len == 0) {
ret = _usb_stro_read_csw(device);
if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
}
} else {
memcpy(pBuf, disk->udisk_512_buf, rx_len);
if (disk->remain_len == 0) {
ret = _usb_stro_read_csw(device);
if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
}
}
disk->async_prev_lba = lba;
//异步预读
if (disk->remain_len == 0) {
ret = _usb_stro_read_cbw_request(device, read_block_num, lba + 1); //cbw
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len = read_block_num * 512;
}
//data
ret = usb_bulk_receive_async_no_wait(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
disk->udisk_512_buf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= rx_len;
if (disk->remain_len == 0) {
//data请求完,等待发送csw
disk->need_send_csw = 1;
}
disk->dev_status = DEV_OPEN;
return num_lba;
__exit:
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d", __func__, __LINE__);
return 0;
}
#endif
//****************************youning***********************************----->
#if UDISK_READ_AHEAD_ENABLE
static int _usb_stor_read_ahead_cbw(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
//log_info("func:%s,line:%d\n", __func__, __LINE__);
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 curlun = usb_stor_get_curlun(disk);
u8 read_block_num = UDISK_READ_AHEAD_BLOCK_NUM; //需要预读扇区数量
if (lba + read_block_num - 1 >= disk->capacity[curlun].block_num) {
read_block_num = disk->capacity[curlun].block_num - lba;
log_info("usb_read_ahead over capacity!!!%d,%d,%d\n", read_block_num, disk->capacity[curlun].block_num - 1, lba);
}
disk->remain_len = read_block_num * 512;
int ret = 0;
ret = _usb_stro_read_cbw_request(device, read_block_num, lba); //cbw
check_usb_read_ahead(ret);
return 0;
__exit:
return ret;
}
static int _usb_stor_read_ahead_data(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
//log_info("func:%s,line:%d\n", __func__, __LINE__);
if (num_lba == 0) {
return 0;
}
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
u32 rx_len = num_lba * 512;
int ret;
if (disk->remain_len != 0) {
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
check_usb_read_ahead(ret);
disk->remain_len -= rx_len;
disk->udisk_read_ahead_lba_last = lba + num_lba - 1;
}
if (disk->remain_len == 0) {
ret = _usb_stro_read_csw(device);
check_usb_read_ahead(ret);
}
return 0;
__exit:
return ret;
}
static int _usb_stor_read_ahead(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
//log_info("func:%s,line:%d\n", __func__, __LINE__);
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
int ret = 0;
if ((lba != disk->udisk_read_ahead_lba_last + 1) || disk->remain_len == 0) {
ret = _usb_stor_read_ahead_data(device, NULL, disk->remain_len / 512, lba); //预读中止,把上一次的剩下的读完
check_usb_read_ahead(ret);
ret = _usb_stor_read_ahead_cbw(device, pBuf, num_lba, lba);
check_usb_read_ahead(ret);
ret = _usb_stor_read_ahead_data(device, pBuf, num_lba, lba);
check_usb_read_ahead(ret);
} else {
ret = _usb_stor_read_ahead_data(device, pBuf, num_lba, lba);
check_usb_read_ahead(ret);
}
return num_lba; //read success
__exit:
return 0; //read error
}
#endif
//****************************youning***********************************<-----
/**
* @brief usb_stor_read 从U盘的lba扇区读取num_lba个扇区
*
* @param device 设备句柄
* @param pBuf 读buffer缓冲区,芯片所有memory都可以
* @param lba 需要读取的扇区地址
* @param num_lba 需要读取的扇区数量
*
* @return 负数表示失败
* 大于0的表示读取的字节数(Byte)
*/
static int _usb_stor_read(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
const u32 curlun = usb_stor_get_curlun(disk);
u8 read_retry = 0;
int ret;
u32 rx_cnt;
/* u32 rx_len = num_lba * disk->capacity[curlun].block_size; */
u32 rx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
if (disk->capacity[curlun].block_size > 512) {
// 扇区大于512Byte
return _usb_stor_read_big_block(device, disk->capacity[curlun].block_size, pBuf, num_lba, lba);
}
if (lba + num_lba - 1 >= disk->capacity[curlun].block_num) {
return -DEV_ERR_OVER_CAPACITY;
}
#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
if (disk->async_en) {
return _usb_stro_read_async(device, pBuf, num_lba, lba);
}
#endif
#if UDISK_READ_AHEAD_ENABLE
if (disk->udisk_read_ahead_en) {
return _usb_stor_read_ahead(device, pBuf, num_lba, lba);
}
#endif
ret = _usb_stro_read_cbw_request(device, num_lba, lba);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
pBuf,
rx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->dev_status = DEV_OPEN;
return num_lba;
__exit:
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d", __func__, __LINE__);
return 0;
}
static int usb_stor_read(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_read(device, pBuf, num_lba, lba);
usb_h_mutex_post(host_dev);
return ret;
}
/**
* @brief usb_stor_write 写数据到U盘
*
* @param device
* @param pBuf 数据buffer
* @param lba 需要写入的扇区地址
* @param num_lba 需要写入的扇区数量
*
* @return 负数表示写入失败
* 正数为写入的字节数 (Byte)
*/
static int _usb_stor_write(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
u32 ret;
const u32 txmaxp = usb_stor_txmaxp(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
const u32 curlun = usb_stor_get_curlun(disk);
if (lba + num_lba - 1 >= disk->capacity[curlun].block_num) {
log_error("%s %d", __func__, __LINE__);
return -DEV_ERR_OVER_CAPACITY;
}
if (disk->capacity[curlun].block_size > 512) {
log_error(" %s disk bolock size %d not support write", __func__, disk->capacity[curlun].block_size);
return -DEV_ERR_NO_WRITE;
}
if (disk->read_only) {
log_error("%s %d", __func__, __LINE__);
return -DEV_ERR_NO_WRITE;
}
/* u32 tx_len = num_lba * disk->capacity[curlun].block_size; */
u32 tx_len = num_lba * 512; //filesystem uses the fixed BLOCK_SIZE
#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
/* r_printf("write lba : %d %d txlen:%d\n",lba,disk->remain_len,tx_len); */
/* 确保预读read剩余的包读完,才开始写 */
_usb_stor_async_wait_sem(host_dev);
while (disk->remain_len) {
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
NULL,
tx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
disk->remain_len -= tx_len;
disk->need_send_csw = 1;
}
if (disk->remain_len == 0) {
//csw
if (disk->need_send_csw) {
ret = _usb_stro_read_csw(device);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
}
disk->need_send_csw = 0;
disk->async_prev_lba = 0;
}
#endif
#if UDISK_READ_AHEAD_ENABLE
if (disk->remain_len) {
_usb_stor_read_ahead_data(device, NULL, disk->remain_len / 512, disk->udisk_read_ahead_lba_last + 1); //预读中止,把上一次的剩下的读完
disk->udisk_read_ahead_lba_last = -1;
}
#endif
disk->dev_status = DEV_WRITE;
disk->suspend_cnt = 0;
usb_init_cbw(device, USB_DIR_OUT, WRITE_10, tx_len);
disk->cbw.bCBWLength = 0xA;
lba = cpu_to_be32(lba);
memcpy(disk->cbw.lba, &lba, sizeof(lba));
disk->cbw.LengthH = HIBYTE(num_lba);
disk->cbw.LengthL = LOBYTE(num_lba);
//cbw
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
(u8 *)&disk->cbw,
sizeof(struct usb_scsi_cbw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//data
ret = usb_bulk_only_send(device,
disk->udisk_ep.host_epout,
txmaxp,
disk->udisk_ep.target_epout,
pBuf,
tx_len);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
goto __exit;
}
if (disk->csw.bCSWStatus) {
ret = usb_stor_request_sense(device);
if (ret) {
ret = -DEV_ERR_OFFLINE;
}
if (ret == -DEV_ERR_OFFLINE) {
log_error("%s:%d\n", __func__, __LINE__);
goto __exit;
}
log_info("usb_stor_sense =%x", disk->sense.SenseKey);
return 0;
}
disk->dev_status = DEV_OPEN;
return num_lba;//DEV_ERR_NONE;
__exit:
if (disk->dev_status != DEV_CLOSE) {
disk->dev_status = DEV_OPEN;
}
log_error("%s---%d\n", __func__, __LINE__);
/* usb_stor_force_reset(usb_id); */
return 0;
}
static int usb_stor_write(struct device *device, void *pBuf, u32 num_lba, u32 lba)
{
int ret;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
ret = usb_stor_check_status(host_dev);
if (ret) {
return ret;
}
ret = usb_h_mutex_pend(host_dev);
if (ret == OS_TIMEOUT) {
return -OS_TIMEOUT;
}
ret = _usb_stor_write(device, pBuf, num_lba, lba);
usb_h_mutex_post(host_dev);
return ret;
}
#if ENABLE_DISK_HOTPLUG
static void usb_stor_tick_handle(void *arg)
{
struct device *device = (struct device *)arg;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);//(device);
const usb_dev usb_id = host_device2id(host_dev);
int ret;
r_printf("A");
if (disk == NULL) {
return;
}
r_printf("B");
if (disk->dev_status == DEV_OPEN) {
r_printf("C");
ret = usb_stor_read_capacity(device);
r_printf("D");
}
#if 0
#if 1
disk->suspend_cnt++;
if ((disk->suspend_cnt > 6) && (disk->dev_status == DEV_OPEN)) {
usb_h_entry_suspend(usb_id);
disk->suspend_cnt = 0;
disk->dev_status = DEV_SUSPEND;
}
#else
ret = usb_stor_test_unit_ready(device);
if (ret < DEV_ERR_NONE) {
return ;
}
if (disk->csw.bCSWStatus) {
usb_stor_request_sense(device);
/* puts("request sense\n"); */
/* put_buf((u8 *)&disk->sense, sizeof(disk->sense)); */
if ((disk->sense.SenseKey & 0x0f) == NOT_READY) {
if (disk->sense.ASC == 0x3a && disk->sense.ASCQ == 0x00) {
disk->media_sta_cur = 0;
}
} else if ((disk->sense.SenseKey & 0x0f) == UNIT_ATTENTION) {
if (disk->sense.ASC == 0x28 && disk->sense.ASCQ == 0x00) {
disk->media_sta_cur = 1;
}
}
} else {
disk->media_sta_cur = 1;
}
if (disk->media_sta_cur != disk->media_sta_prev) {
if (disk->media_sta_cur) {
log_info("udisk media insert");
usb_stor_read_capacity(device);
usb_stor_mode_sense6(device);
} else {
log_info("udisk media eject");
}
}
disk->media_sta_prev = disk->media_sta_cur;
#endif
#endif
}
#endif
/**
* @brief usb_stor_init
*
* @param device
*
* @return
*/
static int usb_stor_init(struct device *device)
{
int ret = DEV_ERR_NONE;
u32 state = 0;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
#if UDISK_READ_AHEAD_ENABLE
disk->udisk_read_ahead_lba_last = -1;
disk->remain_len = 0;
disk->udisk_read_ahead_en = 0;
#endif
if (!host_dev_status(host_dev)) {
return -DEV_ERR_OFFLINE;
}
const usb_dev usb_id = host_device2id(host_dev);
if (host_dev->private_data.status == 0) {
return -ENODEV;
}
if (!disk) {
log_error("%s not enough memory");
return -DEV_ERR_OUTOFMEMORY;
}
disk->dev_status = DEV_INIT;
disk->udisk_ep.epin_buf = usb_h_alloc_ep_buffer(usb_id, disk->udisk_ep.host_epin | USB_DIR_IN, disk->udisk_ep.rxmaxp * 2);
usb_write_rxfuncaddr(usb_id, disk->udisk_ep.host_epin, host_dev->private_data.devnum);
usb_h_ep_config(usb_id, disk->udisk_ep.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, disk->udisk_ep.epin_buf, disk->udisk_ep.rxmaxp);
disk->udisk_ep.epout_buf = usb_h_alloc_ep_buffer(usb_id, disk->udisk_ep.host_epout | USB_DIR_OUT, disk->udisk_ep.txmaxp);
usb_write_txfuncaddr(usb_id, disk->udisk_ep.host_epout, host_dev->private_data.devnum);
usb_h_ep_config(usb_id, disk->udisk_ep.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, disk->udisk_ep.epout_buf, disk->udisk_ep.txmaxp);
u8 lun = 0;
ret = get_msd_max_lun(host_dev, &lun);
if (ret != DEV_ERR_NONE) {
/* disk->dev_status = DEV_IDLE; */
/* usb_stor_force_reset(usb_id); */
log_error("ret = %d\n", ret);
/* return ret; */
}
disk->lun = lun;
int retry = 5;
while (retry) {
retry --;
if (ret == -DEV_ERR_OFFLINE) {
log_error("disk offline");
break;
}
switch (state) {
case 0:
log_info("--- inquery ---");
ret = usb_stor_inquiry(device);
if (ret < DEV_ERR_NONE) {
os_time_dly(30);
if (retry == 2) {
ret = -DEV_ERR_OFFLINE;
} else {
ret = DEV_ERR_NONE;
}
} else {
state++;
}
break;
case 1:
log_info("--- test unit ready ---");
ret = usb_stor_test_unit_ready(device);
if (ret < DEV_ERR_NONE) {
os_time_dly(50);
} else if (disk->csw.bCSWStatus) {
os_time_dly(50);
ret = usb_stor_request_sense(device);
if ((disk->sense.SenseKey & 0x0f) != NO_SENSE) {
if (disk->sense.SenseKey == NOT_READY) {
os_time_dly(30);
disk->curlun++;
if (disk->curlun > disk->lun) {
disk->curlun = 0;
}
}
}
} else {
state++;
}
break;
case 2:
log_info("--- read capacity ---");
ret = usb_stor_read_capacity(device);
if (ret < DEV_ERR_NONE) {
os_time_dly(50);
} else if (disk->csw.bCSWStatus) {
os_time_dly(50);
ret = usb_stor_request_sense(device);
if ((disk->sense.SenseKey & 0x0f) != NO_SENSE) {
os_time_dly(30);
}
} else {
log_info("udisk mount succ");
state = 0xff;
}
break;
default:
retry = 0;
break;
}
}
state = 0;
if (ret != DEV_ERR_NONE) {
disk->dev_status = DEV_IDLE;
/* usb_stor_force_reset(usb_id); */
log_error("ret = %d\n", ret);
if (disk->udisk_ep.epin_buf) {
usb_h_free_ep_buffer(usb_id, disk->udisk_ep.epin_buf);
disk->udisk_ep.epin_buf = NULL;
}
if (disk->udisk_ep.epout_buf) {
usb_h_free_ep_buffer(usb_id, disk->udisk_ep.epout_buf);
disk->udisk_ep.epout_buf = NULL;
}
} else {
/* disk->test_unit_ready_tick = sys_timer_add(device,usb_stor_tick_handle,200); */
#if ENABLE_DISK_HOTPLUG
disk->media_sta_cur = 1;
disk->media_sta_prev = 1;
#endif
}
disk->suspend_cnt = 0;
return ret;
}
/**
* @brief usb_stor_ioctrl
*
* @param device
* @param cmd 支持下面的命令
* |命令|功能|
* |---|---|
* |IOCTL_GET_ID|U盘位于总线的地址0表示不在线|
* |IOCTL_GET_BLOCK_SIZE|获取扇区大小|
* |IOCTL_GET_CAPACITY|获取磁盘容量|
* |IOCTL_GET_MAX_LUN|获取最大磁盘数量<最大支持两个磁盘>|
* |IOCTL_GET_CUR_LUN|获取当前的磁盘号|
* |IOCTL_SET_CUR_LUN|设置当前的磁盘号|
* @param arg
*
* @return 0----成功
* 其他值---失败-
*/
static int usb_stor_ioctrl(struct device *device, u32 cmd, u32 arg)
{
int ret = DEV_ERR_NONE;
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
u32 devnum = host_dev->private_data.devnum;
u32 curlun = usb_stor_get_curlun(disk);
const u32 rxmaxp = usb_stor_rxmaxp(disk);
if (disk == NULL) {
return -ENOTTY;
}
switch (cmd) {
case IOCTL_GET_ID:
*(u32 *)arg = devnum;
break;
case IOCTL_GET_BLOCK_SIZE:
*(u32 *)arg = disk->capacity[curlun].block_size;
break;
case IOCTL_GET_BLOCK_NUMBER:
*(u32 *)arg = disk->capacity[curlun].block_num;
break;
case IOCTL_GET_CAPACITY:
*(u32 *)arg = disk->capacity[curlun].block_num;
break;
case IOCTL_GET_MAX_LUN:
*(u32 *)arg = disk->lun;
break;
case IOCTL_GET_CUR_LUN:
*(u32 *)arg = curlun;
break;
case IOCTL_SET_CUR_LUN:
if (arg > disk->lun) {
return -EINVAL;
}
usb_stor_set_curlun(disk, arg);
ret = usb_stor_read_capacity(device);
if (ret < 0) {
log_error("usb disk unit%d is not ready", curlun);
return -EFAULT;
} else if (disk->csw.bCSWStatus) {
usb_stor_request_sense(device);
if (disk->sense.SenseKey != NO_SENSE) {
log_error("usb disk unit%d is not ready", curlun);
}
return -EFAULT;
}
/* usb_stor_mode_sense6(device); */
break;
case IOCTL_CHECK_WRITE_PROTECT:
if (disk->read_only) {
*(u32 *)arg = 1;
} else {
*(u32 *)arg = 0;
}
break;
case IOCTL_GET_STATUS:
#if ENABLE_DISK_HOTPLUG
if (disk->media_sta_cur) {
#else
if (1) {
#endif
log_info("usb disk unit%d is online", curlun);
*(u32 *)arg = 1;
} else {
log_info("usb disk unit%d is offline", curlun);
*(u32 *)arg = 0;
}
break;
case IOCTL_SET_FORCE_RESET:
ret = usb_stor_force_reset(usb_id);
break;
case IOCTL_SET_ASYNC_MODE:
g_printf(">> UDISK IOCTL_SET_ASYNC_MODE %d\n", arg);
#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
usb_h_mutex_pend(host_dev);
_usb_stor_async_wait_sem(host_dev);
if (arg == 0) {
if (disk->remain_len == 0) {
if (disk->need_send_csw) {
//已取完data,需要发csw
ret = _usb_stro_read_csw(device);
if (ret < DEV_ERR_NONE) {
log_error("%s:%d ret:%d\n", __func__, __LINE__, ret);
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
}
disk->need_send_csw = 0;
}
}
//这里要确保上次cbw 请求的数据读取完毕
//data
while (disk->remain_len) {
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
NULL,
512);
disk->remain_len -= 512;
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
disk->remain_len = 0; //data 接收错误直接发csw
}
if (disk->remain_len == 0) {
//csw
ret = usb_bulk_only_receive(device,
disk->udisk_ep.host_epin,
rxmaxp,
disk->udisk_ep.target_epin,
(u8 *)&disk->csw,
sizeof(struct usb_scsi_csw));
if (ret < DEV_ERR_NONE) {
log_error("%s:%d\n", __func__, __LINE__);
} else if (ret != sizeof(struct usb_scsi_csw)) {
ret = -DEV_ERR_UNKNOW;
log_error("%s:%d\n", __func__, __LINE__);
}
break;
}
}
}
disk->async_en = arg;
disk->async_prev_lba = MASS_LBA_INIT;
disk->need_send_csw = 0;
set_async_mode(usb_id, BULK_ASYNC_MODE_EXIT);
usb_h_mutex_post(host_dev);
#endif
#if UDISK_READ_AHEAD_ENABLE
/* printf("last lba %d, remain_len %d\n", disk->udisk_read_ahead_lba_last, disk->remain_len); */
usb_h_mutex_pend(host_dev);
if (arg == 0) {
u32 lba = disk->udisk_read_ahead_lba_last + 1;
/* printf("remain_len %d, lba %d\n", disk->remain_len, lba); */
ret = _usb_stor_read_ahead_data(device, NULL, disk->remain_len / 512, lba); //预读中止,把上一次的剩下的读完
check_usb_read_ahead(ret);
}
disk->udisk_read_ahead_lba_last = -1;
disk->udisk_read_ahead_en = arg;
usb_h_mutex_post(host_dev);
#endif
break;
default:
return -ENOTTY;
}
__exit:
return ret;
}
/**
* @brief usb_msd_parser
*
* @param device
* @param pBuf
*
* @return
*/
int usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
int len = sizeof(struct usb_interface_descriptor);
const usb_dev usb_id = host_device2id(host_dev);
udisk_device[usb_id].private_data = host_dev;
host_dev->interface_info[interface_num] = &udisk_inf[usb_id];
struct mass_storage *disk = host_device2disk(host_dev);
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
return -USB_DT_ENDPOINT;
}
len += USB_DT_ENDPOINT_SIZE;
pBuf += USB_DT_ENDPOINT_SIZE;
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (end_desc->bEndpointAddress & USB_DIR_IN) {
disk->udisk_ep.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
disk->udisk_ep.target_epin = end_desc->bEndpointAddress & 0x0f;
#if HUSB_MODE
disk->udisk_ep.rxmaxp = end_desc->wMaxPacketSize;
#endif
log_debug("D(%d)->H(%d)", disk->udisk_ep.target_epin, disk->udisk_ep.host_epin);
} else {
disk->udisk_ep.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
disk->udisk_ep.target_epout = end_desc->bEndpointAddress & 0x0f;
#if HUSB_MODE
disk->udisk_ep.txmaxp = end_desc->wMaxPacketSize;
#endif
log_debug("H(%d)->D(%d)", disk->udisk_ep.host_epout, disk->udisk_ep.target_epout);
}
}
}
return len;
}
/**
* @brief usb_stor_open
*
* @param node
* @param device
* @param arg
*
* @return
*/
static int usb_stor_open(const char *name, struct device **device, void *arg)
{
int ret;
if (name && name[5] == '1') {
*device = &udisk_device[1];
} else {
*device = &udisk_device[0];
}
struct usb_host_device *host_dev = device_to_usbdev(*device);
struct mass_storage *disk = host_device2disk(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
log_debug("=====================usb_stor_open===================== %d", disk->dev_status);
if (disk->dev_status != DEV_IDLE) {
*device = NULL;
if (disk->dev_status == DEV_CLOSE) {
log_error("%s() fail, disconnect\n", __func__);
return -DEV_ERR_NOT_MOUNT;
} else {
return DEV_ERR_NONE;
}
}
memset(&disk->mutex, 0, sizeof(disk->mutex));
os_mutex_create(&disk->mutex);
disk->remain_len = 0;
disk->prev_lba = 0;
#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
disk->async_prev_lba = MASS_LBA_INIT;
disk->need_send_csw = 0;
disk->async_en = 0; //默认关闭预读模式
set_async_mode(usb_id, BULK_ASYNC_MODE_EXIT);
#if UDISK_READ_512_ASYNC_ENABLE
if (!disk->udisk_512_buf) {
disk->udisk_512_buf = zalloc(512);
}
#endif
#endif
ret = usb_stor_init(*device);
if (ret) {
*device = NULL;
log_error("usb_stor_init err %d\n", ret);
return -ENODEV;
}
log_debug("device %x", (u32)*device);
log_debug("mass storage dev name %s", name);
usb_h_mutex_pend(host_dev);
disk->dev_status = DEV_OPEN;
usb_h_mutex_post(host_dev);
return DEV_ERR_NONE;
}
/**
* @brief usb_stor_close
*
* @param device
*
* @return
*/
static int usb_stor_close(struct device *device)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
struct mass_storage *disk = host_device2disk(host_dev);
int ret;
if (disk->dev_status == DEV_IDLE) {
return 0;
}
log_info("=====================usb_stor_close=====================");
if (disk) {
log_info("=====================usb_stor_close===================== 333");
ret = usb_h_mutex_pend(host_dev);
const usb_dev usb_id = host_device2id(host_dev);
usb_clr_intr_rxe(usb_id, disk->udisk_ep.host_epin);
disk->dev_status = DEV_IDLE;
if (disk->udisk_ep.epin_buf) {
usb_h_free_ep_buffer(host_device2id(host_dev), disk->udisk_ep.epin_buf);
disk->udisk_ep.epin_buf = NULL;
}
if (disk->udisk_ep.epout_buf) {
usb_h_free_ep_buffer(host_device2id(host_dev), disk->udisk_ep.epout_buf);
disk->udisk_ep.epout_buf = NULL;
}
if (ret != OS_ERR_NONE) {
log_error("disk close pend timeout!!!\n");
} else {
usb_h_mutex_post(host_dev);
}
log_info("=====================usb_stor_close===================== 1222 ");
os_mutex_del(&disk->mutex, 0);
memset(&disk->mutex, 0, sizeof(disk->mutex));
#if UDISK_READ_512_ASYNC_ENABLE
if (disk->udisk_512_buf) {
free(disk->udisk_512_buf);
disk->udisk_512_buf = NULL;
}
#endif
}
return DEV_ERR_NONE;
}
static bool usb_stor_online(const struct dev_node *node)
{
struct device *device;
if (node->name && node->name[5] == '1') {
device = &udisk_device[1];
} else {
device = &udisk_device[0];
}
struct usb_host_device *host_dev;
struct mass_storage *disk;
host_dev = device_to_usbdev(device);
if (!host_dev) {
return false;
}
disk = host_device2disk(host_dev);
if (disk) {
return disk->online;
/* return true;//disk->media_sta_cur ? true : false; */
}
return false;
}
const struct device_operations mass_storage_ops = {
.init = NULL,
.online = usb_stor_online,
.open = usb_stor_open,
.read = usb_stor_read,
.write = usb_stor_write,
.ioctl = usb_stor_ioctrl,
.close = usb_stor_close,
};
static u8 usb_stor0_idle_query(void)
{
struct device *device = &udisk_device[0];
struct usb_host_device *host_dev = device_to_usbdev(device);
if (!host_dev) {
return true;
}
struct mass_storage *disk = host_device2disk(host_dev);
if (disk) {
return (disk->dev_status == DEV_IDLE) ? true : false;
}
return true;
}
REGISTER_LP_TARGET(usb_stor0_lp_target) = {
.name = "udisk0",
.is_idle = usb_stor0_idle_query,
};
static u8 usb_stor1_idle_query(void)
{
struct device *device = &udisk_device[1];
struct usb_host_device *host_dev = device_to_usbdev(device);
if (!host_dev) {
return true;
}
struct mass_storage *disk = host_device2disk(host_dev);
if (disk) {
return (disk->dev_status == DEV_IDLE) ? true : false;
}
return true;
}
REGISTER_LP_TARGET(usb_stor1_lp_target) = {
.name = "udisk1",
.is_idle = usb_stor1_idle_query,
};
#if 0
#include "event/device_event.h"
#define UDISK_SPEED_TEST_EN 1 //速度测试总控使能
#define UDISK_W_TIME_EN 1 //写入速度测试使能
#define UDISK_R_TIME_EN 1 //读取速度测试使能
#define UDISK_W_EN UDISK_W_TIME_EN
#define UDISK_R_EN UDISK_R_TIME_EN
#define BLOCKS_TO_KICKSTARTS 64 //多少块统计一次时间
#define TOTAL_TEST_TIME (20 * 1024 * 1024)
#define READ_WRITE_ONCE_BYTES (4 * 1024)
static u8 msd_test_buf[READ_WRITE_ONCE_BYTES * 2];
static JL_TIMER_TypeDef *pTimer;
static u32 timer_irq_idx;
static u32 t_counter;
static u32 wr_blocks;
static u32 rd_blocks;
static u32 wr_time;
static u32 rd_time;
static u32 wr_KBps_min;
static u32 rd_KBps_min;
static u32 wr_KBps_max;
static u32 rd_KBps_max;
static u32 wr_KBps_avg;
static u32 rd_KBps_avg;
___interrupt
void udisk_speed_test_irq()
{
pTimer->CON |= BIT(14);
t_counter++;
}
void udisk_speed_test_init()
{
int i = 0;
JL_TIMER_TypeDef *tregs[] = {
JL_TIMER0, JL_TIMER1, JL_TIMER2, JL_TIMER3,
JL_TIMER4, JL_TIMER5,
};
u32 tmr_irq_idx_tbl[6] = {
IRQ_TIMER0_IDX, IRQ_TIMER1_IDX, IRQ_TIMER2_IDX, IRQ_TIMER3_IDX,
IRQ_TIMER4_IDX, IRQ_TIMER5_IDX,
};
wr_blocks = 0;
rd_blocks = 0;
wr_time = 0;
rd_time = 0;
t_counter = 0;
wr_KBps_min = 0xffffffff;
rd_KBps_min = 0xffffffff;
wr_KBps_max = 0;
rd_KBps_max = 0;
wr_KBps_avg = 0;
rd_KBps_avg = 0;
timer_irq_idx = tmr_irq_idx_tbl[5];
for (i = 0; i < 6; i++) {
pTimer = tregs[5 - i];
if ((pTimer->CON & 3) == 0) {
timer_irq_idx = tmr_irq_idx_tbl[5 - i];
break;
}
}
if (i == 6) {
log_error("find idle timer fail\n");
pTimer = NULL;
return;
}
log_info("lsb clock %d\n", clk_get("lsb"));
log_info("timer%d is found\n", 5 - i);
request_irq(timer_irq_idx, 7, udisk_speed_test_irq, 0);
pTimer->CNT = 0;
pTimer->PRD = clk_get("lsb") / 4 * 10 / 1000; //10ms
pTimer->CON = (1 << 4) | (1 << 10) | (1 << 14); //sel lsb_clk, div4
}
void udisk_speed_test_uninit()
{
if (pTimer) {
unrequest_irq(timer_irq_idx, 0);
pTimer->CON = BIT(14);
pTimer = NULL;
}
}
void udisk_speed_test_probe()
{
if (pTimer) {
t_counter = 0;
pTimer->CNT = 0;
pTimer->CON |= BIT(0) | BIT(14);
}
}
u32 udisk_speed_test_capture()
{
u32 time = 0;
if (pTimer) {
pTimer->CON &= ~BIT(0);
time = (t_counter * pTimer->PRD + pTimer->CNT) / (clk_get("lsb") / 4000000); //unit in us
}
return time;
}
void udisk_write_speed_dump(u32 cur_time, u32 numOflba)
{
u32 KBps = 0;
if (pTimer) {
wr_time += cur_time;
wr_blocks += numOflba;
if (wr_blocks >= BLOCKS_TO_KICKSTARTS) {
// Bytes/us = (KB/1024)/(s/1000000) = KB/s * (1000000/1024) =
// KB/s * (16075 / 16) = (15625 / 16) KB/s
KBps = (wr_blocks * 512) * 15625 / 16 / wr_time;
log_info("w: %d blocks, t %d us, %d KB/s\n", wr_blocks, wr_time, KBps);
if (KBps < wr_KBps_min) {
wr_KBps_min = KBps;
}
if (KBps > wr_KBps_max) {
wr_KBps_max = KBps;
}
wr_KBps_avg = (wr_KBps_avg + KBps) / 2;
wr_time = 0;
wr_blocks = 0;
}
}
}
void udisk_read_speed_dump(u32 cur_time, u32 numOflba)
{
u32 KBps = 0;
if (pTimer) {
rd_time += cur_time;
rd_blocks += numOflba;
if (rd_blocks >= BLOCKS_TO_KICKSTARTS) {
// Bytes/us = (KB/1024)/(s/1000000) = KB/s * (1000000/1024) =
// KB/s * (16075 / 16) = (15625 / 16) KB/s
KBps = (rd_blocks * 512) * 15625 / 16 / rd_time;
log_info("r: %d blocks, t %d us, %d KB/s\n", rd_blocks, rd_time, KBps);
if (KBps < rd_KBps_min) {
rd_KBps_min = KBps;
}
if (KBps > rd_KBps_max) {
rd_KBps_max = KBps;
}
rd_KBps_avg = (rd_KBps_avg + KBps) / 2;
rd_time = 0;
rd_blocks = 0;
}
}
}
void udisk_speed_summary_dump()
{
log_info("w: min %d, max %d, avg %d\n", wr_KBps_min, wr_KBps_max, wr_KBps_avg);
log_info("r: min %d, max %d, avg %d\n", rd_KBps_min, rd_KBps_max, rd_KBps_avg);
}
void usb_host_test()
{
___usb_test:
usb_host_mount(0, 3, 20, 200);
struct device *device;
usb_stor_open("udisk0", &device, NULL);
log_info("%s---%d\n", __func__, __LINE__);
u32 lba = 0;
while (1) {
u32 *p = (u32 *)msd_test_buf;
u32 numOflba = sizeof(msd_test_buf) / 512;
if ((usb_stor_read(device, p, numOflba, lba)) != numOflba) {
printf("read error %d", lba);
while (1);
}
#if 1
if (usb_stor_write(device, p, numOflba, lba) != numOflba) {
printf("write error %d", lba);
while (1);
}
if ((usb_stor_read(device, p, numOflba, lba)) != numOflba) {
printf("read error %d", lba);
while (1);
}
#endif
for (int i = 0; i < numOflba * 512 / 4; i++) {
if (p[i] != (i + lba * 0x80)) {
printf("@lba:%x offset %x %x != %x ", lba, i, p[i], i + lba * 0x80);
/* put_buf(p, numOflba * 512); */
/* while (1); */
}
}
wdt_clear();
lba += numOflba;
}
}
void usb_host_test2(u8 usbid)
{
int err = 0;
struct device *device;
char dev_name[16] = "udisk#";
log_info("udisk test start\n");
dev_name[5] = '0' + usbid;
err = usb_stor_open(dev_name, &device, NULL);
if (err) {
return;
}
//测试起始地址
u32 lba = 0;
//每一次读写大小(byte)
u32 numOflba = READ_WRITE_ONCE_BYTES / 512;
ASSERT(numOflba * 512 * 2 <= sizeof(msd_test_buf));
u32 *p1 = (u32 *)((u32)msd_test_buf);
u32 *p2 = (u32 *)((u32)msd_test_buf + numOflba * 512);
u32 seed;
u32 block_num = 0;
u32 block_size = 0;
//总测试数据量(byte),设一个较大的值可用于煲机测试
u32 test_size = TOTAL_TEST_TIME;
u32 xus = 0;
extern void wdt_clear();
usb_stor_ioctrl(device, IOCTL_GET_BLOCK_NUMBER, (u32)&block_num);
usb_stor_ioctrl(device, IOCTL_GET_BLOCK_SIZE, (u32)&block_size);
log_info("block_num %d, block_size %d\n", block_num, block_size);
#if UDISK_SPEED_TEST_EN
udisk_speed_test_init();
#endif
test_size /= 512;
while (test_size) {
if (numOflba > test_size) {
numOflba = test_size;
}
seed = rand32();
for (int i = 0; i < numOflba * 512 / 4; i++) {
p1[i] = seed + i;
}
#if UDISK_SPEED_TEST_EN && UDISK_W_TIME_EN
udisk_speed_test_probe();
#endif
#if UDISK_W_EN
err = usb_stor_write(device, (u8 *)p1, numOflba, lba);
if (err != numOflba) {
log_error("udisk write fail, lba %x, err %d\n", lba, err);
while (1) {
wdt_clear();
}
}
#endif
#if UDISK_SPEED_TEST_EN && UDISK_W_TIME_EN
xus = udisk_speed_test_capture();
udisk_write_speed_dump(xus, numOflba);
#endif
/* wdt_clear(); */
memset((u8 *)p2, 0, numOflba * 512);
#if UDISK_SPEED_TEST_EN && UDISK_R_TIME_EN
udisk_speed_test_probe();
#endif
#if UDISK_R_EN
err = usb_stor_read(device, (u8 *)p2, numOflba, lba);
if (err != numOflba) {
log_error("udisk read fail, lba %x, err %d\n", lba, err);
while (1) {
wdt_clear();
}
}
#endif
#if UDISK_SPEED_TEST_EN && UDISK_R_TIME_EN
xus = udisk_speed_test_capture();
udisk_read_speed_dump(xus, numOflba);
#endif
/* wdt_clear(); */
#if UDISK_W_EN && UDISK_R_EN
for (int i = 0; i < numOflba * 512 / 4; i++) {
if (p1[i] != p2[i]) {
log_info("udisk read/write data different, lba %x, offset %x, offset %% 16 = %x\n", lba, i * 4, i * 4 % 16);
printf_buf(&((u8 *)p1)[i * 4 / 16 * 16 - 32], 64);
printf("-----------------------------\n");
printf_buf(&((u8 *)p2)[i * 4 / 16 * 16 - 32], 64);
while (1) {
wdt_clear();
}
}
}
log_info("lba %d pass\n", lba);
#endif
lba += numOflba;
test_size -= numOflba;
}
log_info("udisk test pass\n");
__exit:
#if UDISK_SPEED_TEST_EN
udisk_speed_summary_dump();
udisk_speed_test_uninit();
#endif
usb_stor_close(device);
}
static int udisk_test_event_handler(struct sys_event *e)
{
struct device_event *event = (struct device_event *)e->payload;
char *usb_msg;
u8 usbid;
if (e->from == DEVICE_EVENT_FROM_OTG) {
usb_msg = (char *)event->value;
usbid = usb_msg[2] - '0';
if (usb_msg[0] == 'h') {
if (event->event == DEVICE_EVENT_IN) {
if (!usb_host_mount(usbid, 3, 56, 50)) {
usb_host_test2(usbid);
}
} else if (event->event == DEVICE_EVENT_OUT) {
usb_host_unmount(usbid);
}
}
}
return -EINVAL;
}
SYS_EVENT_STATIC_HANDLER_REGISTER(udisk_test) = {
.event_type = SYS_DEVICE_EVENT,
.prob_handler = udisk_test_event_handler,
.post_handler = NULL,
};
#endif
#endif