Blame view
drivers/base/platform.c
30.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 |
/* * platform.c - platform 'pseudo' bus for legacy devices * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * * This file is released under the GPLv2 * * Please see Documentation/driver-model/platform.txt for more * information. */ |
daa412267 driver core: plat... |
12 |
#include <linux/string.h> |
d052d1bef Create platform_d... |
13 |
#include <linux/platform_device.h> |
05212157e drivercore/of: Ad... |
14 |
#include <linux/of_device.h> |
9ec36cafe of/irq: do irq re... |
15 |
#include <linux/of_irq.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 19 20 |
#include <linux/module.h> #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/bootmem.h> #include <linux/err.h> |
4e57b6817 [PATCH] fix missi... |
21 |
#include <linux/slab.h> |
9d7302299 PM: Run-time PM p... |
22 |
#include <linux/pm_runtime.h> |
689ae231a platform: Add sup... |
23 |
#include <linux/idr.h> |
91e568780 ACPI: Add support... |
24 |
#include <linux/acpi.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
|
a1bdc7aad [PATCH] drivers/b... |
26 |
#include "base.h" |
bed2b42d9 PM / Runtime: All... |
27 |
#include "power/power.h" |
a1bdc7aad [PATCH] drivers/b... |
28 |
|
689ae231a platform: Add sup... |
29 30 |
/* For automatically allocated device IDs */ static DEFINE_IDA(platform_devid_ida); |
1da177e4c Linux-2.6.12-rc2 |
31 |
struct device platform_bus = { |
1e0b2cf93 driver core: stru... |
32 |
.init_name = "platform", |
1da177e4c Linux-2.6.12-rc2 |
33 |
}; |
a96b20420 [PATCH] Driver Co... |
34 |
EXPORT_SYMBOL_GPL(platform_bus); |
1da177e4c Linux-2.6.12-rc2 |
35 36 |
/** |
a77ce8167 driver core: Add ... |
37 |
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used |
7de636fa2 driver core: fix ... |
38 |
* @pdev: platform device |
a77ce8167 driver core: Add ... |
39 40 41 42 43 |
* * This is called before platform_device_add() such that any pdev_archdata may * be setup before the platform_notifier is called. So if a user needs to * manipulate any relevant information in the pdev_archdata they can do: * |
b1d6d8225 drivers/base: fix... |
44 |
* platform_device_alloc() |
0258e182e driver core: plat... |
45 46 |
* ... manipulate ... * platform_device_add() |
a77ce8167 driver core: Add ... |
47 48 49 50 51 52 53 54 55 |
* * And if they don't care they can just call platform_device_register() and * everything will just work out. */ void __weak arch_setup_pdev_archdata(struct platform_device *pdev) { } /** |
4a3ad20cc Driver core: codi... |
56 57 58 59 |
* platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type * @num: resource index |
1da177e4c Linux-2.6.12-rc2 |
60 |
*/ |
4a3ad20cc Driver core: codi... |
61 62 |
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) |
1da177e4c Linux-2.6.12-rc2 |
63 64 65 66 67 |
{ int i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; |
c9f66169f resource: add res... |
68 69 |
if (type == resource_type(r) && num-- == 0) return r; |
1da177e4c Linux-2.6.12-rc2 |
70 71 72 |
} return NULL; } |
a96b20420 [PATCH] Driver Co... |
73 |
EXPORT_SYMBOL_GPL(platform_get_resource); |
1da177e4c Linux-2.6.12-rc2 |
74 75 |
/** |
4a3ad20cc Driver core: codi... |
76 77 78 |
* platform_get_irq - get an IRQ for a device * @dev: platform device * @num: IRQ number index |
1da177e4c Linux-2.6.12-rc2 |
79 80 81 |
*/ int platform_get_irq(struct platform_device *dev, unsigned int num) { |
5cf8f7db8 sparc: Add sparc ... |
82 83 84 85 86 87 |
#ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ if (!dev || num >= dev->archdata.num_irqs) return -ENXIO; return dev->archdata.irqs[num]; #else |
9ec36cafe of/irq: do irq re... |
88 89 90 91 92 |
struct resource *r; if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) return of_irq_get(dev->dev.of_node, num); r = platform_get_resource(dev, IORESOURCE_IRQ, num); |
1da177e4c Linux-2.6.12-rc2 |
93 |
|
305b3228f [PATCH] driver co... |
94 |
return r ? r->start : -ENXIO; |
5cf8f7db8 sparc: Add sparc ... |
95 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
96 |
} |
a96b20420 [PATCH] Driver Co... |
97 |
EXPORT_SYMBOL_GPL(platform_get_irq); |
1da177e4c Linux-2.6.12-rc2 |
98 99 |
/** |
4a3ad20cc Driver core: codi... |
100 101 102 103 |
* platform_get_resource_byname - get a resource for a device by name * @dev: platform device * @type: resource type * @name: resource name |
1da177e4c Linux-2.6.12-rc2 |
104 |
*/ |
4a3ad20cc Driver core: codi... |
105 |
struct resource *platform_get_resource_byname(struct platform_device *dev, |
c0afe7ba5 driver core: Cons... |
106 107 |
unsigned int type, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
108 109 110 111 112 |
{ int i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; |
1b8cb9290 driver core: Chec... |
113 114 |
if (unlikely(!r->name)) continue; |
c9f66169f resource: add res... |
115 116 |
if (type == resource_type(r) && !strcmp(r->name, name)) return r; |
1da177e4c Linux-2.6.12-rc2 |
117 118 119 |
} return NULL; } |
a96b20420 [PATCH] Driver Co... |
120 |
EXPORT_SYMBOL_GPL(platform_get_resource_byname); |
1da177e4c Linux-2.6.12-rc2 |
121 122 |
/** |
d6ff85513 driver: platform:... |
123 |
* platform_get_irq_byname - get an IRQ for a device by name |
4a3ad20cc Driver core: codi... |
124 125 |
* @dev: platform device * @name: IRQ name |
1da177e4c Linux-2.6.12-rc2 |
126 |
*/ |
c0afe7ba5 driver core: Cons... |
127 |
int platform_get_irq_byname(struct platform_device *dev, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
128 |
{ |
4a3ad20cc Driver core: codi... |
129 130 |
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); |
1da177e4c Linux-2.6.12-rc2 |
131 |
|
305b3228f [PATCH] driver co... |
132 |
return r ? r->start : -ENXIO; |
1da177e4c Linux-2.6.12-rc2 |
133 |
} |
a96b20420 [PATCH] Driver Co... |
134 |
EXPORT_SYMBOL_GPL(platform_get_irq_byname); |
1da177e4c Linux-2.6.12-rc2 |
135 136 |
/** |
4a3ad20cc Driver core: codi... |
137 138 139 |
* platform_add_devices - add a numbers of platform devices * @devs: array of platform devices to add * @num: number of platform devices in array |
1da177e4c Linux-2.6.12-rc2 |
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
*/ int platform_add_devices(struct platform_device **devs, int num) { int i, ret = 0; for (i = 0; i < num; i++) { ret = platform_device_register(devs[i]); if (ret) { while (--i >= 0) platform_device_unregister(devs[i]); break; } } return ret; } |
a96b20420 [PATCH] Driver Co... |
156 |
EXPORT_SYMBOL_GPL(platform_add_devices); |
1da177e4c Linux-2.6.12-rc2 |
157 |
|
37c12e749 [DRIVER MODEL] Im... |
158 159 160 161 |
struct platform_object { struct platform_device pdev; char name[1]; }; |
1da177e4c Linux-2.6.12-rc2 |
162 |
/** |
3c31f07ad Driver core: Fix ... |
163 |
* platform_device_put - destroy a platform device |
4a3ad20cc Driver core: codi... |
164 |
* @pdev: platform device to free |
37c12e749 [DRIVER MODEL] Im... |
165 |
* |
4a3ad20cc Driver core: codi... |
166 167 |
* Free all memory associated with a platform device. This function must * _only_ be externally called in error cases. All other usage is a bug. |
37c12e749 [DRIVER MODEL] Im... |
168 169 170 171 172 173 174 175 176 177 |
*/ void platform_device_put(struct platform_device *pdev) { if (pdev) put_device(&pdev->dev); } EXPORT_SYMBOL_GPL(platform_device_put); static void platform_device_release(struct device *dev) { |
4a3ad20cc Driver core: codi... |
178 179 |
struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); |
37c12e749 [DRIVER MODEL] Im... |
180 |
|
7096d0422 of/device: Rework... |
181 |
of_device_node_put(&pa->pdev.dev); |
37c12e749 [DRIVER MODEL] Im... |
182 |
kfree(pa->pdev.dev.platform_data); |
e710d7d5a mfd: Fetch cell p... |
183 |
kfree(pa->pdev.mfd_cell); |
37c12e749 [DRIVER MODEL] Im... |
184 185 186 187 188 |
kfree(pa->pdev.resource); kfree(pa); } /** |
3c31f07ad Driver core: Fix ... |
189 |
* platform_device_alloc - create a platform device |
4a3ad20cc Driver core: codi... |
190 191 |
* @name: base name of the device we're adding * @id: instance id |
37c12e749 [DRIVER MODEL] Im... |
192 |
* |
4a3ad20cc Driver core: codi... |
193 194 |
* Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. |
37c12e749 [DRIVER MODEL] Im... |
195 |
*/ |
1359555eb Driver core: Make... |
196 |
struct platform_device *platform_device_alloc(const char *name, int id) |
37c12e749 [DRIVER MODEL] Im... |
197 198 199 200 201 202 203 204 205 206 |
{ struct platform_object *pa; pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL); if (pa) { strcpy(pa->name, name); pa->pdev.name = pa->name; pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; |
a77ce8167 driver core: Add ... |
207 |
arch_setup_pdev_archdata(&pa->pdev); |
37c12e749 [DRIVER MODEL] Im... |
208 |
} |
93ce3061b [PATCH] Driver Co... |
209 |
return pa ? &pa->pdev : NULL; |
37c12e749 [DRIVER MODEL] Im... |
210 211 212 213 |
} EXPORT_SYMBOL_GPL(platform_device_alloc); /** |
3c31f07ad Driver core: Fix ... |
214 |
* platform_device_add_resources - add resources to a platform device |
4a3ad20cc Driver core: codi... |
215 216 217 |
* @pdev: platform device allocated by platform_device_alloc to add resources to * @res: set of resources that needs to be allocated for the device * @num: number of resources |
37c12e749 [DRIVER MODEL] Im... |
218 |
* |
4a3ad20cc Driver core: codi... |
219 220 221 |
* Add a copy of the resources to the platform device. The memory * associated with the resources will be freed when the platform device is * released. |
37c12e749 [DRIVER MODEL] Im... |
222 |
*/ |
4a3ad20cc Driver core: codi... |
223 |
int platform_device_add_resources(struct platform_device *pdev, |
0b7f1a7ef platform: Make pl... |
224 |
const struct resource *res, unsigned int num) |
37c12e749 [DRIVER MODEL] Im... |
225 |
{ |
cea896238 driver core/platf... |
226 |
struct resource *r = NULL; |
37c12e749 [DRIVER MODEL] Im... |
227 |
|
cea896238 driver core/platf... |
228 229 230 231 |
if (res) { r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); if (!r) return -ENOMEM; |
37c12e749 [DRIVER MODEL] Im... |
232 |
} |
cea896238 driver core/platf... |
233 |
|
4a03d6f7c driver core/platf... |
234 |
kfree(pdev->resource); |
cea896238 driver core/platf... |
235 236 237 |
pdev->resource = r; pdev->num_resources = num; return 0; |
37c12e749 [DRIVER MODEL] Im... |
238 239 240 241 |
} EXPORT_SYMBOL_GPL(platform_device_add_resources); /** |
3c31f07ad Driver core: Fix ... |
242 |
* platform_device_add_data - add platform-specific data to a platform device |
4a3ad20cc Driver core: codi... |
243 244 245 |
* @pdev: platform device allocated by platform_device_alloc to add resources to * @data: platform specific data for this platform device * @size: size of platform specific data |
37c12e749 [DRIVER MODEL] Im... |
246 |
* |
4a3ad20cc Driver core: codi... |
247 248 249 |
* Add a copy of platform specific data to the platform device's * platform_data pointer. The memory associated with the platform data * will be freed when the platform device is released. |
37c12e749 [DRIVER MODEL] Im... |
250 |
*/ |
4a3ad20cc Driver core: codi... |
251 252 |
int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) |
37c12e749 [DRIVER MODEL] Im... |
253 |
{ |
27a33f9e8 driver core/platf... |
254 |
void *d = NULL; |
5cfc64ceb base/platform: Sa... |
255 |
|
27a33f9e8 driver core/platf... |
256 257 258 259 |
if (data) { d = kmemdup(data, size, GFP_KERNEL); if (!d) return -ENOMEM; |
37c12e749 [DRIVER MODEL] Im... |
260 |
} |
27a33f9e8 driver core/platf... |
261 |
|
251e031d1 driver core/platf... |
262 |
kfree(pdev->dev.platform_data); |
27a33f9e8 driver core/platf... |
263 264 |
pdev->dev.platform_data = d; return 0; |
37c12e749 [DRIVER MODEL] Im... |
265 266 267 268 |
} EXPORT_SYMBOL_GPL(platform_device_add_data); /** |
4a3ad20cc Driver core: codi... |
269 270 |
* platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding |
1da177e4c Linux-2.6.12-rc2 |
271 |
* |
4a3ad20cc Driver core: codi... |
272 273 |
* This is part 2 of platform_device_register(), though may be called * separately _iff_ pdev was allocated by platform_device_alloc(). |
1da177e4c Linux-2.6.12-rc2 |
274 |
*/ |
37c12e749 [DRIVER MODEL] Im... |
275 |
int platform_device_add(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
276 |
{ |
689ae231a platform: Add sup... |
277 |
int i, ret; |
1da177e4c Linux-2.6.12-rc2 |
278 279 280 281 282 283 284 285 |
if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; |
689ae231a platform: Add sup... |
286 287 |
switch (pdev->id) { default: |
1e0b2cf93 driver core: stru... |
288 |
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); |
689ae231a platform: Add sup... |
289 290 |
break; case PLATFORM_DEVID_NONE: |
acc0e90fb driver core: fix ... |
291 |
dev_set_name(&pdev->dev, "%s", pdev->name); |
689ae231a platform: Add sup... |
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
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; } |
1da177e4c Linux-2.6.12-rc2 |
307 308 309 310 311 |
for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) |
1e0b2cf93 driver core: stru... |
312 |
r->name = dev_name(&pdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
313 314 315 |
p = r->parent; if (!p) { |
c9f66169f resource: add res... |
316 |
if (resource_type(r) == IORESOURCE_MEM) |
1da177e4c Linux-2.6.12-rc2 |
317 |
p = &iomem_resource; |
c9f66169f resource: add res... |
318 |
else if (resource_type(r) == IORESOURCE_IO) |
1da177e4c Linux-2.6.12-rc2 |
319 320 |
p = &ioport_resource; } |
d960bb4db [PATCH] Allow ove... |
321 |
if (p && insert_resource(p, r)) { |
0258e182e driver core: plat... |
322 323 |
dev_err(&pdev->dev, "failed to claim resource %d ", i); |
1da177e4c Linux-2.6.12-rc2 |
324 325 326 327 328 329 330 |
ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s ", |
1e0b2cf93 driver core: stru... |
331 |
dev_name(&pdev->dev), dev_name(pdev->dev.parent)); |
1da177e4c Linux-2.6.12-rc2 |
332 |
|
e39155322 [PATCH] Driver Co... |
333 |
ret = device_add(&pdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
334 335 336 337 |
if (ret == 0) return ret; failed: |
689ae231a platform: Add sup... |
338 339 340 341 |
if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } |
c9f66169f resource: add res... |
342 343 344 345 346 347 348 |
while (--i >= 0) { struct resource *r = &pdev->resource[i]; unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r); } |
689ae231a platform: Add sup... |
349 |
err_out: |
1da177e4c Linux-2.6.12-rc2 |
350 351 |
return ret; } |
37c12e749 [DRIVER MODEL] Im... |
352 353 354 |
EXPORT_SYMBOL_GPL(platform_device_add); /** |
4a3ad20cc Driver core: codi... |
355 356 |
* platform_device_del - remove a platform-level device * @pdev: platform device we're removing |
1da177e4c Linux-2.6.12-rc2 |
357 |
* |
4a3ad20cc Driver core: codi... |
358 359 360 |
* Note that this function will also release all memory- and port-based * resources owned by the device (@dev->resource). This function must * _only_ be externally called in error cases. All other usage is a bug. |
1da177e4c Linux-2.6.12-rc2 |
361 |
*/ |
93ce3061b [PATCH] Driver Co... |
362 |
void platform_device_del(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
363 364 365 366 |
{ int i; if (pdev) { |
dc4c15d44 platform: reorder... |
367 |
device_del(&pdev->dev); |
689ae231a platform: Add sup... |
368 369 370 371 |
if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } |
1da177e4c Linux-2.6.12-rc2 |
372 373 |
for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; |
c9f66169f resource: add res... |
374 375 376 |
unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) |
1da177e4c Linux-2.6.12-rc2 |
377 378 |
release_resource(r); } |
1da177e4c Linux-2.6.12-rc2 |
379 380 |
} } |
93ce3061b [PATCH] Driver Co... |
381 382 383 |
EXPORT_SYMBOL_GPL(platform_device_del); /** |
4a3ad20cc Driver core: codi... |
384 385 |
* platform_device_register - add a platform-level device * @pdev: platform device we're adding |
93ce3061b [PATCH] Driver Co... |
386 |
*/ |
4a3ad20cc Driver core: codi... |
387 |
int platform_device_register(struct platform_device *pdev) |
93ce3061b [PATCH] Driver Co... |
388 389 |
{ device_initialize(&pdev->dev); |
a77ce8167 driver core: Add ... |
390 |
arch_setup_pdev_archdata(pdev); |
93ce3061b [PATCH] Driver Co... |
391 392 |
return platform_device_add(pdev); } |
a96b20420 [PATCH] Driver Co... |
393 |
EXPORT_SYMBOL_GPL(platform_device_register); |
93ce3061b [PATCH] Driver Co... |
394 395 |
/** |
4a3ad20cc Driver core: codi... |
396 397 |
* platform_device_unregister - unregister a platform-level device * @pdev: platform device we're unregistering |
93ce3061b [PATCH] Driver Co... |
398 |
* |
4a3ad20cc Driver core: codi... |
399 400 401 |
* Unregistration is done in 2 steps. First we release all resources * and remove it from the subsystem, then we drop reference count by * calling platform_device_put(). |
93ce3061b [PATCH] Driver Co... |
402 |
*/ |
4a3ad20cc Driver core: codi... |
403 |
void platform_device_unregister(struct platform_device *pdev) |
93ce3061b [PATCH] Driver Co... |
404 405 406 407 |
{ platform_device_del(pdev); platform_device_put(pdev); } |
a96b20420 [PATCH] Driver Co... |
408 |
EXPORT_SYMBOL_GPL(platform_device_unregister); |
1da177e4c Linux-2.6.12-rc2 |
409 |
|
1da177e4c Linux-2.6.12-rc2 |
410 |
/** |
01dcc60a7 new helper to cre... |
411 |
* platform_device_register_full - add a platform-level device with |
44f28bdea Driver core: redu... |
412 |
* resources and platform-specific data |
49a4ec188 fix hotplug for l... |
413 |
* |
01dcc60a7 new helper to cre... |
414 |
* @pdevinfo: data used to create device |
d8bf25408 platform: add new... |
415 |
* |
f0eae0ed3 driver-core: docu... |
416 |
* Returns &struct platform_device pointer on success, or ERR_PTR() on error. |
d8bf25408 platform: add new... |
417 |
*/ |
01dcc60a7 new helper to cre... |
418 |
struct platform_device *platform_device_register_full( |
5a3072be6 drivers_base: mak... |
419 |
const struct platform_device_info *pdevinfo) |
d8bf25408 platform: add new... |
420 |
{ |
44f28bdea Driver core: redu... |
421 |
int ret = -ENOMEM; |
d8bf25408 platform: add new... |
422 |
struct platform_device *pdev; |
d8bf25408 platform: add new... |
423 |
|
01dcc60a7 new helper to cre... |
424 |
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); |
44f28bdea Driver core: redu... |
425 |
if (!pdev) |
01dcc60a7 new helper to cre... |
426 427 428 |
goto err_alloc; pdev->dev.parent = pdevinfo->parent; |
7b1998116 ACPI / driver cor... |
429 |
ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion); |
01dcc60a7 new helper to cre... |
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
if (pdevinfo->dma_mask) { /* * This memory isn't freed when the device is put, * I don't have a nice idea for that though. Conceptually * dma_mask in struct device should not be a pointer. * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 */ pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); if (!pdev->dev.dma_mask) goto err; *pdev->dev.dma_mask = pdevinfo->dma_mask; pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; } |
d8bf25408 platform: add new... |
446 |
|
01dcc60a7 new helper to cre... |
447 448 |
ret = platform_device_add_resources(pdev, pdevinfo->res, pdevinfo->num_res); |
807508c8f base/platform: Si... |
449 450 |
if (ret) goto err; |
44f28bdea Driver core: redu... |
451 |
|
01dcc60a7 new helper to cre... |
452 453 |
ret = platform_device_add_data(pdev, pdevinfo->data, pdevinfo->size_data); |
807508c8f base/platform: Si... |
454 455 |
if (ret) goto err; |
d8bf25408 platform: add new... |
456 |
|
44f28bdea Driver core: redu... |
457 458 459 |
ret = platform_device_add(pdev); if (ret) { err: |
7b1998116 ACPI / driver cor... |
460 |
ACPI_COMPANION_SET(&pdev->dev, NULL); |
01dcc60a7 new helper to cre... |
461 462 463 |
kfree(pdev->dev.dma_mask); err_alloc: |
44f28bdea Driver core: redu... |
464 465 466 |
platform_device_put(pdev); return ERR_PTR(ret); } |
d8bf25408 platform: add new... |
467 468 |
return pdev; |
d8bf25408 platform: add new... |
469 |
} |
01dcc60a7 new helper to cre... |
470 |
EXPORT_SYMBOL_GPL(platform_device_register_full); |
d8bf25408 platform: add new... |
471 |
|
00d3dcdd9 [DRIVER MODEL] Ad... |
472 473 474 475 |
static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); |
94d76d5de platform / ACPI: ... |
476 |
int ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
477 |
|
9383f4c6b ACPI / platform: ... |
478 |
acpi_dev_pm_attach(_dev, true); |
94d76d5de platform / ACPI: ... |
479 480 |
ret = drv->probe(dev); |
9383f4c6b ACPI / platform: ... |
481 |
if (ret) |
94d76d5de platform / ACPI: ... |
482 |
acpi_dev_pm_detach(_dev, true); |
3f9120b04 driver core: prev... |
483 484 485 486 487 |
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported "); ret = -ENXIO; } |
94d76d5de platform / ACPI: ... |
488 |
return ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
489 |
} |
c67334fbd Driver core: plat... |
490 491 492 493 |
static int platform_drv_probe_fail(struct device *_dev) { return -ENXIO; } |
00d3dcdd9 [DRIVER MODEL] Ad... |
494 495 496 497 |
static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); |
94d76d5de platform / ACPI: ... |
498 |
int ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
499 |
|
94d76d5de platform / ACPI: ... |
500 |
ret = drv->remove(dev); |
9383f4c6b ACPI / platform: ... |
501 |
acpi_dev_pm_detach(_dev, true); |
94d76d5de platform / ACPI: ... |
502 503 |
return ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
504 505 506 507 508 509 510 511 |
} static void platform_drv_shutdown(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); drv->shutdown(dev); |
9383f4c6b ACPI / platform: ... |
512 |
acpi_dev_pm_detach(_dev, true); |
00d3dcdd9 [DRIVER MODEL] Ad... |
513 |
} |
00d3dcdd9 [DRIVER MODEL] Ad... |
514 |
/** |
9447057ea platform_device: ... |
515 |
* __platform_driver_register - register a driver for platform-level devices |
4a3ad20cc Driver core: codi... |
516 |
* @drv: platform driver structure |
08801f966 driver-core: fix ... |
517 |
* @owner: owning module/driver |
00d3dcdd9 [DRIVER MODEL] Ad... |
518 |
*/ |
9447057ea platform_device: ... |
519 520 |
int __platform_driver_register(struct platform_driver *drv, struct module *owner) |
00d3dcdd9 [DRIVER MODEL] Ad... |
521 |
{ |
9447057ea platform_device: ... |
522 |
drv->driver.owner = owner; |
00d3dcdd9 [DRIVER MODEL] Ad... |
523 524 525 526 527 528 529 |
drv->driver.bus = &platform_bus_type; if (drv->probe) drv->driver.probe = platform_drv_probe; if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; |
783ea7d4e Driver Core: Rewo... |
530 |
|
00d3dcdd9 [DRIVER MODEL] Ad... |
531 532 |
return driver_register(&drv->driver); } |
9447057ea platform_device: ... |
533 |
EXPORT_SYMBOL_GPL(__platform_driver_register); |
00d3dcdd9 [DRIVER MODEL] Ad... |
534 535 |
/** |
3c31f07ad Driver core: Fix ... |
536 |
* platform_driver_unregister - unregister a driver for platform-level devices |
4a3ad20cc Driver core: codi... |
537 |
* @drv: platform driver structure |
00d3dcdd9 [DRIVER MODEL] Ad... |
538 539 540 541 542 543 |
*/ void platform_driver_unregister(struct platform_driver *drv) { driver_unregister(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_unregister); |
c67334fbd Driver core: plat... |
544 545 546 |
/** * platform_driver_probe - register driver for non-hotpluggable device * @drv: platform driver structure |
3f9120b04 driver core: prev... |
547 |
* @probe: the driver probe routine, probably from an __init section |
c67334fbd Driver core: plat... |
548 549 550 551 552 553 554 555 556 557 |
* * Use this instead of platform_driver_register() when you know the device * is not hotpluggable and has already been registered, and you want to * remove its run-once probe() infrastructure from memory after the driver * has bound to the device. * * One typical use for this would be with drivers for controllers integrated * into system-on-chip processors, where the controller devices have been * configured as part of board setup. * |
3f9120b04 driver core: prev... |
558 |
* Note that this is incompatible with deferred probing. |
647c86d0a driver core: warn... |
559 |
* |
c67334fbd Driver core: plat... |
560 561 562 |
* Returns zero if the driver registered and bound to a device, else returns * a negative error code and with the driver not registered. */ |
c63e07834 Driver core: "pla... |
563 |
int __init_or_module platform_driver_probe(struct platform_driver *drv, |
c67334fbd Driver core: plat... |
564 565 566 |
int (*probe)(struct platform_device *)) { int retval, code; |
3f9120b04 driver core: prev... |
567 568 569 570 571 |
/* * Prevent driver from requesting probe deferral to avoid further * futile probe attempts. */ drv->prevent_deferred_probe = true; |
1a6f2a751 Driver core: allo... |
572 573 |
/* make sure driver won't have bind/unbind attributes */ drv->driver.suppress_bind_attrs = true; |
c67334fbd Driver core: plat... |
574 575 576 |
/* temporary section violation during probe() */ drv->probe = probe; retval = code = platform_driver_register(drv); |
1a6f2a751 Driver core: allo... |
577 578 |
/* * Fixup that section violation, being paranoid about code scanning |
c67334fbd Driver core: plat... |
579 580 581 582 |
* the list of drivers in order to probe new devices. Check to see * if the probe was successful, and make sure any forced probes of * new devices fail. */ |
d79d32440 driver core: plat... |
583 |
spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); |
c67334fbd Driver core: plat... |
584 |
drv->probe = NULL; |
e5dd12784 Driver core: move... |
585 |
if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) |
c67334fbd Driver core: plat... |
586 587 |
retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; |
d79d32440 driver core: plat... |
588 |
spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); |
c67334fbd Driver core: plat... |
589 590 591 592 593 594 |
if (code != retval) platform_driver_unregister(drv); return retval; } EXPORT_SYMBOL_GPL(platform_driver_probe); |
1da177e4c Linux-2.6.12-rc2 |
595 |
|
ecdf6ceb8 Driver core: add ... |
596 597 598 599 600 601 602 603 604 605 606 |
/** * platform_create_bundle - register driver and create corresponding device * @driver: platform driver structure * @probe: the driver probe routine, probably from an __init section * @res: set of resources that needs to be allocated for the device * @n_res: number of resources * @data: platform specific data for this platform device * @size: size of platform specific data * * Use this in legacy-style modules that probe hardware directly and * register a single platform device and corresponding platform driver. |
f0eae0ed3 driver-core: docu... |
607 608 |
* * Returns &struct platform_device pointer on success, or ERR_PTR() on error. |
ecdf6ceb8 Driver core: add ... |
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
*/ struct platform_device * __init_or_module platform_create_bundle( struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, const void *data, size_t size) { struct platform_device *pdev; int error; pdev = platform_device_alloc(driver->driver.name, -1); if (!pdev) { error = -ENOMEM; goto err_out; } |
807508c8f base/platform: Si... |
624 625 626 |
error = platform_device_add_resources(pdev, res, n_res); if (error) goto err_pdev_put; |
ecdf6ceb8 Driver core: add ... |
627 |
|
807508c8f base/platform: Si... |
628 629 630 |
error = platform_device_add_data(pdev, data, size); if (error) goto err_pdev_put; |
ecdf6ceb8 Driver core: add ... |
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 |
error = platform_device_add(pdev); if (error) goto err_pdev_put; error = platform_driver_probe(driver, probe); if (error) goto err_pdev_del; return pdev; err_pdev_del: platform_device_del(pdev); err_pdev_put: platform_device_put(pdev); err_out: return ERR_PTR(error); } EXPORT_SYMBOL_GPL(platform_create_bundle); |
a0245f7ad [PATCH] platform_... |
650 651 652 653 654 655 |
/* modalias support enables more hands-off userspace setup: * (a) environment variable lets new-style hotplug events work once system is * fully running: "modprobe $MODALIAS" * (b) sysfs attribute lets new-style coldplug recover from hotplug events * mishandled before system is fully running: "modprobe $(cat modalias)" */ |
4a3ad20cc Driver core: codi... |
656 657 |
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) |
a0245f7ad [PATCH] platform_... |
658 659 |
{ struct platform_device *pdev = to_platform_device(dev); |
8c4ff6d00 ACPI: fix module ... |
660 |
int len; |
b9f73067f platform: introdu... |
661 662 663 |
len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; |
8c4ff6d00 ACPI: fix module ... |
664 665 666 667 668 669 |
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; len = snprintf(buf, PAGE_SIZE, "platform:%s ", pdev->name); |
a0245f7ad [PATCH] platform_... |
670 671 672 |
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } |
d06262e58 driver-core: plat... |
673 |
static DEVICE_ATTR_RO(modalias); |
a0245f7ad [PATCH] platform_... |
674 |
|
d06262e58 driver-core: plat... |
675 676 677 |
static struct attribute *platform_dev_attrs[] = { &dev_attr_modalias.attr, NULL, |
a0245f7ad [PATCH] platform_... |
678 |
}; |
d06262e58 driver-core: plat... |
679 |
ATTRIBUTE_GROUPS(platform_dev); |
a0245f7ad [PATCH] platform_... |
680 |
|
7eff2e7a8 Driver core: chan... |
681 |
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) |
a0245f7ad [PATCH] platform_... |
682 683 |
{ struct platform_device *pdev = to_platform_device(dev); |
eca393016 of: Merge of_plat... |
684 685 686 |
int rc; /* Some devices have extra OF data and an OF-style MODALIAS */ |
0258e182e driver core: plat... |
687 |
rc = of_device_uevent_modalias(dev, env); |
eca393016 of: Merge of_plat... |
688 689 |
if (rc != -ENODEV) return rc; |
a0245f7ad [PATCH] platform_... |
690 |
|
8c4ff6d00 ACPI: fix module ... |
691 692 693 |
rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; |
57fee4a58 platform: introdu... |
694 |
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, |
0a26813c9 drivers_base: pla... |
695 |
pdev->name); |
a0245f7ad [PATCH] platform_... |
696 697 |
return 0; } |
57fee4a58 platform: introdu... |
698 |
static const struct platform_device_id *platform_match_id( |
831fad2f7 Driver core: make... |
699 |
const struct platform_device_id *id, |
57fee4a58 platform: introdu... |
700 701 702 703 704 705 706 707 708 709 710 |
struct platform_device *pdev) { while (id->name[0]) { if (strcmp(pdev->name, id->name) == 0) { pdev->id_entry = id; return id; } id++; } return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
711 |
/** |
4a3ad20cc Driver core: codi... |
712 713 714 |
* platform_match - bind platform device to platform driver. * @dev: device. * @drv: driver. |
1da177e4c Linux-2.6.12-rc2 |
715 |
* |
4a3ad20cc Driver core: codi... |
716 717 718 719 720 721 722 |
* Platform device IDs are assumed to be encoded like this: * "<name><instance>", where <name> is a short description of the type of * device, like "pci" or "floppy", and <instance> is the enumerated * instance of the device, like '0' or '42'. Driver IDs are simply * "<name>". So, extract the <name> from the platform_device structure, * and compare it against the name of the driver. Return whether they match * or not. |
1da177e4c Linux-2.6.12-rc2 |
723 |
*/ |
4a3ad20cc Driver core: codi... |
724 |
static int platform_match(struct device *dev, struct device_driver *drv) |
1da177e4c Linux-2.6.12-rc2 |
725 |
{ |
71b3e0c1a platform: make be... |
726 |
struct platform_device *pdev = to_platform_device(dev); |
57fee4a58 platform: introdu... |
727 |
struct platform_driver *pdrv = to_platform_driver(drv); |
05212157e drivercore/of: Ad... |
728 729 730 |
/* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; |
91e568780 ACPI: Add support... |
731 732 733 |
/* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; |
05212157e drivercore/of: Ad... |
734 |
/* Then try to match against the id table */ |
57fee4a58 platform: introdu... |
735 736 |
if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; |
1da177e4c Linux-2.6.12-rc2 |
737 |
|
57fee4a58 platform: introdu... |
738 |
/* fall-back to driver name match */ |
1e0b2cf93 driver core: stru... |
739 |
return (strcmp(pdev->name, drv->name) == 0); |
1da177e4c Linux-2.6.12-rc2 |
740 |
} |
25e18499e Implement new sus... |
741 742 743 |
#ifdef CONFIG_PM_SLEEP static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) |
1da177e4c Linux-2.6.12-rc2 |
744 |
{ |
783ea7d4e Driver Core: Rewo... |
745 746 |
struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_device *pdev = to_platform_device(dev); |
1da177e4c Linux-2.6.12-rc2 |
747 |
int ret = 0; |
783ea7d4e Driver Core: Rewo... |
748 749 |
if (dev->driver && pdrv->suspend) ret = pdrv->suspend(pdev, mesg); |
386415d88 PM: platform_bus ... |
750 751 752 |
return ret; } |
25e18499e Implement new sus... |
753 |
static int platform_legacy_resume(struct device *dev) |
1da177e4c Linux-2.6.12-rc2 |
754 |
{ |
783ea7d4e Driver Core: Rewo... |
755 756 |
struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_device *pdev = to_platform_device(dev); |
1da177e4c Linux-2.6.12-rc2 |
757 |
int ret = 0; |
783ea7d4e Driver Core: Rewo... |
758 759 |
if (dev->driver && pdrv->resume) ret = pdrv->resume(pdev); |
9480e307c [PATCH] DRIVER MO... |
760 |
|
1da177e4c Linux-2.6.12-rc2 |
761 762 |
return ret; } |
69c9dd1ec PM: Export platfo... |
763 |
#endif /* CONFIG_PM_SLEEP */ |
9d7302299 PM: Run-time PM p... |
764 |
|
25e18499e Implement new sus... |
765 |
#ifdef CONFIG_SUSPEND |
69c9dd1ec PM: Export platfo... |
766 |
int platform_pm_suspend(struct device *dev) |
25e18499e Implement new sus... |
767 768 769 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
770 771 772 773 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
774 775 776 777 778 779 780 781 |
if (drv->pm->suspend) ret = drv->pm->suspend(dev); } else { ret = platform_legacy_suspend(dev, PMSG_SUSPEND); } return ret; } |
69c9dd1ec PM: Export platfo... |
782 |
int platform_pm_resume(struct device *dev) |
25e18499e Implement new sus... |
783 784 785 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
786 787 788 789 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
790 791 792 793 794 795 796 797 |
if (drv->pm->resume) ret = drv->pm->resume(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
798 |
#endif /* CONFIG_SUSPEND */ |
25e18499e Implement new sus... |
799 |
|
1f112cee0 PM / Hibernate: I... |
800 |
#ifdef CONFIG_HIBERNATE_CALLBACKS |
25e18499e Implement new sus... |
801 |
|
69c9dd1ec PM: Export platfo... |
802 |
int platform_pm_freeze(struct device *dev) |
25e18499e Implement new sus... |
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 |
{ struct device_driver *drv = dev->driver; int ret = 0; if (!drv) return 0; if (drv->pm) { if (drv->pm->freeze) ret = drv->pm->freeze(dev); } else { ret = platform_legacy_suspend(dev, PMSG_FREEZE); } return ret; } |
69c9dd1ec PM: Export platfo... |
819 |
int platform_pm_thaw(struct device *dev) |
25e18499e Implement new sus... |
820 821 822 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
823 824 825 826 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
827 828 829 830 831 832 833 834 |
if (drv->pm->thaw) ret = drv->pm->thaw(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
835 |
int platform_pm_poweroff(struct device *dev) |
25e18499e Implement new sus... |
836 837 838 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
839 840 841 842 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
843 844 845 846 847 848 849 850 |
if (drv->pm->poweroff) ret = drv->pm->poweroff(dev); } else { ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); } return ret; } |
69c9dd1ec PM: Export platfo... |
851 |
int platform_pm_restore(struct device *dev) |
25e18499e Implement new sus... |
852 853 854 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
855 856 857 858 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
859 860 861 862 863 864 865 866 |
if (drv->pm->restore) ret = drv->pm->restore(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
867 |
#endif /* CONFIG_HIBERNATE_CALLBACKS */ |
25e18499e Implement new sus... |
868 |
|
d9ab77161 Driver Core: Make... |
869 |
static const struct dev_pm_ops platform_dev_pm_ops = { |
8b313a38e PM / Platform: Us... |
870 871 |
.runtime_suspend = pm_generic_runtime_suspend, .runtime_resume = pm_generic_runtime_resume, |
69c9dd1ec PM: Export platfo... |
872 |
USE_PLATFORM_PM_SLEEP_OPS |
25e18499e Implement new sus... |
873 |
}; |
1da177e4c Linux-2.6.12-rc2 |
874 875 |
struct bus_type platform_bus_type = { .name = "platform", |
d06262e58 driver-core: plat... |
876 |
.dev_groups = platform_dev_groups, |
1da177e4c Linux-2.6.12-rc2 |
877 |
.match = platform_match, |
a0245f7ad [PATCH] platform_... |
878 |
.uevent = platform_uevent, |
9d7302299 PM: Run-time PM p... |
879 |
.pm = &platform_dev_pm_ops, |
1da177e4c Linux-2.6.12-rc2 |
880 |
}; |
a96b20420 [PATCH] Driver Co... |
881 |
EXPORT_SYMBOL_GPL(platform_bus_type); |
1da177e4c Linux-2.6.12-rc2 |
882 883 884 |
int __init platform_bus_init(void) { |
fbfb14455 driver core fixes... |
885 |
int error; |
13977091a Driver Core: earl... |
886 |
early_platform_cleanup(); |
fbfb14455 driver core fixes... |
887 888 889 890 891 892 893 |
error = device_register(&platform_bus); if (error) return error; error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); return error; |
1da177e4c Linux-2.6.12-rc2 |
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 |
} #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK u64 dma_get_required_mask(struct device *dev) { u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); u64 mask; if (!high_totalram) { /* convert to mask just covering totalram */ low_totalram = (1 << (fls(low_totalram) - 1)); low_totalram += low_totalram - 1; mask = low_totalram; } else { high_totalram = (1 << (fls(high_totalram) - 1)); high_totalram += high_totalram - 1; mask = (((u64)high_totalram) << 32) + 0xffffffff; } |
e88a0c2ca drivers: fix dma_... |
913 |
return mask; |
1da177e4c Linux-2.6.12-rc2 |
914 915 916 |
} EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif |
13977091a Driver Core: earl... |
917 918 919 920 921 |
static __initdata LIST_HEAD(early_platform_driver_list); static __initdata LIST_HEAD(early_platform_device_list); /** |
4d26e139f Driver core: Earl... |
922 |
* early_platform_driver_register - register early platform driver |
d86c1302c Driver core: plat... |
923 |
* @epdrv: early_platform driver structure |
13977091a Driver Core: earl... |
924 |
* @buf: string passed from early_param() |
4d26e139f Driver core: Earl... |
925 926 |
* * Helper function for early_platform_init() / early_platform_init_buffer() |
13977091a Driver Core: earl... |
927 928 929 930 |
*/ int __init early_platform_driver_register(struct early_platform_driver *epdrv, char *buf) { |
c60e0504c Driver Core: Earl... |
931 |
char *tmp; |
13977091a Driver Core: earl... |
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 |
int n; /* Simply add the driver to the end of the global list. * Drivers will by default be put on the list in compiled-in order. */ if (!epdrv->list.next) { INIT_LIST_HEAD(&epdrv->list); list_add_tail(&epdrv->list, &early_platform_driver_list); } /* If the user has specified device then make sure the driver * gets prioritized. The driver of the last device specified on * command line will be put first on the list. */ n = strlen(epdrv->pdrv->driver.name); if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { list_move(&epdrv->list, &early_platform_driver_list); |
c60e0504c Driver Core: Earl... |
949 950 |
/* Allow passing parameters after device name */ if (buf[n] == '\0' || buf[n] == ',') |
13977091a Driver Core: earl... |
951 |
epdrv->requested_id = -1; |
c60e0504c Driver Core: Earl... |
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 |
else { epdrv->requested_id = simple_strtoul(&buf[n + 1], &tmp, 10); if (buf[n] != '.' || (tmp == &buf[n + 1])) { epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; n = 0; } else n += strcspn(&buf[n + 1], ",") + 1; } if (buf[n] == ',') n++; if (epdrv->bufsize) { memcpy(epdrv->buffer, &buf[n], min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); epdrv->buffer[epdrv->bufsize - 1] = '\0'; } |
13977091a Driver Core: earl... |
971 972 973 974 975 976 |
} return 0; } /** |
4d26e139f Driver core: Earl... |
977 |
* early_platform_add_devices - adds a number of early platform devices |
13977091a Driver Core: earl... |
978 979 |
* @devs: array of early platform devices to add * @num: number of early platform devices in array |
4d26e139f Driver core: Earl... |
980 981 982 |
* * Used by early architecture code to register early platform devices and * their platform data. |
13977091a Driver Core: earl... |
983 984 985 986 987 988 989 990 991 992 993 |
*/ void __init early_platform_add_devices(struct platform_device **devs, int num) { struct device *dev; int i; /* simply add the devices to list */ for (i = 0; i < num; i++) { dev = &devs[i]->dev; if (!dev->devres_head.next) { |
bed2b42d9 PM / Runtime: All... |
994 |
pm_runtime_early_init(dev); |
13977091a Driver Core: earl... |
995 996 997 998 999 1000 1001 1002 |
INIT_LIST_HEAD(&dev->devres_head); list_add_tail(&dev->devres_head, &early_platform_device_list); } } } /** |
4d26e139f Driver core: Earl... |
1003 |
* early_platform_driver_register_all - register early platform drivers |
13977091a Driver Core: earl... |
1004 |
* @class_str: string to identify early platform driver class |
4d26e139f Driver core: Earl... |
1005 1006 1007 1008 |
* * Used by architecture code to register all early platform drivers * for a certain class. If omitted then only early platform drivers * with matching kernel command line class parameters will be registered. |
13977091a Driver Core: earl... |
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
*/ void __init early_platform_driver_register_all(char *class_str) { /* The "class_str" parameter may or may not be present on the kernel * command line. If it is present then there may be more than one * matching parameter. * * Since we register our early platform drivers using early_param() * we need to make sure that they also get registered in the case * when the parameter is missing from the kernel command line. * * We use parse_early_options() to make sure the early_param() gets * called at least once. The early_param() may be called more than * once since the name of the preferred device may be specified on * the kernel command line. early_platform_driver_register() handles * this case for us. */ parse_early_options(class_str); } /** |
4d26e139f Driver core: Earl... |
1030 |
* early_platform_match - find early platform device matching driver |
d86c1302c Driver core: plat... |
1031 |
* @epdrv: early platform driver structure |
13977091a Driver Core: earl... |
1032 1033 |
* @id: id to match against */ |
a82579106 drivers / platfor... |
1034 |
static struct platform_device * __init |
13977091a Driver Core: earl... |
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
early_platform_match(struct early_platform_driver *epdrv, int id) { struct platform_device *pd; list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) if (platform_match(&pd->dev, &epdrv->pdrv->driver)) if (pd->id == id) return pd; return NULL; } /** |
4d26e139f Driver core: Earl... |
1048 |
* early_platform_left - check if early platform driver has matching devices |
d86c1302c Driver core: plat... |
1049 |
* @epdrv: early platform driver structure |
13977091a Driver Core: earl... |
1050 1051 |
* @id: return true if id or above exists */ |
a82579106 drivers / platfor... |
1052 |
static int __init early_platform_left(struct early_platform_driver *epdrv, |
13977091a Driver Core: earl... |
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
int id) { struct platform_device *pd; list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) if (platform_match(&pd->dev, &epdrv->pdrv->driver)) if (pd->id >= id) return 1; return 0; } /** |
4d26e139f Driver core: Earl... |
1066 |
* early_platform_driver_probe_id - probe drivers matching class_str and id |
13977091a Driver Core: earl... |
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 |
* @class_str: string to identify early platform driver class * @id: id to match against * @nr_probe: number of platform devices to successfully probe before exiting */ static int __init early_platform_driver_probe_id(char *class_str, int id, int nr_probe) { struct early_platform_driver *epdrv; struct platform_device *match; int match_id; int n = 0; int left = 0; list_for_each_entry(epdrv, &early_platform_driver_list, list) { /* only use drivers matching our class_str */ if (strcmp(class_str, epdrv->class_str)) continue; if (id == -2) { match_id = epdrv->requested_id; left = 1; } else { match_id = id; left += early_platform_left(epdrv, id); /* skip requested id */ switch (epdrv->requested_id) { case EARLY_PLATFORM_ID_ERROR: case EARLY_PLATFORM_ID_UNSET: break; default: if (epdrv->requested_id == id) match_id = EARLY_PLATFORM_ID_UNSET; } } switch (match_id) { case EARLY_PLATFORM_ID_ERROR: |
0258e182e driver core: plat... |
1107 1108 1109 |
pr_warn("%s: unable to parse %s parameter ", class_str, epdrv->pdrv->driver.name); |
13977091a Driver Core: earl... |
1110 1111 1112 1113 1114 1115 1116 1117 1118 |
/* fall-through */ case EARLY_PLATFORM_ID_UNSET: match = NULL; break; default: match = early_platform_match(epdrv, match_id); } if (match) { |
a636ee7fb driver core: Earl... |
1119 1120 1121 1122 1123 |
/* * Set up a sensible init_name to enable * dev_name() and others to be used before the * rest of the driver core is initialized. */ |
06fe53beb driver core: Earl... |
1124 |
if (!match->dev.init_name && slab_is_available()) { |
a636ee7fb driver core: Earl... |
1125 |
if (match->id != -1) |
bd05086bb driver core: Conv... |
1126 1127 1128 1129 |
match->dev.init_name = kasprintf(GFP_KERNEL, "%s.%d", match->name, match->id); |
a636ee7fb driver core: Earl... |
1130 |
else |
bd05086bb driver core: Conv... |
1131 1132 1133 |
match->dev.init_name = kasprintf(GFP_KERNEL, "%s", match->name); |
a636ee7fb driver core: Earl... |
1134 |
|
a636ee7fb driver core: Earl... |
1135 1136 1137 |
if (!match->dev.init_name) return -ENOMEM; } |
bd05086bb driver core: Conv... |
1138 |
|
13977091a Driver Core: earl... |
1139 |
if (epdrv->pdrv->probe(match)) |
0258e182e driver core: plat... |
1140 1141 1142 |
pr_warn("%s: unable to probe %s early. ", class_str, match->name); |
13977091a Driver Core: earl... |
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
else n++; } if (n >= nr_probe) break; } if (left) return n; else return -ENODEV; } /** |
4d26e139f Driver core: Earl... |
1158 |
* early_platform_driver_probe - probe a class of registered drivers |
13977091a Driver Core: earl... |
1159 1160 1161 |
* @class_str: string to identify early platform driver class * @nr_probe: number of platform devices to successfully probe before exiting * @user_only: only probe user specified early platform devices |
4d26e139f Driver core: Earl... |
1162 1163 1164 1165 |
* * Used by architecture code to probe registered early platform drivers * within a certain class. For probe to happen a registered early platform * device matching a registered early platform driver is needed. |
13977091a Driver Core: earl... |
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
*/ int __init early_platform_driver_probe(char *class_str, int nr_probe, int user_only) { int k, n, i; n = 0; for (i = -2; n < nr_probe; i++) { k = early_platform_driver_probe_id(class_str, i, nr_probe - n); if (k < 0) break; n += k; if (user_only) break; } return n; } /** * early_platform_cleanup - clean up early platform code */ void __init early_platform_cleanup(void) { struct platform_device *pd, *pd2; /* clean up the devres list used to chain devices */ list_for_each_entry_safe(pd, pd2, &early_platform_device_list, dev.devres_head) { list_del(&pd->dev.devres_head); memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); } } |