Objective: To study USB in depth and take notes here. Welcome to the discussion.
[Linux 3.2] [Driver/USB/CORE/devio. C]
Definition: 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]
Function: 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]
Function: 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;}
The main function of this function is implemented through driver_register. Detailed analysis will be performed later.
Other functions are as follows:
1. usbfs_update_special () ==> it is related to the USB file system and is not analyzed for the time being.
2. usb_create_newid_file () ==> create the newid attribute file, which can be viewed under/sys/bus/USB/Drivers/usbfs.
3. usb_create_removeid_file () ==> create the removeid attribute file, which can be viewed under/sys/bus/USB/Drivers/usbfs.
4. Output Information: usbcore: registered new interface driver usbfs
Question: What is the role of the newid and removeid attribute files?
Answer: Wait for answers.
Analyze the driver_register function:
1. First, check whether the subsys_private structure of the driver is initialized. If no, the system reports a bug.
2. Check whether probe, remove, and shutdown functions are available for the driver and driver to be registered. If any, print the kernel warning information.
3. Check whether the driver has been registered on the bus to which the driver belongs. If the error message is returned after registration.
4. Call bus_add_driver to register the driver.
5. Call driver_add_groups to add group attributes.
6. Return.
Finally, analyze 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;}
The function is to add a driver to the bus.
1. bus_get () => increase the Count of bus by 1;
2. kzarloc: allocate driver_private memory space.
3. initialize the klist_devices linked list of the driver.
4. kobject_init_and_add () ==> create a usb fs folder under/sys/bus/USB/Drivers.
5. If the bus supports drivers_autoprobe, call driver_attach. (USB Bus Support)
6. driver_create_file ==> create a uevent attribute file under/sys/bus/USB/Drivers/usbfs.
7. driver_add_attrs () => Add the bus attribute to/sys/bus/USB/Drivers/usbfs.
8. add_bind_files () ==> create bind and unbind attribute files in/sys/bus/USB/Drivers/usbfs.
9. kobject_uevent () ==> send a kobj_add event.
Files under/sys/bus/USB/Drivers/usbfs:
Bind module new_id remove_id uevent unbind