OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [macintosh/] [via-maciisi.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Device driver for the IIsi-style ADB on some Mac LC and II-class machines
3
 *
4
 * Based on via-cuda.c and via-macii.c, as well as the original
5
 * adb-bus.c, which in turn is somewhat influenced by (but uses no
6
 * code from) the NetBSD HWDIRECT ADB code.  Original IIsi driver work
7
 * was done by Robert Thompson and integrated into the old style
8
 * driver by Michael Schmitz.
9
 *
10
 * Original sources (c) Alan Cox, Paul Mackerras, and others.
11
 *
12
 * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org>
13
 *
14
 * 7/13/2000- extensive changes by Andrew McPherson <andrew@macduff.dhs.org>
15
 * Works about 30% of the time now.
16
 */
17
 
18
#include <linux/types.h>
19
#include <linux/errno.h>
20
#include <linux/kernel.h>
21
#include <linux/sched.h>
22
#include <linux/adb.h>
23
#include <linux/cuda.h>
24
#include <linux/delay.h>
25
#include <asm/macintosh.h>
26
#include <asm/macints.h>
27
#include <asm/machw.h>
28
#include <asm/mac_via.h>
29
 
30
static volatile unsigned char *via;
31
 
32
/* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */
33
#define RS              0x200           /* skip between registers */
34
#define B               0                /* B-side data */
35
#define A               RS              /* A-side data */
36
#define DIRB            (2*RS)          /* B-side direction (1=output) */
37
#define DIRA            (3*RS)          /* A-side direction (1=output) */
38
#define SR              (10*RS)         /* Shift register */
39
#define ACR             (11*RS)         /* Auxiliary control register */
40
#define IFR             (13*RS)         /* Interrupt flag register */
41
#define IER             (14*RS)         /* Interrupt enable register */
42
 
43
/* Bits in B data register: all active low */
44
#define TREQ            0x08            /* Transfer request (input) */
45
#define TACK            0x10            /* Transfer acknowledge (output) */
46
#define TIP             0x20            /* Transfer in progress (output) */
47
#define ST_MASK         0x30            /* mask for selecting ADB state bits */
48
 
49
/* Bits in ACR */
50
#define SR_CTRL         0x1c            /* Shift register control bits */
51
#define SR_EXT          0x0c            /* Shift on external clock */
52
#define SR_OUT          0x10            /* Shift out if 1 */
53
 
54
/* Bits in IFR and IER */
55
#define IER_SET         0x80            /* set bits in IER */
56
#define IER_CLR         0                /* clear bits in IER */
57
#define SR_INT          0x04            /* Shift register full/empty */
58
#define SR_DATA         0x08            /* Shift register data */
59
#define SR_CLOCK        0x10            /* Shift register clock */
60
 
61
#define ADB_DELAY 150
62
 
63
#undef DEBUG_MACIISI_ADB
64
 
65
static struct adb_request* current_req = NULL;
66
static struct adb_request* last_req = NULL;
67
static unsigned char maciisi_rbuf[16];
68
static unsigned char *reply_ptr = NULL;
69
static int data_index;
70
static int reading_reply;
71
static int reply_len;
72
static int tmp;
73
static int need_sync;
74
 
75
static enum maciisi_state {
76
    idle,
77
    sending,
78
    reading,
79
} maciisi_state;
80
 
81
static int maciisi_probe(void);
82
static int maciisi_init(void);
83
static int maciisi_send_request(struct adb_request* req, int sync);
84
static void maciisi_sync(struct adb_request *req);
85
static int maciisi_write(struct adb_request* req);
86
static void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
87
static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
88
static int maciisi_init_via(void);
89
static void maciisi_poll(void);
90
static int maciisi_start(void);
91
 
92
struct adb_driver via_maciisi_driver = {
93
        "Mac IIsi",
94
        maciisi_probe,
95
        maciisi_init,
96
        maciisi_send_request,
97
        NULL, /* maciisi_adb_autopoll, */
98
        maciisi_poll,
99
        NULL /* maciisi_reset_adb_bus */
100
};
101
 
102
static int
103
maciisi_probe(void)
104
{
105
        if (macintosh_config->adb_type != MAC_ADB_IISI)
106
                return -ENODEV;
107
 
108
        via = via1;
109
        return 0;
110
}
111
 
112
static int
113
maciisi_init(void)
114
{
115
        int err;
116
 
117
        if (via == NULL)
118
                return -ENODEV;
119
 
120
        if ((err = maciisi_init_via())) {
121
                printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err);
122
                via = NULL;
123
                return err;
124
        }
125
 
126
        if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST,
127
                        "ADB", maciisi_interrupt)) {
128
                printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB);
