• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/macintosh/
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
37static enum adb_iop_state {
38    idle,
39    sending,
40    awaiting_reply
41} adb_iop_state;
42
43static void adb_iop_start(void);
44static int adb_iop_probe(void);
45static int adb_iop_init(void);
46static int adb_iop_send_request(struct adb_request *, int);
47static int adb_iop_write(struct adb_request *);
48static int adb_iop_autopoll(int);
49static void adb_iop_poll(void);
50static int adb_iop_reset_bus(void);
51
52struct adb_driver adb_iop_driver = {
53	"ISM IOP",
54	adb_iop_probe,
55	adb_iop_init,
56	adb_iop_send_request,
57	adb_iop_autopoll,
58	adb_iop_poll,
59	adb_iop_reset_bus
60};
61
62static void adb_iop_end_req(struct adb_request *req, int state)
63{
64	req->complete = 1;
65	current_req = req->next;
66	if (req->done) (*req->done)(req);
67	adb_iop_state = state;
68}
69
70/*
71 * Completion routine for ADB commands sent to the IOP.
72 *
73 * This will be called when a packet has been successfully sent.
74 */
75
76static void adb_iop_complete(struct iop_msg *msg)
77{
78	struct adb_request *req;
79	uint flags;
80
81	local_irq_save(flags);
82
83	req = current_req;
84	if ((adb_iop_state == sending) && req && req->reply_expected) {
85		adb_iop_state = awaiting_reply;
86	}
87
88	local_irq_restore(flags);
89}
90
91/*
92 * Listen for ADB messages from the IOP.
93 *
94 * This will be called when unsolicited messages (usually replies to TALK
95 * commands or autopoll packets) are received.
96 */
97
98static void adb_iop_listen(struct iop_msg *msg)
99{
100	struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
101	struct adb_request *req;
102	uint flags;
103#ifdef DEBUG_ADB_IOP
104	int i;
105#endif
106
107	local_irq_save(flags);
108
109	req = current_req;
110
111#ifdef DEBUG_ADB_IOP
112	printk("adb_iop_listen %p: rcvd packet, %d bytes: %02X %02X", req,
113		(uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
114	for (i = 0; i < amsg->count; i++)
115		printk(" %02X", (uint) amsg->data[i]);
116	printk("\n");
117#endif
118
119	/* Handle a timeout. Timeout packets seem to occur even after */
120	/* we've gotten a valid reply to a TALK, so I'm assuming that */
121	/* a "timeout" is actually more like an "end-of-data" signal. */
122	/* We need to send back a timeout packet to the IOP to shut   */
123	/* it up, plus complete the current request, if any.          */
124
125	if (amsg->flags & ADB_IOP_TIMEOUT) {
126		msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL;
127		msg->reply[1] = 0;
128		msg->reply[2] = 0;
129		if (req && (adb_iop_state != idle)) {
130			adb_iop_end_req(req, idle);
131		}
132	} else {
133		/* TODO: is it possible for more than one chunk of data  */
134		/*       to arrive before the timeout? If so we need to */
135		/*       use reply_ptr here like the other drivers do.  */
136		if ((adb_iop_state == awaiting_reply) &&
137		    (amsg->flags & ADB_IOP_EXPLICIT)) {
138			req->reply_len = amsg->count + 1;
139			memcpy(req->reply, &amsg->cmd, req->reply_len);
140		} else {
141			adb_input(&amsg->cmd, amsg->count + 1,
142				  amsg->flags & ADB_IOP_AUTOPOLL);
143		}
144		memcpy(msg->reply, msg->message, IOP_MSG_LEN);
145	}
146	iop_complete_message(msg);
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	unsigned long flags;
160	struct adb_request *req;
161	struct adb_iopmsg amsg;
162#ifdef DEBUG_ADB_IOP
163	int i;
164#endif
165
166	/* get the packet to send */
167	req = current_req;
168	if (!req) return;
169
170	local_irq_save(flags);
171
172#ifdef DEBUG_ADB_IOP
173	printk("adb_iop_start %p: sending packet, %d bytes:", req, req->nbytes);
174	for (i = 0 ; i < req->nbytes ; i++)
175		printk(" %02X", (uint) req->data[i]);
176	printk("\n");
177#endif
178
179	/* The IOP takes MacII-style packets, so */
180	/* strip the initial ADB_PACKET byte.    */
181
182	amsg.flags = ADB_IOP_EXPLICIT;
183	amsg.count = req->nbytes - 2;
184
185	/* amsg.data immediately follows amsg.cmd, effectively making */
186	/* amsg.cmd a pointer to the beginning of a full ADB packet.  */
187	memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
188
189	req->sent = 1;
190	adb_iop_state = sending;
191	local_irq_restore(flags);
192
193	/* Now send it. The IOP manager will call adb_iop_complete */
194	/* when the packet has been sent.                          */
195
196	iop_send_message(ADB_IOP, ADB_CHAN, req,
197			 sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
198}
199
200int adb_iop_probe(void)
201{
202	if (!iop_ism_present) return -ENODEV;
203	return 0;
204}
205
206int adb_iop_init(void)
207{
208	printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
209	iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
210	return 0;
211}
212
213int adb_iop_send_request(struct adb_request *req, int sync)
214{
215	int err;
216
217	err = adb_iop_write(req);
218	if (err) return err;
219
220	if (sync) {
221		while (!req->complete) adb_iop_poll();
222	}
223	return 0;
224}
225
226static int adb_iop_write(struct adb_request *req)
227{
228	unsigned long flags;
229
230	if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
231		req->complete = 1;
232		return -EINVAL;
233	}
234
235	local_irq_save(flags);
236
237	req->next = NULL;
238	req->sent = 0;
239	req->complete = 0;
240	req->reply_len = 0;
241
242	if (current_req != 0) {
243		last_req->next = req;
244		last_req = req;
245	} else {
246		current_req = req;
247		last_req = req;
248	}
249
250	local_irq_restore(flags);
251	if (adb_iop_state == idle) adb_iop_start();
252	return 0;
253}
254
255int adb_iop_autopoll(int devs)
256{
257	/* TODO: how do we enable/disable autopoll? */
258	return 0;
259}
260
261void adb_iop_poll(void)
262{
263	if (adb_iop_state == idle) adb_iop_start();
264	iop_ism_irq(0, (void *) ADB_IOP);
265}
266
267int adb_iop_reset_bus(void)
268{
269	struct adb_request req = {
270		.reply_expected = 0,
271		.nbytes = 2,
272		.data = { ADB_PACKET, 0 },
273	};
274
275	adb_iop_write(&req);
276	while (!req.complete) {
277		adb_iop_poll();
278		schedule();
279	}
280
281	return 0;
282}
283