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)
  70                (*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)
 173                return;
 174
 175        local_irq_save(flags);
 176
 177#ifdef DEBUG_ADB_IOP
 178        printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes);
 179        for (i = 0; i < req->nbytes; i++)
 180                printk(" %02X", (uint)req->data[i]);
 181        printk("\n");
 182#endif
 183
 184        /* The IOP takes MacII-style packets, so */
 185        /* strip the initial ADB_PACKET byte.    */
 186
 187        amsg.flags = ADB_IOP_EXPLICIT;
 188        amsg.count = req->nbytes - 2;
 189
 190        /* amsg.data immediately follows amsg.cmd, effectively making */
 191        /* amsg.cmd a pointer to the beginning of a full ADB packet.  */
 192        memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
 193
 194        req->sent = 1;
 195        adb_iop_state = sending;
 196        local_irq_restore(flags);
 197
 198        /* Now send it. The IOP manager will call adb_iop_complete */
 199        /* when the packet has been sent.                          */
 200
 201        iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
 202                         adb_iop_complete);
 203}
 204
 205int adb_iop_probe(void)
 206{
 207        if (!iop_ism_present)
 208                return -ENODEV;
 209        return 0;
 210}
 211
 212int adb_iop_init(void)
 213{
 214        pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
 215        iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
 216        return 0;
 217}
 218
 219int adb_iop_send_request(struct adb_request *req, int sync)
 220{
 221        int err;
 222
 223        err = adb_iop_write(req);
 224        if (err)
 225                return err;
 226
 227        if (sync) {
 228                while (!req->complete)
 229                        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        local_irq_save(flags);
 244
 245        req->next = NULL;
 246        req->sent = 0;
 247        req->complete = 0;
 248        req->reply_len = 0;
 249
 250        if (current_req != 0) {
 251                last_req->next = req;
 252                last_req = req;
 253        } else {
 254                current_req = req;
 255                last_req = req;
 256        }
 257
 258        local_irq_restore(flags);
 259
 260        if (adb_iop_state == idle)
 261                adb_iop_start();
 262        return 0;
 263}
 264
 265int adb_iop_autopoll(int devs)
 266{
 267        /* TODO: how do we enable/disable autopoll? */
 268        return 0;
 269}
 270
 271void adb_iop_poll(void)
 272{
 273        if (adb_iop_state == idle)
 274                adb_iop_start();
 275        iop_ism_irq_poll(ADB_IOP);
 276}
 277
 278int adb_iop_reset_bus(void)
 279{
 280        struct adb_request req = {
 281                .reply_expected = 0,
 282                .nbytes = 2,
 283                .data = { ADB_PACKET, 0 },
 284        };
 285
 286        adb_iop_write(&req);
 287        while (!req.complete) {
 288                adb_iop_poll();
 289                schedule();
 290        }
 291
 292        return 0;
 293}
 294