diff options
Diffstat (limited to 'drivers/base/platform.c')
| -rw-r--r-- | drivers/base/platform.c | 139 |
1 files changed, 116 insertions, 23 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4fa954b07ac4..4b4b565c835f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -128,7 +128,7 @@ struct platform_object { | |||
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | /** | 130 | /** |
| 131 | * platform_device_put | 131 | * platform_device_put - destroy a platform device |
| 132 | * @pdev: platform device to free | 132 | * @pdev: platform device to free |
| 133 | * | 133 | * |
| 134 | * Free all memory associated with a platform device. This function must | 134 | * Free all memory associated with a platform device. This function must |
| @@ -152,7 +152,7 @@ static void platform_device_release(struct device *dev) | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | /** | 154 | /** |
| 155 | * platform_device_alloc | 155 | * platform_device_alloc - create a platform device |
| 156 | * @name: base name of the device we're adding | 156 | * @name: base name of the device we're adding |
| 157 | * @id: instance id | 157 | * @id: instance id |
| 158 | * | 158 | * |
| @@ -177,7 +177,7 @@ struct platform_device *platform_device_alloc(const char *name, int id) | |||
| 177 | EXPORT_SYMBOL_GPL(platform_device_alloc); | 177 | EXPORT_SYMBOL_GPL(platform_device_alloc); |
| 178 | 178 | ||
| 179 | /** | 179 | /** |
| 180 | * platform_device_add_resources | 180 | * platform_device_add_resources - add resources to a platform device |
| 181 | * @pdev: platform device allocated by platform_device_alloc to add resources to | 181 | * @pdev: platform device allocated by platform_device_alloc to add resources to |
| 182 | * @res: set of resources that needs to be allocated for the device | 182 | * @res: set of resources that needs to be allocated for the device |
| 183 | * @num: number of resources | 183 | * @num: number of resources |
| @@ -202,7 +202,7 @@ int platform_device_add_resources(struct platform_device *pdev, | |||
| 202 | EXPORT_SYMBOL_GPL(platform_device_add_resources); | 202 | EXPORT_SYMBOL_GPL(platform_device_add_resources); |
| 203 | 203 | ||
| 204 | /** | 204 | /** |
| 205 | * platform_device_add_data | 205 | * platform_device_add_data - add platform-specific data to a platform device |
| 206 | * @pdev: platform device allocated by platform_device_alloc to add resources to | 206 | * @pdev: platform device allocated by platform_device_alloc to add resources to |
| 207 | * @data: platform specific data for this platform device | 207 | * @data: platform specific data for this platform device |
| 208 | * @size: size of platform specific data | 208 | * @size: size of platform specific data |
| @@ -344,7 +344,7 @@ void platform_device_unregister(struct platform_device *pdev) | |||
| 344 | EXPORT_SYMBOL_GPL(platform_device_unregister); | 344 | EXPORT_SYMBOL_GPL(platform_device_unregister); |
| 345 | 345 | ||
| 346 | /** | 346 | /** |
| 347 | * platform_device_register_simple | 347 | * platform_device_register_simple - add a platform-level device and its resources |
| 348 | * @name: base name of the device we're adding | 348 | * @name: base name of the device we're adding |
| 349 | * @id: instance id | 349 | * @id: instance id |
| 350 | * @res: set of resources that needs to be allocated for the device | 350 | * @res: set of resources that needs to be allocated for the device |
| @@ -362,6 +362,8 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); | |||
| 362 | * enumeration tasks, they don't fully conform to the Linux driver model. | 362 | * enumeration tasks, they don't fully conform to the Linux driver model. |
| 363 | * In particular, when such drivers are built as modules, they can't be | 363 | * In particular, when such drivers are built as modules, they can't be |
| 364 | * "hotplugged". | 364 | * "hotplugged". |
| 365 | * | ||
| 366 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
| 365 | */ | 367 | */ |
| 366 | struct platform_device *platform_device_register_simple(const char *name, | 368 | struct platform_device *platform_device_register_simple(const char *name, |
| 367 | int id, | 369 | int id, |
| @@ -396,7 +398,7 @@ error: | |||
| 396 | EXPORT_SYMBOL_GPL(platform_device_register_simple); | 398 | EXPORT_SYMBOL_GPL(platform_device_register_simple); |
| 397 | 399 | ||
| 398 | /** | 400 | /** |
| 399 | * platform_device_register_data | 401 | * platform_device_register_data - add a platform-level device with platform-specific data |
| 400 | * @parent: parent device for the device we're adding | 402 | * @parent: parent device for the device we're adding |
| 401 | * @name: base name of the device we're adding | 403 | * @name: base name of the device we're adding |
| 402 | * @id: instance id | 404 | * @id: instance id |
| @@ -408,6 +410,8 @@ EXPORT_SYMBOL_GPL(platform_device_register_simple); | |||
| 408 | * allocated for the device allows drivers using such devices to be | 410 | * allocated for the device allows drivers using such devices to be |
| 409 | * unloaded without waiting for the last reference to the device to be | 411 | * unloaded without waiting for the last reference to the device to be |
| 410 | * dropped. | 412 | * dropped. |
| 413 | * | ||
| 414 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
| 411 | */ | 415 | */ |
| 412 | struct platform_device *platform_device_register_data( | 416 | struct platform_device *platform_device_register_data( |
| 413 | struct device *parent, | 417 | struct device *parent, |
| @@ -441,6 +445,7 @@ error: | |||
| 441 | platform_device_put(pdev); | 445 | platform_device_put(pdev); |
| 442 | return ERR_PTR(retval); | 446 | return ERR_PTR(retval); |
| 443 | } | 447 | } |
| 448 | EXPORT_SYMBOL_GPL(platform_device_register_data); | ||
| 444 | 449 | ||
| 445 | static int platform_drv_probe(struct device *_dev) | 450 | static int platform_drv_probe(struct device *_dev) |
| 446 | { | 451 | { |
| @@ -472,7 +477,7 @@ static void platform_drv_shutdown(struct device *_dev) | |||
| 472 | } | 477 | } |
| 473 | 478 | ||
| 474 | /** | 479 | /** |
| 475 | * platform_driver_register | 480 | * platform_driver_register - register a driver for platform-level devices |
| 476 | * @drv: platform driver structure | 481 | * @drv: platform driver structure |
| 477 | */ | 482 | */ |
| 478 | int platform_driver_register(struct platform_driver *drv) | 483 | int platform_driver_register(struct platform_driver *drv) |
| @@ -490,7 +495,7 @@ int platform_driver_register(struct platform_driver *drv) | |||
| 490 | EXPORT_SYMBOL_GPL(platform_driver_register); | 495 | EXPORT_SYMBOL_GPL(platform_driver_register); |
| 491 | 496 | ||
| 492 | /** | 497 | /** |
| 493 | * platform_driver_unregister | 498 | * platform_driver_unregister - unregister a driver for platform-level devices |
| 494 | * @drv: platform driver structure | 499 | * @drv: platform driver structure |
| 495 | */ | 500 | */ |
| 496 | void platform_driver_unregister(struct platform_driver *drv) | 501 | void platform_driver_unregister(struct platform_driver *drv) |
| @@ -547,6 +552,66 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, | |||
| 547 | } | 552 | } |
| 548 | EXPORT_SYMBOL_GPL(platform_driver_probe); | 553 | EXPORT_SYMBOL_GPL(platform_driver_probe); |
| 549 | 554 | ||
| 555 | /** | ||
| 556 | * platform_create_bundle - register driver and create corresponding device | ||
| 557 | * @driver: platform driver structure | ||
| 558 | * @probe: the driver probe routine, probably from an __init section | ||
| 559 | * @res: set of resources that needs to be allocated for the device | ||
| 560 | * @n_res: number of resources | ||
| 561 | * @data: platform specific data for this platform device | ||
| 562 | * @size: size of platform specific data | ||
| 563 | * | ||
| 564 | * Use this in legacy-style modules that probe hardware directly and | ||
| 565 | * register a single platform device and corresponding platform driver. | ||
| 566 | * | ||
| 567 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
| 568 | */ | ||
| 569 | struct platform_device * __init_or_module platform_create_bundle( | ||
| 570 | struct platform_driver *driver, | ||
| 571 | int (*probe)(struct platform_device *), | ||
| 572 | struct resource *res, unsigned int n_res, | ||
| 573 | const void *data, size_t size) | ||
| 574 | { | ||
| 575 | struct platform_device *pdev; | ||
| 576 | int error; | ||
| 577 | |||
| 578 | pdev = platform_device_alloc(driver->driver.name, -1); | ||
| 579 | if (!pdev) { | ||
| 580 | error = -ENOMEM; | ||
| 581 | goto err_out; | ||
| 582 | } | ||
| 583 | |||
| 584 | if (res) { | ||
| 585 | error = platform_device_add_resources(pdev, res, n_res); | ||
| 586 | if (error) | ||
| 587 | goto err_pdev_put; | ||
| 588 | } | ||
| 589 | |||
| 590 | if (data) { | ||
| 591 | error = platform_device_add_data(pdev, data, size); | ||
| 592 | if (error) | ||
| 593 | goto err_pdev_put; | ||
| 594 | } | ||
| 595 | |||
| 596 | error = platform_device_add(pdev); | ||
| 597 | if (error) | ||
| 598 | goto err_pdev_put; | ||
| 599 | |||
| 600 | error = platform_driver_probe(driver, probe); | ||
| 601 | if (error) | ||
| 602 | goto err_pdev_del; | ||
| 603 | |||
| 604 | return pdev; | ||
| 605 | |||
| 606 | err_pdev_del: | ||
| 607 | platform_device_del(pdev); | ||
| 608 | err_pdev_put: | ||
| 609 | platform_device_put(pdev); | ||
| 610 | err_out: | ||
| 611 | return ERR_PTR(error); | ||
| 612 | } | ||
| 613 | EXPORT_SYMBOL_GPL(platform_create_bundle); | ||
| 614 | |||
| 550 | /* modalias support enables more hands-off userspace setup: | 615 | /* modalias support enables more hands-off userspace setup: |
| 551 | * (a) environment variable lets new-style hotplug events work once system is | 616 | * (a) environment variable lets new-style hotplug events work once system is |
| 552 | * fully running: "modprobe $MODALIAS" | 617 | * fully running: "modprobe $MODALIAS" |
| @@ -577,7 +642,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 577 | } | 642 | } |
| 578 | 643 | ||
| 579 | static const struct platform_device_id *platform_match_id( | 644 | static const struct platform_device_id *platform_match_id( |
| 580 | struct platform_device_id *id, | 645 | const struct platform_device_id *id, |
| 581 | struct platform_device *pdev) | 646 | struct platform_device *pdev) |
| 582 | { | 647 | { |
| 583 | while (id->name[0]) { | 648 | while (id->name[0]) { |
| @@ -993,14 +1058,16 @@ static __initdata LIST_HEAD(early_platform_driver_list); | |||
| 993 | static __initdata LIST_HEAD(early_platform_device_list); | 1058 | static __initdata LIST_HEAD(early_platform_device_list); |
| 994 | 1059 | ||
| 995 | /** | 1060 | /** |
| 996 | * early_platform_driver_register | 1061 | * early_platform_driver_register - register early platform driver |
| 997 | * @epdrv: early_platform driver structure | 1062 | * @epdrv: early_platform driver structure |
| 998 | * @buf: string passed from early_param() | 1063 | * @buf: string passed from early_param() |
| 1064 | * | ||
| 1065 | * Helper function for early_platform_init() / early_platform_init_buffer() | ||
| 999 | */ | 1066 | */ |
| 1000 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, | 1067 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, |
| 1001 | char *buf) | 1068 | char *buf) |
| 1002 | { | 1069 | { |
| 1003 | unsigned long index; | 1070 | char *tmp; |
| 1004 | int n; | 1071 | int n; |
| 1005 | 1072 | ||
| 1006 | /* Simply add the driver to the end of the global list. | 1073 | /* Simply add the driver to the end of the global list. |
| @@ -1019,22 +1086,40 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv, | |||
| 1019 | if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { | 1086 | if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { |
| 1020 | list_move(&epdrv->list, &early_platform_driver_list); | 1087 | list_move(&epdrv->list, &early_platform_driver_list); |
| 1021 | 1088 | ||
| 1022 | if (!strcmp(buf, epdrv->pdrv->driver.name)) | 1089 | /* Allow passing parameters after device name */ |
| 1090 | if (buf[n] == '\0' || buf[n] == ',') | ||
| 1023 | epdrv->requested_id = -1; | 1091 | epdrv->requested_id = -1; |
| 1024 | else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10, | 1092 | else { |
| 1025 | &index) == 0) | 1093 | epdrv->requested_id = simple_strtoul(&buf[n + 1], |
| 1026 | epdrv->requested_id = index; | 1094 | &tmp, 10); |
| 1027 | else | 1095 | |
| 1028 | epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; | 1096 | if (buf[n] != '.' || (tmp == &buf[n + 1])) { |
| 1097 | epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; | ||
| 1098 | n = 0; | ||
| 1099 | } else | ||
| 1100 | n += strcspn(&buf[n + 1], ",") + 1; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | if (buf[n] == ',') | ||
| 1104 | n++; | ||
| 1105 | |||
| 1106 | if (epdrv->bufsize) { | ||
| 1107 | memcpy(epdrv->buffer, &buf[n], | ||
| 1108 | min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); | ||
| 1109 | epdrv->buffer[epdrv->bufsize - 1] = '\0'; | ||
| 1110 | } | ||
| 1029 | } | 1111 | } |
| 1030 | 1112 | ||
| 1031 | return 0; | 1113 | return 0; |
| 1032 | } | 1114 | } |
| 1033 | 1115 | ||
| 1034 | /** | 1116 | /** |
| 1035 | * early_platform_add_devices - add a numbers of early platform devices | 1117 | * early_platform_add_devices - adds a number of early platform devices |
| 1036 | * @devs: array of early platform devices to add | 1118 | * @devs: array of early platform devices to add |
| 1037 | * @num: number of early platform devices in array | 1119 | * @num: number of early platform devices in array |
| 1120 | * | ||
| 1121 | * Used by early architecture code to register early platform devices and | ||
| 1122 | * their platform data. | ||
| 1038 | */ | 1123 | */ |
| 1039 | void __init early_platform_add_devices(struct platform_device **devs, int num) | 1124 | void __init early_platform_add_devices(struct platform_device **devs, int num) |
| 1040 | { | 1125 | { |
| @@ -1054,8 +1139,12 @@ void __init early_platform_add_devices(struct platform_device **devs, int num) | |||
| 1054 | } | 1139 | } |
| 1055 | 1140 | ||
| 1056 | /** | 1141 | /** |
| 1057 | * early_platform_driver_register_all | 1142 | * early_platform_driver_register_all - register early platform drivers |
| 1058 | * @class_str: string to identify early platform driver class | 1143 | * @class_str: string to identify early platform driver class |
| 1144 | * | ||
| 1145 | * Used by architecture code to register all early platform drivers | ||
| 1146 | * for a certain class. If omitted then only early platform drivers | ||
| 1147 | * with matching kernel command line class parameters will be registered. | ||
| 1059 | */ | 1148 | */ |
| 1060 | void __init early_platform_driver_register_all(char *class_str) | 1149 | void __init early_platform_driver_register_all(char *class_str) |
| 1061 | { | 1150 | { |
| @@ -1077,7 +1166,7 @@ void __init early_platform_driver_register_all(char *class_str) | |||
| 1077 | } | 1166 | } |
| 1078 | 1167 | ||
| 1079 | /** | 1168 | /** |
| 1080 | * early_platform_match | 1169 | * early_platform_match - find early platform device matching driver |
| 1081 | * @epdrv: early platform driver structure | 1170 | * @epdrv: early platform driver structure |
| 1082 | * @id: id to match against | 1171 | * @id: id to match against |
| 1083 | */ | 1172 | */ |
| @@ -1095,7 +1184,7 @@ early_platform_match(struct early_platform_driver *epdrv, int id) | |||
| 1095 | } | 1184 | } |
| 1096 | 1185 | ||
| 1097 | /** | 1186 | /** |
| 1098 | * early_platform_left | 1187 | * early_platform_left - check if early platform driver has matching devices |
| 1099 | * @epdrv: early platform driver structure | 1188 | * @epdrv: early platform driver structure |
| 1100 | * @id: return true if id or above exists | 1189 | * @id: return true if id or above exists |
| 1101 | */ | 1190 | */ |
| @@ -1113,7 +1202,7 @@ static __init int early_platform_left(struct early_platform_driver *epdrv, | |||
| 1113 | } | 1202 | } |
| 1114 | 1203 | ||
| 1115 | /** | 1204 | /** |
| 1116 | * early_platform_driver_probe_id | 1205 | * early_platform_driver_probe_id - probe drivers matching class_str and id |
| 1117 | * @class_str: string to identify early platform driver class | 1206 | * @class_str: string to identify early platform driver class |
| 1118 | * @id: id to match against | 1207 | * @id: id to match against |
| 1119 | * @nr_probe: number of platform devices to successfully probe before exiting | 1208 | * @nr_probe: number of platform devices to successfully probe before exiting |
| @@ -1183,10 +1272,14 @@ static int __init early_platform_driver_probe_id(char *class_str, | |||
| 1183 | } | 1272 | } |
| 1184 | 1273 | ||
| 1185 | /** | 1274 | /** |
| 1186 | * early_platform_driver_probe | 1275 | * early_platform_driver_probe - probe a class of registered drivers |
| 1187 | * @class_str: string to identify early platform driver class | 1276 | * @class_str: string to identify early platform driver class |
| 1188 | * @nr_probe: number of platform devices to successfully probe before exiting | 1277 | * @nr_probe: number of platform devices to successfully probe before exiting |
| 1189 | * @user_only: only probe user specified early platform devices | 1278 | * @user_only: only probe user specified early platform devices |
| 1279 | * | ||
| 1280 | * Used by architecture code to probe registered early platform drivers | ||
| 1281 | * within a certain class. For probe to happen a registered early platform | ||
| 1282 | * device matching a registered early platform driver is needed. | ||
| 1190 | */ | 1283 | */ |
| 1191 | int __init early_platform_driver_probe(char *class_str, | 1284 | int __init early_platform_driver_probe(char *class_str, |
| 1192 | int nr_probe, | 1285 | int nr_probe, |
