📄 bus.c
字号:
/** * bus_attach_device - add device to bus * @dev: device tried to attach to a driver * * - Add device to bus's list of devices. * - Try to attach to driver. */void bus_attach_device(struct device * dev){ struct bus_type *bus = dev->bus; int ret = 0; if (bus) { dev->is_registered = 1; if (bus->drivers_autoprobe) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) klist_add_tail(&dev->knode_bus, &bus->klist_devices); else dev->is_registered = 0; }}/** * bus_remove_device - remove device from bus * @dev: device to be removed * * - Remove symlink from bus's directory. * - Delete device from bus's list. * - Detach from its driver. * - Drop reference taken in bus_add_device(). */void bus_remove_device(struct device * dev){ if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); if (dev->is_registered) { dev->is_registered = 0; klist_del(&dev->knode_bus); } pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); device_release_driver(dev); bus_put(dev->bus); }}static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv){ int error = 0; int i; if (bus->drv_attrs) { for (i = 0; attr_name(bus->drv_attrs[i]); i++) { error = driver_create_file(drv, &bus->drv_attrs[i]); if (error) goto Err; } } Done: return error; Err: while (--i >= 0) driver_remove_file(drv, &bus->drv_attrs[i]); goto Done;}static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv){ int i; if (bus->drv_attrs) { for (i = 0; attr_name(bus->drv_attrs[i]); i++) driver_remove_file(drv, &bus->drv_attrs[i]); }}#ifdef CONFIG_HOTPLUG/* * Thanks to drivers making their tables __devinit, we can't allow manual * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled. */static int __must_check add_bind_files(struct device_driver *drv){ int ret; ret = driver_create_file(drv, &driver_attr_unbind); if (ret == 0) { ret = driver_create_file(drv, &driver_attr_bind); if (ret) driver_remove_file(drv, &driver_attr_unbind); } return ret;}static void remove_bind_files(struct device_driver *drv){ driver_remove_file(drv, &driver_attr_bind); driver_remove_file(drv, &driver_attr_unbind);}static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, show_drivers_autoprobe, store_drivers_autoprobe);static int add_probe_files(struct bus_type *bus){ int retval; retval = bus_create_file(bus, &bus_attr_drivers_probe); if (retval) goto out; retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); if (retval) bus_remove_file(bus, &bus_attr_drivers_probe);out: return retval;}static void remove_probe_files(struct bus_type *bus){ bus_remove_file(bus, &bus_attr_drivers_autoprobe); bus_remove_file(bus, &bus_attr_drivers_probe);}#elsestatic inline int add_bind_files(struct device_driver *drv) { return 0; }static inline void remove_bind_files(struct device_driver *drv) {}static inline int add_probe_files(struct bus_type *bus) { return 0; }static inline void remove_probe_files(struct bus_type *bus) {}#endifstatic ssize_t driver_uevent_store(struct device_driver *drv, const char *buf, size_t count){ enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) kobject_uevent(&drv->kobj, action); return count;}static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);/** * bus_add_driver - Add a driver to the bus. * @drv: driver. * */int bus_add_driver(struct device_driver *drv){ struct bus_type * bus = bus_get(drv->bus); int error = 0; if (!bus) return -EINVAL; pr_debug("bus %s: add driver %s\n", bus->name, drv->name); error = kobject_set_name(&drv->kobj, "%s", drv->name); if (error) goto out_put_bus; drv->kobj.kset = &bus->drivers; error = kobject_register(&drv->kobj); if (error) goto out_put_bus; if (drv->bus->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } klist_add_tail(&drv->knode_bus, &bus->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", __FUNCTION__, 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", __FUNCTION__, drv->name); } error = add_bind_files(drv); if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __FUNCTION__, drv->name); } return error;out_unregister: kobject_unregister(&drv->kobj);out_put_bus: bus_put(bus); return error;}/** * bus_remove_driver - delete driver from bus's knowledge. * @drv: driver. * * Detach the driver from the devices it controls, and remove * it from its bus's list of drivers. Finally, we drop the reference * to the bus we took in bus_add_driver(). */void bus_remove_driver(struct device_driver * drv){ if (!drv->bus) return; remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); driver_remove_file(drv, &driver_attr_uevent); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); kobject_unregister(&drv->kobj); bus_put(drv->bus);}/* Helper for bus_rescan_devices's iter */static int __must_check bus_rescan_devices_helper(struct device *dev, void *data){ int ret = 0; if (!dev->driver) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); ret = device_attach(dev); if (dev->parent) up(&dev->parent->sem); } return ret < 0 ? ret : 0;}/** * bus_rescan_devices - rescan devices on the bus for possible drivers * @bus: the bus to scan. * * This function will look for devices on the bus with no driver * attached and rescan it against existing drivers to see if it matches * any by calling device_attach() for the unbound devices. */int bus_rescan_devices(struct bus_type * bus){ return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);}/** * device_reprobe - remove driver for a device and probe for a new driver * @dev: the device to reprobe * * This function detaches the attached driver (if any) for the given * device and restarts the driver probing process. It is intended * to use if probing criteria changed during a devices lifetime and * driver attachment should change accordingly. */int device_reprobe(struct device *dev){ if (dev->driver) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); device_release_driver(dev); if (dev->parent) up(&dev->parent->sem); } return bus_rescan_devices_helper(dev, NULL);}EXPORT_SYMBOL_GPL(device_reprobe);/** * find_bus - locate bus by name. * @name: name of bus. * * Call kset_find_obj() to iterate over list of buses to * find a bus by name. Return bus if found. * * Note that kset_find_obj increments bus' reference count. */#if 0struct bus_type * find_bus(char * name){ struct kobject * k = kset_find_obj(&bus_subsys.kset, name); return k ? to_bus(k) : NULL;}#endif /* 0 *//** * bus_add_attrs - Add default attributes for this bus. * @bus: Bus that has just been registered. */static int bus_add_attrs(struct bus_type * bus){ int error = 0; int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) { error = bus_create_file(bus,&bus->bus_attrs[i]); if (error) goto Err; } } Done: return error; Err: while (--i >= 0) bus_remove_file(bus,&bus->bus_attrs[i]); goto Done;}static void bus_remove_attrs(struct bus_type * bus){ int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) bus_remove_file(bus,&bus->bus_attrs[i]); }}static void klist_devices_get(struct klist_node *n){ struct device *dev = container_of(n, struct device, knode_bus); get_device(dev);}static void klist_devices_put(struct klist_node *n){ struct device *dev = container_of(n, struct device, knode_bus); put_device(dev);}static ssize_t bus_uevent_store(struct bus_type *bus, const char *buf, size_t count){ enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) kobject_uevent(&bus->subsys.kobj, action); return count;}static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);/** * bus_register - register a bus with the system. * @bus: bus. * * Once we have that, we registered the bus with the kobject * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the bus. */int bus_register(struct bus_type * bus){ int retval; BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); if (retval) goto out; bus->subsys.kobj.kset = &bus_subsys; retval = subsystem_register(&bus->subsys); if (retval) goto out; retval = bus_create_file(bus, &bus_attr_uevent); if (retval) goto bus_uevent_fail; kobject_set_name(&bus->devices.kobj, "devices"); bus->devices.kobj.parent = &bus->subsys.kobj; retval = kset_register(&bus->devices); if (retval) goto bus_devices_fail; kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; bus->drivers.ktype = &driver_ktype; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, NULL, NULL); bus->drivers_autoprobe = 1; retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; retval = bus_add_attrs(bus); if (retval) goto bus_attrs_fail; pr_debug("bus type '%s' registered\n", bus->name); return 0;bus_attrs_fail: remove_probe_files(bus);bus_probe_files_fail: kset_unregister(&bus->drivers);bus_drivers_fail: kset_unregister(&bus->devices);bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent);bus_uevent_fail: subsystem_unregister(&bus->subsys);out: return retval;}/** * bus_unregister - remove a bus from the system * @bus: bus. * * Unregister the child subsystems and the bus itself. * Finally, we call bus_put() to release the refcount */void bus_unregister(struct bus_type * bus){ pr_debug("bus %s: unregistering\n", bus->name); bus_remove_attrs(bus); remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys);}int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb){ return blocking_notifier_chain_register(&bus->bus_notifier, nb);}EXPORT_SYMBOL_GPL(bus_register_notifier);int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb){ return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);}EXPORT_SYMBOL_GPL(bus_unregister_notifier);int __init buses_init(void){ return subsystem_register(&bus_subsys);}EXPORT_SYMBOL_GPL(bus_for_each_dev);EXPORT_SYMBOL_GPL(bus_find_device);EXPORT_SYMBOL_GPL(bus_for_each_drv);EXPORT_SYMBOL_GPL(bus_register);EXPORT_SYMBOL_GPL(bus_unregister);EXPORT_SYMBOL_GPL(bus_rescan_devices);EXPORT_SYMBOL_GPL(bus_create_file);EXPORT_SYMBOL_GPL(bus_remove_file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -