diff options
Diffstat (limited to 'drivers/base/core.c')
| -rw-r--r-- | drivers/base/core.c | 95 | 
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d2f7ac..334ec7ef1960 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -534,6 +534,52 @@ static DEVICE_ATTR_RO(dev);  struct kset *devices_kset;  /** + * devices_kset_move_before - Move device in the devices_kset's list. + * @deva: Device to move. + * @devb: Device @deva should come before. + */ +static void devices_kset_move_before(struct device *deva, struct device *devb) +{ +	if (!devices_kset) +		return; +	pr_debug("devices_kset: Moving %s before %s\n", +		 dev_name(deva), dev_name(devb)); +	spin_lock(&devices_kset->list_lock); +	list_move_tail(&deva->kobj.entry, &devb->kobj.entry); +	spin_unlock(&devices_kset->list_lock); +} + +/** + * devices_kset_move_after - Move device in the devices_kset's list. + * @deva: Device to move + * @devb: Device @deva should come after. + */ +static void devices_kset_move_after(struct device *deva, struct device *devb) +{ +	if (!devices_kset) +		return; +	pr_debug("devices_kset: Moving %s after %s\n", +		 dev_name(deva), dev_name(devb)); +	spin_lock(&devices_kset->list_lock); +	list_move(&deva->kobj.entry, &devb->kobj.entry); +	spin_unlock(&devices_kset->list_lock); +} + +/** + * devices_kset_move_last - move the device to the end of devices_kset's list. + * @dev: device to move + */ +void devices_kset_move_last(struct device *dev) +{ +	if (!devices_kset) +		return; +	pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); +	spin_lock(&devices_kset->list_lock); +	list_move_tail(&dev->kobj.entry, &devices_kset->list); +	spin_unlock(&devices_kset->list_lock); +} + +/**   * device_create_file - create sysfs attribute file for device.   * @dev: device.   * @attr: device attribute descriptor. @@ -662,6 +708,9 @@ void device_initialize(struct device *dev)  	INIT_LIST_HEAD(&dev->devres_head);  	device_pm_init(dev);  	set_dev_node(dev, -1); +#ifdef CONFIG_GENERIC_MSI_IRQ +	INIT_LIST_HEAD(&dev->msi_list); +#endif  }  EXPORT_SYMBOL_GPL(device_initialize); @@ -1252,6 +1301,19 @@ void device_unregister(struct device *dev)  }  EXPORT_SYMBOL_GPL(device_unregister); +static struct device *prev_device(struct klist_iter *i) +{ +	struct klist_node *n = klist_prev(i); +	struct device *dev = NULL; +	struct device_private *p; + +	if (n) { +		p = to_device_private_parent(n); +		dev = p->device; +	} +	return dev; +} +  static struct device *next_device(struct klist_iter *i)  {  	struct klist_node *n = klist_next(i); @@ -1341,6 +1403,36 @@ int device_for_each_child(struct device *parent, void *data,  EXPORT_SYMBOL_GPL(device_for_each_child);  /** + * device_for_each_child_reverse - device child iterator in reversed order. + * @parent: parent struct device. + * @fn: function to be called for each device. + * @data: data for the callback. + * + * Iterate over @parent's child devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + */ +int device_for_each_child_reverse(struct device *parent, void *data, +				  int (*fn)(struct device *dev, void *data)) +{ +	struct klist_iter i; +	struct device *child; +	int error = 0; + +	if (!parent->p) +		return 0; + +	klist_iter_init(&parent->p->klist_children, &i); +	while ((child = prev_device(&i)) && !error) +		error = fn(child, data); +	klist_iter_exit(&i); +	return error; +} +EXPORT_SYMBOL_GPL(device_for_each_child_reverse); + +/**   * device_find_child - device iterator for locating a particular device.   * @parent: parent struct device   * @match: Callback function to check device @@ -1923,12 +2015,15 @@ int device_move(struct device *dev, struct device *new_parent,  		break;  	case DPM_ORDER_DEV_AFTER_PARENT:  		device_pm_move_after(dev, new_parent); +		devices_kset_move_after(dev, new_parent);  		break;  	case DPM_ORDER_PARENT_BEFORE_DEV:  		device_pm_move_before(new_parent, dev); +		devices_kset_move_before(new_parent, dev);  		break;  	case DPM_ORDER_DEV_LAST:  		device_pm_move_last(dev); +		devices_kset_move_last(dev);  		break;  	}  |