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, |