U 盘

news/2024/10/23 10:18:55

目录
  • 1 USB 大容量存储设备
  • 2 设备描述符
  • 3 字符串描述符
  • 4 配置描述符集合
    • 4.1 配置描述符
    • 4.2 接口描述符
    • 4.3 端点描述符
  • 6 类特殊请求
    • 6.1 Get Max LUN 请求
    • 6.2 Bulk-Only Mass Storage Reset 请求
  • 7 Bulk-Only 传输协议的数据流模型
    • 7.1 CBW 的结构
    • 7.2 CSW 的结构
    • 7.3 对批量数据的处理
  • 8 SCSI 命令集和 UFI 命令集
    • 8.1 查询命令 INQUIRY
    • 8.2 读格式化容量命令 READ FORMAT CAPACITIES
    • 8.3 读容量命令 READ CAPACITY
    • 8.4 READ(10) 命令
    • 8.5 WRITE(10) 命令
    • 8.6 REQUEST SENSE 命令
    • 8.7 TEST UNIT READY 命令
  • 9 FAT 文件系统
    • 9.1 关于 DBR
    • 9.2 关于 FAT 表
    • 9.3 关于目录项
  • 总结

《圈圈教你学USB》 第 8 章学习笔记。这篇文章我们会结合 daplink 源码来看。

1 USB 大容量存储设备

  • 1)USB 协议规定的大容量存储设备(Mass Storage Device,MSD)包括:U 盘、USB 移动硬盘、USB 移动光驱。

  • 2)MSD 设备的接口描述符中,有以下取值:

    • (1)接口类(bInterfaceClass):0x08 表示 MSD 设备
    • (2)接口子类(bInterfaceSubClass):0x06 表示 SCSI(Small Computer System Interface,小型计算机系统接口) 命令集
    • (3)接口协议(bInterfaceProtocol):0x00/0x01 需要使用中断传输;0x05 仅使用批量传输

2 设备描述符

1)设备描述符的结构如下表:

2)设备描述符在 daplink 中的实现(位于 source/usb/usb_lib.c 文件):

/* USB Device Standard Descriptor */
__WEAK \
const U8 USBD_DeviceDescriptor[] = {USB_DEVICE_DESC_SIZE,                 /* bLength */USB_DEVICE_DESCRIPTOR_TYPE,           /* bDescriptorType */
#if (USBD_BOS_ENABLE)WBVAL(0x0210), /* 2.10 */             /* bcdUSB */
#elif ((USBD_HS_ENABLE) || (USBD_MULTI_IF))WBVAL(0x0200), /* 2.00 */             /* bcdUSB */
#elseWBVAL(0x0110), /* 1.10 */             /* bcdUSB */
#endif
#if (USBD_MULTI_IF)USB_DEVICE_CLASS_MISCELLANEOUS,       /* bDeviceClass */0x02,                                 /* bDeviceSubClass */0x01,                                 /* bDeviceProtocol */
#elif (USBD_CDC_ACM_ENABLE)USB_DEVICE_CLASS_COMMUNICATIONS,      /* bDeviceClass CDC*/0x00,                                 /* bDeviceSubClass */0x00,                                 /* bDeviceProtocol */
#else0x00,                                 /* bDeviceClass */0x00,                                 /* bDeviceSubClass */0x00,                                 /* bDeviceProtocol */
#endifUSBD_MAX_PACKET0,                     /* bMaxPacketSize0 */WBVAL(USBD_DEVDESC_IDVENDOR),         /* idVendor */WBVAL(USBD_DEVDESC_IDPRODUCT),        /* idProduct */WBVAL(USBD_DEVDESC_BCDDEVICE),        /* bcdDevice */0x01,                                 /* iManufacturer */0x02,                                 /* iProduct */0x03 * USBD_STRDESC_SER_ENABLE,       /* iSerialNumber */0x01                                  /* bNumConfigurations: one possible configuration*/
};

3 字符串描述符

