1、前言
当使用functionfs创建出一个function并mount后,就会在目录中生成ep0的文件,该文件便是内核中的ep0端点,该端点会在整个协商过程中使用。
2、协商过程
使用functionfs的协商过程和在内核中的协商基本一致,基本围绕ep0进行。如有添加协议头,则在bind过程中加以识别。
首先需要打开functionfs默认创建的ep0文件,成功打开后,需要连续写入接口描述信息和端点描述信息。接着写入字符串信息,这些信息使用lsusb时展示,在此会使用到2个头文件,分别是<linux/usb/ch9.h>和<linux/usb/functionfs.h>。
描述信息成功写入后,mount的目录会多出在描述信息中的端点,并且ep0会返回对应的事件,这时就需要读取ep0的返回信息。根据ep0的事件类型,做出相应的回应便可完成协商。没有添加协议的情况下可以直接返回0,
3、描述信息构成
描述信息和在内核中的构成有所区别,有一个header,header中添加填充描述信息魔术字,FUNCTIONFS_DESCRIPTORS_MAGIC,然后是描述信息大小,使用了多少个端点,接着依次是接口描述信息和使用的端点描述信息。
4、使用到的结构体
truct usb_functionfs_descs_head_v2 {
__le32 magic;
__le32 length;
__le32 flags;
/*
* __le32 fs_count, hs_count, fs_count; must be included manually in
* the structure taking flags into consideration.
*/
} __attribute__((packed));
/* Descriptor of an non-audio endpoint */
struct usb_endpoint_descriptor_no_audio {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval;
} __attribute__((packed));
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wData[1]; /* UTF-16LE encoded */
} __attribute__ ((packed));
5、通信
当协商成功之后,就可以使用目录中的ep1,ep2。。。epn进行通信。整个过程和操作文件一样。