129
                return -EAGAIN;
130
        }
131
 
132
        printk("adb: Mac IIsi driver v0.2 for Unified ADB.\n");
133
        return 0;
134
}
135
 
136
/* Flush data from the ADB controller */
137
static void
138
maciisi_stfu(void)
139
{
140
        int status = via[B] & (TIP|TREQ);
141
 
142
        if (status & TREQ) {
143
#ifdef DEBUG_MACIISI_ADB
144
                printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n");
145
#endif
146
                return;
147
        }
148
 
149
        udelay(ADB_DELAY);
150
        via[ACR] &= ~SR_OUT;
151
        via[IER] = IER_CLR | SR_INT;
152
 
153
        udelay(ADB_DELAY);
154
 
155
        status = via[B] & (TIP|TREQ);
156
 
157
        if (!(status & TREQ))
158
        {
159
                via[B] |= TIP;
160
 
161
                while(1)
162
                {
163
                        int poll_timeout = ADB_DELAY * 5;
164
                        /* Poll for SR interrupt */
165
                        while (!(via[IFR] & SR_INT) && poll_timeout-- > 0)
166
                                status = via[B] & (TIP|TREQ);
167
 
168
                        tmp = via[SR]; /* Clear shift register */
169
#ifdef DEBUG_MACIISI_ADB
170
                        printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d data %x\n",
171
                               status, poll_timeout, tmp);
172
#endif  
173
                        if(via[B] & TREQ)
174
                                break;
175
 
176
                        /* ACK on-off */
177
                        via[B] |= TACK;
178
                        udelay(ADB_DELAY);
179
                        via[B] &= ~TACK;
180
                }
181
 
182
                /* end frame */
183
                via[B] &= ~TIP;
184
                udelay(ADB_DELAY);
185
        }
186
 
187
        via[IER] = IER_SET | SR_INT;
188
}
189
 
190
/* All specifically VIA-related initialization goes here */
191
static int
192
maciisi_init_via(void)
193
{
194
        int     i;
195
 
196
        /* Set the lines up. We want TREQ as input TACK|TIP as output */
197
        via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
198
        /* Shift register on input */
199
        via[ACR]  = (via[ACR] & ~SR_CTRL) | SR_EXT;
200
#ifdef DEBUG_MACIISI_ADB
201
        printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ));
202
#endif
203
        /* Wipe any pending data and int */
204
        tmp = via[SR];
205
        /* Enable keyboard interrupts */
206
        via[IER] = IER_SET | SR_INT;
207
        /* Set initial state: idle */
208
        via[B] &= ~(TACK|TIP);
209
        /* Clear interrupt bit */
210
        via[IFR] = SR_INT;
211
 
212
        for(i = 0; i < 60; i++) {
213
                udelay(ADB_DELAY);
214
                maciisi_stfu();
215
                udelay(ADB_DELAY);
216
                if(via[B] & TREQ)
217
                        break;
218
        }
219
        if (i == 60)
220
                printk(KERN_ERR "maciisi_init_via: bus jam?\n");
221
 
222
        maciisi_state = idle;
223
        need_sync = 0;
224
 
225
        return 0;
226
}
227
 
228
/* Send a request, possibly waiting for a reply */
229
static int
230
maciisi_send_request(struct adb_request* req, int sync)
231
{
232
        int i;
233
 
234
#ifdef DEBUG_MACIISI_ADB
235
        static int dump_packet = 0;
236
#endif
237
 
238
        if (via == NULL) {
239
                req->complete = 1;
240
                return -ENXIO;
241
        }
242
 
243
#ifdef DEBUG_MACIISI_ADB
244
        if (dump_packet) {
245
                printk(KERN_DEBUG "maciisi_send_request:");
246
                for (i = 0; i < req->nbytes; i++) {
247
                        printk(" %.2x", req->data[i]);
248
                }
249
                printk(" sync %d\n", sync);
250
        }
251
#endif
252
 
253
        req->reply_expected = 1;
254
 
255
        i = maciisi_write(req);
256
        if (i)
257
        {
258
                /* Normally, if a packet requires syncing, that happens at the end of
259
                 * maciisi_send_request. But if the transfer fails, it will be restarted
260
                 * by maciisi_interrupt(). We use need_sync to tell maciisi_interrupt
261
                 * when to sync a packet that it sends out.
262
                 *
263
                 * Suggestions on a better way to do this are welcome.
264
                 */
265
                if(i == -EBUSY && sync)
266
                        need_sync = 1;
267
                else
268
                        need_sync = 0;
269
                return i;
270
        }
271
        if(sync)
272
                maciisi_sync(req);
273
 
274
        return 0;
275
}
276
 
