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
  12#include <linux/types.h>
  13#include <linux/kernel.h>
  14#include <linux/mm.h>
  15#include <linux/delay.h>
  16#include <linux/init.h>
  17
  18#include <asm/macintosh.h>
  19#include <asm/macints.h>
  20#include <asm/mac_iop.h>
  21#include <asm/adb_iop.h>
  22#include <asm/unaligned.h>
  23
  24#include <linux/adb.h>
  25
  26static struct adb_request *current_req;
  27static struct adb_request *last_req;
  28static unsigned int autopoll_devs;
  29static u8 autopoll_addr;
  30
  31static enum adb_iop_state {
  32        idle,
  33        sending,
  34        awaiting_reply
  35} adb_iop_state;
  36
  37static void adb_iop_start(void);
  38static int adb_iop_probe(void);
  39static int adb_iop_init(void);
  40static int adb_iop_send_request(struct adb_request *, int);
  41static int adb_iop_write(struct adb_request *);
  42static int adb_iop_autopoll(int);
  43static void adb_iop_poll(void);
  44static int adb_iop_reset_bus(void);
  45
  46/* ADB command byte structure */
  47#define ADDR_MASK       0xF0
  48#define OP_MASK         0x0C
  49#define TALK            0x0C
  50
  51struct adb_driver adb_iop_driver = {
  52        .name         = "ISM IOP",
  53        .probe        = adb_iop_probe,
  54        .init         = adb_iop_init,
  55        .send_request = adb_iop_send_request,
  56        .autopoll     = adb_iop_autopoll,
  57        .poll         = adb_iop_poll,
  58        .reset_bus    = adb_iop_reset_bus
  59};
  60
  61static void adb_iop_done(void)
  62{
  63        struct adb_request *req = current_req;
  64
  65        adb_iop_state = idle;
  66
  67        req->complete = 1;
  68        current_req = req->next;
  69        if (req->done)
  70                (*req->done)(req);
  71
  72        if (adb_iop_state == idle)
  73                adb_iop_start();
  74}
  75
  76/*
  77 * Completion routine for ADB commands sent to the IOP.
  78 *
  79 * This will be called when a packet has been successfully sent.
  80 */
  81
  82static void adb_iop_complete(struct iop_msg *msg)
  83{
  84        unsigned long flags;
  85
  86        local_irq_save(flags);
  87
  88        adb_iop_state = awaiting_reply;
  89
  90        local_irq_restore(flags);
  91}
  92
  93/*
  94 * Listen for ADB messages from the IOP.
  95 *
  96 * This will be called when unsolicited IOP messages are received.
  97 * These IOP messages can carry ADB autopoll responses and also occur
  98 * after explicit ADB commands.
  99 */
 100
 101static void adb_iop_listen(struct iop_msg *msg)
 102{
 103        struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
 104        u8 addr = (amsg->cmd & ADDR_MASK) >> 4;
 105        u8 op = amsg->cmd & OP_MASK;
 106        unsigned long flags;
 107        bool req_done = false;
 108
 109        local_irq_save(flags);
 110
 111        /* Responses to Talk commands may be unsolicited as they are
 112         * produced when the IOP polls devices. They are mostly timeouts.
 113         */
 114        if (op == TALK && ((1 << addr) & autopoll_devs))
 115                autopoll_addr = addr;
 116
 117        switch (amsg->flags & (ADB_IOP_EXPLICIT |
 118                               ADB_IOP_AUTOPOLL |
 119                               ADB_IOP_TIMEOUT)) {
 120        case ADB_IOP_EXPLICIT:
 121        case ADB_IOP_EXPLICIT | ADB_IOP_TIMEOUT:
 122                if (adb_iop_state == awaiting_reply) {
 123                        struct adb_request *req = current_req;
 124
 125                        if (req->reply_expected) {
 126                                req->reply_len = amsg->count + 1;
 127                                memcpy(req->reply, &amsg->cmd, req->reply_len);
 128                        }
 129
 130                        req_done = true;
 131                }
 132                break;
 133        case ADB_IOP_AUTOPOLL:
 134                if (((1 << addr) & autopoll_devs) &&
 135                    amsg->cmd == ADB_READREG(addr, 0))
 136                        adb_input(&amsg->cmd, amsg->count + 1, 1);
 137                break;
 138        }
 139        msg->reply[0] = autopoll_addr ? ADB_IOP_AUTOPOLL : 0;
 140        msg->reply[1] = 0;
 141        msg->reply[2] = autopoll_addr ? ADB_READREG(autopoll_addr, 0) : 0;
 142        iop_complete_message(msg);
 143
 144        if (req_done)
 145                adb_iop_done();
 146
 147        local_irq_restore(flags);
 148}
 149
 150/*
 151 * Start sending an ADB packet, IOP style
 152 *
 153 * There isn't much to do other than hand the packet over to the IOP
 154 * after encapsulating it in an adb_iopmsg.
 155 */
 156
 157static void adb_iop_start(void)
 158{
 159        struct adb_request *req;
 160        struct adb_iopmsg amsg;
 161
 162        /* get the packet to send */
 163        req = current_req;
 164        if (!req)
 165                return;
 166
 167        /* The IOP takes MacII-style packets, so strip the initial
 168         * ADB_PACKET byte.
 169         */
 170        amsg.flags = ADB_IOP_EXPLICIT;
 171        amsg.count = req->nbytes - 2;
 172
 173        /* amsg.data immediately follows amsg.cmd, effectively making
 174         * &amsg.cmd a pointer to the beginning of a full ADB packet.
 175         */
 176        memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
 177
 178        req->sent = 1;
 179        adb_iop_state = sending;
 180
 181        /* Now send it. The IOP manager will call adb_iop_complete
 182         * when the message has been sent.
 183         */
 184        iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
 185                         adb_iop_complete);
 186}
 187
 188static int adb_iop_probe(void)
 189{
 190        if (!iop_ism_present)
 191                return -ENODEV;
 192        return 0;
 193}
 194
 195static int adb_iop_init(void)
 196{
 197        pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
 198        iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
 199        return 0;
 200}
 201
 202static int adb_iop_send_request(struct adb_request *req, int sync)
 203{
 204        int err;
 205
 206        err = adb_iop_write(req);
 207        if (err)
 208                return err;
 209
 210        if (sync) {
 211                while (!req->complete)
 212                        adb_iop_poll();
 213        }
 214        return 0;
 215}
 216
 217static int adb_iop_write(struct adb_request *req)
 218{
 219        unsigned long flags;
 220
 221        if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
 222                req->complete = 1;
 223                return -EINVAL;
 224        }
 225
 226        req->next = NULL;
 227        req->sent = 0;
 228        req->complete = 0;
 229        req->reply_len = 0;
 230
 231        local_irq_save(flags);
 232
 233        if (current_req) {
 234                last_req->next = req;
 235                last_req = req;
 236        } else {
 237                current_req = req;
 238                last_req = req;
 239        }
 240
 241        if (adb_iop_state == idle)
 242                adb_iop_start();
 243
 244        local_irq_restore(flags);
 245
 246        return 0;
 247}
 248
 249static void adb_iop_set_ap_complete(struct iop_msg *msg)
 250{
 251        struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
 252
 253        autopoll_devs = get_unaligned_be16(amsg->data);
 254        if (autopoll_devs & (1 << autopoll_addr))
 255                return;
 256        autopoll_addr = autopoll_devs ? (ffs(autopoll_devs) - 1) : 0;
 257}
 258
 259static int adb_iop_autopoll(int devs)
 260{
 261        struct adb_iopmsg amsg;
 262        unsigned long flags;
 263        unsigned int mask = (unsigned int)devs & 0xFFFE;
 264
 265        local_irq_save(flags);
 266
 267        amsg.flags = ADB_IOP_SET_AUTOPOLL | (mask ? ADB_IOP_AUTOPOLL : 0);
 268        amsg.count = 2;
 269        amsg.cmd = 0;
 270        put_unaligned_be16(mask, amsg.data);
 271
 272        iop_send_message(ADB_IOP, ADB_CHAN, NULL, sizeof(amsg), (__u8 *)&amsg,
 273                         adb_iop_set_ap_complete);
 274
 275        local_irq_restore(flags);
 276
 277        return 0;
 278}
 279
 280static void adb_iop_poll(void)
 281{
 282        iop_ism_irq_poll(ADB_IOP);
 283}
 284
 285static int adb_iop_reset_bus(void)
 286{
 287        struct adb_request req;
 288
 289        /* Command = 0, Address = ignored */
 290        adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
 291        adb_iop_send_request(&req, 1);
 292
 293        /* Don't want any more requests during the Global Reset low time. */
 294        mdelay(3);
 295
 296        return 0;
 297}
 298