usb_interface->usb_host_interface->usb_host_endpoint->usb_endpoint_descriptor
usb_set_intfdata(interface, dev); retval = usb_register_dev(interface, &skel_class); if (retval) { err("Not able to get a minor for this device."); usb_set_intfdata(interface, NULL); goto error; } info("USB Skeleton device now attached to USBSkel-%d", interface->minor); return 0;usb_set_intfdata, 把刚才初始化得到的dev(usb_skel类型)保存在usb_interface中,以便其他函数使用。这样做是因为,dev是一个局部变量,其他函数没法获得,但其他函数(比如open)可以访问usb_interface,这样,也就可以访问usb_skel里的具体字段了。如open函数中,dev = usb_get_intfdata(interface)。
下面讲一下usb_register_dev相关的内容。
一个USB interface对应一种USB逻辑设备,比如鼠标、键盘、音频流。所以,在USB范畴中,device一般就是指一个interface。一个驱动只控制一个interface。这样,usb_register_dev自然是注册一个interface,所以usb_register_dev的第一个参数是interface(usb_interface类型)。
接着介绍下skel_class:
static struct usb_class_driver skel_class = {
.name = "usb/skel%d", .fops = &skel_fops, .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, .minor_base = USB_SKEL_MINOR_BASE,};
其中,skel_fops定义为:
static struct file_operations skel_fops = {
.owner = THIS_MODULE, .read = skel_read, .write = skel_write, .open = skel_open, .release = skel_release,};
skel_fops是真正完成对设备IO操作的函数集。
usb_register_dev注册一次,获取一个次设备号。该次设备号从usb_class_driver -> minor_base开始分配。
usb_register_dev(interface, &skel_class),也就是说,一个usb_interface对应一个次设备号。结合上面举的interface例子,可以知道,鼠标、键盘各自对应一个不同的次设备号。
4.Disconnect
当设备从主机拔出时,usb子系统会自动地调用disconnect,他做的事情不多,最重要的是注销class_driver(交还次设备号)和interface的data。然后用kref_put(&dev->kref, skel_delete)进行清理。
static void skel_disconnect(struct usb_interface *interface)
{
struct usb_skel *dev; int minor = interface->minor; lock_kernel(); dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); usb_deregister_dev(interface, &skel_class); unlock_kernel(); kref_put(&dev->kref, skel_delete); info("USB Skeleton #%d now disconnected", minor);}