linux/drivers/macintosh/adb-iop.c
<<
>>
Prefs
   1/*
   2 * I/O Processor (IOP) ADB Driver
   3 * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
   4 * Based on via-cuda.c by Paul Mackerras.
   5 *
   6 * 1999-07-01 (jmt) - First implementation for new driver architecture.
   7 *
   8 * 1999-07-31 (jmt) - First working version.
   9 *
  10 * TODO:
  11 *
  12 * o Implement SRQ handling.
  13 */
  14
  15#include <linux/types.h>
  16#include <linux/kernel.h>
  17#include <linux/mm.h>
  18#include <linux/delay.h>
  19#include <linux/init.h>
  20#include <linux/proc_fs.h>
  21
  22#include <asm/macintosh.h> 
  23#include <asm/macints.h> 
  24#include <asm/mac_iop.h>
  25#include <asm/mac_oss.h>
  26#include <asm/adb_iop.h>
  27
  28#include <linux/adb.h> 
  29
  30/*#define DEBUG_ADB_IOP*/
  31
  32extern void iop_ism_irq(int, void *);
  33
  34static struct adb_request *current_req;
  35static struct adb_request *last_req;
  36#if 0
  37static unsigned char reply_buff[16];
  38static unsigned char *reply_ptr;
  39#endif
  40
  41static enum adb_iop_state {
  42    idle,
  43    sending,
  44    awaiting_reply
  45} adb_iop_state;
  46
  47static void adb_iop_start(void);
  48static int adb_iop_probe(void);
  49static int adb_iop_init(void);
  50static int adb_iop_send_request(struct adb_request *, int);
  51static int adb_iop_write(struct adb_request *);
  52static int adb_iop_autopoll(int);
  53static void adb_iop_poll(void);
  54static int adb_iop_reset_bus(void);
  55
  56struct adb_driver adb_iop_driver = {
  57        "ISM IOP",
  58        adb_iop_probe,
  59        adb_iop_init,
  60        adb_iop_send_request,
  61        adb_iop_autopoll,
  62        adb_iop_poll,
  63        adb_iop_reset_bus
  64};
  65
  66static void adb_iop_end_req(struct adb_request *req, int state)
  67{
  68        req->complete = 1;
  69        current_req = req->next;
  70        if (req->done) (*req->done)(req);
  71        adb_iop_state = state;
  72}
  73
  74/*
  75 * Completion routine for ADB commands sent to the IOP.
  76 *
  77 * This will be called when a packet has been successfully sent.
  78 */
  79
  80static void adb_iop_complete(struct iop_msg *msg)
  81{
  82        struct adb_request *req;
  83        unsigned long flags;
  84
  85        local_irq_save(flags);
  86
  87        req = current_req;
  88        if ((adb_iop_state == sending) && req && req->reply_expected) {
  89                adb_iop_state = awaiting_reply;
  90        }
  91
  92        local_irq_restore(flags);
  93}
  94
  95/*
  96 * Listen for ADB messages from the IOP.
  97 *
  98 * This will be called when unsolicited messages (usually replies to TALK
  99 * commands or autopoll packets) are received.
 100 */
 101
 102static void adb_iop_listen(struct iop_msg *msg)
 103{
 104        struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
 105        struct adb_request *req;
 106        unsigned long flags;
 107#ifdef DEBUG_ADB_IOP
 108        int i;
 109#endif
 110
 111        local_irq_save(flags);
 112
 113        req = current_req;
 114
 115#ifdef DEBUG_ADB_IOP
 116        printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req,
 117                (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
 118        for (i = 0; i < amsg->count; i++)
 119                printk(" %02X", (uint) amsg->data[i]);
 120        printk("\n");
 121#endif
 122
 123        /* Handle a timeout. Timeout packets seem to occur even after */
 124        /* we've gotten a valid reply to a TALK, so I'm assuming that */
 125        /* a "timeout" is actually more like an "end-of-data" signal. */
 126        /* We need to send back a timeout packet to the IOP to shut   */
 127        /* it up, plus complete the current request, if any.          */
 128
 129        if (amsg->flags & ADB_IOP_TIMEOUT) {
 130                msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL;
 131                msg->reply[1] = 0;
 132                msg->reply[2] = 0;
 133                if (req && (adb_iop_state != idle)) {
 134                        adb_iop_end_req(req, idle);
 135                }
 136        } else {
 137                /* TODO: is it possible for more than one chunk of data  */
 138                /*       to arrive before the timeout? If so we need to */
 139                /*       use reply_ptr here like the other drivers do.  */
 140                if ((adb_iop_state == awaiting_reply) &&
 141                    (amsg->flags & ADB_IOP_EXPLICIT)) {
 142                        req->reply_len = amsg->count + 1;
 143                        memcpy(req->reply, &amsg->cmd, req->reply_len);
 144                } else {
 145                        adb_input(&amsg->cmd, amsg->count + 1,
 146                                  amsg->flags & ADB_IOP_AUTOPOLL);
 147                }
 148                memcpy(msg->reply, msg->message, IOP_MSG_LEN);
 149        }
 150        iop_complete_message(msg);
 151        local_irq_restore(flags);
 152}
 153
 154/*
 155 * Start sending an ADB packet, IOP style
 156 *
 157 * There isn't much to do other than hand the packet over to the IOP
 158 * after encapsulating it in an adb_iopmsg.
 159 */
 160
 161static void adb_iop_start(void)
 162{
 163        unsigned long flags;
 164        struct adb_request *req;
 165        struct adb_iopmsg amsg;
 166#ifdef DEBUG_ADB_IOP
 167        int i;
 168#endif
 169
 170        /* get the packet to send */
 171        req = current_req;
 172        if (!req) return;
 173
 174        local_irq_save(flags);
 175
 176#ifdef DEBUG_ADB_IOP
 177        printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes);
 178        for (i = 0 ; i < req->nbytes ; i++)
 179                printk(" %02X", (uint) req->data[i]);
 180        printk("\n");
 181#endif
 182
 183        /* The IOP takes MacII-style packets, so */
 184        /* strip the initial ADB_PACKET byte.    */
 185
 186        amsg.flags = ADB_IOP_EXPLICIT;
 187        amsg.count = req->nbytes - 2;
 188
 189        /* amsg.data immediately follows amsg.cmd, effectively making */
 190        /* amsg.cmd a pointer to the beginning of a full ADB packet.  */
 191        memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
 192
 193        req->sent = 1;
 194        adb_iop_state = sending;
 195        local_irq_restore(flags);
 196
 197        /* Now send it. The IOP manager will call adb_iop_complete */
 198        /* when the packet has been sent.                          */
 199
 200        iop_send_message(ADB_IOP, ADB_CHAN, req,
 201                         sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
 202}
 203
 204int adb_iop_probe(void)
 205{
 206        if (!iop_ism_present) return -ENODEV;
 207        return 0;
 208}
 209
 210int adb_iop_init(void)
 211{
 212        printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
 213        iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
 214        return 0;
 215}
 216
 217int adb_iop_send_request(struct adb_request *req, int sync)
 218{
 219        int err;
 220
 221        err = adb_iop_write(req);
 222        if (err) return err;
 223
 224        if (sync) {
 225                while (!req->complete) adb_iop_poll();
 226        }
 227        return 0;
 228}
 229
 230static int adb_iop_write(struct adb_request *req)
 231{
 232        unsigned long flags;
 233
 234        if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
 235                req->complete = 1;
 236                return -EINVAL;
 237        }
 238
 239        local_irq_save(flags);
 240
 241        req->next = NULL;
 242        req->sent = 0;
 243        req->complete = 0;
 244        req->reply_len = 0;
 245
 246        if (current_req != 0) {
 247                last_req->next = req;
 248                last_req = req;
 249        } else {
 250                current_req = req;
 251                last_req = req;
 252        }
 253
 254        local_irq_restore(flags);
 255        if (adb_iop_state == idle) adb_iop_start();
 256        return 0;
 257}
 258
 259int adb_iop_autopoll(int devs)
 260{
 261        /* TODO: how do we enable/disable autopoll? */
 262        return 0;
 263}
 264
 265void adb_iop_poll(void)
 266{
 267        if (adb_iop_state == idle) adb_iop_start();
 268        iop_ism_irq(0, (void *) ADB_IOP);
 269}
 270
 271int adb_iop_reset_bus(void)
 272{
 273        struct adb_request req = {
 274                .reply_expected = 0,
 275                .nbytes = 2,
 276                .data = { ADB_PACKET, 0 },
 277        };
 278
 279        adb_iop_write(&req);
 280        while (!req.complete) {
 281                adb_iop_poll();
 282                schedule();
 283        }
 284
 285        return 0;
 286}
 287
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.