当需要使用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设备.的更多相关文章

  1. Linux下的硬件驱动——USB设备(转载)

    usb_bulk_msg函数 当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs 提 ...

  2. Ubuntu/Windows下利用“HIDAPI”库函数实现与Hid类USB设备通信

    一.背景: 最近在做的一个项目需要使用USB传递数据,对USB理解不是很深,USB的系统驱动编写则更是天方 夜谭,因此将设备配置成HID类设备成为了首选.其最大的好处在于,LINUX/Windows系 ...

  3. 实现Linux下的U盘(USB Mass Storage)驱动

    如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...

  4. 如何实现Linux下的U盘(USB Mass Storage)驱动

    如何实现Linux下的U盘(USB Mass Storage)驱动 版本:v0.7 How to Write Linux USB MSC (Mass Storage Class) Driver Cri ...

  5. USB mass storage协议

    这一节主要把在实现“linux模拟U盘功能”过程中的一些调试过程记录下来,并加以解析. 一.背景知识     1.USB Mass Storage类规范概述        USB 组织在univers ...

  6. USB Mass Storage大容量存储的基本知识

    http://www.crifan.com/files/doc/docbook/usb_disk_driver/release/htmls/ch02_msc_basic.html 目录 2.1. US ...

  7. 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 ...

  8. USB Mass Storage协议分析

    目录 简介 指令数据和状态协议 CBW指令格式 CSWCommand Status Wrapper状态格式 SCSI命令集 Format Unit Inquiry MODE SELECT 简介 USB ...

  9. android 与usb 设备通信(二)

    再次遇到android  mUsbManager.getDevicelist() 得不到usb 设备的问题.于是深入去探讨android 与usb 外围设备通信的问题.第一篇文章写的有点乱,本质就是需 ...

随机推荐

  1. ThinkPHP---拓展之jQuery的ajax

    [前言] 用Sublime开发时,推荐下载一个jQuery插件,可以智能化创建基本函数格式,支持自动生成,可以提高开发效率 (1)jQuery里ajax方法有几个? 答:有4个,分别为post.get ...

  2. HDU - 2041 - 超级楼梯(dp)

    题意: 有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? 思路: 如何到第n阶台阶,只能从n-1和n-2台阶上去,那么只需要计算到n-1阶台阶和到n-2阶台 ...

  3. CUDA 动态编译(NVRTC)简记

    在linux上用sublime text 3上写完CUDA代码和c++代码后,想用code::blocks去一并编译,就像visual studio那样一键编译运行,但发现在code::blocks上 ...

  4. db2层级查询

    CREATE VIEW v_orgtype99 asSELECT t1.SYS_ORG_TYPE_NAME top_name1, t2.SYS_ORG_TYPE_NAME top_name2, --若 ...

  5. linux free命令-显示内存的使用情况

    更多Linux 性能监测与优化 关注 Linux命令大全 free命令可以显示当前系统未使用的和已使用的内存数目,还可以显示被内核使用的内存缓冲区. 语法 free(选项) 选项 -b:以Byte为单 ...

  6. JSP页面中的指令标识

    JSP页面中的指令标识 制作人:全心全意 指令标识主要用于设定整个JSP页面范围内都有效的相关信息,它是被服务器解释并执行的,不会产生任何内容输出到网页中.也就是说,指令标识对于客户端浏览器是不可见的 ...

  7. [bzoj1044][HAOI2008][木棍分割] (二分+贪心+dp+队列优化)

    Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长 ...

  8. [bzoj4241][历史研究] (分块)

    Description IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记.JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件. ...

  9. 2.8 补充:shell脚本执行方法

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限.   方法一:切换到shell脚本 ...

  10. HDU 1249 三角形的分割

    可以将三角形的三条边一条一条加进图形中观察 假设添加第n个三角形 前n-1个三角形将区域划分为sum[n-1] 第n个三角形每条边最多能经过前n-1个三角形每条三角形的两条边 , 一条边切完增加了 2 ...