1802 lines
52 KiB
C
1802 lines
52 KiB
C
/** * @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);
|
||
|
||
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 = {0};//SEC(.usb_h_udisk);
|
||
|
||
static const struct usb_interface_info udisk_inf = {
|
||
.ctrl = (struct interface_ctrl *) &udisk_ops,
|
||
.dev.disk = &mass_stor,
|
||
};
|
||
|
||
static struct device udisk_device ;//SEC(.usb_h_udisk);
|
||
static struct udisk_end_desc udisk_ep ;//SEC(.usb_h_udisk);
|
||
|
||
#define host_device2disk(host_dev) (udisk_inf.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_h_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
|
||
return udisk_ep.txmaxp;
|
||
#else
|
||
return 0x40;
|
||
#endif
|
||
}
|
||
static int usb_stor_rxmaxp(struct mass_storage *disk)
|
||
{
|
||
#if HUSB_MODE
|
||
return 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 == 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)
|
||
{
|
||
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 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_h_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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp, 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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
udisk_ep.target_epin,
|
||
pBuf,
|
||
len);
|
||
remain_len -= len;
|
||
if (remain_len == 0) {
|
||
//csw
|
||
ret = usb_bulk_only_receive(device,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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;
|
||
return ret;
|
||
}
|
||
|
||
#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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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
|
||
|
||
/**
|
||
* @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_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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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_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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epout,
|
||
txmaxp,
|
||
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,
|
||
udisk_ep.host_epin,
|
||
rxmaxp,
|
||
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
|
||
*/
|
||
int usb_stor_init(struct device *device)
|
||
{
|
||
log_debug("%s---%d\n", __func__, __LINE__);
|
||
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
|
||
log_error("%s() disk = %x", __func__, disk);
|
||
|
||
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;
|
||
|
||
const u32 txmaxp = usb_stor_txmaxp(disk);
|
||
const u32 rxmaxp = usb_stor_rxmaxp(disk);
|
||
|
||
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(retry);
|
||
if (retry == 3) {
|
||
ret = -DEV_ERR_OFFLINE;
|
||
}
|
||
} 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);
|
||
} 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_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;
|
||
}
|
||
|
||
return ret;
|
||
|
||
__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 = 0;
|
||
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
||
udisk_device.private_data = host_dev;
|
||
|
||
host_dev->interface_info[interface_num] = &udisk_inf;
|
||
|
||
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) {
|
||
udisk_ep.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
|
||
udisk_ep.target_epin = end_desc->bEndpointAddress & 0x0f;
|
||
#if HUSB_MODE
|
||
udisk_ep.rxmaxp = end_desc->wMaxPacketSize;
|
||
#endif
|
||
log_debug("D(%d)->H(%d)", udisk_ep.target_epin, udisk_ep.host_epin);
|
||
} else {
|
||
udisk_ep.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
|
||
udisk_ep.target_epout = end_desc->bEndpointAddress & 0x0f;
|
||
#if HUSB_MODE
|
||
udisk_ep.txmaxp = end_desc->wMaxPacketSize;
|
||
#endif
|
||
log_debug("H(%d)->D(%d)", udisk_ep.host_epout, udisk_ep.target_epout);
|
||
}
|
||
}
|
||
}
|
||
u8 *ep_buffer = usb_h_get_ep_buffer(usb_id, udisk_ep.host_epin | USB_DIR_IN);
|
||
usb_h_ep_config(usb_id, udisk_ep.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
|
||
|
||
|
||
ep_buffer = usb_h_get_ep_buffer(usb_id, udisk_ep.host_epout | USB_DIR_OUT);
|
||
usb_h_ep_config(usb_id, udisk_ep.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, ep_buffer, 64);
|
||
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;
|
||
*device = &udisk_device;
|
||
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);
|
||
log_debug("=====================usb_stor_open===================== %d", disk->dev_status);
|
||
if (disk->dev_status != DEV_IDLE) {
|
||
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;
|
||
ret = usb_stor_init(*device);
|
||
if (ret) {
|
||
log_error("usb_stor_init err %d\n", ret);
|
||
return -ENODEV;
|
||
}
|
||
log_debug("device %x", (u32)*device);
|
||
|
||
|
||
usb_h_mutex_pend(host_dev);
|
||
if (*device) {
|
||
log_error("mass storage dev name %s", name);
|
||
disk->dev_status = DEV_OPEN;
|
||
usb_h_mutex_post(host_dev);
|
||
return DEV_ERR_NONE;
|
||
} else {
|
||
usb_h_mutex_post(host_dev);
|
||
return -ENODEV;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief usb_stor_close
|
||
*
|
||
* @param device
|
||
*
|
||
* @return
|
||
*/
|
||
static int usb_stor_close(struct device *device)
|
||
{
|
||
log_debug("%s---%d\n", __func__, __LINE__);
|
||
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, udisk_ep.host_epin);
|
||
|
||
disk->dev_status = DEV_IDLE;
|
||
|
||
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));
|
||
}
|
||
return DEV_ERR_NONE;
|
||
}
|
||
|
||
static bool usb_stor_online(const struct dev_node *node)
|
||
{
|
||
struct device *device = &udisk_device;
|
||
struct mass_storage *disk = udisk_inf.dev.disk;;
|
||
if (disk) {
|
||
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_stor_idle_query(void)
|
||
{
|
||
struct device *device = &udisk_device;
|
||
struct mass_storage *disk = host_device2disk(host_dev);
|
||
if (disk) {
|
||
return (disk->dev_status == DEV_IDLE) ? true : false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
REGISTER_LP_TARGET(usb_stor_lp_target) = {
|
||
.name = "udisk",
|
||
.is_idle = usb_stor_idle_query,
|
||
};
|
||
|
||
#if 0
|
||
u32 usb_host_mount(const usb_dev id, u32 retry, u32 reset_delay, u32 mount_timeout);
|
||
extern u8 msd_test_buf[32 * 1024];
|
||
void dump_usb_buf();
|
||
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;
|
||
}
|
||
}
|
||
#endif
|
||
#endif
|