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