利用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 外围设备通信的问题.第一篇文章写的有点乱,本质就是需 ...
随机推荐
- python3 操作excel表
python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库可从这里下载https://pypi.python.org/pypi.下面分别记录py ...
- 26-Ubuntu-文件和目录命令-其他命令-管道
管道 Linux允许将一个命令的输出可以通过管道作为另一个命令的输入. 可以理解为现实生活中的管子,管子的一头塞东西进去,另一头取出来,这里的 | 左右分为两端,左端塞东西(写),右端取东西(读). ...
- list查询棚舍面积的时候,所有棚舍面积的value都是一样的
解决办法 将pickingid在查list之前set到对象中,通过id来匹配查询 具体代码: FarmHouse farmHouse=new FarmHouse(); farmHouse.setPic ...
- mysql5.7报Access denied for xxx@localhost 的解决
使用root用户登录mysql数据库若如下报错 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using passwor ...
- linux基础常用语句--新手
查询:ls查看全部内容:ls -n删除:rm -rf 文件名创建目录: mkdir解压:rpm -验证是否安装:rpm -p 文件名rpm -ivh --nodeps 不需要前置条件的安装查询当前路径 ...
- linux diff3-比较3个文件不同的地方
推荐:更多Linux 文件查找和比较 命令关注:linux命令大全 diff3命令用于比较3个文件,将3个文件的不同的地方显示到标准输出. 语法 diff3(选项)(参数) 选项 -a:把所有的文件都 ...
- 51nod 1285 山峰和分段
[题解] 枚举n的各个因数作为段长,O(n)判断每一段内是否有山峰即可. #include<cstdio> #include<cstring> #include<algo ...
- dev的动态汉化
放控件TcxLocalizer.将其FIlename设定成汉化文件.ini.选择Locale的值是中文,然后active=true.OK了文件如下 ini如下: [2052] CHINA_STR=&q ...
- No buffer space available错误解决方案
生产环境,突然爆发问题,网络正常,但是报网络不通错误,重启tomcat立刻好使 开始以为是tomcat的问题,调查了很久,后来加上堆栈日志才发现 简单来说,就是1-4分钟之内,使用了大量的http请求 ...
- JavaSE 学习笔记之反射技术(二十四)
反射技术:其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员.简单说:反射技术可以对一个类进行解剖. 反射的好 ...