11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I/O Processor (IOP) ADB Driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org) 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on via-cuda.c by Paul Mackerras. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1999-07-01 (jmt) - First implementation for new driver architecture. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1999-07-31 (jmt) - First working version. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Implement SRQ handling. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/macintosh.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/macints.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mac_iop.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mac_oss.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/adb_iop.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/adb.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*#define DEBUG_ADB_IOP*/ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 327d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsextern void iop_ism_irq(int, void *); 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct adb_request *current_req; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct adb_request *last_req; 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char reply_buff[16]; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char *reply_ptr; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic enum adb_iop_state { 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idle, 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sending, 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds awaiting_reply 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} adb_iop_state; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adb_iop_start(void); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_probe(void); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_init(void); 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_send_request(struct adb_request *, int); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_write(struct adb_request *); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_autopoll(int); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adb_iop_poll(void); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_reset_bus(void); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct adb_driver adb_iop_driver = { 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ISM IOP", 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_probe, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_init, 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_send_request, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_autopoll, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_poll, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_reset_bus 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adb_iop_end_req(struct adb_request *req, int state) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = 1; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_req = req->next; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->done) (*req->done)(req); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_state = state; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Completion routine for ADB commands sent to the IOP. 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will be called when a packet has been successfully sent. 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 807d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void adb_iop_complete(struct iop_msg *msg) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_request *req; 8338b7a2ae0ad3e29e1881b82c0f421ba5db148e3dGeert Uytterhoeven unsigned long flags; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = current_req; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((adb_iop_state == sending) && req && req->reply_expected) { 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_state = awaiting_reply; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Listen for ADB messages from the IOP. 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will be called when unsolicited messages (usually replies to TALK 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * commands or autopoll packets) are received. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1027d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void adb_iop_listen(struct iop_msg *msg) 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_request *req; 10638b7a2ae0ad3e29e1881b82c0f421ba5db148e3dGeert Uytterhoeven unsigned long flags; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ADB_IOP 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = current_req; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ADB_IOP 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req, 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < amsg->count; i++) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %02X", (uint) amsg->data[i]); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle a timeout. Timeout packets seem to occur even after */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we've gotten a valid reply to a TALK, so I'm assuming that */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* a "timeout" is actually more like an "end-of-data" signal. */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We need to send back a timeout packet to the IOP to shut */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* it up, plus complete the current request, if any. */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amsg->flags & ADB_IOP_TIMEOUT) { 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->reply[1] = 0; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->reply[2] = 0; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req && (adb_iop_state != idle)) { 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_end_req(req, idle); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO: is it possible for more than one chunk of data */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* to arrive before the timeout? If so we need to */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use reply_ptr here like the other drivers do. */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((adb_iop_state == awaiting_reply) && 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (amsg->flags & ADB_IOP_EXPLICIT)) { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->reply_len = amsg->count + 1; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(req->reply, &amsg->cmd, req->reply_len); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1457d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells adb_input(&amsg->cmd, amsg->count + 1, 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amsg->flags & ADB_IOP_AUTOPOLL); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(msg->reply, msg->message, IOP_MSG_LEN); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iop_complete_message(msg); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start sending an ADB packet, IOP style 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There isn't much to do other than hand the packet over to the IOP 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after encapsulating it in an adb_iopmsg. 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void adb_iop_start(void) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_request *req; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_iopmsg amsg; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ADB_IOP 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get the packet to send */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = current_req; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) return; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ADB_IOP 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < req->nbytes ; i++) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %02X", (uint) req->data[i]); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The IOP takes MacII-style packets, so */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* strip the initial ADB_PACKET byte. */ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amsg.flags = ADB_IOP_EXPLICIT; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amsg.count = req->nbytes - 2; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* amsg.data immediately follows amsg.cmd, effectively making */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* amsg.cmd a pointer to the beginning of a full ADB packet. */ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->sent = 1; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_state = sending; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now send it. The IOP manager will call adb_iop_complete */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* when the packet has been sent. */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iop_send_message(ADB_IOP, ADB_CHAN, req, 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(amsg), (__u8 *) &amsg, adb_iop_complete); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adb_iop_probe(void) 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!iop_ism_present) return -ENODEV; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adb_iop_init(void) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("adb: IOP ISM driver v0.4 for Unified ADB.\n"); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB"); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adb_iop_send_request(struct adb_request *req, int sync) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = adb_iop_write(req); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) return err; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sync) { 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!req->complete) adb_iop_poll(); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int adb_iop_write(struct adb_request *req) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) { 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = 1; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241a5d361fc24b75ea51e219367ee32c64422a2134fAl Viro req->next = NULL; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->sent = 0; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = 0; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->reply_len = 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current_req != 0) { 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_req->next = req; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_req = req; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current_req = req; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_req = req; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adb_iop_state == idle) adb_iop_start(); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adb_iop_autopoll(int devs) 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO: how do we enable/disable autopoll? */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid adb_iop_poll(void) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (adb_iop_state == idle) adb_iop_start(); 2682850bc273776cbb1b510c5828e9e456dffb50a32Al Viro iop_ism_irq(0, (void *) ADB_IOP); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint adb_iop_reset_bus(void) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct adb_request req = { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .reply_expected = 0, 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .nbytes = 2, 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .data = { ADB_PACKET, 0 }, 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_write(&req); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!req.complete) { 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adb_iop_poll(); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 287