当需要使用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. POJ_1847_Tram

    Tram Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11159   Accepted: 4089 Description ...

  2. URL解析-URLComponents

    let components = URLComponents(url: fakeUrl, resolvingAgainstBaseURL: false)! http://10.100.140.84/m ...

  3. 系统信号-signal.h

    #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ ...

  4. Functions of the call stack

    https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME As noted above, the primary purpose of a call s ...

  5. CAD动态绘制样条线(网页版)

    在CAD设计时,需要绘制样条线,用户可以设置样条线线重及颜色等属性. 主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数.详细说明如 ...

  6. 第二节:SQLServer导出-重置sa密码-常用sql语句

    1.SQLServer导出: 点击要导出数据库----->右键(任务)----->生成脚本----->下一步----->下一步(高级)要编写脚本的数据类型---选择架构和数据 ...

  7. for循环,字典遍历(一)

    #items(): 返回字典中所有 key.value #keys(): 返回字典中所有 key 的列表 #values():返回字典中所有 value 的列表 my_dict = {'语文':89, ...

  8. JAVA基础——异常--解析

      简介 异常处理是java语言的重要特性之一,<Three Rules for effective Exception Handling>一文中是这么解释的:它主要帮助我们在debug的 ...

  9. 【反向并查集、联通图】P1197 [JSOI2008]星球大战

    题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧 ...

  10. 洛谷——P2047 [NOI2007]社交网络

    P2047 [NOI2007]社交网络 $Floyd$,一眼看到就是他(博主是不小心瞄到了这个题的标签吧qwq) 这个题目只要预处理出$S$到$T$的最短路的条数即可,类似$Spfa$的更新方法 如果 ...