批量传输:自定义接口实现
2022-05-04
1432
12
[TOC]
在进行 usb 传输的过程中,往往需要大容量传输。无外乎批量传输。典型的批量传输协议如下:
cdc-acm :usb 转串口。win10 以下需要 pc 驱动。
massstroage:U 盘设备。
通常仅仅只需要批量传输,而不想引入复杂的协议,这个时候自定义接口进行批量传输就比较合适了,需要注意的是自定义接口需要安装pc驱动, host 并不支持自定义的接口。
1. 描述符布局
Inerface Descriptor
Endpoint Descruptor(in)
Endpoint Descruptor(out)
2. 描述符介绍
自定义接口:关联两个端点
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof(intf_desc),
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 0x02,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0x0,
.bInterfaceProtocol = 0x0,
};
端点描述符:in/out 端点
static struct usb_endpoint_descriptor hs_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor hs_bulk_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
整体接口描述符:
static struct usb_descriptor_header *hs_intf_descs[] = {
//(struct usb_descriptor_header *) &iad_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_bulk_out_desc,
(struct usb_descriptor_header *) &hs_bulk_in_desc,
NULL,
};
接口描述符如下:
3. 复合设备
有的时候我们需要在已有的设备功能上,添加一个接口自定义功能。这个时候就需要添加复合设备。复合设备独立接口设备唯一区别在于接口描述符和设备描述符符不同。
- 设备描述符:按照杂项设备处理
- 自定义接口,添加一个iad 关联
IAD Descriptor
Inerface Descriptor
Endpoint Descruptor(in)
Endpoint Descruptor(out)
IAD 描述符:
static struct usb_interface_assoc_descriptor iad_desc = {
.bLength = sizeof(iad_desc),
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = 0, // 动态修改
.bInterfaceCount = 1,
.bFunctionClass = 0xFF, // vendor
.bFunctionSubClass = 0x00,
.bFunctionProtocol = 0x00,
.iFunction = 0,
};
整体接口描述符:
static struct usb_descriptor_header *hs_intf_descs[] = {
(struct usb_descriptor_header *) &iad_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_bulk_out_desc,
(struct usb_descriptor_header *) &hs_bulk_in_desc,
NULL,
};
自定义接口描述符如下:
4. 驱动适配
对于自定义接口,需要按照pc 驱动,否则 windows 端无法识别。
使用 zadig-2.5.exe 按照对应接口的设备驱动。这里是接口2
不同的驱动对应不同的系统调用。
winUSB:对应 libusb(1.0) 系统调用
libusbK:对应libusbK 系统调用
libusb-win32:对应libusb-0.1(libusb-win32) 系统调用
有关libusb、libusbK、libusb-win32 之间的关系本文不做过多介绍,这里只是版本的差异。
5. 主机应用
以libusb 为例介绍。
5.1 控制传输
int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *data, uint16_t wLength, unsigned int timeout);
控制写:
...
libusb_device_handle* handle = dev->handle;
int status = libusb_control_transfer(
handle,
/* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE,
/* bRequest */ bRequest,
/* wValue */ 0,
/* wIndex */ 0,
/* Data */ (unsigned char *)data,
/* wLength */ len,
ms);
控制读:
...
libusb_device_handle* handle = dev->handle;
int status = libusb_control_transfer(
handle,
/* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE,
/* bRequest */ bRequest,
/* wValue */ 0,
/* wIndex */ 0,
/* Data */ (unsigned char*)(*data),
/* wLength */ len,
ms);
return status;
5.2 批量传输
int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
unsigned char endpoint, unsigned char *data, int length,
int *actual_length, unsigned int timeout);
批量读:
int bulk_read(struct bulkusbdev* dev, void* buffer, size_t len, int ms)
{
int size, errcode;
libusb_device_handle* handle = dev->handle;
uint8_t endpoint_in = dev->endpoint_in;
errcode = libusb_bulk_transfer(handle, endpoint_in,(unsigned char*) buffer, len, &size, ms);
if (errcode < 0)
{
printf("read: %s\n", libusb_strerror((enum libusb_error)errcode));
return -1;
}
return size;
}
批量写:
int bulk_write(struct bulkusbdev* dev, void* buffer, int len, int ms)
{
int size, errcode;
libusb_device_handle* handle = dev->handle;
uint8_t endpoint_out = dev->endpoint_out;
errcode = libusb_bulk_transfer(handle, endpoint_out, (unsigned char*)buffer, len, &size, ms);
if (errcode<0)
{
printf("write: %s\n", libusb_strerror((enum libusb_error)errcode));
return -1;
}
return size;
}
6. 总结
本文简单介绍了,USB 设备自定义批量传输的设备描述符实现,有关不同的平台,设备驱动实现方式不一。掌握了描述符,基本就掌握了设备实现的核心。参考对应平台做相关移植即可。
注释:有关windows 驱动仅学习使用,商用可能需要做数字签名
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936