aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/via-cuda.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macintosh/via-cuda.c')
-rw-r--r--drivers/macintosh/via-cuda.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 76d21775fc35..741a93a3eb61 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16];
82static unsigned char *reply_ptr; 82static unsigned char *reply_ptr;
83static int reading_reply; 83static int reading_reply;
84static int data_index; 84static int data_index;
85static int cuda_irq;
85#ifdef CONFIG_PPC 86#ifdef CONFIG_PPC
86static struct device_node *vias; 87static struct device_node *vias;
87#endif 88#endif
@@ -160,10 +161,8 @@ int __init find_via_cuda(void)
160 /* Clear and enable interrupts, but only on PPC. On 68K it's done */ 161 /* Clear and enable interrupts, but only on PPC. On 68K it's done */
161 /* for us by the main VIA driver in arch/m68k/mac/via.c */ 162 /* for us by the main VIA driver in arch/m68k/mac/via.c */
162 163
163#ifndef CONFIG_MAC
164 out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ 164 out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */
165 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ 165 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
166#endif
167 166
168 /* enable autopoll */ 167 /* enable autopoll */
169 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); 168 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
@@ -181,24 +180,22 @@ int __init find_via_cuda(void)
181 180
182static int __init via_cuda_start(void) 181static int __init via_cuda_start(void)
183{ 182{
184 unsigned int irq;
185
186 if (via == NULL) 183 if (via == NULL)
187 return -ENODEV; 184 return -ENODEV;
188 185
189#ifdef CONFIG_MAC 186#ifdef CONFIG_MAC
190 irq = IRQ_MAC_ADB; 187 cuda_irq = IRQ_MAC_ADB;
191#else /* CONFIG_MAC */ 188#else /* CONFIG_MAC */
192 irq = irq_of_parse_and_map(vias, 0); 189 cuda_irq = irq_of_parse_and_map(vias, 0);
193 if (irq == NO_IRQ) { 190 if (cuda_irq == NO_IRQ) {
194 printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", 191 printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
195 vias->full_name); 192 vias->full_name);
196 return -ENODEV; 193 return -ENODEV;
197 } 194 }
198#endif /* CONFIG_MAP */ 195#endif /* CONFIG_MAC */
199 196
200 if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { 197 if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
201 printk(KERN_ERR "via-cuda: can't request irq %d\n", irq); 198 printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
202 return -EAGAIN; 199 return -EAGAIN;
203 } 200 }
204 201
@@ -238,6 +235,7 @@ cuda_init(void)
238 printk(KERN_ERR "cuda_init_via() failed\n"); 235 printk(KERN_ERR "cuda_init_via() failed\n");
239 return -ENODEV; 236 return -ENODEV;
240 } 237 }
238 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
241 239
242 return via_cuda_start(); 240 return via_cuda_start();
243#endif 241#endif
@@ -263,15 +261,17 @@ cuda_init_via(void)
263 out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ 261 out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
264 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ 262 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
265 (void)in_8(&via[SR]); /* clear any left-over data */ 263 (void)in_8(&via[SR]); /* clear any left-over data */
266#ifndef CONFIG_MAC 264#ifdef CONFIG_PPC
267 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ 265 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
268 (void)in_8(&via[IER]); 266 (void)in_8(&via[IER]);
267#else
268 out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
269#endif 269#endif
270 270
271 /* delay 4ms and then clear any pending interrupt */ 271 /* delay 4ms and then clear any pending interrupt */
272 mdelay(4); 272 mdelay(4);
273 (void)in_8(&via[SR]); 273 (void)in_8(&via[SR]);
274 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 274 out_8(&via[IFR], SR_INT);
275 275
276 /* sync with the CUDA - assert TACK without TIP */ 276 /* sync with the CUDA - assert TACK without TIP */
277 out_8(&via[B], in_8(&via[B]) & ~TACK); 277 out_8(&via[B], in_8(&via[B]) & ~TACK);
@@ -282,7 +282,7 @@ cuda_init_via(void)
282 /* wait for the interrupt and then clear it */ 282 /* wait for the interrupt and then clear it */
283 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); 283 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
284 (void)in_8(&via[SR]); 284 (void)in_8(&via[SR]);
285 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 285 out_8(&via[IFR], SR_INT);
286 286
287 /* finish the sync by negating TACK */ 287 /* finish the sync by negating TACK */
288 out_8(&via[B], in_8(&via[B]) | TACK); 288 out_8(&via[B], in_8(&via[B]) | TACK);
@@ -291,7 +291,7 @@ cuda_init_via(void)
291 WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); 291 WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
292 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); 292 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
293 (void)in_8(&via[SR]); 293 (void)in_8(&via[SR]);
294 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 294 out_8(&via[IFR], SR_INT);
295 out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ 295 out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */
296 296
297 return 0; 297 return 0;
@@ -428,16 +428,12 @@ cuda_start(void)
428void 428void
429cuda_poll(void) 429cuda_poll(void)
430{ 430{
431 unsigned long flags;
432
433 /* cuda_interrupt only takes a normal lock, we disable 431 /* cuda_interrupt only takes a normal lock, we disable
434 * interrupts here to avoid re-entering and thus deadlocking. 432 * interrupts here to avoid re-entering and thus deadlocking.
435 * An option would be to disable only the IRQ source with
436 * disable_irq(), would that work on m68k ? --BenH
437 */ 433 */
438 local_irq_save(flags); 434 disable_irq(cuda_irq);
439 cuda_interrupt(0, NULL); 435 cuda_interrupt(0, NULL);
440 local_irq_restore(flags); 436 enable_irq(cuda_irq);
441} 437}
442 438
443static irqreturn_t 439static irqreturn_t
@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg)
448 unsigned char ibuf[16]; 444 unsigned char ibuf[16];
449 int ibuf_len = 0; 445 int ibuf_len = 0;
450 int complete = 0; 446 int complete = 0;
451 unsigned char virq;
452 447
453 spin_lock(&cuda_lock); 448 spin_lock(&cuda_lock);
454 449
455 virq = in_8(&via[IFR]) & 0x7f; 450 /* On powermacs, this handler is registered for the VIA IRQ. But it uses
456 out_8(&via[IFR], virq); 451 * just the shift register IRQ -- other VIA interrupt sources are disabled.
457 if ((virq & SR_INT) == 0) { 452 * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
458 spin_unlock(&cuda_lock); 453 * we are polling, the shift register IRQ flag has already been cleared.
459 return IRQ_NONE; 454 */
455
456#ifdef CONFIG_MAC
457 if (!arg)
458#endif
459 {
460 if ((in_8(&via[IFR]) & SR_INT) == 0) {
461 spin_unlock(&cuda_lock);
462 return IRQ_NONE;
463 } else {
464 out_8(&via[IFR], SR_INT);
465 }
460 } 466 }
461 467
462 status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); 468 status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);