277
/* Poll the ADB chip until the request completes */
278
static void maciisi_sync(struct adb_request *req)
279
{
280
        int count = 0;
281
 
282
#ifdef DEBUG_MACIISI_ADB
283
        printk(KERN_DEBUG "maciisi_sync called\n");
284
#endif
285
 
286
        /* If for some reason the ADB chip shuts up on us, we want to avoid an endless loop. */
287
        while (!req->complete && count++ < 50) {
288
                maciisi_poll();
289
        }
290
        /* This could be BAD... when the ADB controller doesn't respond
291
         * for this long, it's probably not coming back :-( */
292
        if(count >= 50) /* Hopefully shouldn't happen */
293
                printk(KERN_ERR "maciisi_send_request: poll timed out!\n");
294
}
295
 
296
/* Enqueue a request, and run the queue if possible */
297
static int
298
maciisi_write(struct adb_request* req)
299
{
300
        unsigned long flags;
301
        int i;
302
 
303
        /* We will accept CUDA packets - the VIA sends them to us, so
304
           it figures that we should be able to send them to it */
305
        if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
306
                printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n");
307
                req->complete = 1;
308
                return -EINVAL;
309
        }
310
        req->next = 0;
311
        req->sent = 0;
312
        req->complete = 0;
313
        req->reply_len = 0;
314
 
315
        save_flags(flags);
316
        cli();
317
 
318
        if (current_req) {
319
                last_req->next = req;
320
                last_req = req;
321
        } else {
322
                current_req = req;
323
                last_req = req;
324
        }
325
        if (maciisi_state == idle)
326
        {
327
                i = maciisi_start();
328
                if(i != 0)
329
                {
330
                        restore_flags(flags);
331
                        return i;
332
                }
333
        }
334
        else
335
        {
336
#ifdef DEBUG_MACIISI_ADB
337
                printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state);
338
#endif
339
                restore_flags(flags);
340
                return -EBUSY;
341
        }
342
 
343
        restore_flags(flags);
344
 
345
        return 0;
346
}
347
 
348
static int
349
maciisi_start(void)
350
{
351
        struct adb_request* req;
352
        int status;
353
 
354
#ifdef DEBUG_MACIISI_ADB
355
        status = via[B] & (TIP | TREQ);
356
 
357
        printk(KERN_DEBUG "maciisi_start called, state=%d, status=%x, ifr=%x\n", maciisi_state, status, via[IFR]);
358
#endif
359
 
360
        if (maciisi_state != idle) {
361
                /* shouldn't happen */
362
                printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n");
363
                return -EBUSY;
364
        }
365
 
366
        req = current_req;
367
        if (req == NULL)
368
                return -EINVAL;
369
 
370
        status = via[B] & (TIP|TREQ);
371
        if (!(status & TREQ)) {
372
#ifdef DEBUG_MACIISI_ADB
373
                printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n");
374
#endif
375
                return -EBUSY;
376
        }
377
 
378
        /* Okay, send */
379
#ifdef DEBUG_MACIISI_ADB
380
        printk(KERN_DEBUG "maciisi_start: sending\n");
381
#endif
382
        /* Set state to active */
383
        via[B] |= TIP;
384
        /* ACK off */
385
        via[B] &= ~TACK;
386
        /* Delay */
387
        udelay(ADB_DELAY);
388
        /* Shift out and send */
389
        via[ACR] |= SR_OUT;
390
        via[SR] = req->data[0];
391
        data_index = 1;
392
        /* ACK on */
393
        via[B] |= TACK;
394
        maciisi_state = sending;
395
 
396
        return 0;
397
}
398
 
