aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/intc.c47
-rw-r--r--drivers/sh/maple/maple.c463
2 files changed, 281 insertions, 229 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 58d24c5a76ce..2269fbcaa182 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -568,6 +568,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
568 if (!data[0] && data[1]) 568 if (!data[0] && data[1])
569 primary = 1; 569 primary = 1;
570 570
571 if (!data[0] && !data[1])
572 pr_warning("intc: missing unique irq mask for "
573 "irq %d (vect 0x%04x)\n", irq, irq2evt(irq));
574
571 data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); 575 data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
572 data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); 576 data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
573 577
@@ -641,6 +645,17 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
641 return 0; 645 return 0;
642} 646}
643 647
648static unsigned char *intc_evt2irq_table;
649
650unsigned int intc_evt2irq(unsigned int vector)
651{
652 unsigned int irq = evt2irq(vector);
653
654 if (intc_evt2irq_table && intc_evt2irq_table[irq])
655 irq = intc_evt2irq_table[irq];
656
657 return irq;
658}
644 659
645void __init register_intc_controller(struct intc_desc *desc) 660void __init register_intc_controller(struct intc_desc *desc)
646{ 661{
@@ -705,9 +720,41 @@ void __init register_intc_controller(struct intc_desc *desc)
705 720
706 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ 721 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
707 722
723 /* keep the first vector only if same enum is used multiple times */
724 for (i = 0; i < desc->nr_vectors; i++) {
725 struct intc_vect *vect = desc->vectors + i;
726 int first_irq = evt2irq(vect->vect);
727
728 if (!vect->enum_id)
729 continue;
730
731 for (k = i + 1; k < desc->nr_vectors; k++) {
732 struct intc_vect *vect2 = desc->vectors + k;
733
734 if (vect->enum_id != vect2->enum_id)
735 continue;
736
737 vect2->enum_id = 0;
738
739 if (!intc_evt2irq_table)
740 intc_evt2irq_table = alloc_bootmem(NR_IRQS);
741
742 if (!intc_evt2irq_table) {
743 pr_warning("intc: cannot allocate evt2irq!\n");
744 continue;
745 }
746
747 intc_evt2irq_table[evt2irq(vect2->vect)] = first_irq;
748 }
749 }
750
751 /* register the vectors one by one */
708 for (i = 0; i < desc->nr_vectors; i++) { 752 for (i = 0; i < desc->nr_vectors; i++) {
709 struct intc_vect *vect = desc->vectors + i; 753 struct intc_vect *vect = desc->vectors + i;
710 754
755 if (!vect->enum_id)
756 continue;
757
711 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); 758 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
712 } 759 }
713} 760}
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index 7e1257af3d41..cab1ab7cfb78 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -1,16 +1,10 @@
1/* 1/*
2 * Core maple bus functionality 2 * Core maple bus functionality
3 * 3 *
4 * Copyright (C) 2007, 2008 Adrian McMenamin 4 * Copyright (C) 2007 - 2009 Adrian McMenamin
5 * Copyright (C) 2001 - 2008 Paul Mundt 5 * Copyright (C) 2001 - 2008 Paul Mundt
6 * 6 * Copyright (C) 2000 - 2001 YAEGASHI Takeshi
7 * Based on 2.4 code by:
8 *
9 * Copyright (C) 2000-2001 YAEGASHI Takeshi
10 * Copyright (C) 2001 M. R. Brown 7 * Copyright (C) 2001 M. R. Brown
11 * Copyright (C) 2001 Paul Mundt
12 *
13 * and others.
14 * 8 *
15 * This file is subject to the terms and conditions of the GNU General Public 9 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file "COPYING" in the main directory of this archive 10 * License. See the file "COPYING" in the main directory of this archive
@@ -32,7 +26,7 @@
32#include <mach/dma.h> 26#include <mach/dma.h>
33#include <mach/sysasic.h> 27#include <mach/sysasic.h>
34 28
35MODULE_AUTHOR("Yaegashi Takeshi, Paul Mundt, M. R. Brown, Adrian McMenamin"); 29MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
36MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); 30MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
37MODULE_LICENSE("GPL v2"); 31MODULE_LICENSE("GPL v2");
38MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}"); 32MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
@@ -49,7 +43,7 @@ static LIST_HEAD(maple_sentq);
49/* mutex to protect queue of waiting packets */ 43/* mutex to protect queue of waiting packets */
50static DEFINE_MUTEX(maple_wlist_lock); 44static DEFINE_MUTEX(maple_wlist_lock);
51 45
52static struct maple_driver maple_dummy_driver; 46static struct maple_driver maple_unsupported_device;
53static struct device maple_bus; 47static struct device maple_bus;
54static int subdevice_map[MAPLE_PORTS]; 48static int subdevice_map[MAPLE_PORTS];
55static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; 49static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
@@ -62,8 +56,9 @@ struct maple_device_specify {
62 int unit; 56 int unit;
63}; 57};
64 58
65static bool checked[4]; 59static bool checked[MAPLE_PORTS];
66static struct maple_device *baseunits[4]; 60static bool empty[MAPLE_PORTS];
61static struct maple_device *baseunits[MAPLE_PORTS];
67 62
68/** 63/**
69 * maple_driver_register - register a maple driver 64 * maple_driver_register - register a maple driver
@@ -97,12 +92,20 @@ void maple_driver_unregister(struct maple_driver *drv)
97EXPORT_SYMBOL_GPL(maple_driver_unregister); 92EXPORT_SYMBOL_GPL(maple_driver_unregister);
98 93
99/* set hardware registers to enable next round of dma */ 94/* set hardware registers to enable next round of dma */
100static void maplebus_dma_reset(void) 95static void maple_dma_reset(void)
101{ 96{
102 ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); 97 ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
103 /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ 98 /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
104 ctrl_outl(1, MAPLE_TRIGTYPE); 99 ctrl_outl(1, MAPLE_TRIGTYPE);
105 ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); 100 /*
101 * Maple system register
102 * bits 31 - 16 timeout in units of 20nsec
103 * bit 12 hard trigger - set 0 to keep responding to VBLANK
104 * bits 9 - 8 set 00 for 2 Mbps, 01 for 1 Mbps
105 * bits 3 - 0 delay (in 1.3ms) between VBLANK and start of DMA
106 * max delay is 11
107 */
108 ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(0xFFFF), MAPLE_SPEED);
106 ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); 109 ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
107 ctrl_outl(1, MAPLE_ENABLE); 110 ctrl_outl(1, MAPLE_ENABLE);
108} 111}
@@ -134,21 +137,16 @@ static void maple_release_device(struct device *dev)
134{ 137{
135 struct maple_device *mdev; 138 struct maple_device *mdev;
136 struct mapleq *mq; 139 struct mapleq *mq;
137 if (!dev) 140
138 return;
139 mdev = to_maple_dev(dev); 141 mdev = to_maple_dev(dev);
140 mq = mdev->mq; 142 mq = mdev->mq;
141 if (mq) { 143 kmem_cache_free(maple_queue_cache, mq->recvbuf);
142 if (mq->recvbufdcsp) 144 kfree(mq);
143 kmem_cache_free(maple_queue_cache, mq->recvbufdcsp);
144 kfree(mq);
145 mq = NULL;
146 }
147 kfree(mdev); 145 kfree(mdev);
148} 146}
149 147
150/** 148/**
151 * maple_add_packet - add a single instruction to the queue 149 * maple_add_packet - add a single instruction to the maple bus queue
152 * @mdev: maple device 150 * @mdev: maple device
153 * @function: function on device being queried 151 * @function: function on device being queried
154 * @command: maple command to add 152 * @command: maple command to add
@@ -158,68 +156,12 @@ static void maple_release_device(struct device *dev)
158int maple_add_packet(struct maple_device *mdev, u32 function, u32 command, 156int maple_add_packet(struct maple_device *mdev, u32 function, u32 command,
159 size_t length, void *data) 157 size_t length, void *data)
160{ 158{
161 int locking, ret = 0; 159 int ret = 0;
162 void *sendbuf = NULL; 160 void *sendbuf = NULL;
163 161
164 mutex_lock(&maple_wlist_lock);
165 /* bounce if device already locked */
166 locking = mutex_is_locked(&mdev->mq->mutex);
167 if (locking) {
168 ret = -EBUSY;
169 goto out;
170 }
171
172 mutex_lock(&mdev->mq->mutex);
173
174 if (length) { 162 if (length) {
175 sendbuf = kmalloc(length * 4, GFP_KERNEL); 163 sendbuf = kzalloc(length * 4, GFP_KERNEL);
176 if (!sendbuf) { 164 if (!sendbuf) {
177 mutex_unlock(&mdev->mq->mutex);
178 ret = -ENOMEM;
179 goto out;
180 }
181 ((__be32 *)sendbuf)[0] = cpu_to_be32(function);
182 }
183
184 mdev->mq->command = command;
185 mdev->mq->length = length;
186 if (length > 1)
187 memcpy(sendbuf + 4, data, (length - 1) * 4);
188 mdev->mq->sendbuf = sendbuf;
189
190 list_add(&mdev->mq->list, &maple_waitq);
191out:
192 mutex_unlock(&maple_wlist_lock);
193 return ret;
194}
195EXPORT_SYMBOL_GPL(maple_add_packet);
196
197/**
198 * maple_add_packet_sleeps - add a single instruction to the queue
199 * @mdev: maple device
200 * @function: function on device being queried
201 * @command: maple command to add
202 * @length: length of command string (in 32 bit words)
203 * @data: remainder of command string
204 *
205 * Same as maple_add_packet(), but waits for the lock to become free.
206 */
207int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
208 u32 command, size_t length, void *data)
209{
210 int locking, ret = 0;
211 void *sendbuf = NULL;
212
213 locking = mutex_lock_interruptible(&mdev->mq->mutex);
214 if (locking) {
215 ret = -EIO;
216 goto out;
217 }
218
219 if (length) {
220 sendbuf = kmalloc(length * 4, GFP_KERNEL);
221 if (!sendbuf) {
222 mutex_unlock(&mdev->mq->mutex);
223 ret = -ENOMEM; 165 ret = -ENOMEM;
224 goto out; 166 goto out;
225 } 167 }
@@ -233,38 +175,35 @@ int maple_add_packet_sleeps(struct maple_device *mdev, u32 function,
233 mdev->mq->sendbuf = sendbuf; 175 mdev->mq->sendbuf = sendbuf;
234 176
235 mutex_lock(&maple_wlist_lock); 177 mutex_lock(&maple_wlist_lock);
236 list_add(&mdev->mq->list, &maple_waitq); 178 list_add_tail(&mdev->mq->list, &maple_waitq);
237 mutex_unlock(&maple_wlist_lock); 179 mutex_unlock(&maple_wlist_lock);
238out: 180out:
239 return ret; 181 return ret;
240} 182}
241EXPORT_SYMBOL_GPL(maple_add_packet_sleeps); 183EXPORT_SYMBOL_GPL(maple_add_packet);
242 184
243static struct mapleq *maple_allocq(struct maple_device *mdev) 185static struct mapleq *maple_allocq(struct maple_device *mdev)
244{ 186{
245 struct mapleq *mq; 187 struct mapleq *mq;
246 188
247 mq = kmalloc(sizeof(*mq), GFP_KERNEL); 189 mq = kzalloc(sizeof(*mq), GFP_KERNEL);
248 if (!mq) 190 if (!mq)
249 goto failed_nomem; 191 goto failed_nomem;
250 192
193 INIT_LIST_HEAD(&mq->list);
251 mq->dev = mdev; 194 mq->dev = mdev;
252 mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); 195 mq->recvbuf = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
253 mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
254 if (!mq->recvbuf) 196 if (!mq->recvbuf)
255 goto failed_p2; 197 goto failed_p2;
256 /* 198 mq->recvbuf->buf = &((mq->recvbuf->bufx)[0]);
257 * most devices do not need the mutex - but
258 * anything that injects block reads or writes
259 * will rely on it
260 */
261 mutex_init(&mq->mutex);
262 199
263 return mq; 200 return mq;
264 201
265failed_p2: 202failed_p2:
266 kfree(mq); 203 kfree(mq);
267failed_nomem: 204failed_nomem:
205 dev_err(&mdev->dev, "could not allocate memory for device (%d, %d)\n",
206 mdev->port, mdev->unit);
268 return NULL; 207 return NULL;
269} 208}
270 209
@@ -272,12 +211,16 @@ static struct maple_device *maple_alloc_dev(int port, int unit)
272{ 211{
273 struct maple_device *mdev; 212 struct maple_device *mdev;
274 213
214 /* zero this out to avoid kobj subsystem
215 * thinking it has already been registered */
216
275 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 217 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
276 if (!mdev) 218 if (!mdev)
277 return NULL; 219 return NULL;
278 220
279 mdev->port = port; 221 mdev->port = port;
280 mdev->unit = unit; 222 mdev->unit = unit;
223
281 mdev->mq = maple_allocq(mdev); 224 mdev->mq = maple_allocq(mdev);
282 225
283 if (!mdev->mq) { 226 if (!mdev->mq) {
@@ -286,19 +229,14 @@ static struct maple_device *maple_alloc_dev(int port, int unit)
286 } 229 }
287 mdev->dev.bus = &maple_bus_type; 230 mdev->dev.bus = &maple_bus_type;
288 mdev->dev.parent = &maple_bus; 231 mdev->dev.parent = &maple_bus;
232 init_waitqueue_head(&mdev->maple_wait);
289 return mdev; 233 return mdev;
290} 234}
291 235
292static void maple_free_dev(struct maple_device *mdev) 236static void maple_free_dev(struct maple_device *mdev)
293{ 237{
294 if (!mdev) 238 kmem_cache_free(maple_queue_cache, mdev->mq->recvbuf);
295 return; 239 kfree(mdev->mq);
296 if (mdev->mq) {
297 if (mdev->mq->recvbufdcsp)
298 kmem_cache_free(maple_queue_cache,
299 mdev->mq->recvbufdcsp);
300 kfree(mdev->mq);
301 }
302 kfree(mdev); 240 kfree(mdev);
303} 241}
304 242
@@ -320,7 +258,7 @@ static void maple_build_block(struct mapleq *mq)
320 maple_lastptr = maple_sendptr; 258 maple_lastptr = maple_sendptr;
321 259
322 *maple_sendptr++ = (port << 16) | len | 0x80000000; 260 *maple_sendptr++ = (port << 16) | len | 0x80000000;
323 *maple_sendptr++ = PHYSADDR(mq->recvbuf); 261 *maple_sendptr++ = PHYSADDR(mq->recvbuf->buf);
324 *maple_sendptr++ = 262 *maple_sendptr++ =
325 mq->command | (to << 8) | (from << 16) | (len << 24); 263 mq->command | (to << 8) | (from << 16) | (len << 24);
326 while (len-- > 0) 264 while (len-- > 0)
@@ -333,20 +271,28 @@ static void maple_send(void)
333 int i, maple_packets = 0; 271 int i, maple_packets = 0;
334 struct mapleq *mq, *nmq; 272 struct mapleq *mq, *nmq;
335 273
336 if (!list_empty(&maple_sentq)) 274 if (!maple_dma_done())
337 return; 275 return;
276
277 /* disable DMA */
278 ctrl_outl(0, MAPLE_ENABLE);
279
280 if (!list_empty(&maple_sentq))
281 goto finish;
282
338 mutex_lock(&maple_wlist_lock); 283 mutex_lock(&maple_wlist_lock);
339 if (list_empty(&maple_waitq) || !maple_dma_done()) { 284 if (list_empty(&maple_waitq)) {
340 mutex_unlock(&maple_wlist_lock); 285 mutex_unlock(&maple_wlist_lock);
341 return; 286 goto finish;
342 } 287 }
343 mutex_unlock(&maple_wlist_lock); 288
344 maple_lastptr = maple_sendbuf; 289 maple_lastptr = maple_sendbuf;
345 maple_sendptr = maple_sendbuf; 290 maple_sendptr = maple_sendbuf;
346 mutex_lock(&maple_wlist_lock); 291
347 list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { 292 list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
348 maple_build_block(mq); 293 maple_build_block(mq);
349 list_move(&mq->list, &maple_sentq); 294 list_del_init(&mq->list);
295 list_add_tail(&mq->list, &maple_sentq);
350 if (maple_packets++ > MAPLE_MAXPACKETS) 296 if (maple_packets++ > MAPLE_MAXPACKETS)
351 break; 297 break;
352 } 298 }
@@ -356,10 +302,13 @@ static void maple_send(void)
356 dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, 302 dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
357 PAGE_SIZE, DMA_BIDIRECTIONAL); 303 PAGE_SIZE, DMA_BIDIRECTIONAL);
358 } 304 }
305
306finish:
307 maple_dma_reset();
359} 308}
360 309
361/* check if there is a driver registered likely to match this device */ 310/* check if there is a driver registered likely to match this device */
362static int check_matching_maple_driver(struct device_driver *driver, 311static int maple_check_matching_driver(struct device_driver *driver,
363 void *devptr) 312 void *devptr)
364{ 313{
365 struct maple_driver *maple_drv; 314 struct maple_driver *maple_drv;
@@ -374,10 +323,7 @@ static int check_matching_maple_driver(struct device_driver *driver,
374 323
375static void maple_detach_driver(struct maple_device *mdev) 324static void maple_detach_driver(struct maple_device *mdev)
376{ 325{
377 if (!mdev)
378 return;
379 device_unregister(&mdev->dev); 326 device_unregister(&mdev->dev);
380 mdev = NULL;
381} 327}
382 328
383/* process initial MAPLE_COMMAND_DEVINFO for each device or port */ 329/* process initial MAPLE_COMMAND_DEVINFO for each device or port */
@@ -385,9 +331,9 @@ static void maple_attach_driver(struct maple_device *mdev)
385{ 331{
386 char *p, *recvbuf; 332 char *p, *recvbuf;
387 unsigned long function; 333 unsigned long function;
388 int matched, retval; 334 int matched, error;
389 335
390 recvbuf = mdev->mq->recvbuf; 336 recvbuf = mdev->mq->recvbuf->buf;
391 /* copy the data as individual elements in 337 /* copy the data as individual elements in
392 * case of memory optimisation */ 338 * case of memory optimisation */
393 memcpy(&mdev->devinfo.function, recvbuf + 4, 4); 339 memcpy(&mdev->devinfo.function, recvbuf + 4, 4);
@@ -395,7 +341,6 @@ static void maple_attach_driver(struct maple_device *mdev)
395 memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); 341 memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1);
396 memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); 342 memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1);
397 memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); 343 memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30);
398 memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60);
399 memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); 344 memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2);
400 memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); 345 memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2);
401 memcpy(mdev->product_name, mdev->devinfo.product_name, 30); 346 memcpy(mdev->product_name, mdev->devinfo.product_name, 30);
@@ -414,43 +359,39 @@ static void maple_attach_driver(struct maple_device *mdev)
414 else 359 else
415 break; 360 break;
416 361
417 printk(KERN_INFO "Maple device detected: %s\n",
418 mdev->product_name);
419 printk(KERN_INFO "Maple device: %s\n", mdev->product_licence);
420
421 function = be32_to_cpu(mdev->devinfo.function); 362 function = be32_to_cpu(mdev->devinfo.function);
422 363
364 dev_info(&mdev->dev, "detected %s: function 0x%lX: at (%d, %d)\n",
365 mdev->product_name, function, mdev->port, mdev->unit);
366
423 if (function > 0x200) { 367 if (function > 0x200) {
424 /* Do this silently - as not a real device */ 368 /* Do this silently - as not a real device */
425 function = 0; 369 function = 0;
426 mdev->driver = &maple_dummy_driver; 370 mdev->driver = &maple_unsupported_device;
427 dev_set_name(&mdev->dev, "%d:0.port", mdev->port); 371 dev_set_name(&mdev->dev, "%d:0.port", mdev->port);
428 } else { 372 } else {
429 printk(KERN_INFO
430 "Maple bus at (%d, %d): Function 0x%lX\n",
431 mdev->port, mdev->unit, function);
432
433 matched = 373 matched =
434 bus_for_each_drv(&maple_bus_type, NULL, mdev, 374 bus_for_each_drv(&maple_bus_type, NULL, mdev,
435 check_matching_maple_driver); 375 maple_check_matching_driver);
436 376
437 if (matched == 0) { 377 if (matched == 0) {
438 /* Driver does not exist yet */ 378 /* Driver does not exist yet */
439 printk(KERN_INFO 379 dev_info(&mdev->dev, "no driver found\n");
440 "No maple driver found.\n"); 380 mdev->driver = &maple_unsupported_device;
441 mdev->driver = &maple_dummy_driver;
442 } 381 }
443 dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port, 382 dev_set_name(&mdev->dev, "%d:0%d.%lX", mdev->port,
444 mdev->unit, function); 383 mdev->unit, function);
445 } 384 }
385
446 mdev->function = function; 386 mdev->function = function;
447 mdev->dev.release = &maple_release_device; 387 mdev->dev.release = &maple_release_device;
448 retval = device_register(&mdev->dev); 388
449 if (retval) { 389 atomic_set(&mdev->busy, 0);
450 printk(KERN_INFO 390 error = device_register(&mdev->dev);
451 "Maple bus: Attempt to register device" 391 if (error) {
452 " (%x, %x) failed.\n", 392 dev_warn(&mdev->dev, "could not register device at"
453 mdev->port, mdev->unit); 393 " (%d, %d), with error 0x%X\n", mdev->unit,
394 mdev->port, error);
454 maple_free_dev(mdev); 395 maple_free_dev(mdev);
455 mdev = NULL; 396 mdev = NULL;
456 return; 397 return;
@@ -462,7 +403,7 @@ static void maple_attach_driver(struct maple_device *mdev)
462 * port and unit then return 1 - allows identification 403 * port and unit then return 1 - allows identification
463 * of which devices need to be attached or detached 404 * of which devices need to be attached or detached
464 */ 405 */
465static int detach_maple_device(struct device *device, void *portptr) 406static int check_maple_device(struct device *device, void *portptr)
466{ 407{
467 struct maple_device_specify *ds; 408 struct maple_device_specify *ds;
468 struct maple_device *mdev; 409 struct maple_device *mdev;
@@ -477,21 +418,25 @@ static int detach_maple_device(struct device *device, void *portptr)
477static int setup_maple_commands(struct device *device, void *ignored) 418static int setup_maple_commands(struct device *device, void *ignored)
478{ 419{
479 int add; 420 int add;
480 struct maple_device *maple_dev = to_maple_dev(device); 421 struct maple_device *mdev = to_maple_dev(device);
481 422 if (mdev->interval > 0 && atomic_read(&mdev->busy) == 0 &&
482 if ((maple_dev->interval > 0) 423 time_after(jiffies, mdev->when)) {
483 && time_after(jiffies, maple_dev->when)) { 424 /* bounce if we cannot add */
484 /* bounce if we cannot lock */ 425 add = maple_add_packet(mdev,
485 add = maple_add_packet(maple_dev, 426 be32_to_cpu(mdev->devinfo.function),
486 be32_to_cpu(maple_dev->devinfo.function),
487 MAPLE_COMMAND_GETCOND, 1, NULL); 427 MAPLE_COMMAND_GETCOND, 1, NULL);
488 if (!add) 428 if (!add)
489 maple_dev->when = jiffies + maple_dev->interval; 429 mdev->when = jiffies + mdev->interval;
490 } else { 430 } else {
491 if (time_after(jiffies, maple_pnp_time)) 431 if (time_after(jiffies, maple_pnp_time))
492 /* This will also bounce */ 432 /* Ensure we don't have block reads and devinfo
493 maple_add_packet(maple_dev, 0, 433 * calls interfering with one another - so flag the
494 MAPLE_COMMAND_DEVINFO, 0, NULL); 434 * device as busy */
435 if (atomic_read(&mdev->busy) == 0) {
436 atomic_set(&mdev->busy, 1);
437 maple_add_packet(mdev, 0,
438 MAPLE_COMMAND_DEVINFO, 0, NULL);
439 }
495 } 440 }
496 return 0; 441 return 0;
497} 442}
@@ -499,29 +444,50 @@ static int setup_maple_commands(struct device *device, void *ignored)
499/* VBLANK bottom half - implemented via workqueue */ 444/* VBLANK bottom half - implemented via workqueue */
500static void maple_vblank_handler(struct work_struct *work) 445static void maple_vblank_handler(struct work_struct *work)
501{ 446{
502 if (!list_empty(&maple_sentq) || !maple_dma_done()) 447 int x, locking;
448 struct maple_device *mdev;
449
450 if (!maple_dma_done())
503 return; 451 return;
504 452
505 ctrl_outl(0, MAPLE_ENABLE); 453 ctrl_outl(0, MAPLE_ENABLE);
506 454
455 if (!list_empty(&maple_sentq))
456 goto finish;
457
458 /*
459 * Set up essential commands - to fetch data and
460 * check devices are still present
461 */
507 bus_for_each_dev(&maple_bus_type, NULL, NULL, 462 bus_for_each_dev(&maple_bus_type, NULL, NULL,
508 setup_maple_commands); 463 setup_maple_commands);
464
465 if (time_after(jiffies, maple_pnp_time)) {
466 /*
467 * Scan the empty ports - bus is flakey and may have
468 * mis-reported emptyness
469 */
470 for (x = 0; x < MAPLE_PORTS; x++) {
471 if (checked[x] && empty[x]) {
472 mdev = baseunits[x];
473 if (!mdev)
474 break;
475 atomic_set(&mdev->busy, 1);
476 locking = maple_add_packet(mdev, 0,
477 MAPLE_COMMAND_DEVINFO, 0, NULL);
478 if (!locking)
479 break;
480 }
481 }
509 482
510 if (time_after(jiffies, maple_pnp_time))
511 maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; 483 maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
512
513 mutex_lock(&maple_wlist_lock);
514 if (!list_empty(&maple_waitq) && list_empty(&maple_sentq)) {
515 mutex_unlock(&maple_wlist_lock);
516 maple_send();
517 } else {
518 mutex_unlock(&maple_wlist_lock);
519 } 484 }
520 485
521 maplebus_dma_reset(); 486finish:
487 maple_send();
522} 488}
523 489
524/* handle devices added via hotplugs - placing them on queue for DEVINFO*/ 490/* handle devices added via hotplugs - placing them on queue for DEVINFO */
525static void maple_map_subunits(struct maple_device *mdev, int submask) 491static void maple_map_subunits(struct maple_device *mdev, int submask)
526{ 492{
527 int retval, k, devcheck; 493 int retval, k, devcheck;
@@ -533,7 +499,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask)
533 ds.unit = k + 1; 499 ds.unit = k + 1;
534 retval = 500 retval =
535 bus_for_each_dev(&maple_bus_type, NULL, &ds, 501 bus_for_each_dev(&maple_bus_type, NULL, &ds,
536 detach_maple_device); 502 check_maple_device);
537 if (retval) { 503 if (retval) {
538 submask = submask >> 1; 504 submask = submask >> 1;
539 continue; 505 continue;
@@ -543,6 +509,7 @@ static void maple_map_subunits(struct maple_device *mdev, int submask)
543 mdev_add = maple_alloc_dev(mdev->port, k + 1); 509 mdev_add = maple_alloc_dev(mdev->port, k + 1);
544 if (!mdev_add) 510 if (!mdev_add)
545 return; 511 return;
512 atomic_set(&mdev_add->busy, 1);
546 maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO, 513 maple_add_packet(mdev_add, 0, MAPLE_COMMAND_DEVINFO,
547 0, NULL); 514 0, NULL);
548 /* mark that we are checking sub devices */ 515 /* mark that we are checking sub devices */
@@ -564,27 +531,45 @@ static void maple_clean_submap(struct maple_device *mdev)
564} 531}
565 532
566/* handle empty port or hotplug removal */ 533/* handle empty port or hotplug removal */
567static void maple_response_none(struct maple_device *mdev, 534static void maple_response_none(struct maple_device *mdev)
568 struct mapleq *mq) 535{
569{ 536 maple_clean_submap(mdev);
570 if (mdev->unit != 0) { 537
571 list_del(&mq->list); 538 if (likely(mdev->unit != 0)) {
572 maple_clean_submap(mdev); 539 /*
573 printk(KERN_INFO 540 * Block devices play up
574 "Maple bus device detaching at (%d, %d)\n", 541 * and give the impression they have
575 mdev->port, mdev->unit); 542 * been removed even when still in place or
543 * trip the mtd layer when they have
544 * really gone - this code traps that eventuality
545 * and ensures we aren't overloaded with useless
546 * error messages
547 */
548 if (mdev->can_unload) {
549 if (!mdev->can_unload(mdev)) {
550 atomic_set(&mdev->busy, 2);
551 wake_up(&mdev->maple_wait);
552 return;
553 }
554 }
555
556 dev_info(&mdev->dev, "detaching device at (%d, %d)\n",
557 mdev->port, mdev->unit);
576 maple_detach_driver(mdev); 558 maple_detach_driver(mdev);
577 return; 559 return;
578 } 560 } else {
579 if (!started || !fullscan) { 561 if (!started || !fullscan) {
580 if (checked[mdev->port] == false) { 562 if (checked[mdev->port] == false) {
581 checked[mdev->port] = true; 563 checked[mdev->port] = true;
582 printk(KERN_INFO "No maple devices attached" 564 empty[mdev->port] = true;
583 " to port %d\n", mdev->port); 565 dev_info(&mdev->dev, "no devices"
566 " to port %d\n", mdev->port);
567 }
568 return;
584 } 569 }
585 return;
586 } 570 }
587 maple_clean_submap(mdev); 571 /* Some hardware devices generate false detach messages on unit 0 */
572 atomic_set(&mdev->busy, 0);
588} 573}
589 574
590/* preprocess hotplugs or scans */ 575/* preprocess hotplugs or scans */
@@ -599,8 +584,11 @@ static void maple_response_devinfo(struct maple_device *mdev,
599 } else { 584 } else {
600 if (mdev->unit != 0) 585 if (mdev->unit != 0)
601 maple_attach_driver(mdev); 586 maple_attach_driver(mdev);
587 if (mdev->unit == 0) {
588 empty[mdev->port] = false;
589 maple_attach_driver(mdev);
590 }
602 } 591 }
603 return;
604 } 592 }
605 if (mdev->unit == 0) { 593 if (mdev->unit == 0) {
606 submask = recvbuf[2] & 0x1F; 594 submask = recvbuf[2] & 0x1F;
@@ -611,6 +599,17 @@ static void maple_response_devinfo(struct maple_device *mdev,
611 } 599 }
612} 600}
613 601
602static void maple_response_fileerr(struct maple_device *mdev, void *recvbuf)
603{
604 if (mdev->fileerr_handler) {
605 mdev->fileerr_handler(mdev, recvbuf);
606 return;
607 } else
608 dev_warn(&mdev->dev, "device at (%d, %d) reports"
609 "file error 0x%X\n", mdev->port, mdev->unit,
610 ((int *)recvbuf)[1]);
611}
612
614static void maple_port_rescan(void) 613static void maple_port_rescan(void)
615{ 614{
616 int i; 615 int i;
@@ -621,12 +620,6 @@ static void maple_port_rescan(void)
621 if (checked[i] == false) { 620 if (checked[i] == false) {
622 fullscan = 0; 621 fullscan = 0;
623 mdev = baseunits[i]; 622 mdev = baseunits[i];
624 /*
625 * test lock in case scan has failed
626 * but device is still locked
627 */
628 if (mutex_is_locked(&mdev->mq->mutex))
629 mutex_unlock(&mdev->mq->mutex);
630 maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO, 623 maple_add_packet(mdev, 0, MAPLE_COMMAND_DEVINFO,
631 0, NULL); 624 0, NULL);
632 } 625 }
@@ -637,7 +630,7 @@ static void maple_port_rescan(void)
637static void maple_dma_handler(struct work_struct *work) 630static void maple_dma_handler(struct work_struct *work)
638{ 631{
639 struct mapleq *mq, *nmq; 632 struct mapleq *mq, *nmq;
640 struct maple_device *dev; 633 struct maple_device *mdev;
641 char *recvbuf; 634 char *recvbuf;
642 enum maple_code code; 635 enum maple_code code;
643 636
@@ -646,43 +639,56 @@ static void maple_dma_handler(struct work_struct *work)
646 ctrl_outl(0, MAPLE_ENABLE); 639 ctrl_outl(0, MAPLE_ENABLE);
647 if (!list_empty(&maple_sentq)) { 640 if (!list_empty(&maple_sentq)) {
648 list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { 641 list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
649 recvbuf = mq->recvbuf; 642 mdev = mq->dev;
643 recvbuf = mq->recvbuf->buf;
644 dma_cache_sync(&mdev->dev, recvbuf, 0x400,
645 DMA_FROM_DEVICE);
650 code = recvbuf[0]; 646 code = recvbuf[0];
651 dev = mq->dev;
652 kfree(mq->sendbuf); 647 kfree(mq->sendbuf);
653 mutex_unlock(&mq->mutex);
654 list_del_init(&mq->list); 648 list_del_init(&mq->list);
655
656 switch (code) { 649 switch (code) {
657 case MAPLE_RESPONSE_NONE: 650 case MAPLE_RESPONSE_NONE:
658 maple_response_none(dev, mq); 651 maple_response_none(mdev);
659 break; 652 break;
660 653
661 case MAPLE_RESPONSE_DEVINFO: 654 case MAPLE_RESPONSE_DEVINFO:
662 maple_response_devinfo(dev, recvbuf); 655 maple_response_devinfo(mdev, recvbuf);
656 atomic_set(&mdev->busy, 0);
663 break; 657 break;
664 658
665 case MAPLE_RESPONSE_DATATRF: 659 case MAPLE_RESPONSE_DATATRF:
666 if (dev->callback) 660 if (mdev->callback)
667 dev->callback(mq); 661 mdev->callback(mq);
662 atomic_set(&mdev->busy, 0);
663 wake_up(&mdev->maple_wait);
668 break; 664 break;
669 665
670 case MAPLE_RESPONSE_FILEERR: 666 case MAPLE_RESPONSE_FILEERR:
667 maple_response_fileerr(mdev, recvbuf);
668 atomic_set(&mdev->busy, 0);
669 wake_up(&mdev->maple_wait);
670 break;
671
671 case MAPLE_RESPONSE_AGAIN: 672 case MAPLE_RESPONSE_AGAIN:
672 case MAPLE_RESPONSE_BADCMD: 673 case MAPLE_RESPONSE_BADCMD:
673 case MAPLE_RESPONSE_BADFUNC: 674 case MAPLE_RESPONSE_BADFUNC:
674 printk(KERN_DEBUG 675 dev_warn(&mdev->dev, "non-fatal error"
675 "Maple non-fatal error 0x%X\n", 676 " 0x%X at (%d, %d)\n", code,
676 code); 677 mdev->port, mdev->unit);
678 atomic_set(&mdev->busy, 0);
677 break; 679 break;
678 680
679 case MAPLE_RESPONSE_ALLINFO: 681 case MAPLE_RESPONSE_ALLINFO:
680 printk(KERN_DEBUG 682 dev_notice(&mdev->dev, "extended"
681 "Maple - extended device information" 683 " device information request for (%d, %d)"
682 " not supported\n"); 684 " but call is not supported\n", mdev->port,
685 mdev->unit);
686 atomic_set(&mdev->busy, 0);
683 break; 687 break;
684 688
685 case MAPLE_RESPONSE_OK: 689 case MAPLE_RESPONSE_OK:
690 atomic_set(&mdev->busy, 0);
691 wake_up(&mdev->maple_wait);
686 break; 692 break;
687 693
688 default: 694 default:
@@ -699,20 +705,19 @@ static void maple_dma_handler(struct work_struct *work)
699 if (!fullscan) 705 if (!fullscan)
700 maple_port_rescan(); 706 maple_port_rescan();
701 /* mark that we have been through the first scan */ 707 /* mark that we have been through the first scan */
702 if (started == 0) 708 started = 1;
703 started = 1;
704 } 709 }
705 maplebus_dma_reset(); 710 maple_send();
706} 711}
707 712
708static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) 713static irqreturn_t maple_dma_interrupt(int irq, void *dev_id)
709{ 714{
710 /* Load everything into the bottom half */ 715 /* Load everything into the bottom half */
711 schedule_work(&maple_dma_process); 716 schedule_work(&maple_dma_process);
712 return IRQ_HANDLED; 717 return IRQ_HANDLED;
713} 718}
714 719
715static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) 720static irqreturn_t maple_vblank_interrupt(int irq, void *dev_id)
716{ 721{
717 schedule_work(&maple_vblank_process); 722 schedule_work(&maple_vblank_process);
718 return IRQ_HANDLED; 723 return IRQ_HANDLED;
@@ -720,14 +725,14 @@ static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
720 725
721static int maple_set_dma_interrupt_handler(void) 726static int maple_set_dma_interrupt_handler(void)
722{ 727{
723 return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt, 728 return request_irq(HW_EVENT_MAPLE_DMA, maple_dma_interrupt,
724 IRQF_SHARED, "maple bus DMA", &maple_dummy_driver); 729 IRQF_SHARED, "maple bus DMA", &maple_unsupported_device);
725} 730}
726 731
727static int maple_set_vblank_interrupt_handler(void) 732static int maple_set_vblank_interrupt_handler(void)
728{ 733{
729 return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt, 734 return request_irq(HW_EVENT_VSYNC, maple_vblank_interrupt,
730 IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver); 735 IRQF_SHARED, "maple bus VBLANK", &maple_unsupported_device);
731} 736}
732 737
733static int maple_get_dma_buffer(void) 738static int maple_get_dma_buffer(void)
@@ -740,7 +745,7 @@ static int maple_get_dma_buffer(void)
740 return 0; 745 return 0;
741} 746}
742 747
743static int match_maple_bus_driver(struct device *devptr, 748static int maple_match_bus_driver(struct device *devptr,
744 struct device_driver *drvptr) 749 struct device_driver *drvptr)
745{ 750{
746 struct maple_driver *maple_drv = to_maple_driver(drvptr); 751 struct maple_driver *maple_drv = to_maple_driver(drvptr);
@@ -765,16 +770,18 @@ static void maple_bus_release(struct device *dev)
765{ 770{
766} 771}
767 772
768static struct maple_driver maple_dummy_driver = { 773static struct maple_driver maple_unsupported_device = {
769 .drv = { 774 .drv = {
770 .name = "maple_dummy_driver", 775 .name = "maple_unsupported_device",
771 .bus = &maple_bus_type, 776 .bus = &maple_bus_type,
772 }, 777 },
773}; 778};
774 779/**
780 * maple_bus_type - core maple bus structure
781 */
775struct bus_type maple_bus_type = { 782struct bus_type maple_bus_type = {
776 .name = "maple", 783 .name = "maple",
777 .match = match_maple_bus_driver, 784 .match = maple_match_bus_driver,
778 .uevent = maple_bus_uevent, 785 .uevent = maple_bus_uevent,
779}; 786};
780EXPORT_SYMBOL_GPL(maple_bus_type); 787EXPORT_SYMBOL_GPL(maple_bus_type);
@@ -788,7 +795,8 @@ static int __init maple_bus_init(void)
788{ 795{
789 int retval, i; 796 int retval, i;
790 struct maple_device *mdev[MAPLE_PORTS]; 797 struct maple_device *mdev[MAPLE_PORTS];
791 ctrl_outl(0, MAPLE_STATE); 798
799 ctrl_outl(0, MAPLE_ENABLE);
792 800
793 retval = device_register(&maple_bus); 801 retval = device_register(&maple_bus);
794 if (retval) 802 if (retval)
@@ -798,36 +806,33 @@ static int __init maple_bus_init(void)
798 if (retval) 806 if (retval)
799 goto cleanup_device; 807 goto cleanup_device;
800 808
801 retval = driver_register(&maple_dummy_driver.drv); 809 retval = driver_register(&maple_unsupported_device.drv);
802 if (retval) 810 if (retval)
803 goto cleanup_bus; 811 goto cleanup_bus;
804 812
805 /* allocate memory for maple bus dma */ 813 /* allocate memory for maple bus dma */
806 retval = maple_get_dma_buffer(); 814 retval = maple_get_dma_buffer();
807 if (retval) { 815 if (retval) {
808 printk(KERN_INFO 816 dev_err(&maple_bus, "failed to allocate DMA buffers\n");
809 "Maple bus: Failed to allocate Maple DMA buffers\n");
810 goto cleanup_basic; 817 goto cleanup_basic;
811 } 818 }
812 819
813 /* set up DMA interrupt handler */ 820 /* set up DMA interrupt handler */
814 retval = maple_set_dma_interrupt_handler(); 821 retval = maple_set_dma_interrupt_handler();
815 if (retval) { 822 if (retval) {
816 printk(KERN_INFO 823 dev_err(&maple_bus, "bus failed to grab maple "
817 "Maple bus: Failed to grab maple DMA IRQ\n"); 824 "DMA IRQ\n");
818 goto cleanup_dma; 825 goto cleanup_dma;
819 } 826 }
820 827
821 /* set up VBLANK interrupt handler */ 828 /* set up VBLANK interrupt handler */
822 retval = maple_set_vblank_interrupt_handler(); 829 retval = maple_set_vblank_interrupt_handler();
823 if (retval) { 830 if (retval) {
824 printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); 831 dev_err(&maple_bus, "bus failed to grab VBLANK IRQ\n");
825 goto cleanup_irq; 832 goto cleanup_irq;
826 } 833 }
827 834
828 maple_queue_cache = 835 maple_queue_cache = KMEM_CACHE(maple_buffer, SLAB_HWCACHE_ALIGN);
829 kmem_cache_create("maple_queue_cache", 0x400, 0,
830 SLAB_HWCACHE_ALIGN, NULL);
831 836
832 if (!maple_queue_cache) 837 if (!maple_queue_cache)
833 goto cleanup_bothirqs; 838 goto cleanup_bothirqs;
@@ -838,23 +843,23 @@ static int __init maple_bus_init(void)
838 /* setup maple ports */ 843 /* setup maple ports */
839 for (i = 0; i < MAPLE_PORTS; i++) { 844 for (i = 0; i < MAPLE_PORTS; i++) {
840 checked[i] = false; 845 checked[i] = false;
846 empty[i] = false;
841 mdev[i] = maple_alloc_dev(i, 0); 847 mdev[i] = maple_alloc_dev(i, 0);
842 baseunits[i] = mdev[i];
843 if (!mdev[i]) { 848 if (!mdev[i]) {
844 while (i-- > 0) 849 while (i-- > 0)
845 maple_free_dev(mdev[i]); 850 maple_free_dev(mdev[i]);
846 goto cleanup_cache; 851 goto cleanup_cache;
847 } 852 }
853 baseunits[i] = mdev[i];
854 atomic_set(&mdev[i]->busy, 1);
848 maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL); 855 maple_add_packet(mdev[i], 0, MAPLE_COMMAND_DEVINFO, 0, NULL);
849 subdevice_map[i] = 0; 856 subdevice_map[i] = 0;
850 } 857 }
851 858
852 /* setup maplebus hardware */ 859 maple_pnp_time = jiffies + HZ;
853 maplebus_dma_reset(); 860 /* prepare initial queue */
854 /* initial detection */
855 maple_send(); 861 maple_send();
856 maple_pnp_time = jiffies; 862 dev_info(&maple_bus, "bus core now registered\n");
857 printk(KERN_INFO "Maple bus core now registered.\n");
858 863
859 return 0; 864 return 0;
860 865
@@ -871,7 +876,7 @@ cleanup_dma:
871 free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); 876 free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
872 877
873cleanup_basic: 878cleanup_basic:
874 driver_unregister(&maple_dummy_driver.drv); 879 driver_unregister(&maple_unsupported_device.drv);
875 880
876cleanup_bus: 881cleanup_bus:
877 bus_unregister(&maple_bus_type); 882 bus_unregister(&maple_bus_type);
@@ -880,7 +885,7 @@ cleanup_device:
880 device_unregister(&maple_bus); 885 device_unregister(&maple_bus);
881 886
882cleanup: 887cleanup:
883 printk(KERN_INFO "Maple bus registration failed\n"); 888 printk(KERN_ERR "Maple bus registration failed\n");
884 return retval; 889 return retval;
885} 890}
886/* Push init to later to ensure hardware gets detected */ 891/* Push init to later to ensure hardware gets detected */