利用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 外围设备通信的问题.第一篇文章写的有点乱,本质就是需 ...
随机推荐
- ThinkPHP---拓展之jQuery的ajax
[前言] 用Sublime开发时,推荐下载一个jQuery插件,可以智能化创建基本函数格式,支持自动生成,可以提高开发效率 (1)jQuery里ajax方法有几个? 答:有4个,分别为post.get ...
- HDU - 2041 - 超级楼梯(dp)
题意: 有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? 思路: 如何到第n阶台阶,只能从n-1和n-2台阶上去,那么只需要计算到n-1阶台阶和到n-2阶台 ...
- CUDA 动态编译(NVRTC)简记
在linux上用sublime text 3上写完CUDA代码和c++代码后,想用code::blocks去一并编译,就像visual studio那样一键编译运行,但发现在code::blocks上 ...
- db2层级查询
CREATE VIEW v_orgtype99 asSELECT t1.SYS_ORG_TYPE_NAME top_name1, t2.SYS_ORG_TYPE_NAME top_name2, --若 ...
- linux free命令-显示内存的使用情况
更多Linux 性能监测与优化 关注 Linux命令大全 free命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区. 语法 free(选项) 选项 -b:以Byte为单 ...
- JSP页面中的指令标识
JSP页面中的指令标识 制作人:全心全意 指令标识主要用于设定整个JSP页面范围内都有效的相关信息,它是被服务器解释并执行的,不会产生任何内容输出到网页中.也就是说,指令标识对于客户端浏览器是不可见的 ...
- [bzoj1044][HAOI2008][木棍分割] (二分+贪心+dp+队列优化)
Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长 ...
- [bzoj4241][历史研究] (分块)
Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...
- 2.8 补充:shell脚本执行方法
bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本 ...
- HDU 1249 三角形的分割
可以将三角形的三条边一条一条加进图形中观察 假设添加第n个三角形 前n-1个三角形将区域划分为sum[n-1] 第n个三角形每条边最多能经过前n-1个三角形每条三角形的两条边 , 一条边切完增加了 2 ...