1 /* 2 * platform.c - platform 'pseudo' bus for legacy devices 3 * 4 * Copyright (c) 2002-3 Patrick Mochel 5 * Copyright (c) 2002-3 Open Source Development Labs 6 * 7 * This file is released under the GPLv2 8 * 9 * Please see Documentation/driver-model/platform.txt for more 10 * information. 11 */ 12 13 #include <linux/platform_device.h> 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/dma-mapping.h> 17 #include <linux/bootmem.h> 18 #include <linux/err.h> 19 #include <linux/slab.h> 20 21 #include "base.h" 22 23 #define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver)) 24 25 struct device platform_bus = { 26 .bus_id = "platform", 27 }; 28 29 /** 30 * platform_get_resource - get a resource for a device 31 * @dev: platform device 32 * @type: resource type 33 * @num: resource index 34 */ 35 struct resource * 36 platform_get_resource(struct platform_device *dev, unsigned int type, 37 unsigned int num) 38 { 39 int i; 40 41 for (i = 0; i < dev->num_resources; i++) { 42 struct resource *r = &dev->resource[i]; 43 44 if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM| 45 IORESOURCE_IRQ|IORESOURCE_DMA)) 46 == type) 47 if (num-- == 0) 48 return r; 49 } 50 return NULL; 51 } 52 53 /** 54 * platform_get_irq - get an IRQ for a device 55 * @dev: platform device 56 * @num: IRQ number index 57 */ 58 int platform_get_irq(struct platform_device *dev, unsigned int num) 59 { 60 struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 61 62 return r ? r->start : 0; 63 } 64 65 /** 66 * platform_get_resource_byname - get a resource for a device by name 67 * @dev: platform device 68 * @type: resource type 69 * @name: resource name 70 */ 71 struct resource * 72 platform_get_resource_byname(struct platform_device *dev, unsigned int type, 73 char *name) 74 { 75 int i; 76 77 for (i = 0; i < dev->num_resources; i++) { 78 struct resource *r = &dev->resource[i]; 79 80 if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM| 81 IORESOURCE_IRQ|IORESOURCE_DMA)) == type) 82 if (!strcmp(r->name, name)) 83 return r; 84 } 85 return NULL; 86 } 87 88 /** 89 * platform_get_irq - get an IRQ for a device 90 * @dev: platform device 91 * @name: IRQ name 92 */ 93 int platform_get_irq_byname(struct platform_device *dev, char *name) 94 { 95 struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 96 97 return r ? r->start : 0; 98 } 99 100 /** 101 * platform_add_devices - add a numbers of platform devices 102 * @devs: array of platform devices to add 103 * @num: number of platform devices in array 104 */ 105 int platform_add_devices(struct platform_device **devs, int num) 106 { 107 int i, ret = 0; 108 109 for (i = 0; i < num; i++) { 110 ret = platform_device_register(devs[i]); 111 if (ret) { 112 while (--i >= 0) 113 platform_device_unregister(devs[i]); 114 break; 115 } 116 } 117 118 return ret; 119 } 120 121 struct platform_object { 122 struct platform_device pdev; 123 char name[1]; 124 }; 125 126 /** 127 * platform_device_put 128 * @pdev: platform device to free 129 * 130 * Free all memory associated with a platform device. This function 131 * must _only_ be externally called in error cases. All other usage 132 * is a bug. 133 */ 134 void platform_device_put(struct platform_device *pdev) 135 { 136 if (pdev) 137 put_device(&pdev->dev); 138 } 139 EXPORT_SYMBOL_GPL(platform_device_put); 140 141 static void platform_device_release(struct device *dev) 142 { 143 struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); 144 145 kfree(pa->pdev.dev.platform_data); 146 kfree(pa->pdev.resource); 147 kfree(pa); 148 } 149 150 /** 151 * platform_device_alloc 152 * @name: base name of the device we're adding 153 * @id: instance id 154 * 155 * Create a platform device object which can have other objects attached 156 * to it, and which will have attached objects freed when it is released. 157 */ 158 struct platform_device *platform_device_alloc(const char *name, unsigned int id) 159 { 160 struct platform_object *pa; 161 162 pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL); 163 if (pa) { 164 strcpy(pa->name, name); 165 pa->pdev.name = pa->name; 166 pa->pdev.id = id; 167 device_initialize(&pa->pdev.dev); 168 pa->pdev.dev.release = platform_device_release; 169 } 170 171 return pa ? &pa->pdev : NULL; 172 } 173 EXPORT_SYMBOL_GPL(platform_device_alloc); 174 175 /** 176 * platform_device_add_resources 177 * @pdev: platform device allocated by platform_device_alloc to add resources to 178 * @res: set of resources that needs to be allocated for the device 179 * @num: number of resources 180 * 181 * Add a copy of the resources to the platform device. The memory 182 * associated with the resources will be freed when the platform 183 * device is released. 184 */ 185 int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num) 186 { 187 struct resource *r; 188 189 r = kmalloc(sizeof(struct resource) * num, GFP_KERNEL); 190 if (r) { 191 memcpy(r, res, sizeof(struct resource) * num); 192 pdev->resource = r; 193 pdev->num_resources = num; 194 } 195 return r ? 0 : -ENOMEM; 196 } 197 EXPORT_SYMBOL_GPL(platform_device_add_resources); 198 199 /** 200 * platform_device_add_data 201 * @pdev: platform device allocated by platform_device_alloc to add resources to 202 * @data: platform specific data for this platform device 203 * @size: size of platform specific data 204 * 205 * Add a copy of platform specific data to the platform device's platform_data 206 * pointer. The memory associated with the platform data will be freed 207 * when the platform device is released. 208 */ 209 int platform_device_add_data(struct platform_device *pdev, void *data, size_t size) 210 { 211 void *d; 212 213 d = kmalloc(size, GFP_KERNEL); 214 if (d) { 215 memcpy(d, data, size); 216 pdev->dev.platform_data = d; 217 } 218 return d ? 0 : -ENOMEM; 219 } 220 EXPORT_SYMBOL_GPL(platform_device_add_data); 221 222 /** 223 * platform_device_add - add a platform device to device hierarchy 224 * @pdev: platform device we're adding 225 * 226 * This is part 2 of platform_device_register(), though may be called 227 * separately _iff_ pdev was allocated by platform_device_alloc(). 228 */ 229 int platform_device_add(struct platform_device *pdev) 230 { 231 int i, ret = 0; 232 233 if (!pdev) 234 return -EINVAL; 235 236 if (!pdev->dev.parent) 237 pdev->dev.parent = &platform_bus; 238 239 pdev->dev.bus = &platform_bus_type; 240 241 if (pdev->id != -1) 242 snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); 243 else 244 strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); 245 246 for (i = 0; i < pdev->num_resources; i++) { 247 struct resource *p, *r = &pdev->resource[i]; 248 249 if (r->name == NULL) 250 r->name = pdev->dev.bus_id; 251 252 p = r->parent; 253 if (!p) { 254 if (r->flags & IORESOURCE_MEM) 255 p = &iomem_resource; 256 else if (r->flags & IORESOURCE_IO) 257 p = &ioport_resource; 258 } 259 260 if (p && request_resource(p, r)) { 261 printk(KERN_ERR 262 "%s: failed to claim resource %d\n", 263 pdev->dev.bus_id, i); 264 ret = -EBUSY; 265 goto failed; 266 } 267 } 268 269 pr_debug("Registering platform device '%s'. Parent at %s\n", 270 pdev->dev.bus_id, pdev->dev.parent->bus_id); 271 272 ret = device_register(&pdev->dev); 273 if (ret == 0) 274 return ret; 275 276 failed: 277 while (--i >= 0) 278 if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO)) 279 release_resource(&pdev->resource[i]); 280 return ret; 281 } 282 EXPORT_SYMBOL_GPL(platform_device_add); 283 284 /** 285 * platform_device_register - add a platform-level device 286 * @pdev: platform device we're adding 287 * 288 */ 289 int platform_device_register(struct platform_device * pdev) 290 { 291 device_initialize(&pdev->dev); 292 return platform_device_add(pdev); 293 } 294 295 /** 296 * platform_device_unregister - remove a platform-level device 297 * @pdev: platform device we're removing 298 * 299 * Note that this function will also release all memory- and port-based 300 * resources owned by the device (@dev->resource). 301 */ 302 void platform_device_unregister(struct platform_device * pdev) 303 { 304 int i; 305 306 if (pdev) { 307 for (i = 0; i < pdev->num_resources; i++) { 308 struct resource *r = &pdev->resource[i]; 309 if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO)) 310 release_resource(r); 311 } 312 313 device_unregister(&pdev->dev); 314 } 315 } 316 317 /** 318 * platform_device_register_simple 319 * @name: base name of the device we're adding 320 * @id: instance id 321 * @res: set of resources that needs to be allocated for the device 322 * @num: number of resources 323 * 324 * This function creates a simple platform device that requires minimal 325 * resource and memory management. Canned release function freeing 326 * memory allocated for the device allows drivers using such devices 327 * to be unloaded iwithout waiting for the last reference to the device 328 * to be dropped. 329 */ 330 struct platform_device *platform_device_register_simple(char *name, unsigned int id, 331 struct resource *res, unsigned int num) 332 { 333 struct platform_device *pdev; 334 int retval; 335 336 pdev = platform_device_alloc(name, id); 337 if (!pdev) { 338 retval = -ENOMEM; 339 goto error; 340 } 341 342 if (num) { 343 retval = platform_device_add_resources(pdev, res, num); 344 if (retval) 345 goto error; 346 } 347 348 retval = platform_device_add(pdev); 349 if (retval) 350 goto error; 351 352 return pdev; 353 354 error: 355 platform_device_put(pdev); 356 return ERR_PTR(retval); 357 } 358 359 static int platform_drv_probe(struct device *_dev) 360 { 361 struct platform_driver *drv = to_platform_driver(_dev->driver); 362 struct platform_device *dev = to_platform_device(_dev); 363 364 return drv->probe(dev); 365 } 366 367 static int platform_drv_remove(struct device *_dev) 368 { 369 struct platform_driver *drv = to_platform_driver(_dev->driver); 370 struct platform_device *dev = to_platform_device(_dev); 371 372 return drv->remove(dev); 373 } 374 375 static void platform_drv_shutdown(struct device *_dev) 376 { 377 struct platform_driver *drv = to_platform_driver(_dev->driver); 378 struct platform_device *dev = to_platform_device(_dev); 379 380 drv->shutdown(dev); 381 } 382 383 static int platform_drv_suspend(struct device *_dev, pm_message_t state) 384 { 385 struct platform_driver *drv = to_platform_driver(_dev->driver); 386 struct platform_device *dev = to_platform_device(_dev); 387 388 return drv->suspend(dev, state); 389 } 390 391 static int platform_drv_resume(struct device *_dev) 392 { 393 struct platform_driver *drv = to_platform_driver(_dev->driver); 394 struct platform_device *dev = to_platform_device(_dev); 395 396 return drv->resume(dev); 397 } 398 399 /** 400 * platform_driver_register 401 * @drv: platform driver structure 402 */ 403 int platform_driver_register(struct platform_driver *drv) 404 { 405 drv->driver.bus = &platform_bus_type; 406 if (drv->probe) 407 drv->driver.probe = platform_drv_probe; 408 if (drv->remove) 409 drv->driver.remove = platform_drv_remove; 410 if (drv->shutdown) 411 drv->driver.shutdown = platform_drv_shutdown; 412 if (drv->suspend) 413 drv->driver.suspend = platform_drv_suspend; 414 if (drv->resume) 415 drv->driver.resume = platform_drv_resume; 416 return driver_register(&drv->driver); 417 } 418 EXPORT_SYMBOL_GPL(platform_driver_register); 419 420 /** 421 * platform_driver_unregister 422 * @drv: platform driver structure 423 */ 424 void platform_driver_unregister(struct platform_driver *drv) 425 { 426 driver_unregister(&drv->driver); 427 } 428 EXPORT_SYMBOL_GPL(platform_driver_unregister); 429 430 431 /** 432 * platform_match - bind platform device to platform driver. 433 * @dev: device. 434 * @drv: driver. 435 * 436 * Platform device IDs are assumed to be encoded like this: 437 * "<name><instance>", where <name> is a short description of the 438 * type of device, like "pci" or "floppy", and <instance> is the 439 * enumerated instance of the device, like '0' or '42'. 440 * Driver IDs are simply "<name>". 441 * So, extract the <name> from the platform_device structure, 442 * and compare it against the name of the driver. Return whether 443 * they match or not. 444 */ 445 446 static int platform_match(struct device * dev, struct device_driver * drv) 447 { 448 struct platform_device *pdev = container_of(dev, struct platform_device, dev); 449 450 return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); 451 } 452 453 static int platform_suspend(struct device * dev, pm_message_t state) 454 { 455 int ret = 0; 456 457 if (dev->driver && dev->driver->suspend) 458 ret = dev->driver->suspend(dev, state); 459 460 return ret; 461 } 462 463 static int platform_resume(struct device * dev) 464 { 465 int ret = 0; 466 467 if (dev->driver && dev->driver->resume) 468 ret = dev->driver->resume(dev); 469 470 return ret; 471 } 472 473 struct bus_type platform_bus_type = { 474 .name = "platform", 475 .match = platform_match, 476 .suspend = platform_suspend, 477 .resume = platform_resume, 478 }; 479 480 int __init platform_bus_init(void) 481 { 482 device_register(&platform_bus); 483 return bus_register(&platform_bus_type); 484 } 485 486 #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK 487 u64 dma_get_required_mask(struct device *dev) 488 { 489 u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 490 u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 491 u64 mask; 492 493 if (!high_totalram) { 494 /* convert to mask just covering totalram */ 495 low_totalram = (1 << (fls(low_totalram) - 1)); 496 low_totalram += low_totalram - 1; 497 mask = low_totalram; 498 } else { 499 high_totalram = (1 << (fls(high_totalram) - 1)); 500 high_totalram += high_totalram - 1; 501 mask = (((u64)high_totalram) << 32) + 0xffffffff; 502 } 503 return mask & *dev->dma_mask; 504 } 505 EXPORT_SYMBOL_GPL(dma_get_required_mask); 506 #endif 507 508 EXPORT_SYMBOL_GPL(platform_bus); 509 EXPORT_SYMBOL_GPL(platform_bus_type); 510 EXPORT_SYMBOL_GPL(platform_add_devices); 511 EXPORT_SYMBOL_GPL(platform_device_register); 512 EXPORT_SYMBOL_GPL(platform_device_register_simple); 513 EXPORT_SYMBOL_GPL(platform_device_unregister); 514 EXPORT_SYMBOL_GPL(platform_get_irq); 515 EXPORT_SYMBOL_GPL(platform_get_resource); 516 EXPORT_SYMBOL_GPL(platform_get_irq_byname); 517 EXPORT_SYMBOL_GPL(platform_get_resource_byname); 518