diff options
| author | Adrian McMenamin <adrian@newgolddream.dyndns.info> | 2008-02-06 18:51:21 -0500 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2008-02-14 00:22:07 -0500 |
| commit | b3c69e248176f7a123d519d63e7c0d68783d52c3 (patch) | |
| tree | 5cd739142e1a293f4d38642202591609d6c0a3d3 | |
| parent | b9482378916abb9a1e0a2334187cdc67f2deda2c (diff) | |
maple: more robust device detection.
Replacement second-in-series patch:
This patch fixes up memory leaks and, by delaying initialisation, makes
device detection more robust.
It also makes clearer the difference between struct maple_device and
struct device, as well as cleaning up the interrupt request code
(without changing its function in any way).
Also now removes redundant registration checking.
Signed-off-by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
| -rw-r--r-- | drivers/sh/maple/maple.c | 202 |
1 files changed, 105 insertions, 97 deletions
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index 9c48ccc44c29..616e2266e913 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/mach/dma.h> | 31 | #include <asm/mach/dma.h> |
| 32 | #include <asm/mach/sysasic.h> | 32 | #include <asm/mach/sysasic.h> |
| 33 | #include <asm/mach/maple.h> | 33 | #include <asm/mach/maple.h> |
| 34 | #include <linux/delay.h> | ||
| 34 | 35 | ||
| 35 | MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); | 36 | MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); |
| 36 | MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); | 37 | MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); |
| @@ -53,7 +54,7 @@ static struct device maple_bus; | |||
| 53 | static int subdevice_map[MAPLE_PORTS]; | 54 | static int subdevice_map[MAPLE_PORTS]; |
| 54 | static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; | 55 | static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; |
| 55 | static unsigned long maple_pnp_time; | 56 | static unsigned long maple_pnp_time; |
| 56 | static int started, scanning, liststatus; | 57 | static int started, scanning, liststatus, realscan; |
| 57 | static struct kmem_cache *maple_queue_cache; | 58 | static struct kmem_cache *maple_queue_cache; |
| 58 | 59 | ||
| 59 | struct maple_device_specify { | 60 | struct maple_device_specify { |
| @@ -73,7 +74,6 @@ int maple_driver_register(struct device_driver *drv) | |||
| 73 | drv->bus = &maple_bus_type; | 74 | drv->bus = &maple_bus_type; |
| 74 | return driver_register(drv); | 75 | return driver_register(drv); |
| 75 | } | 76 | } |
| 76 | |||
| 77 | EXPORT_SYMBOL_GPL(maple_driver_register); | 77 | EXPORT_SYMBOL_GPL(maple_driver_register); |
| 78 | 78 | ||
| 79 | /* set hardware registers to enable next round of dma */ | 79 | /* set hardware registers to enable next round of dma */ |
| @@ -95,15 +95,14 @@ static void maplebus_dma_reset(void) | |||
| 95 | * @function: the function code for the device | 95 | * @function: the function code for the device |
| 96 | */ | 96 | */ |
| 97 | void maple_getcond_callback(struct maple_device *dev, | 97 | void maple_getcond_callback(struct maple_device *dev, |
| 98 | void (*callback) (struct mapleq * mq), | 98 | void (*callback) (struct mapleq *mq), |
| 99 | unsigned long interval, unsigned long function) | 99 | unsigned long interval, unsigned long function) |
| 100 | { | 100 | { |
| 101 | dev->callback = callback; | 101 | dev->callback = callback; |
| 102 | dev->interval = interval; | 102 | dev->interval = interval; |
| 103 | dev->function = cpu_to_be32(function); | 103 | dev->function = cpu_to_be32(function); |
| 104 | dev->when = jiffies; | 104 | dev->when = jiffies; |
| 105 | } | 105 | } |
| 106 | |||
| 107 | EXPORT_SYMBOL_GPL(maple_getcond_callback); | 106 | EXPORT_SYMBOL_GPL(maple_getcond_callback); |
| 108 | 107 | ||
| 109 | static int maple_dma_done(void) | 108 | static int maple_dma_done(void) |
| @@ -113,10 +112,19 @@ static int maple_dma_done(void) | |||
| 113 | 112 | ||
| 114 | static void maple_release_device(struct device *dev) | 113 | static void maple_release_device(struct device *dev) |
| 115 | { | 114 | { |
| 116 | if (dev->type) { | 115 | struct maple_device *mdev; |
| 117 | kfree(dev->type->name); | 116 | struct mapleq *mq; |
| 118 | kfree(dev->type); | 117 | if (!dev) |
| 118 | return; | ||
| 119 | mdev = to_maple_dev(dev); | ||
| 120 | mq = mdev->mq; | ||
| 121 | if (mq) { | ||
| 122 | if (mq->recvbufdcsp) | ||
| 123 | kmem_cache_free(maple_queue_cache, mq->recvbufdcsp); | ||
| 124 | kfree(mq); | ||
| 125 | mq = NULL; | ||
| 119 | } | 126 | } |
| 127 | kfree(mdev); | ||
| 120 | } | 128 | } |
| 121 | 129 | ||
| 122 | /** | 130 | /** |
| @@ -129,10 +137,9 @@ void maple_add_packet(struct mapleq *mq) | |||
| 129 | list_add(&mq->list, &maple_waitq); | 137 | list_add(&mq->list, &maple_waitq); |
| 130 | mutex_unlock(&maple_list_lock); | 138 | mutex_unlock(&maple_list_lock); |
| 131 | } | 139 | } |
| 132 | |||
| 133 | EXPORT_SYMBOL_GPL(maple_add_packet); | 140 | EXPORT_SYMBOL_GPL(maple_add_packet); |
| 134 | 141 | ||
| 135 | static struct mapleq *maple_allocq(struct maple_device *dev) | 142 | static struct mapleq *maple_allocq(struct maple_device *mdev) |
| 136 | { | 143 | { |
| 137 | struct mapleq *mq; | 144 | struct mapleq *mq; |
| 138 | 145 | ||
| @@ -140,7 +147,7 @@ static struct mapleq *maple_allocq(struct maple_device *dev) | |||
| 140 | if (!mq) | 147 | if (!mq) |
| 141 | return NULL; | 148 | return NULL; |
| 142 | 149 | ||
| 143 | mq->dev = dev; | 150 | mq->dev = mdev; |
| 144 | mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); | 151 | mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); |
| 145 | mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); | 152 | mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); |
| 146 | if (!mq->recvbuf) { | 153 | if (!mq->recvbuf) { |
| @@ -153,22 +160,24 @@ static struct mapleq *maple_allocq(struct maple_device *dev) | |||
| 153 | 160 | ||
| 154 | static struct maple_device *maple_alloc_dev(int port, int unit) | 161 | static struct maple_device *maple_alloc_dev(int port, int unit) |
| 155 | { | 162 | { |
| 156 | struct maple_device *dev; | 163 | struct maple_device *mdev; |
| 157 | 164 | ||
| 158 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 165 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); |
| 159 | if (!dev) | 166 | if (!mdev) |
| 160 | return NULL; | 167 | return NULL; |
| 161 | 168 | ||
| 162 | dev->port = port; | 169 | mdev->port = port; |
| 163 | dev->unit = unit; | 170 | mdev->unit = unit; |
| 164 | dev->mq = maple_allocq(dev); | 171 | mdev->mq = maple_allocq(mdev); |
| 165 | 172 | ||
| 166 | if (!dev->mq) { | 173 | if (!mdev->mq) { |
| 167 | kfree(dev); | 174 | kfree(mdev); |
| 168 | return NULL; | 175 | return NULL; |
| 169 | } | 176 | } |
| 170 | 177 | mdev->dev.bus = &maple_bus_type; | |
| 171 | return dev; | 178 | mdev->dev.parent = &maple_bus; |
| 179 | mdev->function = 0; | ||
| 180 | return mdev; | ||
| 172 | } | 181 | } |
| 173 | 182 | ||
| 174 | static void maple_free_dev(struct maple_device *mdev) | 183 | static void maple_free_dev(struct maple_device *mdev) |
| @@ -176,7 +185,9 @@ static void maple_free_dev(struct maple_device *mdev) | |||
| 176 | if (!mdev) | 185 | if (!mdev) |
| 177 | return; | 186 | return; |
| 178 | if (mdev->mq) { | 187 | if (mdev->mq) { |
| 179 | kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); | 188 | if (mdev->mq->recvbufdcsp) |
| 189 | kmem_cache_free(maple_queue_cache, | ||
| 190 | mdev->mq->recvbufdcsp); | ||
| 180 | kfree(mdev->mq); | 191 | kfree(mdev->mq); |
| 181 | } | 192 | } |
| 182 | kfree(mdev); | 193 | kfree(mdev); |
| @@ -260,80 +271,89 @@ static void maple_detach_driver(struct maple_device *mdev) | |||
| 260 | mdev->driver->disconnect(mdev); | 271 | mdev->driver->disconnect(mdev); |
| 261 | } | 272 | } |
| 262 | mdev->driver = NULL; | 273 | mdev->driver = NULL; |
| 263 | if (mdev->registered) { | 274 | device_unregister(&mdev->dev); |
| 264 | maple_release_device(&mdev->dev); | 275 | mdev = NULL; |
| 265 | device_unregister(&mdev->dev); | ||
| 266 | } | ||
| 267 | mdev->registered = 0; | ||
| 268 | maple_free_dev(mdev); | ||
| 269 | } | 276 | } |
| 270 | 277 | ||
| 271 | /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ | 278 | /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ |
| 272 | static void maple_attach_driver(struct maple_device *dev) | 279 | static void maple_attach_driver(struct maple_device *mdev) |
| 273 | { | 280 | { |
| 274 | char *p; | 281 | char *p, *recvbuf; |
| 275 | |||
| 276 | char *recvbuf; | ||
| 277 | unsigned long function; | 282 | unsigned long function; |
| 278 | int matched, retval; | 283 | int matched, retval; |
| 279 | 284 | ||
| 280 | recvbuf = dev->mq->recvbuf; | 285 | recvbuf = mdev->mq->recvbuf; |
| 281 | memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); | 286 | /* copy the data as individual elements in |
| 282 | memcpy(dev->product_name, dev->devinfo.product_name, 30); | 287 | * case of memory optimisation */ |
| 283 | memcpy(dev->product_licence, dev->devinfo.product_licence, 60); | 288 | memcpy(&mdev->devinfo.function, recvbuf + 4, 4); |
| 284 | dev->product_name[30] = '\0'; | 289 | memcpy(&mdev->devinfo.function_data[0], recvbuf + 8, 12); |
| 285 | dev->product_licence[60] = '\0'; | 290 | memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); |
| 286 | 291 | memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); | |
| 287 | for (p = dev->product_name + 29; dev->product_name <= p; p--) | 292 | memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); |
| 293 | memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60); | ||
| 294 | memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); | ||
| 295 | memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); | ||
| 296 | memcpy(mdev->product_name, mdev->devinfo.product_name, 30); | ||
| 297 | mdev->product_name[30] = '\0'; | ||
| 298 | memcpy(mdev->product_licence, mdev->devinfo.product_licence, 60); | ||
| 299 | mdev->product_licence[60] = '\0'; | ||
| 300 | |||
| 301 | for (p = mdev->product_name + 29; mdev->product_name <= p; p--) | ||
| 288 | if (*p == ' ') | 302 | if (*p == ' ') |
| 289 | *p = '\0'; | 303 | *p = '\0'; |
| 290 | else | 304 | else |
| 291 | break; | 305 | break; |
| 292 | 306 | for (p = mdev->product_licence + 59; mdev->product_licence <= p; p--) | |
| 293 | for (p = dev->product_licence + 59; dev->product_licence <= p; p--) | ||
| 294 | if (*p == ' ') | 307 | if (*p == ' ') |
| 295 | *p = '\0'; | 308 | *p = '\0'; |
| 296 | else | 309 | else |
| 297 | break; | 310 | break; |
| 298 | 311 | ||
| 299 | function = be32_to_cpu(dev->devinfo.function); | 312 | if (realscan) { |
| 313 | printk(KERN_INFO "Maple device detected: %s\n", | ||
| 314 | mdev->product_name); | ||
| 315 | printk(KERN_INFO "Maple device: %s\n", mdev->product_licence); | ||
| 316 | } | ||
| 317 | |||
| 318 | function = be32_to_cpu(mdev->devinfo.function); | ||
| 300 | 319 | ||
| 301 | if (function > 0x200) { | 320 | if (function > 0x200) { |
| 302 | /* Do this silently - as not a real device */ | 321 | /* Do this silently - as not a real device */ |
| 303 | function = 0; | 322 | function = 0; |
| 304 | dev->driver = &maple_dummy_driver; | 323 | mdev->driver = &maple_dummy_driver; |
| 305 | sprintf(dev->dev.bus_id, "%d:0.port", dev->port); | 324 | sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port); |
| 306 | } else { | 325 | } else { |
| 307 | printk(KERN_INFO | 326 | if (realscan) |
| 308 | "Maple bus at (%d, %d): Connected function 0x%lX\n", | 327 | printk(KERN_INFO |
| 309 | dev->port, dev->unit, function); | 328 | "Maple bus at (%d, %d): Function 0x%lX\n", |
| 329 | mdev->port, mdev->unit, function); | ||
| 310 | 330 | ||
| 311 | matched = | 331 | matched = |
| 312 | bus_for_each_drv(&maple_bus_type, NULL, dev, | 332 | bus_for_each_drv(&maple_bus_type, NULL, mdev, |
| 313 | attach_matching_maple_driver); | 333 | attach_matching_maple_driver); |
| 314 | 334 | ||
| 315 | if (matched == 0) { | 335 | if (matched == 0) { |
| 316 | /* Driver does not exist yet */ | 336 | /* Driver does not exist yet */ |
| 317 | printk(KERN_INFO | 337 | if (realscan) |
| 318 | "No maple driver found for this device\n"); | 338 | printk(KERN_INFO |
| 319 | dev->driver = &maple_dummy_driver; | 339 | "No maple driver found.\n"); |
| 340 | mdev->driver = &maple_dummy_driver; | ||
| 320 | } | 341 | } |
| 321 | 342 | sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port, | |
| 322 | sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, | 343 | mdev->unit, function); |
| 323 | dev->unit, function); | ||
| 324 | } | 344 | } |
| 325 | dev->function = function; | 345 | mdev->function = function; |
| 326 | dev->dev.bus = &maple_bus_type; | 346 | mdev->dev.release = &maple_release_device; |
| 327 | dev->dev.parent = &maple_bus; | 347 | retval = device_register(&mdev->dev); |
| 328 | dev->dev.release = &maple_release_device; | ||
| 329 | retval = device_register(&dev->dev); | ||
| 330 | if (retval) { | 348 | if (retval) { |
| 331 | printk(KERN_INFO | 349 | printk(KERN_INFO |
| 332 | "Maple bus: Attempt to register device (%x, %x) failed.\n", | 350 | "Maple bus: Attempt to register device" |
| 333 | dev->port, dev->unit); | 351 | " (%x, %x) failed.\n", |
| 334 | maple_free_dev(dev); | 352 | mdev->port, mdev->unit); |
| 353 | maple_free_dev(mdev); | ||
| 354 | mdev = NULL; | ||
| 355 | return; | ||
| 335 | } | 356 | } |
| 336 | dev->registered = 1; | ||
| 337 | } | 357 | } |
| 338 | 358 | ||
| 339 | /* | 359 | /* |
| @@ -519,7 +539,8 @@ static void maple_dma_handler(struct work_struct *work) | |||
| 519 | 539 | ||
| 520 | case MAPLE_RESPONSE_ALLINFO: | 540 | case MAPLE_RESPONSE_ALLINFO: |
| 521 | printk(KERN_DEBUG | 541 | printk(KERN_DEBUG |
| 522 | "Maple - extended device information not supported\n"); | 542 | "Maple - extended device information" |
| 543 | " not supported\n"); | ||
| 523 | break; | 544 | break; |
| 524 | 545 | ||
| 525 | case MAPLE_RESPONSE_OK: | 546 | case MAPLE_RESPONSE_OK: |
| @@ -555,26 +576,16 @@ static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) | |||
| 555 | return IRQ_HANDLED; | 576 | return IRQ_HANDLED; |
| 556 | } | 577 | } |
| 557 | 578 | ||
| 558 | static struct irqaction maple_dma_irq = { | ||
| 559 | .name = "maple bus DMA handler", | ||
| 560 | .handler = maplebus_dma_interrupt, | ||
| 561 | .flags = IRQF_SHARED, | ||
| 562 | }; | ||
| 563 | |||
| 564 | static struct irqaction maple_vblank_irq = { | ||
| 565 | .name = "maple bus VBLANK handler", | ||
| 566 | .handler = maplebus_vblank_interrupt, | ||
| 567 | .flags = IRQF_SHARED, | ||
| 568 | }; | ||
| 569 | |||
| 570 | static int maple_set_dma_interrupt_handler(void) | 579 | static int maple_set_dma_interrupt_handler(void) |
| 571 | { | 580 | { |
| 572 | return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); | 581 | return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt, |
| 582 | IRQF_SHARED, "maple bus DMA", &maple_dummy_driver); | ||
| 573 | } | 583 | } |
| 574 | 584 | ||
| 575 | static int maple_set_vblank_interrupt_handler(void) | 585 | static int maple_set_vblank_interrupt_handler(void) |
| 576 | { | 586 | { |
| 577 | return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); | 587 | return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt, |
| 588 | IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver); | ||
| 578 | } | 589 | } |
| 579 | 590 | ||
| 580 | static int maple_get_dma_buffer(void) | 591 | static int maple_get_dma_buffer(void) |
| @@ -618,7 +629,7 @@ static struct maple_driver maple_dummy_driver = { | |||
| 618 | .drv = { | 629 | .drv = { |
| 619 | .name = "maple_dummy_driver", | 630 | .name = "maple_dummy_driver", |
| 620 | .bus = &maple_bus_type, | 631 | .bus = &maple_bus_type, |
| 621 | }, | 632 | }, |
| 622 | }; | 633 | }; |
| 623 | 634 | ||
| 624 | struct bus_type maple_bus_type = { | 635 | struct bus_type maple_bus_type = { |
| @@ -626,7 +637,6 @@ struct bus_type maple_bus_type = { | |||
| 626 | .match = match_maple_bus_driver, | 637 | .match = match_maple_bus_driver, |
| 627 | .uevent = maple_bus_uevent, | 638 | .uevent = maple_bus_uevent, |
| 628 | }; | 639 | }; |
| 629 | |||
| 630 | EXPORT_SYMBOL_GPL(maple_bus_type); | 640 | EXPORT_SYMBOL_GPL(maple_bus_type); |
| 631 | 641 | ||
| 632 | static struct device maple_bus = { | 642 | static struct device maple_bus = { |
| @@ -678,7 +688,7 @@ static int __init maple_bus_init(void) | |||
| 678 | 688 | ||
| 679 | maple_queue_cache = | 689 | maple_queue_cache = |
| 680 | kmem_cache_create("maple_queue_cache", 0x400, 0, | 690 | kmem_cache_create("maple_queue_cache", 0x400, 0, |
| 681 | SLAB_HWCACHE_ALIGN, NULL); | 691 | SLAB_POISON|SLAB_HWCACHE_ALIGN, NULL); |
| 682 | 692 | ||
| 683 | if (!maple_queue_cache) | 693 | if (!maple_queue_cache) |
| 684 | goto cleanup_bothirqs; | 694 | goto cleanup_bothirqs; |
| @@ -691,50 +701,48 @@ static int __init maple_bus_init(void) | |||
| 691 | maple_free_dev(mdev[i]); | 701 | maple_free_dev(mdev[i]); |
| 692 | goto cleanup_cache; | 702 | goto cleanup_cache; |
| 693 | } | 703 | } |
| 694 | mdev[i]->registered = 0; | ||
| 695 | mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; | 704 | mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; |
| 696 | mdev[i]->mq->length = 0; | 705 | mdev[i]->mq->length = 0; |
| 697 | maple_attach_driver(mdev[i]); | ||
| 698 | maple_add_packet(mdev[i]->mq); | 706 | maple_add_packet(mdev[i]->mq); |
| 707 | /* delay aids hardware detection */ | ||
| 708 | udelay(20); | ||
| 699 | subdevice_map[i] = 0; | 709 | subdevice_map[i] = 0; |
| 700 | } | 710 | } |
| 701 | 711 | ||
| 712 | realscan = 1; | ||
| 702 | /* setup maplebus hardware */ | 713 | /* setup maplebus hardware */ |
| 703 | maplebus_dma_reset(); | 714 | maplebus_dma_reset(); |
| 704 | |||
| 705 | /* initial detection */ | 715 | /* initial detection */ |
| 706 | maple_send(); | 716 | maple_send(); |
| 707 | |||
| 708 | maple_pnp_time = jiffies; | 717 | maple_pnp_time = jiffies; |
| 709 | |||
| 710 | printk(KERN_INFO "Maple bus core now registered.\n"); | 718 | printk(KERN_INFO "Maple bus core now registered.\n"); |
| 711 | 719 | ||
| 712 | return 0; | 720 | return 0; |
| 713 | 721 | ||
| 714 | cleanup_cache: | 722 | cleanup_cache: |
| 715 | kmem_cache_destroy(maple_queue_cache); | 723 | kmem_cache_destroy(maple_queue_cache); |
| 716 | 724 | ||
| 717 | cleanup_bothirqs: | 725 | cleanup_bothirqs: |
| 718 | free_irq(HW_EVENT_VSYNC, 0); | 726 | free_irq(HW_EVENT_VSYNC, 0); |
| 719 | 727 | ||
| 720 | cleanup_irq: | 728 | cleanup_irq: |
| 721 | free_irq(HW_EVENT_MAPLE_DMA, 0); | 729 | free_irq(HW_EVENT_MAPLE_DMA, 0); |
| 722 | 730 | ||
| 723 | cleanup_dma: | 731 | cleanup_dma: |
| 724 | free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); | 732 | free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); |
| 725 | 733 | ||
| 726 | cleanup_basic: | 734 | cleanup_basic: |
| 727 | driver_unregister(&maple_dummy_driver.drv); | 735 | driver_unregister(&maple_dummy_driver.drv); |
| 728 | 736 | ||
| 729 | cleanup_bus: | 737 | cleanup_bus: |
| 730 | bus_unregister(&maple_bus_type); | 738 | bus_unregister(&maple_bus_type); |
| 731 | 739 | ||
| 732 | cleanup_device: | 740 | cleanup_device: |
| 733 | device_unregister(&maple_bus); | 741 | device_unregister(&maple_bus); |
| 734 | 742 | ||
| 735 | cleanup: | 743 | cleanup: |
| 736 | printk(KERN_INFO "Maple bus registration failed\n"); | 744 | printk(KERN_INFO "Maple bus registration failed\n"); |
| 737 | return retval; | 745 | return retval; |
| 738 | } | 746 | } |
| 739 | 747 | /* Push init to later to ensure hardware gets detected */ | |
| 740 | subsys_initcall(maple_bus_init); | 748 | fs_initcall(maple_bus_init); |