在 daplink 中的实现由于篇幅原因不再展示,感兴趣的可以在 source/usb/usb_lib.c 文件中找 USBD_StringDescriptor 即可。

4 配置描述符集合

要想找到 daplink 中描述符的实现位置,可以首先找到定义在 source/usb/usb_def.h 文件中的 USB Descriptor Types(USB 描述符类型),然后根据这些类型来找到各个描述符。

4.1 配置描述符

1)配置描述符的结构:

2)配置描述符实现(见 source/usb/usb_lib.c 文件中的 start_desc_fill() 函数):

const U8 start_desc[] = {/* Configuration 1 */USB_CONFIGUARTION_DESC_SIZE,                // bLengthUSB_CONFIGURATION_DESCRIPTOR_TYPE,          // bDescriptorTypeWBVAL(USBD_WTOTALLENGTH_MAX),               // wTotalLengthUSBD_IF_NUM_MAX,                            // bNumInterfaces0x01,                                       // bConfigurationValue: 0x01 is used to select this configuration0x00,                                       // iConfiguration: no string to describe this configurationUSBD_CFGDESC_BMATTRIBUTES |                 // bmAttributes(USBD_POWER << 6),USBD_CFGDESC_BMAXPOWER                      // bMaxPower, device power consumption
};

4.2 接口描述符

1)接口描述符的结构:

2)daplink 中,在 source/usb/usb_lib.c 文件定义了许多种接口描述符:HID(人机交互设备)、WEBUSB(网页端USB)、MSC(大容量设备类)、BULK(批量设备类)、ADC(音频设备类)、CDC_ACM(通信设备类)。

4.3 端点描述符

1)端点描述符的结构:

2)daplink 中,每个接口描述符后都会跟着端点描述符,比如我们的 MSC 接口描述符后面的端点描述符如下:

#define MSC_EP                          /* MSC Endpoints for Low-speed/Full-speed */                        \
/* Endpoint, EP Bulk IN */                                                                                  \USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \USB_ENDPOINT_IN(USBD_MSC_EP_BULKIN),  /* bEndpointAddress */                                              \USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \WBVAL(USBD_MSC_WMAXPACKETSIZE),       /* wMaxPacketSize */                                                \0x00,                                 /* bInterval: ignore for Bulk transfer */                           \\
/* Endpoint, EP Bulk OUT */                                                                                 \USB_ENDPOINT_DESC_SIZE,               /* bLength */                                                       \USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */                                               \USB_ENDPOINT_OUT(USBD_MSC_EP_BULKOUT),/* bEndpointAddress */                                              \USB_ENDPOINT_TYPE_BULK,               /* bmAttributes */                                                  \WBVAL(USBD_MSC_WMAXPACKETSIZE),       /* wMaxPacketSize */                                                \0x00,                                 /* bInterval: ignore for Bulk transfer */

6 类特殊请求

第 1 章我们知道:
(1)USB 以包为基本单位来传输,多个包组成事务来保证传输完整性,同时包又可以分成不同的域。
(2)包的结构为:同步域 + 包标识符(PID,Packet Identifier) + [域] + 包结束符 EOP(End Of Packet)。
(3)根据包 PID 的不同可以将包分为:令牌包、数据包、握手包、特殊包。

第 3 章我们知道:
设备请求(结构见下图):可以通过 bmRequestType 的 bit[6:5] 来设置请求类型。如为 0 时为标准请求;为 1 时为类请求。

这一节将介绍 2 个类特殊请求(即 bmRequestType 的 bit[6:5] = 1)。
在 MSD 设备的 Bulk Only Transprot 协议中,规定了 2 个类特殊请求:Bulk-Only Mass Storage Reset(复位到命令状态) 和 Get Max LUN(获取最大逻辑单元)。

在 daplink 的 source/usb/usbd_core.c 文件的 USBD_EndPoint0() 函数中,可以看到 标准请求、类请求、厂商请求的处理逻辑,其中就包含下方的两个类特殊请求的处理,感兴趣可以看看。

