硬件:三星s5p4418
linux version:3.4.39
ubuntu:14.04
usb camera:whois
1,将usb camera驱动打入内核,插上usb camera,系统启动后会在kmesg中有如下提示:
<6>[ 1.015000] usb 1-1: New USB device found, idVendor=0547, idProduct=1002 <6>[ 1.015000] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 <6>[ 1.015000] usb 1-1: Product: U02_Sensor <6>[ 1.015000] usb 1-1: Manufacturer: Whois <6>[ 1.138000] android_usb gadget: android_usb ready <4>[ 1.143000] ==========usb_whois_init start======== <4>[ 1.148000] ==========whois probe start======== <6>[ 1.155000] whois_usbcam 1-1:1.0: whois USB camera now attached to whoiscam0== <6>[ 1.165000] usbcore: registered new interface driver whois_usbcam <4>[ 1.172000] ==========usb_whois_init end========
随后内核启动调用驱动
static int __init usb_whois_init(void) { int result; printk("==========usb_whois_init start========\n"); result = usb_register(&whois_driver); if (result) printk("usb_register failed. Error number %d", result); printk("==========usb_whois_init end========\n"); return result; } module_init(usb_whois_init);
初始化驱动的过程就是注册USB驱动的过程,它会把驱动里的支持的厂商设备ID加到内核中,供内核使用。内核如果找到对应的设备,则加载相应的驱动。
这一点和设备-总线-驱动的设备模型有点不一样,不是通过设备名和驱动名称配对,probe的。
从上面kmsg的信息可以判断usb设备和驱动因为verdorID和productID号的一致,被内核匹配,并调用驱动的probe,进行探测,生成相应的设备节点。
此时在/dev下面可以看到节点;
whoiscam0
如果拔掉usb camera节点会消失。
usb 1-1: USB disconnect, device number 2 <6>[ 14.370000] whois_usbcam 1-1:1.0: USB whoiscam0 now disconnected
usb 1-1: New USB device found, idVendor=0547, idProduct=1002 <6>[ 25.064000] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 <6>[ 25.071000] usb 1-1: Product: U02_Sensor <6>[ 25.075000] usb 1-1: Manufacturer: Whois <4>[ 25.081000] ==========whois probe start======== <6>[ 25.088000] whois_usbcam 1-1:1.0: whois USB camera now attached to whoiscam0==驱动的probe再次被调用。
为了能够让大家更清晰的看到usb驱动,我从内核里拷贝一个简单的usbled的驱动附在下面:
/* * USB LED driver */ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/usb.h> enum led_type { DELCOM_VISUAL_SIGNAL_INDICATOR, DREAM_CHEEKY_WEBMAIL_NOTIFIER, }; <span style="color:#FF0000;">/* table of devices that work with this driver */ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0fc5, 0x1223), .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR }, { USB_DEVICE(0x1d34, 0x0004), .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, { USB_DEVICE(0x1d34, 0x000a), .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, { }, }; MODULE_DEVICE_TABLE(usb, id_table);</span> struct usb_led { struct usb_device *udev; unsigned char blue; unsigned char red; unsigned char green; enum led_type type; }; <span style="color:#FF0000;">static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)</span> { struct usb_device *udev = interface_to_usbdev(interface); struct usb_led *dev = NULL; int retval = -ENOMEM; dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "out of memory\n"); goto error_mem; } dev->udev = usb_get_dev(udev); dev->type = id->driver_info; usb_set_intfdata(interface, dev); retval = device_create_file(&interface->dev, &dev_attr_blue); if (retval) goto error; retval = device_create_file(&interface->dev, &dev_attr_red); if (retval) goto error; retval = device_create_file(&interface->dev, &dev_attr_green); if (retval) goto error; if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) { unsigned char *enable; enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL); if (!enable) { dev_err(&interface->dev, "out of memory\n"); retval = -ENOMEM; goto error; } retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x09, 0x21, 0x200, 0, enable, 8, 2000); kfree(enable); if (retval != 8) goto error; } dev_info(&interface->dev, "USB LED device now attached\n"); return 0; error: device_remove_file(&interface->dev, &dev_attr_blue); device_remove_file(&interface->dev, &dev_attr_red); device_remove_file(&interface->dev, &dev_attr_green); usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); kfree(dev); error_mem: return retval; } static void led_disconnect(struct usb_interface *interface) { struct usb_led *dev; dev = usb_get_intfdata(interface); device_remove_file(&interface->dev, &dev_attr_blue); device_remove_file(&interface->dev, &dev_attr_red); device_remove_file(&interface->dev, &dev_attr_green); /* first remove the files, then set the pointer to NULL */ usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); kfree(dev); dev_info(&interface->dev, "USB LED now disconnected\n"); } static struct usb_driver led_driver = { .name = "usbled", <span style="color:#FF0000;"><strong>.probe = led_probe,</strong></span> .disconnect = led_disconnect, <span style="color:#FF0000;"><strong>.id_table = id_table,</strong></span> }; module_usb_driver(led_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL");
1,在USB设备组织结构中,从上到下分为设备(device)、配置(config)、接口(interface)和端点(endpoint)四个层次。USB设备程序绑定到接口上。
对于这四个层次的简单描述如下:
设备通常具有一个或多个的配置
配置经常具有一个或多个的接口
接口没有或具有一个以上的端点
1) USB设备:对应数据结构struct usb_device
2) 配置:struct usb_host_config (任一时刻,只能有一个配置生效)
3)USB接口:struct usb_interface (USB 核心将其传递给USB设备驱动,并由USB设备驱动负责后续的控制。一个USB接口代表一个基本功能,每个USB驱动控制一个接口。所以一个物理上的硬件设备可能需要 一个以上的驱动程序。)
4)端点: struct usb_host_endpoint ,它所包含的真实端点信息在另一个结构中:struct usb_endpoint_descriptor(端点描述符,包含所有的USB特定数据)。
2,USB设备的probe和断开当有USB设备插入时,usb host会获取设备的verdorID和productID号,对比加载到内核的usb设备驱动所支持的verdorID和productID号然后找到相应的驱动,并进行probe操作(创立节点等)。如果usb设备被拔出,则执行相应的断开操作:如
.disconnect = led_disconnect,参考:http://blog.csdn.net/myarrow/article/details/7013198