diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 12:10:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 12:10:44 -0700 |
commit | 06d2fe153b9b35e57221e35831a26918f462db68 (patch) | |
tree | f77cb72dfba7f2a47ceb93e120abd9399a24a1b9 /drivers/base/platform.c | |
parent | 3aebd34b1200a902a8662da8845824a02f00772e (diff) | |
parent | e0f21e6d52cc245e7d4f7e02ca4b7b6571660ec2 (diff) |
Merge tag 'driver-core-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core merge from Greg Kroah-Hartman:
"Here is the big driver core update for 3.7-rc1.
A number of firmware_class.c updates (as you saw a month or so ago),
and some hyper-v updates and some printk fixes as well. All patches
that are outside of the drivers/base area have been acked by the
respective maintainers, and have all been in the linux-next tree for a
while.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
* tag 'driver-core-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (95 commits)
memory: tegra{20,30}-mc: Fix reading incorrect register in mc_readl()
device.h: Add missing inline to #ifndef CONFIG_PRINTK dev_vprintk_emit
memory: emif: Add ifdef CONFIG_DEBUG_FS guard for emif_debugfs_[init|exit]
Documentation: Fixes some translation error in Documentation/zh_CN/gpio.txt
Documentation: Remove 3 byte redundant code at the head of the Documentation/zh_CN/arm/booting
Documentation: Chinese translation of Documentation/video4linux/omap3isp.txt
device and dynamic_debug: Use dev_vprintk_emit and dev_printk_emit
dev: Add dev_vprintk_emit and dev_printk_emit
netdev_printk/netif_printk: Remove a superfluous logging colon
netdev_printk/dynamic_netdev_dbg: Directly call printk_emit
dev_dbg/dynamic_debug: Update to use printk_emit, optimize stack
driver-core: Shut up dev_dbg_reatelimited() without DEBUG
tools/hv: Parse /etc/os-release
tools/hv: Check for read/write errors
tools/hv: Fix exit() error code
tools/hv: Fix file handle leak
Tools: hv: Implement the KVP verb - KVP_OP_GET_IP_INFO
Tools: hv: Rename the function kvp_get_ip_address()
Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO
Tools: hv: Add an example script to configure an interface
...
Diffstat (limited to 'drivers/base/platform.c')
-rw-r--r-- | drivers/base/platform.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a1a722502587..ddeca142293c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -20,9 +20,13 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/idr.h> #include "base.h" +/* For automatically allocated device IDs */ +static DEFINE_IDA(platform_devid_ida); + #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ driver)) @@ -99,6 +103,9 @@ struct resource *platform_get_resource_byname(struct platform_device *dev, for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; + if (unlikely(!r->name)) + continue; + if (type == resource_type(r) && !strcmp(r->name, name)) return r; } @@ -263,7 +270,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_data); */ int platform_device_add(struct platform_device *pdev) { - int i, ret = 0; + int i, ret; if (!pdev) return -EINVAL; @@ -273,10 +280,27 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; - if (pdev->id != -1) + switch (pdev->id) { + default: dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - else + break; + case PLATFORM_DEVID_NONE: dev_set_name(&pdev->dev, "%s", pdev->name); + break; + case PLATFORM_DEVID_AUTO: + /* + * Automatically allocated device ID. We mark it as such so + * that we remember it must be freed, and we append a suffix + * to avoid namespace collision with explicit IDs. + */ + ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); + if (ret < 0) + goto err_out; + pdev->id = ret; + pdev->id_auto = true; + dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); + break; + } for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; @@ -309,6 +333,11 @@ int platform_device_add(struct platform_device *pdev) return ret; failed: + if (pdev->id_auto) { + ida_simple_remove(&platform_devid_ida, pdev->id); + pdev->id = PLATFORM_DEVID_AUTO; + } + while (--i >= 0) { struct resource *r = &pdev->resource[i]; unsigned long type = resource_type(r); @@ -317,6 +346,7 @@ int platform_device_add(struct platform_device *pdev) release_resource(r); } + err_out: return ret; } EXPORT_SYMBOL_GPL(platform_device_add); @@ -336,6 +366,11 @@ void platform_device_del(struct platform_device *pdev) if (pdev) { device_del(&pdev->dev); + if (pdev->id_auto) { + ida_simple_remove(&platform_devid_ida, pdev->id); + pdev->id = PLATFORM_DEVID_AUTO; + } + for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; unsigned long type = resource_type(r); |