linux-old/drivers/macintosh/via-maciisi.c
<<
>>
Prefs
   1/*
   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
  30static 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
  65static struct adb_request* current_req = NULL;
  66static struct adb_request* last_req = NULL;
  67static unsigned char maciisi_rbuf[16];
  68static unsigned char *reply_ptr = NULL;
  69static int data_index;
  70static int reading_reply;
  71static int reply_len;
  72static int tmp;
  73static int need_sync;
  74
  75static enum maciisi_state {
  76    idle,
  77    sending,
  78    reading,
  79} maciisi_state;
  80
  81static int maciisi_probe(void);
  82static int maciisi_init(void);
  83static int maciisi_send_request(struct adb_request* req, int sync);
  84static void maciisi_sync(struct adb_request *req);
  85static int maciisi_write(struct adb_request* req);
  86static void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
  87static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
  88static int maciisi_init_via(void);
  89static void maciisi_poll(void);
  90static int maciisi_start(void);
  91
  92struct 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
 102static int
 103maciisi_probe(void)
 104{
 105        if (macintosh_config->adb_type != MAC_ADB_IISI)
 106                return -ENODEV;
 107
 108        via = via1;
 109        return 0;
 110}
 111
 112static int
 113maciisi_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 */
 137static void
 138maciisi_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 */
 191static int
 192maciisi_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 */
 229static int
 230maciisi_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 */
 278static 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 */
 297static int
 298maciisi_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
 348static int
 349maciisi_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
 399void
 400maciisi_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 :( */
 418static void
 419maciisi_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
 642static void
 643maciisi_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}
 663
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.