399
void
400
maciisi_poll(void)
401
{
402
        unsigned long flags;
403
 
404
        save_flags(flags);
405
        cli();
406
        if (via[IFR] & SR_INT) {
407
                maciisi_interrupt(0, 0, 0);
408
        }
409
        else /* avoid calling this function too quickly in a loop */
410
                udelay(ADB_DELAY);
411
 
412
        restore_flags(flags);
413
}
414
 
415
/* Shift register interrupt - this is *supposed* to mean that the
416
   register is either full or empty. In practice, I have no idea what
417
   it means :( */
418
static void
419
maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
420
{
421
        int status;
422
        struct adb_request *req;
423
#ifdef DEBUG_MACIISI_ADB
424
        static int dump_reply = 0;
425
#endif
426
        int i;
427
        unsigned long flags;
428
 
429
        save_flags(flags);
430
        cli();
431
 
432
        status = via[B] & (TIP|TREQ);
433
#ifdef DEBUG_MACIISI_ADB
434
        printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);
435
#endif
436
 
437
        if (!(via[IFR] & SR_INT)) {
438
                /* Shouldn't happen, we hope */
439
                printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n");
440
                restore_flags(flags);
441
                return;
442
        }
443
 
444
        /* Clear the interrupt */
445
        /* via[IFR] = SR_INT; */
446
 
447
 switch_start:
448
        switch (maciisi_state) {
449
        case idle:
450
                if (status & TIP)
451
                        printk(KERN_ERR "maciisi_interrupt: state is idle but TIP asserted!\n");
452
 
453
                if(!reading_reply)
454
                        udelay(ADB_DELAY);
455
                /* Shift in */
456
                via[ACR] &= ~SR_OUT;
457
                /* Signal start of frame */
458
                via[B] |= TIP;
459
                /* Clear the interrupt (throw this value on the floor, it's useless) */
460
                tmp = via[SR];
461
                /* ACK adb chip, high-low */
462
                via[B] |= TACK;
463
                udelay(ADB_DELAY);
464
                via[B] &= ~TACK;
465
                reply_len = 0;
466
                maciisi_state = reading;
467
                if (reading_reply) {
468
                        reply_ptr = current_req->reply;
469
                } else {
470
                        reply_ptr = maciisi_rbuf;
471
                }
472
                break;
473
 
474
        case sending:
475
                /* via[SR]; */
476
                /* Set ACK off */
477
                via[B] &= ~TACK;
478
                req = current_req;
479
 
480
                if (!(status & TREQ)) {
481
                        /* collision */
482
                        printk(KERN_ERR "maciisi_interrupt: send collision\n");
483
                        /* Set idle and input */
484
                        via[ACR] &= ~SR_OUT;
485
                        tmp = via[SR];
486
                        via[B] &= ~TIP;
487
                        /* Must re-send */
488
                        reading_reply = 0;
489
                        reply_len = 0;
490
                        maciisi_state = idle;
491
                        udelay(ADB_DELAY);
492
                        /* process this now, because the IFR has been cleared */
493
                        goto switch_start;
494
                }
495
 
496
                udelay(ADB_DELAY);
497
 
498
                if (data_index >= req->nbytes) {
499
                        /* Sent the whole packet, put the bus back in idle state */
500
                        /* Shift in, we are about to read a reply (hopefully) */
501
                        via[ACR] &= ~SR_OUT;
502
                        tmp = via[SR];
503
                        /* End of frame */
504
                        via[B] &= ~TIP;
505
                        req->sent = 1;
506
                        maciisi_state = idle;
507
                        if (req->reply_expected) {
508
                                /* Note: only set this once we've
509
                                   successfully sent the packet */
510
                                reading_reply = 1;
511
                        } else {
512
                                current_req = req->next;
513
                                if (req->done)
514
                                        (*req->done)(req);
515
                                /* Do any queued requests now */
516
                                i = maciisi_start();
517
                                if(i == 0 && need_sync) {
518
                                        /* Packet needs to be synced */
519
                                        maciisi_sync(current_req);
520
                                }
521
                                if(i != -EBUSY)
522
                                        need_sync = 0;
523
                        }
524
                } else {
525
                        /* Sending more stuff */
526
                        /* Shift out */
527
                        via[ACR] |= SR_OUT;
528
                        /* Write */
529
                        via[SR] = req->data[data_index++];
530
                        /* Signal 'byte ready' */
531
                        via[B] |= TACK;
532
                }
533
                break;
534
 
535
        case reading:
536
                /* Shift in */
537
                /* via[ACR] &= ~SR_OUT; */ /* Not in 2.2 */
538
                if (reply_len++ > 16) {
539
                        printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
540
                        via[B] |= TACK;
541
                        udelay(ADB_DELAY);
542
                        via[B] &= ~(TACK|TIP);
543
                        maciisi_state = idle;
544
                        i = maciisi_start();
545
                        if(i == 0 && need_sync) {
546
                                /* Packet needs to be synced */
547
                                maciisi_sync(current_req);
548
                        }
549
                        if(i != -EBUSY)
550
                                need_sync = 0;
551
                        break;
552
                }
553
                /* Read data */
554
                *reply_ptr++ = via[SR];
555
                status = via[B] & (TIP|TREQ);
556
                /* ACK on/off */
557
                via[B] |= TACK;
558
                udelay(ADB_DELAY);
559
                via[B] &= ~TACK;
560
                if (!(status & TREQ))
561
                        break; /* more stuff to deal with */
562
 
563
                /* end of frame */
564
                via[B] &= ~TIP;
565
                tmp = via[SR]; /* That's what happens in 2.2 */
566
                udelay(ADB_DELAY); /* Give controller time to recover */
567
 
568
                /* end of packet, deal with it */
569
                if (reading_reply) {
570
                        req = current_req;
571
                        req->reply_len = reply_ptr - req->reply;
572
                        if (req->data[0] == ADB_PACKET) {
573
                                /* Have to adjust the reply from ADB commands */
574
                                if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
575
                                        /* the 0x2 bit indicates no response */
576
                                        req->reply_len = 0;
577
                                } else {
578
                                        /* leave just the command and result bytes in the reply */
579
                                        req->reply_len -= 2;
580
                                        memmove(req->reply, req->reply + 2, req->reply_len);
581
                                }
582
                        }
583
#ifdef DEBUG_MACIISI_ADB
584
                        if (dump_reply) {
585
                                int i;
586
                                printk(KERN_DEBUG "maciisi_interrupt: reply is ");
587
                                for (i = 0; i < req->reply_len; ++i)
588
                                        printk(" %.2x", req->reply[i]);
589
                                printk("\n");
590
                        }
591
#endif
592
                        req->complete = 1;
593
                        current_req = req->next;
594
                        if (req->done)
595
                                (*req->done)(req);
596
                        /* Obviously, we got it */
597
                        reading_reply = 0;
598
                } else {
599
                        maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
600
                }
