aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
authorAdrian McMenamin <adrian@newgolddream.dyndns.info>2008-02-06 18:51:21 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-02-14 00:22:07 -0500
commitb3c69e248176f7a123d519d63e7c0d68783d52c3 (patch)
tree5cd739142e1a293f4d38642202591609d6c0a3d3 /drivers/sh
parentb9482378916abb9a1e0a2334187cdc67f2deda2c (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>
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/maple/maple.c202
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
35MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); 36MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin");
36MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); 37MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
@@ -53,7 +54,7 @@ static struct device maple_bus;
53static int subdevice_map[MAPLE_PORTS]; 54static int subdevice_map[MAPLE_PORTS];
54static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; 55static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
55static unsigned long maple_pnp_time; 56static unsigned long maple_pnp_time;
56static int started, scanning, liststatus; 57static int started, scanning, liststatus, realscan;
57static struct kmem_cache *maple_queue_cache; 58static struct kmem_cache *maple_queue_cache;
58 59
59struct maple_device_specify { 60struct 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
77EXPORT_SYMBOL_GPL(maple_driver_register); 77EXPORT_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 */
97void maple_getcond_callback(struct maple_device *dev, 97void 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
107EXPORT_SYMBOL_GPL(maple_getcond_callback); 106EXPORT_SYMBOL_GPL(maple_getcond_callback);
108 107
109static int maple_dma_done(void) 108static int maple_dma_done(void)
@@ -113,10 +112,19 @@ static int maple_dma_done(void)
113 112
114static void maple_release_device(struct device *dev) 113static 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
133EXPORT_SYMBOL_GPL(maple_add_packet); 140EXPORT_SYMBOL_GPL(maple_add_packet);
134 141
135static struct mapleq *maple_allocq(struct maple_device *dev) 142static 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
154static struct maple_device *maple_alloc_dev(int port, int unit) 161static 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
174static void maple_free_dev(struct maple_device *mdev) 183static 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 */
272static void maple_attach_driver(struct maple_device *dev) 279static 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
558static struct irqaction maple_dma_irq = {
559 .name = "maple bus DMA handler",
560 .handler = maplebus_dma_interrupt,
561 .flags = IRQF_SHARED,
562};
563
564static struct irqaction maple_vblank_irq = {
565 .name = "maple bus VBLANK handler",
566 .handler = maplebus_vblank_interrupt,
567 .flags = IRQF_SHARED,
568};
569
570static int maple_set_dma_interrupt_handler(void) 579static 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
575static int maple_set_vblank_interrupt_handler(void) 585static 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
580static int maple_get_dma_buffer(void) 591static 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
624struct bus_type maple_bus_type = { 635struct 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
630EXPORT_SYMBOL_GPL(maple_bus_type); 640EXPORT_SYMBOL_GPL(maple_bus_type);
631 641
632static struct device maple_bus = { 642static 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: 722cleanup_cache:
715 kmem_cache_destroy(maple_queue_cache); 723 kmem_cache_destroy(maple_queue_cache);
716 724
717 cleanup_bothirqs: 725cleanup_bothirqs:
718 free_irq(HW_EVENT_VSYNC, 0); 726 free_irq(HW_EVENT_VSYNC, 0);
719 727
720 cleanup_irq: 728cleanup_irq:
721 free_irq(HW_EVENT_MAPLE_DMA, 0); 729 free_irq(HW_EVENT_MAPLE_DMA, 0);
722 730
723 cleanup_dma: 731cleanup_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: 734cleanup_basic:
727 driver_unregister(&maple_dummy_driver.drv); 735 driver_unregister(&maple_dummy_driver.drv);
728 736
729 cleanup_bus: 737cleanup_bus:
730 bus_unregister(&maple_bus_type); 738 bus_unregister(&maple_bus_type);
731 739
732 cleanup_device: 740cleanup_device:
733 device_unregister(&maple_bus); 741 device_unregister(&maple_bus);
734 742
735 cleanup: 743cleanup:
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 */
740subsys_initcall(maple_bus_init); 748fs_initcall(maple_bus_init);