利用mass storage class 做免驱动usb设备.
当需要使用usb bulk传输,想让设备像串口通讯那样和PC主机通信, 通常需要自己做一个PC端的驱动,比较麻烦.
为避免在pc上编写usb设备驱动的麻烦,可以将设备做成mass storage 类的设备,使用通用的驱动.
在通讯之前设备端需要先做两件事:
1,实现mass storage 类的描述符和类请求.
2,实现必要的SCSI命令,让PC认为该设备已正常运作.
我利用修改linux中的gadget zero设备做了一个简单的设备. 如果是在裸机程序下面做,应该也差不多,直接拿芯片厂商BSP中的USB样例程序修改即可.
1实现mass storage 类的描述符和类请求.
mass storage
在linux中对应代码:
1)设备描述符
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = cpu_to_le16(0x0200),
// .bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
.bNumConfigurations = 1,
};
设备描述符没什么特殊的,因为PC端usb驱动是与设备的接口对应的,与mass storage class对应的是接口描述符
2)接口描述符
/* SCSI device types */
#define TYPE_DISK 0x00
#define TYPE_CDROM 0x05 /* USB protocol value = the transport method */
#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
#define USB_PR_BULK 0x50 /* Bulk-only */ /* USB subclass value = the protocol encapsulation */
#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
#define USB_SC_UFI 0x04 /* UFI (floppy) */
#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
#define USB_SC_SCSI 0x06 /* Transparent SCSI */ /* Bulk-only class specific requests */
#define USB_BULK_RESET_REQUEST 0xff
#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe static struct usb_interface_descriptor source_sink_intf = {
.bLength = sizeof source_sink_intf,
.bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2,
// .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = USB_SC_SCSI,
.bInterfaceProtocol = USB_PR_BULK,
/* .iInterface = DYNAMIC */
};
符合usb mass storage 类规范。对应下表
使用SCSI命令集,协议实现是Bulk-Only 传输。
3)实现一个mass storage 类的请求
case USB_BULK_GET_MAX_LUN_REQUEST:
printk("USB_BULK_GET_MAX_LUN_REQUEST\n");
if (ctrl->bRequestType !=
(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
*(u8 *) req->buf = 0; /* Respond with data/status */
req->length = min((u16)1, w_length);
value = usb_ep_queue(f->config->cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
ERROR(f->config->cdev, "source/sinkc response, err %d\n",
value);
return(value);
简单返回了一个0。
在linux中,linux把一些诸如获取描述符之类的请求集中在了一起放在了composite.c 中,不同设备类请求放在各自个f_xxx.c中各自的接口的xxx_setup函数中。
当实现了以上描述符和类请求之后,把嵌入式设备接上电脑,windows就会在设备管理器中列出usb mass storage设备。不过有一个黄色感叹号。
根据usb抓包情况来看是,电脑上面驱动发送SCSI命令数次不成功之后,会重新枚举过程,数次不正常之后就会认为该设备不正常。
2)必要的SCSI命令
大概要处理mass storage pc端驱动发过来的一下命令
#define SC_INQUIRY 0x12
#define SC_TEST_UNIT_READY 0x00
#define SC_READ_CAPACITY 0x25
#define SC_READ_FORMAT_CAPACITIES 0x23
前两条应该是必须的,后两条我也给加上了,去掉行不行,没有测试。
这些命令即可以放到linux gadget driver中也可以放到应用层程序中处理. 我是放到了应用层.
处理的流程基本是:
接收SCSI命令----->处理SCSI命令----->返回状态
基本是按照SCSI协议进行
CBW:Command Block Wrapper 命令块数据包
CSW:Command Status Wrapper 命令执行状态
按照CBW和CSW格式定义结构体:
struct ms_cbw_struct{
u32 dCBWSignature;
u32 dCBWTag;
u32 dCBWDataTransferLength;
u8 bmCBWFlags;
u8 bCBWLUN;
u8 bCBWCBLength;
u8 CBWCB[SCSI_CMD_MAX_LEN];
};
struct ms_csw_struct{
u32 dCSWSignature;
u32 dCSWTag;
u32 dCSWDataResidue;
u8 bCSWStatus;
};
以SC_INQUIRY 命令为例
当我程序收到 0x12 命令,我就要按照scsi协议中该命令的规范来处理,我需要返回下面表格格式的数据给主机

.
第一个字节后5位决定了主机识别成一个cdrom或是可移动盘或其他类型的设备.
RMB表示是否是一个可以移除设备.
Additional length (n-4) 需要填写.
其他的可根据需要填写.
之后返回状态CSW:
dCSWSignature固定为0x53425355,
dCSWTag 与CBW发过来的相同,
dCSWDataResidue等于CBW中要得长度和实际长度的差值.
bCSWStatus 表示命令成功或失败, 0表示成功,其他值表示失败.
另外这条命令
#define SC_TEST_UNIT_READY 0x00
是主机会在空闲时间不停发送的. 并且一开始连上主机,如果这条命令返回的CSW 成功,那么主机会使用READ_FORMAT_CAPACITIES 命令查询格式化的容量,read(10)读文件系统的信息. 如果得不到正确信息windows就会跳出对话框问你要不要格式化等等.
由于现在我并非真的需要做一个U盘之类的设备,所以0x00 命令,我CSW直接返回1. 这样当你点击该设备的盘符,就会提示说没有设备插入. 这对我没有影响,我只是用mass storage这个壳来进行通信的. 只是骗过mass storage的标准驱动而已.
现在我就可以通过自定义的SCSI命令或者改写标准的命令来进行通信了.
利用mass storage class 做免驱动usb设备.的更多相关文章
- Linux下的硬件驱动——USB设备(转载)
usb_bulk_msg函数 当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs 提 ...
- Ubuntu/Windows下利用“HIDAPI”库函数实现与Hid类USB设备通信
一.背景: 最近在做的一个项目需要使用USB传递数据,对USB理解不是很深,USB的系统驱动编写则更是天方 夜谭,因此将设备配置成HID类设备成为了首选.其最大的好处在于,LINUX/Windows系 ...
- 实现Linux下的U盘(USB Mass Storage)驱动
如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...
- 如何实现Linux下的U盘(USB Mass Storage)驱动
如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...
- USB mass storage协议
这一节主要把在实现“linux模拟U盘功能”过程中的一些调试过程记录下来,并加以解析. 一.背景知识 1.USB Mass Storage类规范概述 USB 组织在univers ...
- USB Mass Storage大容量存储的基本知识
http://www.crifan.com/files/doc/docbook/usb_disk_driver/release/htmls/ch02_msc_basic.html 目录 2.1. US ...
- Android USB Connections Explained: MTP, PTP, and USB Mass Storage
Android USB Connections Explained: MTP, PTP, and USB Mass Storage Older Android devices support USB ...
- USB Mass Storage协议分析
目录 简介 指令数据和状态协议 CBW指令格式 CSWCommand Status Wrapper状态格式 SCSI命令集 Format Unit Inquiry MODE SELECT 简介 USB ...
- android 与usb 设备通信(二)
再次遇到android mUsbManager.getDevicelist() 得不到usb 设备的问题.于是深入去探讨android 与usb 外围设备通信的问题.第一篇文章写的有点乱,本质就是需 ...
随机推荐
- HDU_1227_Fast Food_动态规划
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1227 Fast Food Time Limit: 2000/1000 MS (Java/Others) ...
- RocketMQ学习笔记(16)----RocketMQ搭建双主双从(异步复制)集群
1. 修改RocketMQ默认启动端口 由于只有两台机器,部署双主双从需要四个节点,所以只能修改rocketmq的默认启动端口,从官网下载rocketmq的source文件,解压后使用idea打开,全 ...
- 扩增子分析解读5物种注释 OTU表操作
本节课程,需要先完成<扩增子分析解读>系列之前的操作 1质控 实验设计 双端序列合并 2提取barcode 质控及样品拆分 切除扩增引物 3格式转换 去冗余 聚类 4去嵌合体 非细菌序列 ...
- 模板—treap
#include<iostream> #include<cstdio> #include<cstdlib> #define INF 0x7fffffff using ...
- python3.x Day1 用户登录程序练习
训练1: 模拟登陆: 1. 用户输入帐号密码进行登陆 2. 用户信息保存在文件内 3. 用户密码输入错误三次后锁定用户 login2.py: #!/usr/bin/env python # -*- c ...
- react入门-----(jsx语法,在react中获取真实的dom节点)
1.jsx语法 var names = ['Alice', 'Emily', 'Kate']; <!-- HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的 ...
- c++行事准则
1.c++包含多种编程范式,每种范式遵循不同的准则: 2.除了#include和#ifdef之流,其他预处理器别用,多用enum和const: 3.函数声明定义多用const:
- 【Codeforces 339C】Xenia and Weights
[链接] 我是链接,点我呀:) [题意] 在天平上放砝码 你要在左边放一下然后到右边放一下 一直重复这样放m次 每次你放在其中一边都要让另外一边的重量比你少 你可以用1~10中的某些砝码 问你要怎样放 ...
- 抽象类和接口有什么区别---https://blog.csdn.net/csdn_aiyang/article/details/71171886
https://blog.csdn.net/csdn_aiyang/article/details/71171886 概念] 抽象类.具体类是相对的,并非绝对的.抽象是一种概念性名词,具体是一种可 ...
- Leetcode 132.分割回文串II
分割回文串 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回符合要求的最少分割次数. 示例: 输入: "aab" 输出: 1 解释: 进行一次分割就可将 s ...