601
                maciisi_state = idle;
602
                status = via[B] & (TIP|TREQ);
603
                if (!(status & TREQ)) {
604
                        /* Timeout?! More likely, another packet coming in already */
605
#ifdef DEBUG_MACIISI_ADB
606
                        printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
607
                               status, via[IFR]);
608
#endif
609
#if 0
610
                        udelay(ADB_DELAY);
611
                        via[B] |= TIP;
612
 
613
                        maciisi_state = reading;
614
                        reading_reply = 0;
615
                        reply_ptr = maciisi_rbuf;
616
#else
617
                        /* Process the packet now */
618
                        reading_reply = 0;
619
                        goto switch_start;
620
#endif
621
                        /* We used to do this... but the controller might actually have data for us */
622
                        /* maciisi_stfu(); */
623
                }
624
                else {
625
                        /* Do any queued requests now if possible */
626
                        i = maciisi_start();
627
                        if(i == 0 && need_sync) {
628
                                /* Packet needs to be synced */
629
                                maciisi_sync(current_req);
630
                        }
631
                        if(i != -EBUSY)
632
                                need_sync = 0;
633
                }
634
                break;
635
 
636
        default:
637
                printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
638
        }
639
        restore_flags(flags);
640
}
641
 
642
static void
643
maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
644
{
645
#ifdef DEBUG_MACIISI_ADB
646
    int i;
647
#endif
648
 
649
    switch (buf[0]) {
650
    case ADB_PACKET:
651
            adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
652
            break;
653
    default:
654
#ifdef DEBUG_MACIISI_ADB
655
            printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb);
656
            for (i = 0; i < nb; ++i)
657
                    printk(" %.2x", buf[i]);
658
            printk("\n");
659
#endif
660
            break;
661
    }
662
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.