6.1 Get Max LUN 请求

Get Max LUN 请求用来获取最大逻辑单元。

示例:A1 FE 00 00 00 00 01 00

A1      1010_0001B,请求类型为“类请求”
FE      请求代码为 GET MAX LUN
00 00 
00 00   请求接口号
01 00   数据长度为 1 字节

6.2 Bulk-Only Mass Storage Reset 请求

Bulk-Only Mass Storage Reset 请求是通知设备接下来的批量端点输出数据为 CBW 包(Command Block Wrapper,命令块封装包)。

示例:TODO

7 Bulk-Only 传输协议的数据流模型

Bulk-Only 传输协议中,分为 3 个阶段:命令阶段、数据阶段、状态阶段。
(1)命令阶段:由主机通过批量端点发送一个 CBW,其中定义命令、传输数据方向、传输数据数量
(2)数据阶段:传输方向由命令阶段决定
(3)状态阶段:总是由设备返回该命令完成的状态

在 daplink 的 source/usb/msc/usbd_msc.c 文件的 USBD_MSC_BulkOut() 函数中,可以看到获取 CBW 与响应 CSW 的逻辑。

7.1 CBW 的结构

CBW(Command Block Wrapper,命令块封装包)的结构如下:

属性 描述
dCBWSignature 魔数 0x43425355(小端),意为 USBC(USB Command)的 ASCII 码
dCBWTag CBW 标签,主机分配,设备响应时返回
dCBWDataTransferLength 数据阶段传输的数据长度,单位:字节,小端
bmCBWFlags CBW 标志,bit7 表示数据传输方向(0,输出;1,输入),bit[6:0] 为 0
bCBWLUN 目标逻辑单元的编号。bit[3:0] 逻辑单元编号
bCBWCBLengt CBWCB 长度。bit[4:0],有效范围 1~16
CBWCB 需要执行的命令。见第 8 节。

7.2 CSW 的结构

CSW(Command Status Wrapper,命令状态封装包)结构如下:

属性 描述
dCSWSignature 魔数 0x53425355(小端),意为 USBS(USB Satus)的 ASCII 码
dCSWTag CSW 包的标签,值为 CBW 包的 dCBWTag
dCSWDataResidue 命令完成时剩余字节数。表示实际完成传输的字节数与 dCBWDataTransferLength 的差值
bCSWStatus 命令执行状态。0x00 成功;0x01 失败;0x02 阶段错误;其它保留

7.3 对批量数据的处理

8 SCSI 命令集和 UFI 命令集

SCSI(Small Computer System Interface,小型计算机系统接口)对命令及其响应规定了完整的协议。
在 U 盘中常用的 SCSI 命令有:INQUIRY、READ CAPACITY、READ(10)、WRITE(10) 等

UFI(USB Floppy Interface,USB 软盘接口)结合 SCSI-2 和 SFF-8070i 命令集抽取的命令。
UFI 命令出现在 CBW 包的 CBWCB 字段中。最多 16 个字节,不足补0,多余忽略。命令第 1 字节为操作代码。
见 《usbmass-ufi10.pdf》第 4 节 UFI Command Descriptions: https://www.usb.org/document-library/mass-storage-ufi-command-specification-10

8.1 查询命令 INQUIRY

见 daplink 中 source/usb/msc/usbd_msc.c 文件的 USBD_MSC_Inquiry() 函数。

8.2 读格式化容量命令 READ FORMAT CAPACITIES

8.3 读容量命令 READ CAPACITY

8.4 READ(10) 命令

8.5 WRITE(10) 命令

8.6 REQUEST SENSE 命令

8.7 TEST UNIT READY 命令

9 FAT 文件系统

FAT(File Allocation Table,文件分配表)是为了方便文件存储、检索、添加、删除等操作,而提出的一种链表式的文件组织结构。

磁盘物理上以 “扇区” 为单位来组织存储,而 FAT 文件系统则以 “簇” 为单位组织。两者的映射关系为:一般一个簇由几个扇区组成。
FAT 逻辑上是一张表格,表格中的每项保存文件的文件名、文件长度、创建日期、起始簇号等信息。

