目的:對USB作深入學習,在此留下筆記。歡迎討論。
[Linux 3.2] [driver/usb/core/devio.c]
定義:usbfs_driver
- struct usb_driver usbfs_driver = {
- .name = "usbfs",
- .probe = driver_probe,
- .disconnect = driver_disconnect,
- .suspend = driver_suspend,
- .resume = driver_resume,
- };
[Linux 3.2] [include/linux/usb.h]
函數:usb_register();
- /* use a define to avoid include chaining to get THIS_MODULE & friends */
- #define usb_register(driver) \
- usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
[Linux 3.2] [driver/usb/core/driver.c]
函數:usb_register_driver();
- /**
- * usb_register_driver - register a USB interface driver
- * @new_driver: USB operations for the interface driver
- * @owner: module owner of this driver.
- * @mod_name: module name string
- *
- * Registers a USB interface driver with the USB core. The list of
- * unattached interfaces will be rescanned whenever a new driver is
- * added, allowing the new driver to attach to any recognized interfaces.
- * Returns a negative error code on failure and 0 on success.
- *
- * NOTE: if you want your driver to use the USB major number, you must call
- * usb_register_dev() to enable that functionality. This function no longer
- * takes care of that.
- */
- int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
- const char *mod_name)
- {
- int retval = 0;
-
- if (usb_disabled())
- return -ENODEV;
-
- new_driver->drvwrap.for_devices = 0;
- new_driver->drvwrap.driver.name = (char *) new_driver->name;
- new_driver->drvwrap.driver.bus = &usb_bus_type;
- new_driver->drvwrap.driver.probe = usb_probe_interface;
- new_driver->drvwrap.driver.remove = usb_unbind_interface;
- new_driver->drvwrap.driver.owner = owner;
- new_driver->drvwrap.driver.mod_name = mod_name;
- spin_lock_init(&new_driver->dynids.lock);
- INIT_LIST_HEAD(&new_driver->dynids.list);
-
- retval = driver_register(&new_driver->drvwrap.driver);
- if (retval)
- goto out;
-
- usbfs_update_special();
-
- retval = usb_create_newid_file(new_driver);
- if (retval)
- goto out_newid;
-
- retval = usb_create_removeid_file(new_driver);
- if (retval)
- goto out_removeid;
-
- pr_info("%s: registered new interface driver %s\n",
- usbcore_name, new_driver->name);
-
- out:
- return retval;
-
- out_removeid:
- usb_remove_newid_file(new_driver);
- out_newid:
- driver_unregister(&new_driver->drvwrap.driver);
-
- printk(KERN_ERR "%s: error %d registering interface "
- " driver %s\n",
- usbcore_name, retval, new_driver->name);
- goto out;
- }
此函數主要功能實現是通過driver_register實現。後面會詳細分析。
其余功能如下:
1. usbfs_update_special() ==> 跟usb文件系統相關,暫時不分析。
2. usb_create_newid_file() ==> 創建newid屬性文件,在/sys/bus/usb/drivers/usbfs/下面可以看到此文件。
3. usb_create_removeid_file() ==> 創建removeid屬性文件,在/sys/bus/usb/drivers/usbfs/下面可以看到此文件。
4. 輸出信息:usbcore: registered new interface driver usbfs
問題:newid與removeid屬性文件的作用是什麼?
回答:等待解答。
現在分析driver_register功能:
1. 首先判斷,些驅動所屬bus的subsys_private結構有沒有初始化。如果沒有,報bug信息。
2. 判斷需要注冊的driver和driver所屬的bus是否都有probe, remove, shutdown函數。如有,打印kernel warning信息。
3. 判斷此driver已經在driver所屬的bus上面注冊過了。如果注冊過了,打印錯誤信息,並返回。
4. 調用bus_add_driver來注冊driver。
5. 調用driver_add_groups來添加組屬性。
6. 返回。
最後對bus_add_driver進行分析。
- /**
- * bus_add_driver - Add a driver to the bus.
- * @drv: driver.
- */
- int bus_add_driver(struct device_driver *drv)
- {
- struct bus_type *bus;
- struct driver_private *priv;
- int error = 0;
-
- bus = bus_get(drv->bus);
- if (!bus)
- return -EINVAL;
-
- pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- error = -ENOMEM;
- goto out_put_bus;
- }
- klist_init(&priv->klist_devices, NULL, NULL);
- priv->driver = drv;
- drv->p = priv;
- priv->kobj.kset = bus->p->drivers_kset;
- error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
- "%s", drv->name);
- if (error)
- goto out_unregister;
-
- if (drv->bus->p->drivers_autoprobe) {
- error = driver_attach(drv);
- if (error)
- goto out_unregister;
- }
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
- module_add_driver(drv->owner, drv);
-
- error = driver_create_file(drv, &driver_attr_uevent);
- if (error) {
- printk(KERN_ERR "%s: uevent attr (%s) failed\n",
- __func__, drv->name);
- }
- error = driver_add_attrs(bus, drv);
- if (error) {
- /* How the hell do we get out of this pickle? Give up */
- printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
- __func__, drv->name);
- }
-
- if (!drv->suppress_bind_attrs) {
- error = add_bind_files(drv);
- if (error) {
- /* Ditto */
- printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
- __func__, drv->name);
- }
- }
-
- kobject_uevent(&priv->kobj, KOBJ_ADD);
- return 0;
-
- out_unregister:
- kobject_put(&priv->kobj);
- kfree(drv->p);
- drv->p = NULL;
- out_put_bus:
- bus_put(bus);
- return error;
- }
其功能是向bus中添加一個driver。
1. bus_get() ==> bus的計數加1;
2. kzalloc,分配driver_private內存空間。
3. 初始化此driver的klist_devices鏈表。
4. kobject_init_and_add() ==> 在/sys/bus/usb/drivers/下面創建usbfs文件夾。
5. 如果總線支持drivers_autoprobe,調用driver_attach。(USB 總線支持)
6. driver_create_file ==> 在/sys/bus/usb/drivers/usbfs下面創建uevent屬性文件。
7. driver_add_attrs() ==> 將總線的屬性也加到/sys/bus/usb/drivers/usbfs
8. add_bind_files() ==> 在/sys/bus/usb/drivers/usbfs創建bind和unbind屬性文件。
9. kobject_uevent() ==> 發送一個KOBJ_ADD的事件。
在/sys/bus/usb/drivers/usbfs下面的文件:
bind module new_id remove_id uevent unbind