xref: /freebsd/sys/dev/adb/adb_bus.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
1 /*-
2  * Copyright (C) 2008 Nathan Whitehorn
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/module.h>
32 #include <sys/bus.h>
33 #include <sys/conf.h>
34 #include <sys/kernel.h>
35 
36 #include <machine/bus.h>
37 
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40 
41 #include "adb.h"
42 #include "adbvar.h"
43 
44 static int adb_bus_probe(device_t dev);
45 static int adb_bus_attach(device_t dev);
46 static int adb_bus_detach(device_t dev);
47 static void adb_bus_enumerate(void *xdev);
48 static void adb_probe_nomatch(device_t dev, device_t child);
49 static int adb_print_child(device_t dev, device_t child);
50 
51 static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data, u_char *reply);
52 
53 static char *adb_device_string[] = {
54 	"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
55 };
56 
57 static device_method_t adb_bus_methods[] = {
58 	/* Device interface */
59 	DEVMETHOD(device_probe,		adb_bus_probe),
60 	DEVMETHOD(device_attach,	adb_bus_attach),
61 	DEVMETHOD(device_detach,        adb_bus_detach),
62         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
63         DEVMETHOD(device_suspend,       bus_generic_suspend),
64         DEVMETHOD(device_resume,        bus_generic_resume),
65 
66 	/* Bus Interface */
67         DEVMETHOD(bus_probe_nomatch,    adb_probe_nomatch),
68         DEVMETHOD(bus_print_child,	adb_print_child),
69 
70 	{ 0, 0 },
71 };
72 
73 driver_t adb_driver = {
74 	"adb",
75 	adb_bus_methods,
76 	sizeof(struct adb_softc),
77 };
78 
79 devclass_t adb_devclass;
80 
81 static int
82 adb_bus_probe(device_t dev)
83 {
84 	device_set_desc(dev, "Apple Desktop Bus");
85 	return (0);
86 }
87 
88 static int
89 adb_bus_attach(device_t dev)
90 {
91 	struct adb_softc *sc = device_get_softc(dev);
92 	sc->enum_hook.ich_func = adb_bus_enumerate;
93 	sc->enum_hook.ich_arg = dev;
94 
95 	/*
96 	 * We should wait until interrupts are enabled to try to probe
97 	 * the bus. Enumerating the ADB involves receiving packets,
98 	 * which works best with interrupts enabled.
99 	 */
100 
101 	if (config_intrhook_establish(&sc->enum_hook) != 0)
102 		return (ENOMEM);
103 
104 	return (0);
105 }
106 
107 static void
108 adb_bus_enumerate(void *xdev)
109 {
110 	device_t dev = (device_t)xdev;
111 
112 	struct adb_softc *sc = device_get_softc(dev);
113 	uint8_t i, next_free;
114 	uint16_t r3;
115 
116 	sc->sc_dev = dev;
117 	sc->parent = device_get_parent(dev);
118 
119 	sc->packet_reply = 0;
120 	sc->autopoll_mask = 0;
121 	sc->sync_packet = 0xffff;
122 
123 	/* Initialize devinfo */
124 	for (i = 0; i < 16; i++) {
125 		sc->devinfo[i].address = i;
126 		sc->devinfo[i].default_address = 0;
127 	}
128 
129 	/* Reset ADB bus */
130 	adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
131 	DELAY(1500);
132 
133 	/* Enumerate bus */
134 	next_free = 8;
135 
136 	for (i = 1; i <= 7; i++) {
137 	    int8_t first_relocated = -1;
138 	    int reply = 0;
139 
140 	    do {
141 		reply = adb_send_raw_packet_sync(dev,i,
142 			    ADB_COMMAND_TALK,3,0,NULL,NULL);
143 
144 		if (reply) {
145 			/* If we got a response, relocate to next_free */
146 			r3 = sc->devinfo[i].register3;
147 			r3 &= 0xf000;
148 			r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
149 			r3 |= 0x00fe;
150 
151 			adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
152 			    sizeof(uint16_t),(u_char *)(&r3),NULL);
153 
154 			adb_send_raw_packet_sync(dev,next_free,
155 			    ADB_COMMAND_TALK,3,0,NULL,NULL);
156 
157 			sc->devinfo[next_free].default_address = i;
158 			if (first_relocated < 0)
159 				first_relocated = next_free;
160 
161 			next_free++;
162 		} else if (first_relocated > 0) {
163 			/* Collisions removed, relocate first device back */
164 
165 			r3 = sc->devinfo[i].register3;
166 			r3 &= 0xf000;
167 			r3 |= ((uint16_t)(i) & 0x000f) << 8;
168 
169 			adb_send_raw_packet_sync(dev,first_relocated,
170 			    ADB_COMMAND_LISTEN,3,
171 			    sizeof(uint16_t),(u_char *)(&r3),NULL);
172 			adb_send_raw_packet_sync(dev,i,
173 			    ADB_COMMAND_TALK,3,0,NULL,NULL);
174 
175 			sc->devinfo[i].default_address = i;
176 			sc->devinfo[(int)(first_relocated)].default_address = 0;
177 			break;
178 		}
179 	    } while (reply);
180 	}
181 
182 	for (i = 0; i < 16; i++) {
183 		if (sc->devinfo[i].default_address) {
184 			sc->children[i] = device_add_child(dev, NULL, -1);
185 			device_set_ivars(sc->children[i], &sc->devinfo[i]);
186 		}
187 	}
188 
189 	bus_generic_attach(dev);
190 
191 	config_intrhook_disestablish(&sc->enum_hook);
192 }
193 
194 static int adb_bus_detach(device_t dev)
195 {
196 	return (bus_generic_detach(dev));
197 }
198 
199 
200 static void
201 adb_probe_nomatch(device_t dev, device_t child)
202 {
203 	struct adb_devinfo *dinfo;
204 
205 	if (bootverbose) {
206 		dinfo = device_get_ivars(child);
207 
208 		device_printf(dev,"ADB %s at device %d (no driver attached)\n",
209 		    adb_device_string[dinfo->default_address],dinfo->address);
210 	}
211 }
212 
213 u_int
214 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
215     u_char *data)
216 {
217 	struct adb_softc *sc = device_get_softc(dev);
218 	u_char addr = command >> 4;
219 
220 	if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
221 		memcpy(&sc->devinfo[addr].register3,data,2);
222 		sc->devinfo[addr].handler_id = data[1];
223 	}
224 
225 	if (sc->sync_packet == command)  {
226 		memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
227 		atomic_store_rel_int(&sc->packet_reply,len + 1);
228 		wakeup(sc);
229 	}
230 
231 	if (sc->children[addr] != NULL) {
232 		ADB_RECEIVE_PACKET(sc->children[addr],status,
233 			(command & 0x0f) >> 2,command & 0x03,len,data);
234 	}
235 
236 	return (0);
237 }
238 
239 static int
240 adb_print_child(device_t dev, device_t child)
241 {
242 	struct adb_devinfo *dinfo;
243 	int retval = 0;
244 
245 	dinfo = device_get_ivars(child);
246 
247 	retval += bus_print_child_header(dev,child);
248 	printf(" at device %d",dinfo->address);
249 	retval += bus_print_child_footer(dev, child);
250 
251 	return (retval);
252 }
253 
254 u_int
255 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
256 {
257 	u_char command_byte = 0;
258 	struct adb_devinfo *dinfo;
259 	struct adb_softc *sc;
260 
261 	sc = device_get_softc(device_get_parent(dev));
262 	dinfo = device_get_ivars(dev);
263 
264 	command_byte |= dinfo->address << 4;
265 	command_byte |= command << 2;
266 	command_byte |= reg;
267 
268 	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
269 
270 	return (0);
271 }
272 
273 u_int
274 adb_set_autopoll(device_t dev, u_char enable)
275 {
276 	struct adb_devinfo *dinfo;
277 	struct adb_softc *sc;
278 	uint16_t mod = 0;
279 
280 	sc = device_get_softc(device_get_parent(dev));
281 	dinfo = device_get_ivars(dev);
282 
283 	mod = enable << dinfo->address;
284 	if (enable) {
285 		sc->autopoll_mask |= mod;
286 	} else {
287 		mod = ~mod;
288 		sc->autopoll_mask &= mod;
289 	}
290 
291 	ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
292 
293 	return (0);
294 }
295 
296 uint8_t
297 adb_get_device_type(device_t dev)
298 {
299 	struct adb_devinfo *dinfo;
300 
301 	dinfo = device_get_ivars(dev);
302 	return (dinfo->default_address);
303 }
304 
305 uint8_t
306 adb_get_device_handler(device_t dev)
307 {
308 	struct adb_devinfo *dinfo;
309 
310 	dinfo = device_get_ivars(dev);
311 	return (dinfo->handler_id);
312 }
313 
314 static int
315 adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
316     uint8_t reg, int len, u_char *data, u_char *reply)
317 {
318 	u_char command_byte = 0;
319 	struct adb_softc *sc;
320 	int result = -1;
321 	int i = 1;
322 
323 	sc = device_get_softc(dev);
324 
325 	command_byte |= to << 4;
326 	command_byte |= command << 2;
327 	command_byte |= reg;
328 
329 	/* Wait if someone else has a synchronous request pending */
330 	while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
331 		tsleep(sc, 0, "ADB sync", hz/10);
332 
333 	sc->packet_reply = 0;
334 	sc->sync_packet = command_byte;
335 
336 	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
337 
338 	while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
339 		/*
340 		 * Maybe the command got lost? Try resending and polling the
341 		 * controller.
342 		 */
343 		if (i % 40 == 0)
344 			ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
345 			    len, data, 1);
346 
347 		tsleep(sc, 0, "ADB sync", hz/10);
348 		i++;
349 	}
350 
351 	result = sc->packet_reply - 1;
352 
353 	if (reply != NULL && result > 0)
354 		memcpy(reply,sc->syncreg,result);
355 
356 	/* Clear packet sync */
357 	sc->packet_reply = 0;
358 
359 	/*
360 	 * We can't match a value beyond 8 bits, so set sync_packet to
361 	 * 0xffff to avoid collisions.
362 	 */
363 	atomic_set_int(&sc->sync_packet, 0xffff);
364 
365 	return (result);
366 }
367 
368 uint8_t
369 adb_set_device_handler(device_t dev, uint8_t newhandler)
370 {
371 	struct adb_softc *sc;
372 	struct adb_devinfo *dinfo;
373 	uint16_t newr3;
374 
375 	dinfo = device_get_ivars(dev);
376 	sc = device_get_softc(device_get_parent(dev));
377 
378 	newr3 = dinfo->register3 & 0xff00;
379 	newr3 |= (uint16_t)(newhandler);
380 
381 	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN,
382 	    3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
383 	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
384 	    ADB_COMMAND_TALK, 3, 0, NULL, NULL);
385 
386 	return (dinfo->handler_id);
387 }
388 
389 size_t
390 adb_read_register(device_t dev, u_char reg, void *data)
391 {
392 	struct adb_softc *sc;
393 	struct adb_devinfo *dinfo;
394 	size_t result;
395 
396 	dinfo = device_get_ivars(dev);
397 	sc = device_get_softc(device_get_parent(dev));
398 
399 	result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
400 	           ADB_COMMAND_TALK, reg, 0, NULL, data);
401 
402 	return (result);
403 }
404 
405 size_t
406 adb_write_register(device_t dev, u_char reg, size_t len, void *data)
407 {
408 	struct adb_softc *sc;
409 	struct adb_devinfo *dinfo;
410 	size_t result;
411 
412 	dinfo = device_get_ivars(dev);
413 	sc = device_get_softc(device_get_parent(dev));
414 
415 	result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
416 		   ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
417 
418 	result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
419 	           ADB_COMMAND_TALK, reg, 0, NULL, NULL);
420 
421 	return (result);
422 }
423