Blame view
drivers/macintosh/via-cuda.c
19.3 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
d23eee88b via-cuda: Add sup... |
3 4 |
* Device driver for the Cuda and Egret system controllers found on PowerMacs * and 68k Macs. |
1da177e4c Linux-2.6.12-rc2 |
5 |
* |
d23eee88b via-cuda: Add sup... |
6 7 8 |
* The Cuda or Egret is a 6805 microcontroller interfaced to the 6522 VIA. * This MCU controls system power, Parameter RAM, Real Time Clock and the * Apple Desktop Bus (ADB) that connects to the keyboard and mouse. |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 |
* * Copyright (C) 1996 Paul Mackerras. */ #include <stdarg.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 |
#include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/delay.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 21 22 23 24 25 26 |
#include <linux/adb.h> #include <linux/cuda.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #ifdef CONFIG_PPC #include <asm/prom.h> #include <asm/machdep.h> #else #include <asm/macintosh.h> #include <asm/macints.h> |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 |
#include <asm/mac_via.h> #endif #include <asm/io.h> |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 |
#include <linux/init.h> static volatile unsigned char __iomem *via; static DEFINE_SPINLOCK(cuda_lock); |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* VIA registers - spaced 0x200 bytes apart */ #define RS 0x200 /* skip between registers */ #define B 0 /* B-side data */ #define A RS /* A-side data */ #define DIRB (2*RS) /* B-side direction (1=output) */ #define DIRA (3*RS) /* A-side direction (1=output) */ #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ #define SR (10*RS) /* Shift register */ #define ACR (11*RS) /* Auxiliary control register */ #define PCR (12*RS) /* Peripheral control register */ #define IFR (13*RS) /* Interrupt flag register */ #define IER (14*RS) /* Interrupt enable register */ #define ANH (15*RS) /* A-side data, no handshake */ |
d23eee88b via-cuda: Add sup... |
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
/* * When the Cuda design replaced the Egret, some signal names and * logic sense changed. They all serve the same purposes, however. * * VIA pin | Egret pin * ----------------+------------------------------------------ * PB3 (input) | Transceiver session (active low) * PB4 (output) | VIA full (active high) * PB5 (output) | System session (active high) * * VIA pin | Cuda pin * ----------------+------------------------------------------ * PB3 (input) | Transfer request (active low) * PB4 (output) | Byte acknowledge (active low) * PB5 (output) | Transfer in progress (active low) */ /* Bits in Port B data register */ #define TREQ 0x08 /* Transfer request */ #define TACK 0x10 /* Transfer acknowledge */ #define TIP 0x20 /* Transfer in progress */ |
1da177e4c Linux-2.6.12-rc2 |
73 74 75 76 77 78 79 80 81 82 |
/* Bits in ACR */ #define SR_CTRL 0x1c /* Shift register control bits */ #define SR_EXT 0x0c /* Shift on external clock */ #define SR_OUT 0x10 /* Shift out if 1 */ /* Bits in IFR and IER */ #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ |
d23eee88b via-cuda: Add sup... |
83 84 85 86 87 88 89 90 91 92 93 94 |
/* Duration of byte acknowledgement pulse (us) */ #define EGRET_TACK_ASSERTED_DELAY 300 #define EGRET_TACK_NEGATED_DELAY 400 /* Interval from interrupt to start of session (us) */ #define EGRET_SESSION_DELAY 450 #ifdef CONFIG_PPC #define mcu_is_egret false #else static bool mcu_is_egret; #endif |
fd7a65a27 via-cuda: Add TRE... |
95 96 97 98 99 100 101 |
static inline bool TREQ_asserted(u8 portb) { return !(portb & TREQ); } static inline void assert_TIP(void) { |
d23eee88b via-cuda: Add sup... |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
if (mcu_is_egret) { udelay(EGRET_SESSION_DELAY); out_8(&via[B], in_8(&via[B]) | TIP); } else out_8(&via[B], in_8(&via[B]) & ~TIP); } static inline void assert_TIP_and_TACK(void) { if (mcu_is_egret) { udelay(EGRET_SESSION_DELAY); out_8(&via[B], in_8(&via[B]) | TIP | TACK); } else out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK)); |
fd7a65a27 via-cuda: Add TRE... |
116 117 118 119 |
} static inline void assert_TACK(void) { |
d23eee88b via-cuda: Add sup... |
120 121 122 123 124 |
if (mcu_is_egret) { udelay(EGRET_TACK_NEGATED_DELAY); out_8(&via[B], in_8(&via[B]) | TACK); } else out_8(&via[B], in_8(&via[B]) & ~TACK); |
fd7a65a27 via-cuda: Add TRE... |
125 126 127 128 129 130 131 132 133 |
} static inline void toggle_TACK(void) { out_8(&via[B], in_8(&via[B]) ^ TACK); } static inline void negate_TACK(void) { |
d23eee88b via-cuda: Add sup... |
134 135 136 137 138 |
if (mcu_is_egret) { udelay(EGRET_TACK_ASSERTED_DELAY); out_8(&via[B], in_8(&via[B]) & ~TACK); } else out_8(&via[B], in_8(&via[B]) | TACK); |
fd7a65a27 via-cuda: Add TRE... |
139 140 141 142 |
} static inline void negate_TIP_and_TACK(void) { |
d23eee88b via-cuda: Add sup... |
143 144 145 146 147 |
if (mcu_is_egret) { udelay(EGRET_TACK_ASSERTED_DELAY); out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK)); } else out_8(&via[B], in_8(&via[B]) | TIP | TACK); |
fd7a65a27 via-cuda: Add TRE... |
148 |
} |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
static enum cuda_state { idle, sent_first_byte, sending, reading, read_done, awaiting_reply } cuda_state; static struct adb_request *current_req; static struct adb_request *last_req; static unsigned char cuda_rbuf[16]; static unsigned char *reply_ptr; static int reading_reply; static int data_index; |
0251c38ce CUDA ADB fixes |
164 |
static int cuda_irq; |
1da177e4c Linux-2.6.12-rc2 |
165 166 167 |
#ifdef CONFIG_PPC static struct device_node *vias; #endif |
872758563 [POWERPC] move va... |
168 |
static int cuda_fully_inited; |
1da177e4c Linux-2.6.12-rc2 |
169 170 171 |
#ifdef CONFIG_ADB static int cuda_probe(void); |
1da177e4c Linux-2.6.12-rc2 |
172 173 174 175 176 177 178 |
static int cuda_send_request(struct adb_request *req, int sync); static int cuda_adb_autopoll(int devs); static int cuda_reset_adb_bus(void); #endif /* CONFIG_ADB */ static int cuda_init_via(void); static void cuda_start(void); |
7d12e780e IRQ: Maintain reg... |
179 180 |
static irqreturn_t cuda_interrupt(int irq, void *arg); static void cuda_input(unsigned char *buf, int nb); |
1da177e4c Linux-2.6.12-rc2 |
181 182 183 184 185 186 187 188 |
void cuda_poll(void); static int cuda_write(struct adb_request *req); int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); #ifdef CONFIG_ADB struct adb_driver via_cuda_driver = { |
18814ee84 mac68k: start CUD... |
189 190 191 192 193 194 |
.name = "CUDA", .probe = cuda_probe, .send_request = cuda_send_request, .autopoll = cuda_adb_autopoll, .poll = cuda_poll, .reset_bus = cuda_reset_adb_bus, |
1da177e4c Linux-2.6.12-rc2 |
195 196 |
}; #endif /* CONFIG_ADB */ |
18814ee84 mac68k: start CUD... |
197 198 199 200 201 |
#ifdef CONFIG_MAC int __init find_via_cuda(void) { struct adb_request req; int err; |
f74faec6b m68k/mac: Replace... |
202 203 |
if (macintosh_config->adb_type != MAC_ADB_CUDA && macintosh_config->adb_type != MAC_ADB_EGRET) |
18814ee84 mac68k: start CUD... |
204 205 206 207 |
return 0; via = via1; cuda_state = idle; |
f74faec6b m68k/mac: Replace... |
208 |
mcu_is_egret = macintosh_config->adb_type == MAC_ADB_EGRET; |
18814ee84 mac68k: start CUD... |
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
err = cuda_init_via(); if (err) { printk(KERN_ERR "cuda_init_via() failed "); via = NULL; return 0; } /* enable autopoll */ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); while (!req.complete) cuda_poll(); return 1; } #else |
51d3082fe [PATCH] powerpc: ... |
226 |
int __init find_via_cuda(void) |
1da177e4c Linux-2.6.12-rc2 |
227 |
{ |
1da177e4c Linux-2.6.12-rc2 |
228 |
struct adb_request req; |
51d3082fe [PATCH] powerpc: ... |
229 |
phys_addr_t taddr; |
018a3d1db [POWERPC] powerma... |
230 |
const u32 *reg; |
51d3082fe [PATCH] powerpc: ... |
231 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
232 233 234 |
if (vias != 0) return 1; |
51d3082fe [PATCH] powerpc: ... |
235 |
vias = of_find_node_by_name(NULL, "via-cuda"); |
1da177e4c Linux-2.6.12-rc2 |
236 237 |
if (vias == 0) return 0; |
1da177e4c Linux-2.6.12-rc2 |
238 |
|
01b2726dd [POWERPC] Rename ... |
239 |
reg = of_get_property(vias, "reg", NULL); |
51d3082fe [PATCH] powerpc: ... |
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
if (reg == NULL) { printk(KERN_ERR "via-cuda: No \"reg\" property ! "); goto fail; } taddr = of_translate_address(vias, reg); if (taddr == 0) { printk(KERN_ERR "via-cuda: Can't translate address ! "); goto fail; } via = ioremap(taddr, 0x2000); if (via == NULL) { printk(KERN_ERR "via-cuda: Can't map address ! "); goto fail; |
1da177e4c Linux-2.6.12-rc2 |
256 |
} |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
cuda_state = idle; sys_ctrler = SYS_CTRLER_CUDA; err = cuda_init_via(); if (err) { printk(KERN_ERR "cuda_init_via() failed "); via = NULL; return 0; } /* Clear and enable interrupts, but only on PPC. On 68K it's done */ /* for us by the main VIA driver in arch/m68k/mac/via.c */ |
1da177e4c Linux-2.6.12-rc2 |
271 272 |
out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ |
1da177e4c Linux-2.6.12-rc2 |
273 274 275 276 277 278 279 |
/* enable autopoll */ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); while (!req.complete) cuda_poll(); return 1; |
51d3082fe [PATCH] powerpc: ... |
280 281 282 283 284 |
fail: of_node_put(vias); vias = NULL; return 0; |
1da177e4c Linux-2.6.12-rc2 |
285 |
} |
18814ee84 mac68k: start CUD... |
286 |
#endif /* !defined CONFIG_MAC */ |
1da177e4c Linux-2.6.12-rc2 |
287 288 289 290 291 |
static int __init via_cuda_start(void) { if (via == NULL) return -ENODEV; |
0ebfff149 [POWERPC] Add new... |
292 |
#ifdef CONFIG_MAC |
0251c38ce CUDA ADB fixes |
293 |
cuda_irq = IRQ_MAC_ADB; |
18814ee84 mac68k: start CUD... |
294 |
#else |
0251c38ce CUDA ADB fixes |
295 |
cuda_irq = irq_of_parse_and_map(vias, 0); |
ef24ba709 powerpc: Remove a... |
296 |
if (!cuda_irq) { |
b6a945ae0 macintosh: Conver... |
297 298 299 |
printk(KERN_ERR "via-cuda: can't map interrupts for %pOF ", vias); |
0ebfff149 [POWERPC] Add new... |
300 301 |
return -ENODEV; } |
18814ee84 mac68k: start CUD... |
302 |
#endif |
0ebfff149 [POWERPC] Add new... |
303 |
|
0251c38ce CUDA ADB fixes |
304 305 306 |
if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { printk(KERN_ERR "via-cuda: can't request irq %d ", cuda_irq); |
1da177e4c Linux-2.6.12-rc2 |
307 308 |
return -EAGAIN; } |
d23eee88b via-cuda: Add sup... |
309 310 |
pr_info("Macintosh Cuda and Egret driver. "); |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
cuda_fully_inited = 1; return 0; } device_initcall(via_cuda_start); #ifdef CONFIG_ADB static int cuda_probe(void) { #ifdef CONFIG_PPC if (sys_ctrler != SYS_CTRLER_CUDA) return -ENODEV; #else |
f74faec6b m68k/mac: Replace... |
326 327 |
if (macintosh_config->adb_type != MAC_ADB_CUDA && macintosh_config->adb_type != MAC_ADB_EGRET) |
1da177e4c Linux-2.6.12-rc2 |
328 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
329 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 |
if (via == NULL) return -ENODEV; return 0; |
1da177e4c Linux-2.6.12-rc2 |
333 334 |
} #endif /* CONFIG_ADB */ |
d23eee88b via-cuda: Add sup... |
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
static int __init sync_egret(void) { if (TREQ_asserted(in_8(&via[B]))) { /* Complete the inbound transfer */ assert_TIP_and_TACK(); while (1) { negate_TACK(); mdelay(1); (void)in_8(&via[SR]); assert_TACK(); if (!TREQ_asserted(in_8(&via[B]))) break; } negate_TIP_and_TACK(); } else if (in_8(&via[B]) & TIP) { /* Terminate the outbound transfer */ negate_TACK(); assert_TACK(); mdelay(1); negate_TIP_and_TACK(); } /* Clear shift register interrupt */ if (in_8(&via[IFR]) & SR_INT) (void)in_8(&via[SR]); return 0; } |
1da177e4c Linux-2.6.12-rc2 |
361 362 363 364 365 |
#define WAIT_FOR(cond, what) \ do { \ int x; \ for (x = 1000; !(cond); --x) { \ if (x == 0) { \ |
523717d14 via-cuda: Cleanup... |
366 367 |
pr_err("Timeout waiting for " what " "); \ |
1da177e4c Linux-2.6.12-rc2 |
368 369 370 371 372 373 374 |
return -ENXIO; \ } \ udelay(100); \ } \ } while (0) static int |
330dae199 mac: Make cuda_in... |
375 |
__init cuda_init_via(void) |
1da177e4c Linux-2.6.12-rc2 |
376 |
{ |
0251c38ce CUDA ADB fixes |
377 |
#ifdef CONFIG_PPC |
1da177e4c Linux-2.6.12-rc2 |
378 379 |
out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ (void)in_8(&via[IER]); |
0251c38ce CUDA ADB fixes |
380 381 |
#else out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ |
1da177e4c Linux-2.6.12-rc2 |
382 |
#endif |
d23eee88b via-cuda: Add sup... |
383 384 385 386 387 388 389 390 |
out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */ out_8(&via[ACR], (in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ (void)in_8(&via[SR]); /* clear any left-over data */ if (mcu_is_egret) return sync_egret(); negate_TIP_and_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
391 392 393 |
/* delay 4ms and then clear any pending interrupt */ mdelay(4); (void)in_8(&via[SR]); |
0251c38ce CUDA ADB fixes |
394 |
out_8(&via[IFR], SR_INT); |
1da177e4c Linux-2.6.12-rc2 |
395 396 |
/* sync with the CUDA - assert TACK without TIP */ |
fd7a65a27 via-cuda: Add TRE... |
397 |
assert_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
398 399 |
/* wait for the CUDA to assert TREQ in response */ |
fd7a65a27 via-cuda: Add TRE... |
400 |
WAIT_FOR(TREQ_asserted(in_8(&via[B])), "CUDA response to sync"); |
1da177e4c Linux-2.6.12-rc2 |
401 402 403 404 |
/* wait for the interrupt and then clear it */ WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); (void)in_8(&via[SR]); |
0251c38ce CUDA ADB fixes |
405 |
out_8(&via[IFR], SR_INT); |
1da177e4c Linux-2.6.12-rc2 |
406 407 |
/* finish the sync by negating TACK */ |
fd7a65a27 via-cuda: Add TRE... |
408 |
negate_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
409 410 |
/* wait for the CUDA to negate TREQ and the corresponding interrupt */ |
fd7a65a27 via-cuda: Add TRE... |
411 |
WAIT_FOR(!TREQ_asserted(in_8(&via[B])), "CUDA response to sync (3)"); |
1da177e4c Linux-2.6.12-rc2 |
412 413 |
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); (void)in_8(&via[SR]); |
0251c38ce CUDA ADB fixes |
414 |
out_8(&via[IFR], SR_INT); |
1da177e4c Linux-2.6.12-rc2 |
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
return 0; } #ifdef CONFIG_ADB /* Send an ADB command */ static int cuda_send_request(struct adb_request *req, int sync) { int i; if ((via == NULL) || !cuda_fully_inited) { req->complete = 1; return -ENXIO; } req->reply_expected = 1; i = cuda_write(req); if (i) return i; if (sync) { while (!req->complete) cuda_poll(); } return 0; } /* Enable/disable autopolling */ static int cuda_adb_autopoll(int devs) { struct adb_request req; if ((via == NULL) || !cuda_fully_inited) return -ENXIO; cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0)); while (!req.complete) cuda_poll(); return 0; } /* Reset adb bus - how do we do this?? */ static int cuda_reset_adb_bus(void) { struct adb_request req; if ((via == NULL) || !cuda_fully_inited) return -ENXIO; cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */ while (!req.complete) cuda_poll(); return 0; } #endif /* CONFIG_ADB */ |
523717d14 via-cuda: Cleanup... |
475 |
|
1da177e4c Linux-2.6.12-rc2 |
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
/* Construct and send a cuda request */ int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...) { va_list list; int i; if (via == NULL) { req->complete = 1; return -ENXIO; } req->nbytes = nbytes; req->done = done; va_start(list, nbytes); for (i = 0; i < nbytes; ++i) req->data[i] = va_arg(list, int); va_end(list); req->reply_expected = 1; return cuda_write(req); } |
4a1b08e84 powerpc: Move via... |
498 |
EXPORT_SYMBOL(cuda_request); |
1da177e4c Linux-2.6.12-rc2 |
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
static int cuda_write(struct adb_request *req) { unsigned long flags; if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { req->complete = 1; return -EINVAL; } req->next = NULL; req->sent = 0; req->complete = 0; req->reply_len = 0; spin_lock_irqsave(&cuda_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; } else { current_req = req; last_req = req; if (cuda_state == idle) cuda_start(); } spin_unlock_irqrestore(&cuda_lock, flags); return 0; } static void cuda_start(void) { |
1da177e4c Linux-2.6.12-rc2 |
532 |
/* assert cuda_state == idle */ |
06d7e9940 via-cuda: Remove ... |
533 |
if (current_req == NULL) |
1da177e4c Linux-2.6.12-rc2 |
534 |
return; |
97ced1aac via-cuda: Initial... |
535 |
data_index = 0; |
fd7a65a27 via-cuda: Add TRE... |
536 |
if (TREQ_asserted(in_8(&via[B]))) |
1da177e4c Linux-2.6.12-rc2 |
537 538 539 540 |
return; /* a byte is coming in from the CUDA */ /* set the shift register to shift out and send a byte */ out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT); |
97ced1aac via-cuda: Initial... |
541 |
out_8(&via[SR], current_req->data[data_index++]); |
d23eee88b via-cuda: Add sup... |
542 543 544 545 |
if (mcu_is_egret) assert_TIP_and_TACK(); else assert_TIP(); |
1da177e4c Linux-2.6.12-rc2 |
546 547 548 549 550 551 |
cuda_state = sent_first_byte; } void cuda_poll(void) { |
ac39452e9 via-cuda: Use spi... |
552 |
cuda_interrupt(0, NULL); |
1da177e4c Linux-2.6.12-rc2 |
553 |
} |
4a1b08e84 powerpc: Move via... |
554 |
EXPORT_SYMBOL(cuda_poll); |
1da177e4c Linux-2.6.12-rc2 |
555 |
|
fe73b582f via-cuda: Prevent... |
556 |
#define ARRAY_FULL(a, p) ((p) - (a) == ARRAY_SIZE(a)) |
1da177e4c Linux-2.6.12-rc2 |
557 |
static irqreturn_t |
7d12e780e IRQ: Maintain reg... |
558 |
cuda_interrupt(int irq, void *arg) |
1da177e4c Linux-2.6.12-rc2 |
559 |
{ |
ac39452e9 via-cuda: Use spi... |
560 |
unsigned long flags; |
fd7a65a27 via-cuda: Add TRE... |
561 |
u8 status; |
1da177e4c Linux-2.6.12-rc2 |
562 563 564 565 |
struct adb_request *req = NULL; unsigned char ibuf[16]; int ibuf_len = 0; int complete = 0; |
458c77f3d macintosh/via-cud... |
566 |
bool full; |
1da177e4c Linux-2.6.12-rc2 |
567 |
|
ac39452e9 via-cuda: Use spi... |
568 |
spin_lock_irqsave(&cuda_lock, flags); |
1da177e4c Linux-2.6.12-rc2 |
569 |
|
18814ee84 mac68k: start CUD... |
570 |
/* On powermacs, this handler is registered for the VIA IRQ. But they use |
0251c38ce CUDA ADB fixes |
571 572 573 574 575 576 577 578 579 580 |
* just the shift register IRQ -- other VIA interrupt sources are disabled. * On m68k macs, the VIA IRQ sources are dispatched individually. Unless * we are polling, the shift register IRQ flag has already been cleared. */ #ifdef CONFIG_MAC if (!arg) #endif { if ((in_8(&via[IFR]) & SR_INT) == 0) { |
ac39452e9 via-cuda: Use spi... |
581 |
spin_unlock_irqrestore(&cuda_lock, flags); |
0251c38ce CUDA ADB fixes |
582 583 584 585 |
return IRQ_NONE; } else { out_8(&via[IFR], SR_INT); } |
1da177e4c Linux-2.6.12-rc2 |
586 |
} |
fd7a65a27 via-cuda: Add TRE... |
587 588 |
status = in_8(&via[B]) & (TIP | TACK | TREQ); |
1da177e4c Linux-2.6.12-rc2 |
589 590 |
switch (cuda_state) { case idle: |
d23eee88b via-cuda: Add sup... |
591 |
/* System controller has unsolicited data for us */ |
1da177e4c Linux-2.6.12-rc2 |
592 |
(void)in_8(&via[SR]); |
d23eee88b via-cuda: Add sup... |
593 |
idle_state: |
fd7a65a27 via-cuda: Add TRE... |
594 |
assert_TIP(); |
1da177e4c Linux-2.6.12-rc2 |
595 596 597 598 599 600 |
cuda_state = reading; reply_ptr = cuda_rbuf; reading_reply = 0; break; case awaiting_reply: |
d23eee88b via-cuda: Add sup... |
601 |
/* System controller has reply data for us */ |
1da177e4c Linux-2.6.12-rc2 |
602 |
(void)in_8(&via[SR]); |
fd7a65a27 via-cuda: Add TRE... |
603 |
assert_TIP(); |
1da177e4c Linux-2.6.12-rc2 |
604 605 606 607 608 609 |
cuda_state = reading; reply_ptr = current_req->reply; reading_reply = 1; break; case sent_first_byte: |
fd7a65a27 via-cuda: Add TRE... |
610 |
if (TREQ_asserted(status)) { |
1da177e4c Linux-2.6.12-rc2 |
611 612 613 |
/* collision */ out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); (void)in_8(&via[SR]); |
fd7a65a27 via-cuda: Add TRE... |
614 |
negate_TIP_and_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
615 |
cuda_state = idle; |
d23eee88b via-cuda: Add sup... |
616 617 618 |
/* Egret does not raise an "aborted" interrupt */ if (mcu_is_egret) goto idle_state; |
1da177e4c Linux-2.6.12-rc2 |
619 |
} else { |
97ced1aac via-cuda: Initial... |
620 |
out_8(&via[SR], current_req->data[data_index++]); |
fd7a65a27 via-cuda: Add TRE... |
621 |
toggle_TACK(); |
d23eee88b via-cuda: Add sup... |
622 623 |
if (mcu_is_egret) assert_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
624 625 626 627 628 629 630 631 632 |
cuda_state = sending; } break; case sending: req = current_req; if (data_index >= req->nbytes) { out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); (void)in_8(&via[SR]); |
fd7a65a27 via-cuda: Add TRE... |
633 |
negate_TIP_and_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
634 635 636 637 638 639 640 641 642 643 644 645 |
req->sent = 1; if (req->reply_expected) { cuda_state = awaiting_reply; } else { current_req = req->next; complete = 1; /* not sure about this */ cuda_state = idle; cuda_start(); } } else { out_8(&via[SR], req->data[data_index++]); |
fd7a65a27 via-cuda: Add TRE... |
646 |
toggle_TACK(); |
d23eee88b via-cuda: Add sup... |
647 648 |
if (mcu_is_egret) assert_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
649 650 651 652 |
} break; case reading: |
458c77f3d macintosh/via-cud... |
653 654 655 |
full = reading_reply ? ARRAY_FULL(current_req->reply, reply_ptr) : ARRAY_FULL(cuda_rbuf, reply_ptr); if (full) |
fe73b582f via-cuda: Prevent... |
656 657 658 |
(void)in_8(&via[SR]); else *reply_ptr++ = in_8(&via[SR]); |
458c77f3d macintosh/via-cud... |
659 |
if (!TREQ_asserted(status) || full) { |
d23eee88b via-cuda: Add sup... |
660 661 |
if (mcu_is_egret) assert_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
662 |
/* that's all folks */ |
fd7a65a27 via-cuda: Add TRE... |
663 |
negate_TIP_and_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
664 |
cuda_state = read_done; |
d23eee88b via-cuda: Add sup... |
665 666 667 |
/* Egret does not raise a "read done" interrupt */ if (mcu_is_egret) goto read_done_state; |
1da177e4c Linux-2.6.12-rc2 |
668 |
} else { |
fd7a65a27 via-cuda: Add TRE... |
669 |
toggle_TACK(); |
d23eee88b via-cuda: Add sup... |
670 671 |
if (mcu_is_egret) negate_TACK(); |
1da177e4c Linux-2.6.12-rc2 |
672 673 674 675 676 |
} break; case read_done: (void)in_8(&via[SR]); |
d23eee88b via-cuda: Add sup... |
677 |
read_done_state: |
1da177e4c Linux-2.6.12-rc2 |
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; if (req->data[0] == ADB_PACKET) { /* Have to adjust the reply from ADB commands */ if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { /* the 0x2 bit indicates no response */ req->reply_len = 0; } else { /* leave just the command and result bytes in the reply */ req->reply_len -= 2; memmove(req->reply, req->reply + 2, req->reply_len); } } current_req = req->next; complete = 1; |
cfbf99801 via-cuda: Fix re-... |
694 |
reading_reply = 0; |
1da177e4c Linux-2.6.12-rc2 |
695 696 697 698 699 700 701 702 703 704 705 |
} else { /* This is tricky. We must break the spinlock to call * cuda_input. However, doing so means we might get * re-entered from another CPU getting an interrupt * or calling cuda_poll(). I ended up using the stack * (it's only for 16 bytes) and moving the actual * call to cuda_input to outside of the lock. */ ibuf_len = reply_ptr - cuda_rbuf; memcpy(ibuf, cuda_rbuf, ibuf_len); } |
cfbf99801 via-cuda: Fix re-... |
706 |
reply_ptr = cuda_rbuf; |
a64662432 via-cuda: Avoid T... |
707 708 709 |
cuda_state = idle; cuda_start(); if (cuda_state == idle && TREQ_asserted(in_8(&via[B]))) { |
fd7a65a27 via-cuda: Add TRE... |
710 |
assert_TIP(); |
1da177e4c Linux-2.6.12-rc2 |
711 |
cuda_state = reading; |
1da177e4c Linux-2.6.12-rc2 |
712 713 714 715 |
} break; default: |
523717d14 via-cuda: Cleanup... |
716 717 |
pr_err("cuda_interrupt: unknown cuda_state %d? ", cuda_state); |
1da177e4c Linux-2.6.12-rc2 |
718 |
} |
ac39452e9 via-cuda: Use spi... |
719 |
spin_unlock_irqrestore(&cuda_lock, flags); |
1da177e4c Linux-2.6.12-rc2 |
720 721 722 723 724 725 726 727 728 729 730 |
if (complete && req) { void (*done)(struct adb_request *) = req->done; mb(); req->complete = 1; /* Here, we assume that if the request has a done member, the * struct request will survive to setting req->complete to 1 */ if (done) (*done)(req); } if (ibuf_len) |
7d12e780e IRQ: Maintain reg... |
731 |
cuda_input(ibuf, ibuf_len); |
1da177e4c Linux-2.6.12-rc2 |
732 733 734 735 |
return IRQ_HANDLED; } static void |
7d12e780e IRQ: Maintain reg... |
736 |
cuda_input(unsigned char *buf, int nb) |
1da177e4c Linux-2.6.12-rc2 |
737 |
{ |
1da177e4c Linux-2.6.12-rc2 |
738 739 740 741 742 743 744 745 746 747 748 749 |
switch (buf[0]) { case ADB_PACKET: #ifdef CONFIG_XMON if (nb == 5 && buf[2] == 0x2c) { extern int xmon_wants_key, xmon_adb_keycode; if (xmon_wants_key) { xmon_adb_keycode = buf[3]; return; } } #endif /* CONFIG_XMON */ #ifdef CONFIG_ADB |
7d12e780e IRQ: Maintain reg... |
750 |
adb_input(buf+2, nb-2, buf[1] & 0x40); |
1da177e4c Linux-2.6.12-rc2 |
751 752 |
#endif /* CONFIG_ADB */ break; |
d23eee88b via-cuda: Add sup... |
753 754 755 756 757 |
case TIMER_PACKET: /* Egret sends these periodically. Might be useful as a 'heartbeat' * to trigger a recovery for the VIA shift register errata. */ break; |
1da177e4c Linux-2.6.12-rc2 |
758 |
default: |
523717d14 via-cuda: Cleanup... |
759 760 |
print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1, buf, nb, false); |
1da177e4c Linux-2.6.12-rc2 |
761 762 |
} } |
0792a2c8e macintosh: Use co... |
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
/* Offset between Unix time (1970-based) and Mac time (1904-based) */ #define RTC_OFFSET 2082844800 time64_t cuda_get_time(void) { struct adb_request req; u32 now; if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) return 0; while (!req.complete) cuda_poll(); if (req.reply_len != 7) pr_err("%s: got %d byte reply ", __func__, req.reply_len); now = (req.reply[3] << 24) + (req.reply[4] << 16) + (req.reply[5] << 8) + req.reply[6]; return (time64_t)now - RTC_OFFSET; } int cuda_set_rtc_time(struct rtc_time *tm) { u32 now; struct adb_request req; now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, now >> 24, now >> 16, now >> 8, now) < 0) return -ENXIO; while (!req.complete) cuda_poll(); if ((req.reply_len != 3) && (req.reply_len != 7)) pr_err("%s: got %d byte reply ", __func__, req.reply_len); return 0; } |