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