blob: 32126958ac66bf56b42c59b1922d88dead22395b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Device driver for the via-cuda on Apple Powermacs.
3 *
4 * The VIA (versatile interface adapter) interfaces to the CUDA,
5 * a 6805 microprocessor core which controls the ADB (Apple Desktop
6 * Bus) which connects to the keyboard and mouse. The CUDA also
7 * controls system power and the RTC (real time clock) chip.
8 *
9 * Copyright (C) 1996 Paul Mackerras.
10 */
11#include <stdarg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/types.h>
13#include <linux/errno.h>
14#include <linux/kernel.h>
15#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/adb.h>
17#include <linux/cuda.h>
18#include <linux/spinlock.h>
19#include <linux/interrupt.h>
20#ifdef CONFIG_PPC
21#include <asm/prom.h>
22#include <asm/machdep.h>
23#else
24#include <asm/macintosh.h>
25#include <asm/macints.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/mac_via.h>
27#endif
28#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/init.h>
30
31static volatile unsigned char __iomem *via;
32static DEFINE_SPINLOCK(cuda_lock);
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034/* VIA registers - spaced 0x200 bytes apart */
35#define RS 0x200 /* skip between registers */
36#define B 0 /* B-side data */
37#define A RS /* A-side data */
38#define DIRB (2*RS) /* B-side direction (1=output) */
39#define DIRA (3*RS) /* A-side direction (1=output) */
40#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
41#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
42#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
43#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
44#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
45#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
46#define SR (10*RS) /* Shift register */
47#define ACR (11*RS) /* Auxiliary control register */
48#define PCR (12*RS) /* Peripheral control register */
49#define IFR (13*RS) /* Interrupt flag register */
50#define IER (14*RS) /* Interrupt enable register */
51#define ANH (15*RS) /* A-side data, no handshake */
52
53/* Bits in B data register: all active low */
54#define TREQ 0x08 /* Transfer request (input) */
55#define TACK 0x10 /* Transfer acknowledge (output) */
56#define TIP 0x20 /* Transfer in progress (output) */
57
58/* Bits in ACR */
59#define SR_CTRL 0x1c /* Shift register control bits */
60#define SR_EXT 0x0c /* Shift on external clock */
61#define SR_OUT 0x10 /* Shift out if 1 */
62
63/* Bits in IFR and IER */
64#define IER_SET 0x80 /* set bits in IER */
65#define IER_CLR 0 /* clear bits in IER */
66#define SR_INT 0x04 /* Shift register full/empty */
67
Finn Thainfd7a65a2016-12-31 19:56:26 -050068static inline bool TREQ_asserted(u8 portb)
69{
70 return !(portb & TREQ);
71}
72
73static inline void assert_TIP(void)
74{
75 out_8(&via[B], in_8(&via[B]) & ~TIP);
76}
77
78static inline void assert_TACK(void)
79{
80 out_8(&via[B], in_8(&via[B]) & ~TACK);
81}
82
83static inline void toggle_TACK(void)
84{
85 out_8(&via[B], in_8(&via[B]) ^ TACK);
86}
87
88static inline void negate_TACK(void)
89{
90 out_8(&via[B], in_8(&via[B]) | TACK);
91}
92
93static inline void negate_TIP_and_TACK(void)
94{
95 out_8(&via[B], in_8(&via[B]) | TIP | TACK);
96}
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static enum cuda_state {
99 idle,
100 sent_first_byte,
101 sending,
102 reading,
103 read_done,
104 awaiting_reply
105} cuda_state;
106
107static struct adb_request *current_req;
108static struct adb_request *last_req;
109static unsigned char cuda_rbuf[16];
110static unsigned char *reply_ptr;
111static int reading_reply;
112static int data_index;
Finn Thain0251c382007-05-01 22:33:00 +0200113static int cuda_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#ifdef CONFIG_PPC
115static struct device_node *vias;
116#endif
Olaf Hering87275852007-02-10 21:35:12 +0100117static int cuda_fully_inited;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119#ifdef CONFIG_ADB
120static int cuda_probe(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121static int cuda_send_request(struct adb_request *req, int sync);
122static int cuda_adb_autopoll(int devs);
123static int cuda_reset_adb_bus(void);
124#endif /* CONFIG_ADB */
125
126static int cuda_init_via(void);
127static void cuda_start(void);
David Howells7d12e782006-10-05 14:55:46 +0100128static irqreturn_t cuda_interrupt(int irq, void *arg);
129static void cuda_input(unsigned char *buf, int nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130void cuda_poll(void);
131static int cuda_write(struct adb_request *req);
132
133int cuda_request(struct adb_request *req,
134 void (*done)(struct adb_request *), int nbytes, ...);
135
136#ifdef CONFIG_ADB
137struct adb_driver via_cuda_driver = {
Finn Thain18814ee2009-11-17 20:03:05 +1100138 .name = "CUDA",
139 .probe = cuda_probe,
140 .send_request = cuda_send_request,
141 .autopoll = cuda_adb_autopoll,
142 .poll = cuda_poll,
143 .reset_bus = cuda_reset_adb_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145#endif /* CONFIG_ADB */
146
Finn Thain18814ee2009-11-17 20:03:05 +1100147#ifdef CONFIG_MAC
148int __init find_via_cuda(void)
149{
150 struct adb_request req;
151 int err;
152
153 if (macintosh_config->adb_type != MAC_ADB_CUDA)
154 return 0;
155
156 via = via1;
157 cuda_state = idle;
158
159 err = cuda_init_via();
160 if (err) {
161 printk(KERN_ERR "cuda_init_via() failed\n");
162 via = NULL;
163 return 0;
164 }
165
166 /* enable autopoll */
167 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
168 while (!req.complete)
169 cuda_poll();
170
171 return 1;
172}
173#else
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100174int __init find_via_cuda(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 struct adb_request req;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100177 phys_addr_t taddr;
Jeremy Kerr018a3d12006-07-12 15:40:29 +1000178 const u32 *reg;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100179 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 if (vias != 0)
182 return 1;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100183 vias = of_find_node_by_name(NULL, "via-cuda");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 if (vias == 0)
185 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Stephen Rothwell01b27262007-04-27 13:41:15 +1000187 reg = of_get_property(vias, "reg", NULL);
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100188 if (reg == NULL) {
189 printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
190 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 }
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100192 taddr = of_translate_address(vias, reg);
193 if (taddr == 0) {
194 printk(KERN_ERR "via-cuda: Can't translate address !\n");
195 goto fail;
196 }
197 via = ioremap(taddr, 0x2000);
198 if (via == NULL) {
199 printk(KERN_ERR "via-cuda: Can't map address !\n");
200 goto fail;
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 cuda_state = idle;
204 sys_ctrler = SYS_CTRLER_CUDA;
205
206 err = cuda_init_via();
207 if (err) {
208 printk(KERN_ERR "cuda_init_via() failed\n");
209 via = NULL;
210 return 0;
211 }
212
213 /* Clear and enable interrupts, but only on PPC. On 68K it's done */
214 /* for us by the main VIA driver in arch/m68k/mac/via.c */
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */
217 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 /* enable autopoll */
220 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
221 while (!req.complete)
222 cuda_poll();
223
224 return 1;
Benjamin Herrenschmidt51d30822005-11-23 17:57:25 +1100225
226 fail:
227 of_node_put(vias);
228 vias = NULL;
229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230}
Finn Thain18814ee2009-11-17 20:03:05 +1100231#endif /* !defined CONFIG_MAC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233static int __init via_cuda_start(void)
234{
235 if (via == NULL)
236 return -ENODEV;
237
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000238#ifdef CONFIG_MAC
Finn Thain0251c382007-05-01 22:33:00 +0200239 cuda_irq = IRQ_MAC_ADB;
Finn Thain18814ee2009-11-17 20:03:05 +1100240#else
Finn Thain0251c382007-05-01 22:33:00 +0200241 cuda_irq = irq_of_parse_and_map(vias, 0);
Michael Ellermanef24ba72016-09-06 21:53:24 +1000242 if (!cuda_irq) {
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000243 printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
244 vias->full_name);
245 return -ENODEV;
246 }
Finn Thain18814ee2009-11-17 20:03:05 +1100247#endif
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000248
Finn Thain0251c382007-05-01 22:33:00 +0200249 if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
250 printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 return -EAGAIN;
252 }
253
Finn Thain523717d2016-12-31 19:56:26 -0500254 pr_info("Macintosh CUDA driver v0.5 for Unified ADB.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 cuda_fully_inited = 1;
257 return 0;
258}
259
260device_initcall(via_cuda_start);
261
262#ifdef CONFIG_ADB
263static int
264cuda_probe(void)
265{
266#ifdef CONFIG_PPC
267 if (sys_ctrler != SYS_CTRLER_CUDA)
268 return -ENODEV;
269#else
270 if (macintosh_config->adb_type != MAC_ADB_CUDA)
271 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if (via == NULL)
274 return -ENODEV;
275 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277#endif /* CONFIG_ADB */
278
279#define WAIT_FOR(cond, what) \
280 do { \
281 int x; \
282 for (x = 1000; !(cond); --x) { \
283 if (x == 0) { \
Finn Thain523717d2016-12-31 19:56:26 -0500284 pr_err("Timeout waiting for " what "\n"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return -ENXIO; \
286 } \
287 udelay(100); \
288 } \
289 } while (0)
290
291static int
Geert Uytterhoeven330dae12013-06-30 12:03:23 +0200292__init cuda_init_via(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500295 negate_TIP_and_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
297 (void)in_8(&via[SR]); /* clear any left-over data */
Finn Thain0251c382007-05-01 22:33:00 +0200298#ifdef CONFIG_PPC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
300 (void)in_8(&via[IER]);
Finn Thain0251c382007-05-01 22:33:00 +0200301#else
302 out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303#endif
304
305 /* delay 4ms and then clear any pending interrupt */
306 mdelay(4);
307 (void)in_8(&via[SR]);
Finn Thain0251c382007-05-01 22:33:00 +0200308 out_8(&via[IFR], SR_INT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310 /* sync with the CUDA - assert TACK without TIP */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500311 assert_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 /* wait for the CUDA to assert TREQ in response */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500314 WAIT_FOR(TREQ_asserted(in_8(&via[B])), "CUDA response to sync");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 /* wait for the interrupt and then clear it */
317 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
318 (void)in_8(&via[SR]);
Finn Thain0251c382007-05-01 22:33:00 +0200319 out_8(&via[IFR], SR_INT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 /* finish the sync by negating TACK */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500322 negate_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 /* wait for the CUDA to negate TREQ and the corresponding interrupt */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500325 WAIT_FOR(!TREQ_asserted(in_8(&via[B])), "CUDA response to sync (3)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
327 (void)in_8(&via[SR]);
Finn Thain0251c382007-05-01 22:33:00 +0200328 out_8(&via[IFR], SR_INT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 return 0;
331}
332
333#ifdef CONFIG_ADB
334/* Send an ADB command */
335static int
336cuda_send_request(struct adb_request *req, int sync)
337{
338 int i;
339
340 if ((via == NULL) || !cuda_fully_inited) {
341 req->complete = 1;
342 return -ENXIO;
343 }
344
345 req->reply_expected = 1;
346
347 i = cuda_write(req);
348 if (i)
349 return i;
350
351 if (sync) {
352 while (!req->complete)
353 cuda_poll();
354 }
355 return 0;
356}
357
358
359/* Enable/disable autopolling */
360static int
361cuda_adb_autopoll(int devs)
362{
363 struct adb_request req;
364
365 if ((via == NULL) || !cuda_fully_inited)
366 return -ENXIO;
367
368 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0));
369 while (!req.complete)
370 cuda_poll();
371 return 0;
372}
373
374/* Reset adb bus - how do we do this?? */
375static int
376cuda_reset_adb_bus(void)
377{
378 struct adb_request req;
379
380 if ((via == NULL) || !cuda_fully_inited)
381 return -ENXIO;
382
383 cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */
384 while (!req.complete)
385 cuda_poll();
386 return 0;
387}
388#endif /* CONFIG_ADB */
Finn Thain523717d2016-12-31 19:56:26 -0500389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390/* Construct and send a cuda request */
391int
392cuda_request(struct adb_request *req, void (*done)(struct adb_request *),
393 int nbytes, ...)
394{
395 va_list list;
396 int i;
397
398 if (via == NULL) {
399 req->complete = 1;
400 return -ENXIO;
401 }
402
403 req->nbytes = nbytes;
404 req->done = done;
405 va_start(list, nbytes);
406 for (i = 0; i < nbytes; ++i)
407 req->data[i] = va_arg(list, int);
408 va_end(list);
409 req->reply_expected = 1;
410 return cuda_write(req);
411}
Anton Blanchard4a1b08e2014-08-20 08:00:01 +1000412EXPORT_SYMBOL(cuda_request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414static int
415cuda_write(struct adb_request *req)
416{
417 unsigned long flags;
418
419 if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
420 req->complete = 1;
421 return -EINVAL;
422 }
423 req->next = NULL;
424 req->sent = 0;
425 req->complete = 0;
426 req->reply_len = 0;
427
428 spin_lock_irqsave(&cuda_lock, flags);
429 if (current_req != 0) {
430 last_req->next = req;
431 last_req = req;
432 } else {
433 current_req = req;
434 last_req = req;
435 if (cuda_state == idle)
436 cuda_start();
437 }
438 spin_unlock_irqrestore(&cuda_lock, flags);
439
440 return 0;
441}
442
443static void
444cuda_start(void)
445{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 /* assert cuda_state == idle */
Finn Thain06d7e992016-12-31 19:56:26 -0500447 if (current_req == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return;
Finn Thainfd7a65a2016-12-31 19:56:26 -0500449 if (TREQ_asserted(in_8(&via[B])))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return; /* a byte is coming in from the CUDA */
451
452 /* set the shift register to shift out and send a byte */
453 out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
Finn Thain06d7e992016-12-31 19:56:26 -0500454 out_8(&via[SR], current_req->data[0]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500455 assert_TIP();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 cuda_state = sent_first_byte;
457}
458
459void
460cuda_poll(void)
461{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /* cuda_interrupt only takes a normal lock, we disable
463 * interrupts here to avoid re-entering and thus deadlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 */
Finn Thain18814ee2009-11-17 20:03:05 +1100465 if (cuda_irq)
466 disable_irq(cuda_irq);
Olof Johansson49f19ce2006-10-05 20:31:10 -0500467 cuda_interrupt(0, NULL);
Finn Thain18814ee2009-11-17 20:03:05 +1100468 if (cuda_irq)
469 enable_irq(cuda_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
Anton Blanchard4a1b08e2014-08-20 08:00:01 +1000471EXPORT_SYMBOL(cuda_poll);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Finn Thainfe73b582016-12-31 19:56:26 -0500473#define ARRAY_FULL(a, p) ((p) - (a) == ARRAY_SIZE(a))
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100476cuda_interrupt(int irq, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Finn Thainfd7a65a2016-12-31 19:56:26 -0500478 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 struct adb_request *req = NULL;
480 unsigned char ibuf[16];
481 int ibuf_len = 0;
482 int complete = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 spin_lock(&cuda_lock);
485
Finn Thain18814ee2009-11-17 20:03:05 +1100486 /* On powermacs, this handler is registered for the VIA IRQ. But they use
Finn Thain0251c382007-05-01 22:33:00 +0200487 * just the shift register IRQ -- other VIA interrupt sources are disabled.
488 * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
489 * we are polling, the shift register IRQ flag has already been cleared.
490 */
491
492#ifdef CONFIG_MAC
493 if (!arg)
494#endif
495 {
496 if ((in_8(&via[IFR]) & SR_INT) == 0) {
497 spin_unlock(&cuda_lock);
498 return IRQ_NONE;
499 } else {
500 out_8(&via[IFR], SR_INT);
501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
Finn Thainfd7a65a2016-12-31 19:56:26 -0500503
504 status = in_8(&via[B]) & (TIP | TACK | TREQ);
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 switch (cuda_state) {
507 case idle:
508 /* CUDA has sent us the first byte of data - unsolicited */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 (void)in_8(&via[SR]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500510 assert_TIP();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 cuda_state = reading;
512 reply_ptr = cuda_rbuf;
513 reading_reply = 0;
514 break;
515
516 case awaiting_reply:
517 /* CUDA has sent us the first byte of data of a reply */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 (void)in_8(&via[SR]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500519 assert_TIP();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 cuda_state = reading;
521 reply_ptr = current_req->reply;
522 reading_reply = 1;
523 break;
524
525 case sent_first_byte:
Finn Thainfd7a65a2016-12-31 19:56:26 -0500526 if (TREQ_asserted(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 /* collision */
528 out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
529 (void)in_8(&via[SR]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500530 negate_TIP_and_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 cuda_state = idle;
532 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 out_8(&via[SR], current_req->data[1]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500534 toggle_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 data_index = 2;
536 cuda_state = sending;
537 }
538 break;
539
540 case sending:
541 req = current_req;
542 if (data_index >= req->nbytes) {
543 out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
544 (void)in_8(&via[SR]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500545 negate_TIP_and_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 req->sent = 1;
547 if (req->reply_expected) {
548 cuda_state = awaiting_reply;
549 } else {
550 current_req = req->next;
551 complete = 1;
552 /* not sure about this */
553 cuda_state = idle;
554 cuda_start();
555 }
556 } else {
557 out_8(&via[SR], req->data[data_index++]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500558 toggle_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560 break;
561
562 case reading:
Finn Thainfe73b582016-12-31 19:56:26 -0500563 if (reading_reply ? ARRAY_FULL(current_req->reply, reply_ptr)
564 : ARRAY_FULL(cuda_rbuf, reply_ptr))
565 (void)in_8(&via[SR]);
566 else
567 *reply_ptr++ = in_8(&via[SR]);
Finn Thainfd7a65a2016-12-31 19:56:26 -0500568 if (!TREQ_asserted(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 /* that's all folks */
Finn Thainfd7a65a2016-12-31 19:56:26 -0500570 negate_TIP_and_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 cuda_state = read_done;
572 } else {
Finn Thainfd7a65a2016-12-31 19:56:26 -0500573 toggle_TACK();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
575 break;
576
577 case read_done:
578 (void)in_8(&via[SR]);
579 if (reading_reply) {
580 req = current_req;
581 req->reply_len = reply_ptr - req->reply;
582 if (req->data[0] == ADB_PACKET) {
583 /* Have to adjust the reply from ADB commands */
584 if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
585 /* the 0x2 bit indicates no response */
586 req->reply_len = 0;
587 } else {
588 /* leave just the command and result bytes in the reply */
589 req->reply_len -= 2;
590 memmove(req->reply, req->reply + 2, req->reply_len);
591 }
592 }
593 current_req = req->next;
594 complete = 1;
Finn Thaincfbf9982016-12-31 19:56:26 -0500595 reading_reply = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 } else {
597 /* This is tricky. We must break the spinlock to call
598 * cuda_input. However, doing so means we might get
599 * re-entered from another CPU getting an interrupt
600 * or calling cuda_poll(). I ended up using the stack
601 * (it's only for 16 bytes) and moving the actual
602 * call to cuda_input to outside of the lock.
603 */
604 ibuf_len = reply_ptr - cuda_rbuf;
605 memcpy(ibuf, cuda_rbuf, ibuf_len);
606 }
Finn Thaincfbf9982016-12-31 19:56:26 -0500607 reply_ptr = cuda_rbuf;
Finn Thaina6466242016-12-31 19:56:26 -0500608 cuda_state = idle;
609 cuda_start();
610 if (cuda_state == idle && TREQ_asserted(in_8(&via[B]))) {
Finn Thainfd7a65a2016-12-31 19:56:26 -0500611 assert_TIP();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 cuda_state = reading;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614 break;
615
616 default:
Finn Thain523717d2016-12-31 19:56:26 -0500617 pr_err("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
619 spin_unlock(&cuda_lock);
620 if (complete && req) {
621 void (*done)(struct adb_request *) = req->done;
622 mb();
623 req->complete = 1;
624 /* Here, we assume that if the request has a done member, the
625 * struct request will survive to setting req->complete to 1
626 */
627 if (done)
628 (*done)(req);
629 }
630 if (ibuf_len)
David Howells7d12e782006-10-05 14:55:46 +0100631 cuda_input(ibuf, ibuf_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return IRQ_HANDLED;
633}
634
635static void
David Howells7d12e782006-10-05 14:55:46 +0100636cuda_input(unsigned char *buf, int nb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 switch (buf[0]) {
639 case ADB_PACKET:
640#ifdef CONFIG_XMON
641 if (nb == 5 && buf[2] == 0x2c) {
642 extern int xmon_wants_key, xmon_adb_keycode;
643 if (xmon_wants_key) {
644 xmon_adb_keycode = buf[3];
645 return;
646 }
647 }
648#endif /* CONFIG_XMON */
649#ifdef CONFIG_ADB
David Howells7d12e782006-10-05 14:55:46 +0100650 adb_input(buf+2, nb-2, buf[1] & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651#endif /* CONFIG_ADB */
652 break;
653
654 default:
Finn Thain523717d2016-12-31 19:56:26 -0500655 print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1,
656 buf, nb, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658}