分类: LINUX
2005-11-17 18:44:22
USB驱动的注册过程总的来说要做如下的事情:首先把驱动连接到驱动链表中,然后开始扫描USB总线,从ROOT HUB开始,查找USB DEVICE,在查找的过程中使用深度遍历方法,即如果是HUB,则查找连接在HUB上的子设备,通过比较设备上的usb_interface 是否有驱动支持了,如果没有则扫描驱动链表,从驱动链表中取得驱动,通过驱动和USB DEVICE的usb_device_id进行匹配,如果匹配则调用驱动的probe函数探测,如果probe返回值不为NULL,将该驱动连接在设备的usb_interface 上。
1。注册驱动
首先把驱动连接到驱动链表中,然后开始扫描USB总线
int usb_register(struct usb_driver *new_driver)
{
if (new_driver->fops != NULL) {
if (usb_minors[new_driver->minor/16]) {
err("error registering %s driver", new_driver->name);
return -EINVAL;
}
usb_minors[new_driver->minor/16] = new_driver;
}
info("registered new driver %s", new_driver->name);
init_MUTEX(&new_driver->serialize);
/* Add it to the list of known drivers */
list_add_tail(&new_driver->driver_list, &usb_driver_list);
usb_scan_devices();
return 0;
}
2。扫描总线链表,选取每一条总线,从总线所指向的ROOT HUB这个设备开始检查驱动是否被驱动所支持。
void usb_scan_devices(void)
{
struct list_head *tmp;
down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
tmp = tmp->next;
usb_check_support(bus->root_hub);
}
up (&usb_bus_list_lock);
}
HUB也是USB DEVICE ,但不是HUB,而是真正的USB DEVICE。
static void usb_check_support(struct usb_device *dev)
{
int i;
if (!dev) {
err("null device being checked!!!");
return;
}
for (i=0; i
usb_check_support(dev->children[i]);
if (!dev->actconfig)
return;
/* now we check this device */
if (dev->devnum > 0)
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
usb_find_interface_driver(dev, i);
}
3。查看USB DEVICE 的接口是否被驱动所支持。
*查看该接口是否已经被驱动了;
*遍历驱动连表,匹配驱动和设备的usb_device_id;
*匹配成功,调用驱动的probe 函数;
*如果probe也探测成功,则把驱动分配给该接口;
static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
{
struct list_head *tmp;
struct usb_interface *interface;
void *private;
const struct usb_device_id *id;
struct usb_driver *driver;
int i;
if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
err("bad find_interface_driver params");
return -1;
}
down(&dev->serialize);
interface = dev->actconfig->interface + ifnum;
if (usb_interface_claimed(interface))
goto out_err;
private = NULL;
for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
driver = list_entry(tmp, struct usb_driver, driver_list);
tmp = tmp->next;
id = driver->id_table;
/* new style driver? */
if (id) {
for (i = 0; i < interface->num_altsetting; i++) {
interface->act_altsetting = i;
id = usb_match_id(dev, interface, id);
if (id) {
down(&driver->serialize);
private = driver->probe(dev,ifnum,id);
up(&driver->serialize);
if (private != NULL)
break;
}
}
/* if driver not bound, leave defaults unchanged */
if (private == NULL)
interface->act_altsetting = 0;
} else { /* "old style" driver */
down(&driver->serialize);
private = driver->probe(dev, ifnum, NULL);
up(&driver->serialize);
}
/* probe() may have changed the config on us */
interface = dev->actconfig->interface + ifnum;
if (private) {
usb_driver_claim_interface(driver, interface, private);
up(&dev->serialize);
return 0;
}
}
out_err:
up(&dev->serialize);
return -1;
}
4。把驱动分配给接口。
将该驱动连接在设备的usb_interface 上,驱动的注册过程完成。
void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
if (!iface || !driver)
return;
dbg("%s driver claimed interface %p", driver->name, iface);
iface->driver = driver;
iface->private_data = priv;
} /* usb_driver_claim_interface() */
5.驱动支持设备的问题研究
* USB设备是一个可直接操作的设备:
例子是扫描仪驱动,如果驱动的file operation 成员不为NULL,则该设备驱动直接被 USB_MAJOR 的驱动程序所支持。
#define USB_MAJOR 180
而且在usb_register 的时候把驱动赋予usb_minors[new_driver->minor/16] = new_driver;所以你打开你的设备的话,通过次设备号从这个数组中取得驱动,通过该usb_minors数组相关驱动的file operation进行调用。
*USB设备是一个视频设备 或者其它的等。
则在驱动调用probe的时候注册为真正被支持的设备,如调用video_register_device注册为被视频驱动(V4L)所支持的设备类型。
6.参考
*《LINUX 内核源代码情景分析》 毛德操、胡希明;