0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/types.h>
0013 #include <linux/kernel.h>
0014 #include <linux/mm.h>
0015 #include <linux/delay.h>
0016 #include <linux/init.h>
0017
0018 #include <asm/macintosh.h>
0019 #include <asm/macints.h>
0020 #include <asm/mac_iop.h>
0021 #include <asm/adb_iop.h>
0022 #include <asm/unaligned.h>
0023
0024 #include <linux/adb.h>
0025
0026 static struct adb_request *current_req;
0027 static struct adb_request *last_req;
0028 static unsigned int autopoll_devs;
0029 static u8 autopoll_addr;
0030
0031 static enum adb_iop_state {
0032 idle,
0033 sending,
0034 awaiting_reply
0035 } adb_iop_state;
0036
0037 static void adb_iop_start(void);
0038 static int adb_iop_probe(void);
0039 static int adb_iop_init(void);
0040 static int adb_iop_send_request(struct adb_request *, int);
0041 static int adb_iop_write(struct adb_request *);
0042 static int adb_iop_autopoll(int);
0043 static void adb_iop_poll(void);
0044 static int adb_iop_reset_bus(void);
0045
0046
0047 #define ADDR_MASK 0xF0
0048 #define OP_MASK 0x0C
0049 #define TALK 0x0C
0050
0051 struct adb_driver adb_iop_driver = {
0052 .name = "ISM IOP",
0053 .probe = adb_iop_probe,
0054 .init = adb_iop_init,
0055 .send_request = adb_iop_send_request,
0056 .autopoll = adb_iop_autopoll,
0057 .poll = adb_iop_poll,
0058 .reset_bus = adb_iop_reset_bus
0059 };
0060
0061 static void adb_iop_done(void)
0062 {
0063 struct adb_request *req = current_req;
0064
0065 adb_iop_state = idle;
0066
0067 req->complete = 1;
0068 current_req = req->next;
0069 if (req->done)
0070 (*req->done)(req);
0071
0072 if (adb_iop_state == idle)
0073 adb_iop_start();
0074 }
0075
0076
0077
0078
0079
0080
0081
0082 static void adb_iop_complete(struct iop_msg *msg)
0083 {
0084 unsigned long flags;
0085
0086 local_irq_save(flags);
0087
0088 adb_iop_state = awaiting_reply;
0089
0090 local_irq_restore(flags);
0091 }
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 static void adb_iop_listen(struct iop_msg *msg)
0102 {
0103 struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
0104 u8 addr = (amsg->cmd & ADDR_MASK) >> 4;
0105 u8 op = amsg->cmd & OP_MASK;
0106 unsigned long flags;
0107 bool req_done = false;
0108
0109 local_irq_save(flags);
0110
0111
0112
0113
0114 if (op == TALK && ((1 << addr) & autopoll_devs))
0115 autopoll_addr = addr;
0116
0117 switch (amsg->flags & (ADB_IOP_EXPLICIT |
0118 ADB_IOP_AUTOPOLL |
0119 ADB_IOP_TIMEOUT)) {
0120 case ADB_IOP_EXPLICIT:
0121 case ADB_IOP_EXPLICIT | ADB_IOP_TIMEOUT:
0122 if (adb_iop_state == awaiting_reply) {
0123 struct adb_request *req = current_req;
0124
0125 if (req->reply_expected) {
0126 req->reply_len = amsg->count + 1;
0127 memcpy(req->reply, &amsg->cmd, req->reply_len);
0128 }
0129
0130 req_done = true;
0131 }
0132 break;
0133 case ADB_IOP_AUTOPOLL:
0134 if (((1 << addr) & autopoll_devs) &&
0135 amsg->cmd == ADB_READREG(addr, 0))
0136 adb_input(&amsg->cmd, amsg->count + 1, 1);
0137 break;
0138 }
0139 msg->reply[0] = autopoll_addr ? ADB_IOP_AUTOPOLL : 0;
0140 msg->reply[1] = 0;
0141 msg->reply[2] = autopoll_addr ? ADB_READREG(autopoll_addr, 0) : 0;
0142 iop_complete_message(msg);
0143
0144 if (req_done)
0145 adb_iop_done();
0146
0147 local_irq_restore(flags);
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157 static void adb_iop_start(void)
0158 {
0159 struct adb_request *req;
0160 struct adb_iopmsg amsg;
0161
0162
0163 req = current_req;
0164 if (!req)
0165 return;
0166
0167
0168
0169
0170 amsg.flags = ADB_IOP_EXPLICIT;
0171 amsg.count = req->nbytes - 2;
0172
0173
0174
0175
0176 memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
0177
0178 req->sent = 1;
0179 adb_iop_state = sending;
0180
0181
0182
0183
0184 iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
0185 adb_iop_complete);
0186 }
0187
0188 static int adb_iop_probe(void)
0189 {
0190 if (!iop_ism_present)
0191 return -ENODEV;
0192 return 0;
0193 }
0194
0195 static int adb_iop_init(void)
0196 {
0197 pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
0198 iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
0199 return 0;
0200 }
0201
0202 static int adb_iop_send_request(struct adb_request *req, int sync)
0203 {
0204 int err;
0205
0206 err = adb_iop_write(req);
0207 if (err)
0208 return err;
0209
0210 if (sync) {
0211 while (!req->complete)
0212 adb_iop_poll();
0213 }
0214 return 0;
0215 }
0216
0217 static int adb_iop_write(struct adb_request *req)
0218 {
0219 unsigned long flags;
0220
0221 if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
0222 req->complete = 1;
0223 return -EINVAL;
0224 }
0225
0226 req->next = NULL;
0227 req->sent = 0;
0228 req->complete = 0;
0229 req->reply_len = 0;
0230
0231 local_irq_save(flags);
0232
0233 if (current_req) {
0234 last_req->next = req;
0235 last_req = req;
0236 } else {
0237 current_req = req;
0238 last_req = req;
0239 }
0240
0241 if (adb_iop_state == idle)
0242 adb_iop_start();
0243
0244 local_irq_restore(flags);
0245
0246 return 0;
0247 }
0248
0249 static void adb_iop_set_ap_complete(struct iop_msg *msg)
0250 {
0251 struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
0252
0253 autopoll_devs = get_unaligned_be16(amsg->data);
0254 if (autopoll_devs & (1 << autopoll_addr))
0255 return;
0256 autopoll_addr = autopoll_devs ? (ffs(autopoll_devs) - 1) : 0;
0257 }
0258
0259 static int adb_iop_autopoll(int devs)
0260 {
0261 struct adb_iopmsg amsg;
0262 unsigned long flags;
0263 unsigned int mask = (unsigned int)devs & 0xFFFE;
0264
0265 local_irq_save(flags);
0266
0267 amsg.flags = ADB_IOP_SET_AUTOPOLL | (mask ? ADB_IOP_AUTOPOLL : 0);
0268 amsg.count = 2;
0269 amsg.cmd = 0;
0270 put_unaligned_be16(mask, amsg.data);
0271
0272 iop_send_message(ADB_IOP, ADB_CHAN, NULL, sizeof(amsg), (__u8 *)&amsg,
0273 adb_iop_set_ap_complete);
0274
0275 local_irq_restore(flags);
0276
0277 return 0;
0278 }
0279
0280 static void adb_iop_poll(void)
0281 {
0282 iop_ism_irq_poll(ADB_IOP);
0283 }
0284
0285 static int adb_iop_reset_bus(void)
0286 {
0287 struct adb_request req;
0288
0289
0290 adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
0291 adb_iop_send_request(&req, 1);
0292
0293
0294 mdelay(3);
0295
0296 return 0;
0297 }