diff options
Diffstat (limited to 'drivers/base/platform.c')
-rw-r--r-- | drivers/base/platform.c | 299 |
1 files changed, 286 insertions, 13 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 349a1013603f..b5b6c973a2e0 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -217,6 +217,7 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, | |||
217 | if (d) { | 217 | if (d) { |
218 | memcpy(d, data, size); | 218 | memcpy(d, data, size); |
219 | pdev->dev.platform_data = d; | 219 | pdev->dev.platform_data = d; |
220 | pdev->platform_data = d; | ||
220 | } | 221 | } |
221 | return d ? 0 : -ENOMEM; | 222 | return d ? 0 : -ENOMEM; |
222 | } | 223 | } |
@@ -246,6 +247,21 @@ int platform_device_add(struct platform_device *pdev) | |||
246 | else | 247 | else |
247 | dev_set_name(&pdev->dev, pdev->name); | 248 | dev_set_name(&pdev->dev, pdev->name); |
248 | 249 | ||
250 | /* We will remove platform_data field from struct device | ||
251 | * if all platform devices pass its platform specific data | ||
252 | * from platform_device. The conversion is going to be a | ||
253 | * long time, so we allow the two cases coexist to make | ||
254 | * this kind of fix more easily*/ | ||
255 | if (pdev->platform_data && pdev->dev.platform_data) { | ||
256 | printk(KERN_ERR | ||
257 | "%s: use which platform_data?\n", | ||
258 | dev_name(&pdev->dev)); | ||
259 | } else if (pdev->platform_data) { | ||
260 | pdev->dev.platform_data = pdev->platform_data; | ||
261 | } else if (pdev->dev.platform_data) { | ||
262 | pdev->platform_data = pdev->dev.platform_data; | ||
263 | } | ||
264 | |||
249 | for (i = 0; i < pdev->num_resources; i++) { | 265 | for (i = 0; i < pdev->num_resources; i++) { |
250 | struct resource *p, *r = &pdev->resource[i]; | 266 | struct resource *p, *r = &pdev->resource[i]; |
251 | 267 | ||
@@ -584,10 +600,25 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
584 | { | 600 | { |
585 | struct platform_device *pdev = to_platform_device(dev); | 601 | struct platform_device *pdev = to_platform_device(dev); |
586 | 602 | ||
587 | add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); | 603 | add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, |
604 | (pdev->id_entry) ? pdev->id_entry->name : pdev->name); | ||
588 | return 0; | 605 | return 0; |
589 | } | 606 | } |
590 | 607 | ||
608 | static const struct platform_device_id *platform_match_id( | ||
609 | struct platform_device_id *id, | ||
610 | struct platform_device *pdev) | ||
611 | { | ||
612 | while (id->name[0]) { | ||
613 | if (strcmp(pdev->name, id->name) == 0) { | ||
614 | pdev->id_entry = id; | ||
615 | return id; | ||
616 | } | ||
617 | id++; | ||
618 | } | ||
619 | return NULL; | ||
620 | } | ||
621 | |||
591 | /** | 622 | /** |
592 | * platform_match - bind platform device to platform driver. | 623 | * platform_match - bind platform device to platform driver. |
593 | * @dev: device. | 624 | * @dev: device. |
@@ -603,9 +634,14 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
603 | */ | 634 | */ |
604 | static int platform_match(struct device *dev, struct device_driver *drv) | 635 | static int platform_match(struct device *dev, struct device_driver *drv) |
605 | { | 636 | { |
606 | struct platform_device *pdev; | 637 | struct platform_device *pdev = to_platform_device(dev); |
638 | struct platform_driver *pdrv = to_platform_driver(drv); | ||
639 | |||
640 | /* match against the id table first */ | ||
641 | if (pdrv->id_table) | ||
642 | return platform_match_id(pdrv->id_table, pdev) != NULL; | ||
607 | 643 | ||
608 | pdev = container_of(dev, struct platform_device, dev); | 644 | /* fall-back to driver name match */ |
609 | return (strcmp(pdev->name, drv->name) == 0); | 645 | return (strcmp(pdev->name, drv->name) == 0); |
610 | } | 646 | } |
611 | 647 | ||
@@ -623,26 +659,24 @@ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) | |||
623 | 659 | ||
624 | static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg) | 660 | static int platform_legacy_suspend_late(struct device *dev, pm_message_t mesg) |
625 | { | 661 | { |
626 | struct platform_driver *drv = to_platform_driver(dev->driver); | 662 | struct platform_driver *pdrv = to_platform_driver(dev->driver); |
627 | struct platform_device *pdev; | 663 | struct platform_device *pdev = to_platform_device(dev); |
628 | int ret = 0; | 664 | int ret = 0; |
629 | 665 | ||
630 | pdev = container_of(dev, struct platform_device, dev); | 666 | if (dev->driver && pdrv->suspend_late) |
631 | if (dev->driver && drv->suspend_late) | 667 | ret = pdrv->suspend_late(pdev, mesg); |
632 | ret = drv->suspend_late(pdev, mesg); | ||
633 | 668 | ||
634 | return ret; | 669 | return ret; |
635 | } | 670 | } |
636 | 671 | ||
637 | static int platform_legacy_resume_early(struct device *dev) | 672 | static int platform_legacy_resume_early(struct device *dev) |
638 | { | 673 | { |
639 | struct platform_driver *drv = to_platform_driver(dev->driver); | 674 | struct platform_driver *pdrv = to_platform_driver(dev->driver); |
640 | struct platform_device *pdev; | 675 | struct platform_device *pdev = to_platform_device(dev); |
641 | int ret = 0; | 676 | int ret = 0; |
642 | 677 | ||
643 | pdev = container_of(dev, struct platform_device, dev); | 678 | if (dev->driver && pdrv->resume_early) |
644 | if (dev->driver && drv->resume_early) | 679 | ret = pdrv->resume_early(pdev); |
645 | ret = drv->resume_early(pdev); | ||
646 | 680 | ||
647 | return ret; | 681 | return ret; |
648 | } | 682 | } |
@@ -956,6 +990,8 @@ int __init platform_bus_init(void) | |||
956 | { | 990 | { |
957 | int error; | 991 | int error; |
958 | 992 | ||
993 | early_platform_cleanup(); | ||
994 | |||
959 | error = device_register(&platform_bus); | 995 | error = device_register(&platform_bus); |
960 | if (error) | 996 | if (error) |
961 | return error; | 997 | return error; |
@@ -986,3 +1022,240 @@ u64 dma_get_required_mask(struct device *dev) | |||
986 | } | 1022 | } |
987 | EXPORT_SYMBOL_GPL(dma_get_required_mask); | 1023 | EXPORT_SYMBOL_GPL(dma_get_required_mask); |
988 | #endif | 1024 | #endif |
1025 | |||
1026 | static __initdata LIST_HEAD(early_platform_driver_list); | ||
1027 | static __initdata LIST_HEAD(early_platform_device_list); | ||
1028 | |||
1029 | /** | ||
1030 | * early_platform_driver_register | ||
1031 | * @edrv: early_platform driver structure | ||
1032 | * @buf: string passed from early_param() | ||
1033 | */ | ||
1034 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, | ||
1035 | char *buf) | ||
1036 | { | ||
1037 | unsigned long index; | ||
1038 | int n; | ||
1039 | |||
1040 | /* Simply add the driver to the end of the global list. | ||
1041 | * Drivers will by default be put on the list in compiled-in order. | ||
1042 | */ | ||
1043 | if (!epdrv->list.next) { | ||
1044 | INIT_LIST_HEAD(&epdrv->list); | ||
1045 | list_add_tail(&epdrv->list, &early_platform_driver_list); | ||
1046 | } | ||
1047 | |||
1048 | /* If the user has specified device then make sure the driver | ||
1049 | * gets prioritized. The driver of the last device specified on | ||
1050 | * command line will be put first on the list. | ||
1051 | */ | ||
1052 | n = strlen(epdrv->pdrv->driver.name); | ||
1053 | if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { | ||
1054 | list_move(&epdrv->list, &early_platform_driver_list); | ||
1055 | |||
1056 | if (!strcmp(buf, epdrv->pdrv->driver.name)) | ||
1057 | epdrv->requested_id = -1; | ||
1058 | else if (buf[n] == '.' && strict_strtoul(&buf[n + 1], 10, | ||
1059 | &index) == 0) | ||
1060 | epdrv->requested_id = index; | ||
1061 | else | ||
1062 | epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; | ||
1063 | } | ||
1064 | |||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | /** | ||
1069 | * early_platform_add_devices - add a numbers of early platform devices | ||
1070 | * @devs: array of early platform devices to add | ||
1071 | * @num: number of early platform devices in array | ||
1072 | */ | ||
1073 | void __init early_platform_add_devices(struct platform_device **devs, int num) | ||
1074 | { | ||
1075 | struct device *dev; | ||
1076 | int i; | ||
1077 | |||
1078 | /* simply add the devices to list */ | ||
1079 | for (i = 0; i < num; i++) { | ||
1080 | dev = &devs[i]->dev; | ||
1081 | |||
1082 | if (!dev->devres_head.next) { | ||
1083 | INIT_LIST_HEAD(&dev->devres_head); | ||
1084 | list_add_tail(&dev->devres_head, | ||
1085 | &early_platform_device_list); | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /** | ||
1091 | * early_platform_driver_register_all | ||
1092 | * @class_str: string to identify early platform driver class | ||
1093 | */ | ||
1094 | void __init early_platform_driver_register_all(char *class_str) | ||
1095 | { | ||
1096 | /* The "class_str" parameter may or may not be present on the kernel | ||
1097 | * command line. If it is present then there may be more than one | ||
1098 | * matching parameter. | ||
1099 | * | ||
1100 | * Since we register our early platform drivers using early_param() | ||
1101 | * we need to make sure that they also get registered in the case | ||
1102 | * when the parameter is missing from the kernel command line. | ||
1103 | * | ||
1104 | * We use parse_early_options() to make sure the early_param() gets | ||
1105 | * called at least once. The early_param() may be called more than | ||
1106 | * once since the name of the preferred device may be specified on | ||
1107 | * the kernel command line. early_platform_driver_register() handles | ||
1108 | * this case for us. | ||
1109 | */ | ||
1110 | parse_early_options(class_str); | ||
1111 | } | ||
1112 | |||
1113 | /** | ||
1114 | * early_platform_match | ||
1115 | * @edrv: early platform driver structure | ||
1116 | * @id: id to match against | ||
1117 | */ | ||
1118 | static __init struct platform_device * | ||
1119 | early_platform_match(struct early_platform_driver *epdrv, int id) | ||
1120 | { | ||
1121 | struct platform_device *pd; | ||
1122 | |||
1123 | list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) | ||
1124 | if (platform_match(&pd->dev, &epdrv->pdrv->driver)) | ||
1125 | if (pd->id == id) | ||
1126 | return pd; | ||
1127 | |||
1128 | return NULL; | ||
1129 | } | ||
1130 | |||
1131 | /** | ||
1132 | * early_platform_left | ||
1133 | * @edrv: early platform driver structure | ||
1134 | * @id: return true if id or above exists | ||
1135 | */ | ||
1136 | static __init int early_platform_left(struct early_platform_driver *epdrv, | ||
1137 | int id) | ||
1138 | { | ||
1139 | struct platform_device *pd; | ||
1140 | |||
1141 | list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) | ||
1142 | if (platform_match(&pd->dev, &epdrv->pdrv->driver)) | ||
1143 | if (pd->id >= id) | ||
1144 | return 1; | ||
1145 | |||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | /** | ||
1150 | * early_platform_driver_probe_id | ||
1151 | * @class_str: string to identify early platform driver class | ||
1152 | * @id: id to match against | ||
1153 | * @nr_probe: number of platform devices to successfully probe before exiting | ||
1154 | */ | ||
1155 | static int __init early_platform_driver_probe_id(char *class_str, | ||
1156 | int id, | ||
1157 | int nr_probe) | ||
1158 | { | ||
1159 | struct early_platform_driver *epdrv; | ||
1160 | struct platform_device *match; | ||
1161 | int match_id; | ||
1162 | int n = 0; | ||
1163 | int left = 0; | ||
1164 | |||
1165 | list_for_each_entry(epdrv, &early_platform_driver_list, list) { | ||
1166 | /* only use drivers matching our class_str */ | ||
1167 | if (strcmp(class_str, epdrv->class_str)) | ||
1168 | continue; | ||
1169 | |||
1170 | if (id == -2) { | ||
1171 | match_id = epdrv->requested_id; | ||
1172 | left = 1; | ||
1173 | |||
1174 | } else { | ||
1175 | match_id = id; | ||
1176 | left += early_platform_left(epdrv, id); | ||
1177 | |||
1178 | /* skip requested id */ | ||
1179 | switch (epdrv->requested_id) { | ||
1180 | case EARLY_PLATFORM_ID_ERROR: | ||
1181 | case EARLY_PLATFORM_ID_UNSET: | ||
1182 | break; | ||
1183 | default: | ||
1184 | if (epdrv->requested_id == id) | ||
1185 | match_id = EARLY_PLATFORM_ID_UNSET; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | switch (match_id) { | ||
1190 | case EARLY_PLATFORM_ID_ERROR: | ||
1191 | pr_warning("%s: unable to parse %s parameter\n", | ||
1192 | class_str, epdrv->pdrv->driver.name); | ||
1193 | /* fall-through */ | ||
1194 | case EARLY_PLATFORM_ID_UNSET: | ||
1195 | match = NULL; | ||
1196 | break; | ||
1197 | default: | ||
1198 | match = early_platform_match(epdrv, match_id); | ||
1199 | } | ||
1200 | |||
1201 | if (match) { | ||
1202 | if (epdrv->pdrv->probe(match)) | ||
1203 | pr_warning("%s: unable to probe %s early.\n", | ||
1204 | class_str, match->name); | ||
1205 | else | ||
1206 | n++; | ||
1207 | } | ||
1208 | |||
1209 | if (n >= nr_probe) | ||
1210 | break; | ||
1211 | } | ||
1212 | |||
1213 | if (left) | ||
1214 | return n; | ||
1215 | else | ||
1216 | return -ENODEV; | ||
1217 | } | ||
1218 | |||
1219 | /** | ||
1220 | * early_platform_driver_probe | ||
1221 | * @class_str: string to identify early platform driver class | ||
1222 | * @nr_probe: number of platform devices to successfully probe before exiting | ||
1223 | * @user_only: only probe user specified early platform devices | ||
1224 | */ | ||
1225 | int __init early_platform_driver_probe(char *class_str, | ||
1226 | int nr_probe, | ||
1227 | int user_only) | ||
1228 | { | ||
1229 | int k, n, i; | ||
1230 | |||
1231 | n = 0; | ||
1232 | for (i = -2; n < nr_probe; i++) { | ||
1233 | k = early_platform_driver_probe_id(class_str, i, nr_probe - n); | ||
1234 | |||
1235 | if (k < 0) | ||
1236 | break; | ||
1237 | |||
1238 | n += k; | ||
1239 | |||
1240 | if (user_only) | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | return n; | ||
1245 | } | ||
1246 | |||
1247 | /** | ||
1248 | * early_platform_cleanup - clean up early platform code | ||
1249 | */ | ||
1250 | void __init early_platform_cleanup(void) | ||
1251 | { | ||
1252 | struct platform_device *pd, *pd2; | ||
1253 | |||
1254 | /* clean up the devres list used to chain devices */ | ||
1255 | list_for_each_entry_safe(pd, pd2, &early_platform_device_list, | ||
1256 | dev.devres_head) { | ||
1257 | list_del(&pd->dev.devres_head); | ||
1258 | memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); | ||
1259 | } | ||
1260 | } | ||
1261 | |||