磁盘格式化成 FAT16 格式后的内容如下:

  • 1)MBR(Master Boot Record,主引导记录):记录 MBR 引导代码、磁盘分区等信息。FAT16 每分区最大只有 2GB(65536x32KB) 存储空间,要映射更多的空间只能添加逻辑分区。

  • 2)EBR(Extended Boot Record,扩展引导记录):MBR 中的磁盘分区表不够用时,使用 EBR

  • 3)DBR(DOS Boot Record,磁盘操作系统引导记录):每个逻辑分区的引导记录。记录分区信息及引导代码。

    MBR、EBR、DBR 通常只占用一个扇区(512KB)

  • 4)FAT1/2:文件分配表,表格项记录文件相关信息。FAT2 为 FAT1 的副本。

9.1 关于 DBR

1)DBR 占据逻辑分区的 0 扇区,大小通常 512 字节。

示例:
来源:DAPLINK 源码的 source/daplink/drag-n-drop/virtual_fs.c 文件

static const mbr_t mbr_tmpl = {/*uint8_t[11]*/.boot_sector = {0xEB, 0x3C, 0x90,'M', 'S', 'D', '0', 'S', '4', '.', '1' // OEM Name in text (8 chars max)},/*uint16_t*/.bytes_per_sector           = 0x0200,       // 512 bytes per sector/*uint8_t */.sectors_per_cluster        = 0x08,         // 4k cluser/*uint16_t*/.reserved_logical_sectors   = 0x0001,       // mbr is 1 sector/*uint8_t */.num_fats                   = 0x02,         // 2 FATs/*uint16_t*/.max_root_dir_entries       = 0x0020,       // 32 dir entries (max)/*uint16_t*/.total_logical_sectors      = 0x1f50,       // sector size * # of sectors = drive size/*uint8_t */.media_descriptor           = 0xf8,         // fixed disc = F8, removable = F0/*uint16_t*/.logical_sectors_per_fat    = 0x0001,       // FAT is 1k - ToDO:need to edit this/*uint16_t*/.physical_sectors_per_track = 0x0001,       // flat/*uint16_t*/.heads                      = 0x0001,       // flat/*uint32_t*/.hidden_sectors             = 0x00000000,   // before mbt, 0/*uint32_t*/.big_sectors_on_drive       = 0x00000000,   // 4k sector. not using large clusters/*uint8_t */.physical_drive_number      = 0x00,/*uint8_t */.not_used                   = 0x00,         // Current head. Linux tries to set this to 0x1/*uint8_t */.boot_record_signature      = 0x29,         // signature is present/*uint32_t*/.volume_id                  = 0x27021974,   // serial number// needs to match the root dir label/*char[11]*/.volume_label               = {'D', 'A', 'P', 'L', 'I', 'N', 'K', '-', 'D', 'N', 'D'},// unused by msft - just a label (FAT, FAT12, FAT16)/*char[8] */.file_system_type           = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '},/*uint8_t[448]*/.bootstrap = {// 篇幅原因省略引导代码},// Signature MUST be 0xAA55 to maintain compatibility (i.e. with Android)./*uint16_t*/.signature = 0xAA55,
};

9.2 关于 FAT 表

1)FAT 表紧跟着 DBR,即从扇区 1 开始。

示例:在 daplink 的 source/daplink/drag-n-drop/virtual_fs.c 文件中的 vfs_init() 函数,结合 FAT16 文件系统的格式,可以看到 mbr 块、fat 块、根目录块的初始化。

