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