概述
一、USB固件和USB传输方式
USB固件:
USB固件一般不需要我们编写,在此不做程序分析。
USB固件中包含USB设备的出厂信息,如厂商ID、产品ID、主版本号和次版本号等。这就是为什么当我们把U盘插入USB口的时候主机可以知道这是一个U盘设备。
除包含出厂信息外,固件中还包含处理USB协议和设备读写操作的程序,如将数据从设备发送到总线上或从总线中将数据读取到设备中。驱动程序只是将USB规范定义的请求发送给固件程序,固件程序负责将数据写入设备中。USB规范定义了USB设备间的通信方式。
USB结构:
USB是主从结构的。所有的USB传输,都是从USB主机这方发起,USB设备没有“主动”通知USB主机的能力。
如USB鼠标滑动一下产生了数据,但它没有能力通知PC机来读数据,只能被动地等待PC来读。
USB传输类型:
1. 控制传输:可靠,时间有保证。如:USB设备的识别过程
2. 批量传输: 可靠, 时间没有保证。如:U盘
3. 中断传输:可靠,实时。如:USB鼠标
4. 实时传输:不可靠,实时。如:USB摄像头
二、Linux USB设备驱动模型
USB设备驱动模型采用总线设备驱动模型,所以它具有三部分:
1. USB Bus
2. USB Device
3. USB Driver
usb_bus和usb_bus_type:
每一条USB总线对应一个struct usb_bus。
1 struct usb_bus { 2 struct device *controller; /* host/master side hardware */ 3 int busnum; /* Bus number (in order of reg) */ 4 const char *bus_name; /* stable id (PCI slot_name etc) */ 5 u8 uses_dma; /* Does the host controller use DMA? */ 6 u8 uses_pio_for_control; /* 7 * Does the host controller use PIO 8 * for control transfers? 9 */ 10 u8 otg_port; /* 0, or number of OTG/HNP port */ 11 unsigned is_b_host:1; /* true during some HNP roleswitches */ 12 unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ 13 unsigned sg_tablesize; /* 0 or largest number of sg list entries */ 14 15 int devnum_next; /* Next open device number in 16 * round-robin allocation */ 17 18 struct usb_devmap devmap; /* device address allocation map */ 19 struct usb_device *root_hub; /* Root hub */ 20 struct usb_bus *hs_companion; /* Companion EHCI bus, if any */ 21 struct list_head bus_list; /* list of busses */ 22 23 int bandwidth_allocated; /* on this bus: how much of the time 24 * reserved for periodic (intr/iso) 25 * requests is used, on average? 26 * Units: microseconds/frame. 27 * Limits: Full/low speed reserve 90%, 28 * while high speed reserves 80%. 29 */ 30 int bandwidth_int_reqs; /* number of Interrupt requests */ 31 int bandwidth_isoc_reqs; /* number of Isoc. requests */ 32 33 #ifdef CONFIG_USB_DEVICEFS 34 struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ 35 #endif 36 37 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) 38 struct mon_bus *mon_bus; /* non-null when associated */ 39 int monitored; /* non-zero when monitored */ 40 #endif 41 };
usb_bus_type定义了一种usb总线类型。在软件层次中,usb_bus属于usb_bus_type。
usb_bus_type通过bus_register(&usb_bus_type)函数向内核注册usb总线。
struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, .pm = &usb_bus_pm_ops, };
其中,match()函数通过id_table来匹配device和driver。
1 static int usb_device_match(struct device *dev, struct device_driver *drv) 2 { 3 /* devices and interfaces are handled separately */ 4 if (is_usb_device(dev)) { 5 6 /* interface drivers never match devices */ 7 if (!is_usb_device_driver(drv)) 8 return 0; 9 10 /* TODO: Add real matching code */ 11 return 1; 12 13 } else if (is_usb_interface(dev)) { 14 struct usb_interface *intf; 15 struct usb_driver *usb_drv; 16 const struct usb_device_id *id; 17 18 /* device drivers never match interfaces */ 19 if (is_usb_device_driver(drv)) 20 return 0; 21 22 intf = to_usb_interface(dev); 23 usb_drv = to_usb_driver(drv); 24 25 /* 匹配interface和driver->id_table */ 26 id = usb_match_id(intf, usb_drv->id_table); 27 if (id) 28 return 1; 29 30 id = usb_match_dynamic_id(intf, usb_drv); 31 if (id) 32 return 1; 33 } 34 35 return 0; 36 }
USB总线的任务有:
1. 识别USB设备
a. 分配地址并将地址告诉USB设备
b. 发出命令获取描述符
2. 查找并安装对应的设备驱动程序
3. 提供USB读写接口
我们现在来分析总线框架:
usb_init() -> bus_register(&usb_bus_type); /* 注册usb总线 */ -> bus_register_notifier(&usb_bus_type, &usb_bus_nb); -> usb_major_init() -> register_chrdev(180, "usb", &usb_fops); -> usb_register(&usbfs_driver); /* usbfs驱动 */ -> usb_hub_init(); /* 初始化USB集线器 */ -> usb_register(&hub_driver); -> kthread_run(hub_thread, NULL, "khubd"); /* 执行线程 */ -> hub_events(); /* 如果有插拔USB设备操作 */ -> hub_port_connect_change(hub, i, portstatus, portchange); -> usb_alloc_dev(hdev, hdev->bus, port1); /* 分配usb内存 */ -> choose_address(udev); /* 设置地址 */ -> hub_port_init(hub, udev, port1, i); /* 获取设备描述符 */ -> usb_deregister(&hub_driver); -> usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
usb_device:
每一个USB设备对应一个struct usb_device。
1 struct usb_device { 2 int devnum; /* 设备号 */ 3 char devpath[16]; /* 设备路径 */ 4 u32 route; 5 enum usb_device_state state; 6 enum usb_device_speed speed; 7 8 struct usb_tt *tt; 9 int ttport; 10 11 unsigned int toggle[2]; 12 13 struct usb_device *parent; 14 struct usb_bus *bus; /* 设备所属总线 */ 15 struct usb_host_endpoint ep0; /* 设备端点 */ 16 17 struct device dev; 18 19 struct usb_device_descriptor descriptor; 20 struct usb_host_config *config; /* 设备配置 */ 21 22 struct usb_host_config *actconfig; 23 struct usb_host_endpoint *ep_in[16]; 24 struct usb_host_endpoint *ep_out[16]; 25 26 char **rawdescriptors; 27 28 unsigned short bus_mA; 29 u8 portnum; 30 u8 level; 31 32 unsigned can_submit:1; 33 unsigned persist_enabled:1; 34 unsigned have_langid:1; 35 unsigned authorized:1; 36 unsigned authenticated:1; 37 unsigned wusb:1; 38 int string_langid; 39 40 /* static strings from the device */ 41 char *product; 42 char *manufacturer; 43 char *serial; 44 45 struct list_head filelist; 46 ... 47 int maxchild; 48 struct usb_device *children[USB_MAXCHILDREN]; 49 50 u32 quirks; 51 atomic_t urbnum; 52 ... 53 struct wusb_dev *wusb_dev; 54 int slot_id; 55 };
其注册函数为int usb_new_device(struct usb_device *udev)。
在USB设备的逻辑组织中,包含设备、配置、接口和端点四个层次。在此我使用宋宝华老师书中图片作为解释:
在Linux内核中,这四个层次通过一组标准的描述符来描述,如下所示。
1. 设备描述符:usb_device用于定义USB设备,usb_device_descriptor用于定义产品ID等。
struct usb_device_descriptor { __u8 bLength; /* 描述符长度 */ __u8 bDescriptorType; /* 描述符类型编号 */ __le16 bcdUSB; /* USB版本号 */ __u8 bDeviceClass; /* USB分配的设备类 */ __u8 bDeviceSubClass; /* USB分配的子类 */ __u8 bDeviceProtocol; /* USB分配的协议 */ __u8 bMaxPacketSize0; /* 端点0的最大包大小 */ __le16 idVendor; /* 厂商编号 */ __le16 idProduct; /* 产品编号 */ __le16 bcdDevice; /* 出厂编号 */ __u8 iManufacturer; __u8 iProduct; __u8 iSerialNumber; __u8 bNumConfigurations; } __attribute__ ((packed));
当一个USB设备插入时,默认的设备编号为0,在未分配新的编号前,PC使用编号0与它通信。
由于PC可能拥有多个USB设备,因此在PC需要访问某个USB设备时,发出的命令含有此USB设备对应的编号地址。
2. 配置描述符:usb_host_config用于定义USB配置,usb_config_descriptor用于定义此配置下的接口数,供电模式和功率要求等。
struct usb_config_descriptor { __u8 bLength; /* 描述符长度 */ __u8 bDescriptorType; /* 描述符类型编号 */ __le16 wTotalLength; /* 配置返回的所有数据大小 */ __u8 bNumInterfaces; /* 配置支持的接口数 */ __u8 bConfigurationValue; __u8 iConfiguration; /* 配置索引值 */ __u8 bmAttributes; /* 供电模式 */ __u8 bMaxPower; /* 最大电流 */ } __attribute__ ((packed));
3. 接口描述符:usb_interface用于定义USB接口,usb_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));
4. 端点描述符:usb_host_endpoint用于定义USB端点,usb_endpoint_descriptor用于定义此端点下的端点地址,方向和类型等。
struct usb_endpoint_descriptor { __u8 bLength; /* 描述符长度 */ __u8 bDescriptorType; /* 描述符类型 */ __u8 bEndpointAddress; /* 端点地址 */ __u8 bmAttributes; /* 端点属性 */ __le16 wMaxPacketSize; /* 最大信息包大小 */ __u8 bInterval; /* NOTE: these two are _only_ in audio endpoints. */ /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ __u8 bRefresh; __u8 bSynchAddress; } __attribute__ ((packed));
我们可以使用“lsusb -v -s 总线号:设备号”查看设备的详细信息
usb_driver:
每一个USB设备驱动对应一个struct usb_driver。
1 struct usb_driver { 2 const char *name; 3 4 int (*probe) (struct usb_interface *intf, 5 const struct usb_device_id *id); 6 7 void (*disconnect) (struct usb_interface *intf); 8 9 int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code, 10 void *buf); 11 12 int (*suspend) (struct usb_interface *intf, pm_message_t message); 13 int (*resume) (struct usb_interface *intf); 14 int (*reset_resume)(struct usb_interface *intf); 15 16 int (*pre_reset)(struct usb_interface *intf); 17 int (*post_reset)(struct usb_interface *intf); 18 19 const struct usb_device_id *id_table; 20 21 struct usb_dynids dynids; 22 struct usbdrv_wrap drvwrap; 23 unsigned int no_dynamic_id:1; 24 unsigned int supports_autosuspend:1; 25 unsigned int soft_unbind:1; 26 };
其注册函数为int usb_register(struct usb_driver *driver)。
1 #define usb_register(driver) 2 usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
三、USB数据传输
USB设备驱动和USB设备通信所有的结构体为USB请求块(USB Request Block,URB)。
struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ void *hcpriv; /* private data for host controller */ atomic_t use_count; /* 用于计数,URB若提交则加1,URB若返回驱动程序减1 */ atomic_t reject; /* submissions will fail */ int unlinked; /* unlink error code */ /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's * current owner */ struct list_head anchor_list; /* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev; /* URB需要发送到的设备 */ struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */ unsigned int pipe; /* (in) pipe information */ unsigned int stream_id; /* (in) stream ID */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ void *transfer_buffer; /* 缓冲区,其数据可以从设备发送到主机,也可以从主机发送到设备 */ dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ struct scatterlist *sg; /* (in) scatter gather buffer list */ int num_sgs; /* (in) number of entries in the sg list */ u32 transfer_buffer_length; /* 表示transfer_buffer或transfer_dma的长度 */ u32 actual_length; /* (return) actual transfer length */ unsigned char *setup_packet; /* (in) setup packet (control only) */ dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ int start_frame; /* (modify) start frame (ISO) */ int number_of_packets; /* (in) number of ISO packets */ int interval; /* (modify) transfer interval * (INT/ISO) */ int error_count; /* (return) number of ISO errors */ void *context; /* (in) context for completion */ usb_complete_t complete; /* (in) completion routine */ struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ };
URB的处理流程:
在USB设备的逻辑层次中,interface是逻辑上的设备,它使用endpoint传输urb。
也就是说,USB设备中每个endpoint都处理一个urb队列,在队列清空之前,一个urb的传输过程如下:
当要进行数据传输时,需要分配、设置和提交一个urb给USB核心。核心对urb进行解析,将控制信息提交给主机控制器,由主机控制器完成数据到设备的传输。此时,驱动程序只需等待。当数据回传到主机控制器后,会转发给USB核心,唤醒等待的驱动程序。
具体函数操作如下图:
各函数声明如下:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) inline void usb_fill_int_urb (struct urb *urb, /* 要初始化的urb指针 */ struct usb_device *dev, /* 所要访问的设备 */ unsigned int pipe, /* 要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建 */ void *transfer_buffer, /* 要传输的数据缓冲区 */ int buffer_length, /* 缓冲区长度 */ usb_complete_t complete_fn, /* 当完成该urb所请求的操作时,要调用的回调函数 */ void *context, /* complet_fn函数所需的上下文,通常取值为dev */ int interval) /*urb被调度的时间间隔 */ inline void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context) void usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, unsigned char *setup_packet, void *transfer_buffer, int buffer_length, usb_complete_t complete_fn, void *context) int usb_submit_urb(struct urb *urb, gfp_t mem_flags); void usb_kill_urb(struct urb *urb); void usb_free_urb(struct urb *urb);
其中complete_fn()就是传输完成函数
四、USB鼠标设备驱动
在熟悉各个函数后,我们在本节完成USB鼠标设备驱动,步骤如下:
1. 分配设置usb_driver
.id_table
.probe
.disconnect
2. 使用usb_register()注册usb_driver
3. 在probe()函数中完成输入子系统和urb设置,最后提交urb
4. 在传输完成函数函数中判断数据,上报数据,重新提交urb
5. 在disconnect()函数中注销urb和输入子系统
6. 使用usb_deregister()注销usb_driver
在编写驱动时,可参考例子drivers/hid/usbhid/usbmouse.c
USB鼠标驱动源代码:
1 #include <linux/module.h> 2 #include <linux/fs.h> 3 #include <linux/init.h> 4 #include <linux/cdev.h> 5 #include <linux/slab.h> 6 #include <linux/device.h> 7 #include <linux/usb/input.h> 8 #include <linux/hid.h> 9 10 #include <asm/uaccess.h> 11 12 static struct usb_device_id mouse_table [] = { 13 { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, 14 USB_INTERFACE_PROTOCOL_MOUSE) }, 15 { } /* Terminating entry */ 16 }; 17 18 static struct input_dev *usbinput; 19 static dma_addr_t usb_buf_phys; 20 static char *buf_mem; 21 static struct urb *usb_urb; 22 static int len; 23 24 static unsigned int cnt; 25 26 static void usb_mouse_irq(struct urb *purb) 27 { 28 #if 0 29 /* 用于测试哪个bit是用于表示左、中、右键 30 * 我所使用的鼠标使用bit[0]表示左、中、右键 31 */ 32 int i; 33 34 printk("cnt: %02d, ", cnt++); 35 for(i = 0; i < len; ++i) 36 { 37 printk("%02x ", buf_mem[i]); 38 } 39 printk("n"); 40 #else 41 static unsigned char preval = 0; /* 用于存储上一个数据 */ 42 if((preval & 1) != (buf_mem[0] & 1)) { /* 鼠标左键数据有变化 */ 43 input_report_key(usbinput, KEY_L, (buf_mem[0] & 1) ? 1 : 0); 44 input_sync(usbinput); 45 } 46 if((preval & (1 << 1)) != (buf_mem[0] & (1 << 1))) { 47 input_report_key(usbinput, KEY_S, (buf_mem[0] & (1 << 1)) ? 1 : 0); 48 input_sync(usbinput); 49 } 50 if((preval & (1 << 2)) != (buf_mem[0] & (1 << 2))) { 51 input_report_key(usbinput, KEY_ENTER, (buf_mem[0] & (1 << 2)) ? 1 : 0); 52 input_sync(usbinput); 53 } 54 preval = buf_mem[0]; 55 #endif 56 57 usb_submit_urb(usb_urb, GFP_KERNEL); 58 59 } 60 61 static int mouse_probe(struct usb_interface *intf, const struct usb_device_id *id) 62 { 63 struct usb_device *dev = interface_to_usbdev(intf); 64 struct usb_host_interface *interface; 65 struct usb_endpoint_descriptor *endpoint; 66 unsigned int pipe; 67 int ret; 68 69 interface = intf->cur_altsetting; 70 endpoint = &interface->endpoint[0].desc; 71 72 /* 1. 输入子系统设置 */ 73 usbinput = input_allocate_device(); 74 75 set_bit(EV_KEY, usbinput->evbit); 76 set_bit(EV_REP, usbinput->evbit); 77 78 set_bit(KEY_L, usbinput->keybit); 79 set_bit(KEY_S, usbinput->keybit); 80 set_bit(KEY_ENTER, usbinput->keybit); 81 82 ret = input_register_device(usbinput); 83 84 /* 2. urb设置 */ 85 usb_urb = usb_alloc_urb(0, GFP_KERNEL); 86 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 87 88 len = endpoint->wMaxPacketSize; 89 buf_mem = usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys); 90 91 usb_fill_int_urb(usb_urb, dev, pipe, buf_mem, len, 92 usb_mouse_irq, NULL, endpoint->bInterval); 93 usb_urb->transfer_dma = usb_buf_phys; 94 usb_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 95 96 return usb_submit_urb(usb_urb, GFP_KERNEL); 97 } 98 99 static void mouse_disconnect(struct usb_interface *intf) 100 { 101 struct usb_device *dev = interface_to_usbdev(intf); 102 103 usb_kill_urb(usb_urb); 104 usb_free_urb(usb_urb); 105 106 usb_free_coherent(dev, len, buf_mem, usb_buf_phys); 107 input_unregister_device(usbinput); 108 input_free_device(usbinput); 109 } 110 111 static struct usb_driver mouse_driver = { 112 .name = "itop4412_mouse", 113 .probe = mouse_probe, 114 .disconnect = mouse_disconnect, 115 .id_table = mouse_table, 116 }; 117 118 static int __init usbmouse_init(void) 119 { 120 return usb_register(&mouse_driver); 121 } 122 123 static void __exit usbmouse_exit(void) 124 { 125 usb_deregister(&mouse_driver); 126 } 127 128 /* 声明段属性 */ 129 module_init(usbmouse_init); 130 module_exit(usbmouse_exit); 131 132 MODULE_LICENSE("GPL");
Makefile:
1 KERN_DIR = /work/itop4412/tools/linux-3.5 2 3 all: 4 make -C $(KERN_DIR) M=`pwd` modules 5 6 clean: 7 make -C $(KERN_DIR) M=`pwd` modules clean 8 rm -rf modules.order 9 10 obj-m += usbmouse.o
测试:
在编译并在开发板上insmod后,会出现如下信息:
input: Unspecified device as /devices/virtual/input/input4
插入USB鼠标后,会出现如下信息:
sbcore: registered new interface driver itop4412_mouse
接下来执行:
# ls /dev/event*
最后一个/dev/event2为USB鼠标对应事件
执行:
#hexdump /dev/event2
接下来按键,效果如下图:
在此我以第一行数据为例解释一下各个数字的意义:
0000000 0393 0000 55a4 0008 0001 001f 0001 0000
次数 秒 微秒 按键类 哪个按键 按下
下一章 十七、块设备驱动
转载于:https://www.cnblogs.com/Lioker/p/10933171.html
最后
以上就是眯眯眼鸡为你收集整理的十六、USB驱动一、USB固件和USB传输方式二、Linux USB设备驱动模型三、USB数据传输四、USB鼠标设备驱动的全部内容,希望文章能够帮你解决十六、USB驱动一、USB固件和USB传输方式二、Linux USB设备驱动模型三、USB数据传输四、USB鼠标设备驱动所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复