file_allocation_table_t fat;
................
void vfs_init(const vfs_filename_t drive_name, uint32_t disk_size)
{
................memset(&mbr, 0, sizeof(mbr));memset(&fat, 0, sizeof(fat));fat_idx = 0;
................// Initialize FATfat_idx = 0;write_fat(&fat, fat_idx, 0xFFF8);    // Media type "media_descriptor"fat_idx++;write_fat(&fat, fat_idx, 0xFFFF);    // FAT12 - always 0xFFF (no meaning), FAT16 - dirty/clean (clean = 0xFFFF)fat_idx++;
................// Initialize root dirdir_idx = 0;dir_current.f[dir_idx] = root_dir_entry;memcpy(dir_current.f[dir_idx].filename, drive_name, sizeof(dir_current.f[0].filename));dir_idx++;
................    
}

9.3 关于目录项

目录项的结构:

示例:在 daplink 的 source/daplink/drag-n-drop/virtual_fs.c 文件中

typedef struct FatDirectoryEntry {vfs_filename_t filename;uint8_t attributes;uint8_t reserved;uint8_t creation_time_ms;uint16_t creation_time;uint16_t creation_date;uint16_t accessed_date;uint16_t first_cluster_high_16;uint16_t modification_time;uint16_t modification_date;uint16_t first_cluster_low_16;uint32_t filesize;
} __attribute__((packed)) FatDirectoryEntry_t;

总结

结合 daplink 来看,根据鸭子定律,当我们通过 USB 总线协议告诉 USB 主机:插入的设备识别为 64MB U 盘,用起来像 64MB U 盘,那么它就是容量为 64MB 的 U 盘。实际上,运行 daplink 的 MCU 怎么可能有那么大的 FLASH。

而且别说是 64MB,就是 64GB 也可以(需要文件系统支持),因为 daplink 只需要一次性数据,并不需要把复制到 U 盘的数据再读取出来,那么这个 DAPLINK U 盘完全就是你强任你强,清风绕山岗了。

同理,找一个具有 USB 外设的 4G 模块和一台云对象存储服务器,理论上是不是可以开发一个云 U 盘出来?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/74949.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

manim边做边学--复数平面

所谓复数平面,就是一种二维坐标系统,用于几何表示复数的场景,其中横轴代表实部,纵轴代表虚部。 每个点对应一个唯一的复数,反之亦然,这种表示方法使得复数的加法、乘法等运算可以通过直观的图形变换来理解。 ComplexPlane是Manim库中用于处理复数平面的类。 它不仅提供了…

3185. 构成整天的下标对数目 II

给你一个整数数组 hours,表示以 小时 为单位的时间,返回一个整数,表示满足 i < j 且 hours[i] + hours[j] 构成 整天 的下标对 i, j 的数目。 整天 定义为时间持续时间是 24 小时的 整数倍 。 例如,1 天是 24 小时,2 天是 48 小时,3 天是 72 小时,以此类推。 示例 1:…

使用dbeaver导出数据csv格式要求

1.分隔符改成使用\t, 默认的会导致数字不对2.下面也要修改下,不然会出现列和值对不上情况

通过集成平台实现聚水潭销售出库单与金蝶云星辰V2的无缝对接

PACKAGE-聚水潭销售出库单对接销售出库单-1 在企业信息化系统的集成过程中,数据的高效、准确传输至关重要。本文将分享一个具体的技术案例:如何通过轻易云数据集成平台,将聚水潭奇门的数据无缝对接到金蝶云星辰V2,实现销售出库单的自动化处理。 本次集成方案命名为“PACKAG…

Windows下给Visual Studio添加OpenSSL

一、安装OpenSSL 1.下载OpenSSL Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions可以下载已经编译好的包含 lib 和 include 文件的安装包 有Win32和Win64可选,这里的位数指的是你使用OpenSSL开发出来的软件的位数版本,而不是你计算机的位数。 注意,…

分享一个开源的文件MD5、Hash值等校验的小工具

官方主页 https://github.com/dragonyee/MyHash 软件截图介绍 一款采用并行计算,充分利用多核CPU性能,快速计算文件哈希值的工具。 功能特点: 1、只支持常用的CRC32、MD5、SHA1、SHA256、SHA512算法; 2、支持多核CPU并行计算,大幅提高计算速度; 3、支持多个文件或文件夹拖…