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/macintosh.h> 23#include <asm/macints.h> 24#include <asm/mac_iop.h> 25#include <asm/mac_oss.h> 26#include <asm/adb_iop.h> 27 28#include <linux/adb.h> 29 30/*#define DEBUG_ADB_IOP*/ 31 32extern void iop_ism_irq(int, void *); 33 34static struct adb_request *current_req; 35static struct adb_request *last_req; 36#if 0 37static unsigned char reply_buff[16]; 38static unsigned char *reply_ptr; 39#endif 40 41static enum adb_iop_state { 42 idle, 43 sending, 44 awaiting_reply 45} adb_iop_state; 46 47static void adb_iop_start(void); 48static int adb_iop_probe(void); 49static int adb_iop_init(void); 50static int adb_iop_send_request(struct adb_request *, int); 51static int adb_iop_write(struct adb_request *); 52static int adb_iop_autopoll(int); 53static void adb_iop_poll(void); 54static int adb_iop_reset_bus(void); 55 56struct adb_driver adb_iop_driver = { 57 "ISM IOP", 58 adb_iop_probe, 59 adb_iop_init, 60 adb_iop_send_request, 61 adb_iop_autopoll, 62 adb_iop_poll, 63 adb_iop_reset_bus 64}; 65 66static void adb_iop_end_req(struct adb_request *req, int state) 67{ 68 req->complete = 1; 69 current_req = req->next; 70 if (req->done) (*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) return; 173 174 local_irq_save(flags); 175 176#ifdef DEBUG_ADB_IOP 177 printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes); 178 for (i = 0 ; i < req->nbytes ; i++) 179 printk(" %02X", (uint) req->data[i]); 180 printk("\n"); 181#endif 182 183 /* The IOP takes MacII-style packets, so */ 184 /* strip the initial ADB_PACKET byte. */ 185 186 amsg.flags = ADB_IOP_EXPLICIT; 187 amsg.count = req->nbytes - 2; 188 189 /* amsg.data immediately follows amsg.cmd, effectively making */ 190 /* amsg.cmd a pointer to the beginning of a full ADB packet. */ 191 memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1); 192 193 req->sent = 1; 194 adb_iop_state = sending; 195 local_irq_restore(flags); 196 197 /* Now send it. The IOP manager will call adb_iop_complete */ 198 /* when the packet has been sent. */ 199 200 iop_send_message(ADB_IOP, ADB_CHAN, req, 201 sizeof(amsg), (__u8 *) &amsg, adb_iop_complete); 202} 203 204int adb_iop_probe(void) 205{ 206 if (!iop_ism_present) return -ENODEV; 207 return 0; 208} 209 210int adb_iop_init(void) 211{ 212 printk("adb: IOP ISM driver v0.4 for Unified ADB.\n"); 213 iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB"); 214 return 0; 215} 216 217int adb_iop_send_request(struct adb_request *req, int sync) 218{ 219 int err; 220 221 err = adb_iop_write(req); 222 if (err) return err; 223 224 if (sync) { 225 while (!req->complete) adb_iop_poll(); 226 } 227 return 0; 228} 229 230static int adb_iop_write(struct adb_request *req) 231{ 232 unsigned long flags; 233 234 if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) { 235 req->complete = 1; 236 return -EINVAL; 237 } 238 239 local_irq_save(flags); 240 241 req->next = NULL; 242 req->sent = 0; 243 req->complete = 0; 244 req->reply_len = 0; 245 246 if (current_req != 0) { 247 last_req->next = req; 248 last_req = req; 249 } else { 250 current_req = req; 251 last_req = req; 252 } 253 254 local_irq_restore(flags); 255 if (adb_iop_state == idle) adb_iop_start(); 256 return 0; 257} 258 259int adb_iop_autopoll(int devs) 260{ 261 /* TODO: how do we enable/disable autopoll? */ 262 return 0; 263} 264 265void adb_iop_poll(void) 266{ 267 if (adb_iop_state == idle) adb_iop_start(); 268 iop_ism_irq(0, (void *) ADB_IOP); 269} 270 271int adb_iop_reset_bus(void) 272{ 273 struct adb_request req = { 274 .reply_expected = 0, 275 .nbytes = 2, 276 .data = { ADB_PACKET, 0 }, 277 }; 278 279 adb_iop_write(&req); 280 while (!req.complete) { 281 adb_iop_poll(); 282 schedule(); 283 } 284 285 return 0; 286} 287