USB 总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配。
USB 的驱动可以分为 3 类:SoC 的 USB 控制器的驱动,主机端 USB 设备的驱动,设备上的 USB Gadget 驱动,通常,对于 USB 这种标准化的设备,内核已经将主机控制器的驱动编写好了,设备上的 Gadget 驱动通常只运行固件程序而不是基于 Linux, 所以驱动工程师的主要工作就是编写主机端的 USB 设备驱动。
下图表示了 Linux 中 USB 子系统的框架结构,和 i2c 一样,USB 子系统也可分为三层:** 设备驱动层 --USB 核心 -- 控制器驱动层 *
作为热插拔总线, USB 和非热插拔总线最大的区别就是总线无法事前获知设备的信息以及设备何时被插入或拔出,所以也就不能使用任意一种形式将设备信息事前写入内核。
为了解决由于热插拔引起的设备识别问题,USB 总线通过枚举的方式来获取一个接入总线的 USB 设备的设备信息——一个由 device->config->interface->endpoint 逐级描述的设备,基于分离的思想,USB 子系统中设计了一组结构来描述这几个维度的设备信息,相比之下,i2c 总线只要一个 i2c_client 即可描述一个设备.
USB 总线上的所有通信都是由主机发起的,所以本质上,USB 都是采用轮询的方式进行的。USB 总线会使用轮询的方式不断检测总线上是否有设备接入,如果有设备接入相应的 D+D - 就会有电平变化。然后总线就会按照 USB 规定的协议与设备进行通信,设备将存储在自身的设备信息依次交给主机,主机将这些信息按照 4 层模型组织起来。上报到内核,内核中的 USB 子系统再去匹配相应的驱动,USB 设备驱动是面向 interface 这一层次的信息的
作为一种高度标准化的设备, 虽然 USB 本身十分复杂, 但是内核已经为我们完成了相当多的工作, 下述的常用设备驱动在内核中已经实现了。很多时候, 驱动的难度不是看设备的复杂程度, 而是看标准化程度
基于分离的思想,USB 子系统也提供了描述一个 USB 设备的结构,只不过基于 USB 协议,完整描述一个 USB 设备信息需要 9 个结构,这些结构中,前 4 个用来描述一个 USB 设备的硬件信息,即设备本身的信息,这些信息是写入到设备的 eeprom 的,在任何 USB 主机中看到的都一样, 这些信息可以使用 lsusb -v 命令来查看; 后 5 个描述一个 USB 设备的软件信息,即除了硬件信息之外,Linux 为了管理一个 USB 设备还要封装一些信息,是 OS-specific 的信息; USB 设备硬件信息和软件信息的关系类似于中断子系统中的硬件中断和内核中断,只不过更复杂一点。
首先说的是那 9 个描述设备信息的结构, 其中的硬件信息是相互独立的, 分别使用 这些结构在内核 "include/uapi/linux/usbch9.h" 有定义, 我就不贴代码了
- //include/uapi/linux/usbch9.h
- 258 struct usb_device_descriptor {
- 259 __u8 bLength;
- 260 __u8 bDescriptorType;
- 262 __le16 bcdUSB;
- 263 __u8 bDeviceClass;
- 264 __u8 bDeviceSubClass;
- 265 __u8 bDeviceProtocol;
- 266 __u8 bMaxPacketSize0;
- 267 __le16 idVendor;
- 268 __le16 idProduct;
- 269 __le16 bcdDevice;
- 270 __u8 iManufacturer;
- 271 __u8 iProduct;
- 272 __u8 iSerialNumber;
- 273 __u8 bNumConfigurations;
- 274
- }
- __attribute__((packed));
- //include/uapi/linux/usbch9.h
- 314 struct usb_config_descriptor {
- 315 __u8 bLength;
- 316 __u8 bDescriptorType;
- 317
- 318 __le16 wTotalLength;
- 319 __u8 bNumInterfaces;
- 320 __u8 bConfigurationValue;
- 321 __u8 iConfiguration;
- 322 __u8 bmAttributes;
- 323 __u8 bMaxPower;
- 324 } __attribute__ ((packed));
- //include/uapi/linux/usbch9.h
- 351 struct usb_interface_descriptor {
- 352 __u8 bLength;
- 353 __u8 bDescriptorType;
- 354 355 __u8 bInterfaceNumber;
- 356 __u8 bAlternateSetting;
- 357 __u8 bNumEndpoints;
- 358 __u8 bInterfaceClass;
- 359 __u8 bInterfaceSubClass;
- 360 __u8 bInterfaceProtocol;
- 361 __u8 iInterface;
- 362
- }
- __attribute__((packed));
- //include/uapi/linux/usbch9.h
- 369 struct usb_endpoint_descriptor {
- 370 __u8 bLength;
- 371 __u8 bDescriptorType;
- 372 373 __u8 bEndpointAddress;
- 374 __u8 bmAttributes;
- 375 __le16 wMaxPacketSize;
- 376 __u8 bInterval;
- 377 378
- /* NOTE: these two are _only_ in audio endpoints. */
- 379
- /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
- 380 __u8 bRefresh;
- 381 __u8 bSynchAddress;
- 382
- }
- __attribute__((packed));
- //include/linux/usb.h
- 510 struct usb_device {
- 511 int devnum;
- 512 char devpath[16];
- 513 u32 route;
- 522 struct usb_device *parent;
- 523 struct usb_bus *bus;
- 524 struct usb_host_endpoint ep0;
- 526 struct device dev;
- 528 struct usb_device_descriptor descriptor;
- 529 struct usb_host_bos *bos;
- 530 struct usb_host_config *config;
- 532 struct usb_host_config *actconfig;
- 557 char *product;
- 558 char *manufacturer;
- 559 char *serial;
- 561 struct list_head filelist;
- 563 int maxchild;
- 568 unsigned long active_duration;
- 569
- 584 };
- //include/linux/usb.h
- 275 struct usb_host_config {
- 276 struct usb_config_descriptor desc;
- 278 char * string;
- /* iConfiguration string, if present */
- 282 struct usb_interface_assoc_descriptor * intf_assoc[USB_MAXIADS];
- 286 struct usb_interface * interface[USB_MAXINTERFACES];
- 290 struct usb_interface_cache * intf_cache[USB_MAXINTERFACES];
- 292 unsigned char * extra;
- /* Extra descriptors */
- 293 int extralen;
- 294
- };
下面这个就是与驱动直接匹配的描述
- 160 struct usb_interface {
- 163 struct usb_host_interface * altsetting;
- 165 struct usb_host_interface * cur_altsetting;
- 167 unsigned num_altsetting;
- /* number of alternate settings */
- 171 struct usb_interface_assoc_descriptor * intf_assoc;
- 173 int minor;
- 175 enum usb_interface_condition condition;
- /* state of binding */
- 176 unsigned sysfs_files_created: 1;
- /* the sysfs attributes exist */
- 177 unsigned ep_devs_created: 1;
- /* endpoint "devices" exist */
- 178 unsigned unregistering: 1;
- /* unregistration is in progress */
- 179 unsigned needs_remote_wakeup: 1;
- /* driver requires remote wakeup */
- 180 unsigned needs_altsetting0: 1;
- /* switch to altsetting 0 is pending */
- 181 unsigned needs_binding: 1;
- /* needs delayed unbind/rebind */
- 182 unsigned reset_running: 1;
- 183 unsigned resetting_device: 1;
- /* true: bandwidth alloc after reset */
- 185 struct device dev;
- /* interface specific device info */
- 186 struct device * usb_dev;
- 187 atomic_t pm_usage_cnt;
- /* usage counter for autosuspend */
- 188 struct work_struct reset_ws;
- /* for resets in atomic context */
- 189
- };
- 77 struct usb_host_interface {
- 78 struct usb_interface_descriptor desc;
- 80 int extralen;
- 81 unsigned char * extra;
- /* Extra descriptors */
- 86 struct usb_host_endpoint * endpoint;
- 88 char * string;
- /* iInterface string, if present */
- 89
- };
endpoint 是 USB 设备 IO 的基本单元
- 64 struct usb_host_endpoint {
- 65 struct usb_endpoint_descriptor desc;
- 66 struct usb_ss_ep_comp_descriptor ss_ep_comp;
- 67 struct list_head urb_list;
- 68 void * hcpriv;
- 69 struct ep_device * ep_dev;
- /* For sysfs info */
- 71 unsigned char * extra;
- /* Extra descriptors */
- 72 int extralen;
- 73 int enabled;
- 74
- };
每一个硬件信息对象都包含在一个软件信息对象中, 而软件信息对象是层层包含的, 所以虽然驱动是基于 interface 描述的, 但是我们可以使用 "list_entry()" 很容易的向上找到 config 和 device 描述, 使用其中的域很容易的找到 endpoint 描述, 这 9 个描述设备的结构关系如下图所示:
与 platform 或 i2c 总线不同的是,usb 总线不允许设备发起通信,所以作为设备驱动, 只有将需要的 "材料" 准备好经由核心层提交到 usb 控制器驱动,让控制器驱动带着这些 "材料" 去轮询设备并将应答带回。这些 "材料" 就是 urb 和相应的注册参数。当 usb_driver 和 usb 设备匹配上后,我们准备一个 urb 对象通过 usb_fill_int_urb()/_bulk_/_control_注册到总线,并在合适的时机通过 usb_submit_urb 向控制器驱动发出发送这个 urb 对象的命令,总线的控制器驱动收到我们的发送命令之后,会根据我们注册时设置的周期不断向匹配的设备发送请求,如果子设备响应了我们的请求,控制器驱动就会将我们注册的 urb 对象填充好,并回调我们的注册函数。
对于海量存储 USB 设备,如果要让设备正常工作, 除了这些流程,还需要加上对缓存区的管理,这部分我们下篇说。
初始化并注册一个中断 urb。函数原型如下:
- static inline void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,
- void *transfer_buffer,int buffer_length,usb_complete_t complete_fn,void *context,int interval)
这个函数参数比较多, urb 表示我们要注册的 urb 对象; dev 表示这个 urb 对象的目的设备; pipe 表示读写管道, 使用 usb_sndintpipe() 和 usb_rcvintpipe() 获取; transfer_buffer 表示传递数据的缓冲区首地址; buffer_length 表示缓冲区长度; complete_fn 表示如果我们发出的 urb 有了回应, 就回调这个函数; context 是回调函数的参数, 由用户定义, 相当于 request_irq 中的 void *dev; interval 就是发送周期, 核心层会以这个参数为周期通过 usb 控制器驱动轮询设备,
urb 和 xxx 一样,要用内核分配函数,其中会做一些初始化的工作
初始化并注册一个海量存储 urb
初始化并注册一个控制 urb
通知内核发送 urb 对象
- 1048 struct usb_driver {
- 1049 const char *name;
- 1051 int (*probe) (struct usb_interface *intf,
- 1052 const struct usb_device_id *id);
- 1054 void (*disconnect) (struct usb_interface *intf);
- 1056 int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
- 1057 void *buf);
- 1059 int (*suspend) (struct usb_interface *intf, pm_message_t message);
- 1060 int (*resume) (struct usb_interface *intf);
- 1061 int (*reset_resume)(struct usb_interface *intf);
- 1063 int (*pre_reset)(struct usb_interface *intf);
- 1064 int (*post_reset)(struct usb_interface *intf);
- 1066 const struct usb_device_id *id_table;
- 1068 struct usb_dynids dynids;
- 1069 struct usbdrv_wrap drvwrap;
- 1070 unsigned int no_dynamic_id:1;
- 1071 unsigned int supports_autosuspend:1;
- 1072 unsigned int disable_hub_initiated_lpm:1;
- 1073 unsigned int soft_unbind:1;
- 1074 };
注册一个 usb_driver 到内核
注销一个 usb_driver
内核提供了如下的宏来构造一个 usb_device_id 对象, 其实也就是对 usb_device_id 中的不同域进行了填充, 由于设备的差异性, 不同的 USB 设备会上报不同的设备信息, 但无论上报哪些信息, 一定属于下面这些宏的一种封装. 可以先使用 lsusb -v 查看设备的硬件信息, 再根据其提供的硬件信息确定 id_table 编写相应的驱动
- 811 #define USB_DEVICE(vend, prod) \
- 812 .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
- 813 .idVendor = (vend), \
- 814 .idProduct = (prod)
- 825 #define USB_DEVICE_VER(vend, prod, lo, hi) \
- 826 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
- 827 .idVendor = (vend), \
- 828 .idProduct = (prod), \
- 829 .bcdDevice_lo = (lo), \
- 830 .bcdDevice_hi = (hi)
- 841 #define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \
- 842 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- 843 USB_DEVICE_ID_MATCH_INT_CLASS, \
- 844 .idVendor = (vend), \
- 845 .idProduct = (prod), \
- 846 .bInterfaceClass = (cl)
- 857 #define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
- 858 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- 859 USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
- 860 .idVendor = (vend), \
- 861 .idProduct = (prod), \
- 862 .bInterfaceProtocol = (pr)
- 873 #define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \
- 874 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- 875 USB_DEVICE_ID_MATCH_INT_NUMBER, \
- 876 .idVendor = (vend), \
- 877 .idProduct = (prod), \
- 878 .bInterfaceNumber = (num)
- 889 #define USB_DEVICE_INFO(cl, sc, pr) \
- 890 .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
- 891 .bDeviceClass = (cl), \
- 892 .bDeviceSubClass = (sc), \
- 893 .bDeviceProtocol = (pr)
- 894
- 904 #define USB_INTERFACE_INFO(cl, sc, pr) \
- 905 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
- 906 .bInterfaceClass = (cl), \
- 907 .bInterfaceSubClass = (sc), \
- 908 .bInterfaceProtocol = (pr)
- 924 #define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
- 925 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
- 926 | USB_DEVICE_ID_MATCH_DEVICE, \
- 927 .idVendor = (vend), \
- 928 .idProduct = (prod), \
- 929 .bInterfaceClass = (cl), \
- 930 .bInterfaceSubClass = (sc), \
- 931 .bInterfaceProtocol = (pr)
- 946 #define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \
- 947 .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
- 948 | USB_DEVICE_ID_MATCH_VENDOR, \
- 949 .idVendor = (vend), \
- 950 .bInterfaceClass = (cl), \
- 951 .bInterfaceSubClass = (sc), \
- 952 .bInterfaceProtocol = (pr)
- 953
下面是内核 "drdrivers/hid/usbhid/usbmouse.c" 中的 ib_table 填写方式, 可以看出, 不仅构造使用了宏, 由于 USB 鼠标是标准设备, 它的属性值也有标准的宏来标识
- 230 static struct usb_device_id usb_mouse_id_table[] = {
- 231 {
- USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 232 USB_INTERFACE_PROTOCOL_MOUSE)
- },
- 233 {}
- /* Terminating entry */
- 234
- };
内核 "drivers/hid/usbhid/usbmouse.c" 就是一个 usb 鼠标的驱动, 这里我根据自己的理解写了一个, 采用的是 "usb 中断设备驱动 + input 子系统" 框架
- #define BUF_SIZE 8
- MODULE_LICENSE("GPL");
- //面向对象, 根据需求封装类
- struct xj_mouse {
- char name[128];
- struct usb_device *dev;
- struct urb *msg;
- struct input_dev *input;
- signed char *buf;
- };
- struct xj_mouse *mouse;
- static int usb_mouse_open(struct input_dev *dev)
- {
- struct xj_mouse *mouse = input_get_drvdata(dev);
- mouse->msg->dev = mouse->dev;
- if (usb_submit_urb(mouse->msg, GFP_KERNEL))
- return -EIO;
- return 0;
- }
- static void usb_mouse_close(struct input_dev *dev)
- {
- struct xj_mouse *mouse = input_get_drvdata(dev);
- usb_kill_urb(mouse->msg);
- }
- static int init_input(struct usb_interface * intf)
- {
- int err=0;
- struct usb_device *dev = mouse->dev;
- struct input_dev *input_dev = mouse->input;
- input_dev->name = mouse->name;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->dev.parent = &intf->dev;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
- input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |BIT_MASK(BTN_EXTRA);
- input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
- input_set_drvdata(input_dev, mouse);
- input_dev->open = usb_mouse_open;
- input_dev->close = usb_mouse_close;
- err = input_register_device(mouse->input);
- return 0;
- }
- static void completion(struct urb * msg)
- {
- int status;
- signed char *buf = mouse->buf;
- struct input_dev *input = mouse->input;
- input_report_key(input, BTN_LEFT, buf[0] & 0x01);
- input_report_key(input, BTN_RIGHT, buf[0] & 0x02);
- input_report_key(input, BTN_MIDDLE, buf[0] & 0x04);
- input_report_key(input, BTN_SIDE, buf[0] & 0x08);
- input_report_key(input, BTN_EXTRA, buf[0] & 0x10);
- input_report_rel(input, REL_X, buf[1]);
- input_report_rel(input, REL_Y, buf[2]);
- input_report_rel(input, REL_WHEEL, buf[3]);
- input_sync(input);
- status = usb_submit_urb (msg, GFP_ATOMIC);
- }
- static int probe(struct usb_interface *intf, const struct usb_device_id *id)
- {
- int pipe;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- //分配、初始化个性结构
- mouse = (struct xj_mouse *)kzalloc(sizeof(struct xj_mouse),GFP_KERNEL);
- mouse->dev=interface_to_usbdev(intf);
- mouse->msg=usb_alloc_urb(0,GFP_KERNEL);
- mouse->input=input_allocate_device();
- mouse->buf=(void *)kzalloc(BUF_SIZE,GFP_KERNEL);
- if (mouse->dev->manufacturer){
- strlcpy(mouse->name, mouse->dev->manufacturer, sizeof(mouse->name));
- mouse->input->name = mouse->name;
- }
- //初始化input设备
- init_input(intf);
- //获取pipe
- interface=intf->cur_altsetting;
- endpoint=&interface->endpoint[0].desc;
- /* 使用dev和endpoint获取端点地址 */
- pipe = usb_rcvintpipe(mouse->dev,endpoint->bEndpointAddress);
- //注册usb驱动
- usb_fill_int_urb(mouse->msg,mouse->dev,pipe,mouse->buf,BUF_SIZE,completion,mouse->msg,endpoint->bInterval);
- return 0;
- }
- static void disconnect(struct usb_interface *intf)
- {
- struct xj_mouse *tmp_mouse = usb_get_intfdata (intf);
- usb_set_intfdata(intf, NULL);
- if (tmp_mouse) {
- usb_kill_urb(tmp_mouse->msg);
- input_unregister_device(tmp_mouse->input);
- usb_free_urb(tmp_mouse->msg);
- kfree(tmp_mouse->buf);
- kfree(tmp_mouse);
- }
- }
- static struct usb_device_id id_table [] ={
- { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) },
- {},
- };
- struct usb_driver mouse_drv = {
- .name = "xj_mouse_drv",
- .probe = probe,
- .disconnect = disconnect,
- .id_table = id_table,
- };
- module_usb_driver(mouse_drv);
来源: http://www.cnblogs.com/xiaojiang1025/p/6500574.html