Files
6CAR/middleware/disk/disk_usb.c
2026-04-18 09:16:58 +08:00

196 lines
5.1 KiB
C

/**
* @file disk_usb.c
*
* Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*
* Description:
*
* Revision History:
* -----------------
*/
#include <Class/MSC/usbh_msc.h>
#include <debug.h>
#include <disk_usb.h>
#include <errno.h>
#include <param.h>
#include <types.h>
/* Maximum blocks of a single transmission */
#define USB_MAX_XFER_BLKS (240u)
#define disk_usb_err(...) ssdk_printf(SSDK_ERR, __VA_ARGS__)
#define disk_usb_warn(...) ssdk_printf(SSDK_WARNING, __VA_ARGS__)
static int disk_usb_read(struct disk_info *info, uint8_t *dst, disk_addr_t addr,
disk_size_t size)
{
USBH_MSC_DEV *p_msc_dev;
USBH_ERR err_usbh;
CPU_INT32U blk_off;
CPU_INT32U blk_cnt;
CPU_INT32U rd_blks;
p_msc_dev = (USBH_MSC_DEV *)info->private_data;
if (!p_msc_dev || !dst || !size) {
return -EINVAL;
}
blk_off = addr / info->block_align_size;
blk_cnt = size / info->block_align_size;
if ((addr != (disk_addr_t)blk_off * info->block_align_size) ||
(size != (disk_size_t)blk_cnt * info->block_align_size)) {
return -EINVAL;
}
if (!IS_ALIGNED(dst, CONFIG_ARCH_CACHE_LINE) ||
!IS_ALIGNED(dst + size, CONFIG_ARCH_CACHE_LINE)) {
disk_usb_warn(
"unaligned rx buffer %p ++ %llx may cause incorrect data\n", dst,
size);
}
while (blk_cnt > 0) {
rd_blks = blk_cnt > USB_MAX_XFER_BLKS ? USB_MAX_XFER_BLKS : blk_cnt;
(void)USBH_MSC_Rd(p_msc_dev, 0u, (CPU_INT32U)blk_off,
(CPU_INT16U)rd_blks,
(CPU_INT32U)info->block_align_size, dst, &err_usbh);
if (err_usbh != USBH_ERR_NONE) {
disk_usb_err("%s: Could not rd MSC dev, USB err: %d.\n", __func__,
err_usbh);
return -EIO;
}
blk_cnt -= rd_blks;
blk_off += rd_blks;
dst += rd_blks * info->block_align_size;
}
return 0;
}
static int disk_usb_write(struct disk_info *info, const uint8_t *src,
disk_addr_t addr, disk_size_t size)
{
USBH_MSC_DEV *p_msc_dev;
USBH_ERR err_usbh;
CPU_INT32U blk_off;
CPU_INT32U blk_cnt;
CPU_INT32U wr_blks;
p_msc_dev = (USBH_MSC_DEV *)info->private_data;
if (!p_msc_dev || !src || !size) {
return -EINVAL;
}
blk_off = addr / info->block_align_size;
blk_cnt = size / info->block_align_size;
if ((addr != (disk_addr_t)blk_off * info->block_align_size) ||
(size != (disk_size_t)blk_cnt * info->block_align_size)) {
return -EINVAL;
}
if (!IS_ALIGNED(src, CONFIG_ARCH_CACHE_LINE) ||
!IS_ALIGNED(src + size, CONFIG_ARCH_CACHE_LINE)) {
disk_usb_warn(
"unaligned tx buffer %p ++ %llx may cause incorrect data\n", src,
size);
}
while (blk_cnt > 0) {
wr_blks = blk_cnt > USB_MAX_XFER_BLKS ? USB_MAX_XFER_BLKS : blk_cnt;
(void)USBH_MSC_Wr(p_msc_dev, 0u, (CPU_INT32U)blk_off,
(CPU_INT16U)wr_blks,
(CPU_INT32U)info->block_align_size, src, &err_usbh);
if (err_usbh != USBH_ERR_NONE) {
printf("%s: Could not wr MSC dev, USB err: %d.\n", __func__,
err_usbh);
return -EIO;
}
blk_cnt -= wr_blks;
blk_off += wr_blks;
src += wr_blks * info->block_align_size;
}
return 0;
}
static int disk_usb_status(struct disk_info *info) { return DISK_STATUS_OK; }
static int disk_usb_ioctl(struct disk_info *info, uint32_t cmd, void *buff)
{
return 0;
}
static struct disk_operations disk_usb_ops = {
.disk_read = disk_usb_read,
.disk_write = disk_usb_write,
.disk_status = disk_usb_status,
.disk_ioctl = disk_usb_ioctl,
};
int register_usb_disk(struct disk_info *info)
{
USBH_MSC_DEV *p_msc_dev;
USBH_ERR err_usbh;
CPU_INT32U blk_nr, blk_sz;
int ret = 0;
if (!info->disk_name || !info->private_data) {
return -1;
}
p_msc_dev = (USBH_MSC_DEV *)info->private_data;
err_usbh = USBH_MSC_Init(p_msc_dev, 0u);
if (err_usbh != USBH_ERR_NONE) {
disk_usb_err("%s: Could not init MSC dev, USB err: %d.\n", __func__,
err_usbh);
return -err_usbh;
}
err_usbh = USBH_MSC_CapacityRd(p_msc_dev, 0u, &blk_nr, &blk_sz);
if (err_usbh != USBH_ERR_NONE) {
disk_usb_err("%s: Could not get MSC dev capacity, USB err: %d.\n",
__func__, err_usbh);
return -err_usbh;
}
info->cache = NULL;
info->disk_size = (uint64_t)blk_nr * blk_sz;
info->disk_offset = 0;
info->erase_size = blk_sz;
info->mem_align_size = CONFIG_ARCH_CACHE_LINE;
info->block_align_size = blk_sz;
info->disk_ops = &disk_usb_ops;
ret = register_disk(info);
if (ret < 0) {
disk_usb_err("usb disk register err:%d\n", ret);
return ret;
}
return 0;
}
int unregister_usb_disk(struct disk_info *info)
{
int ret = 0;
ret = unregister_disk(info);
if (ret < 0) {
disk_usb_err("usb disk unregister err:%d\n", ret);
return ret;
}
return ret;
}