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