xref: /freebsd/sys/dev/adb/adb_bus.c (revision 52267f7411adcc76ede961420e08c0e42f42d415)
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);
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 
122 	mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE);
123 
124 	/* Initialize devinfo */
125 	for (i = 0; i < 16; i++) {
126 		sc->devinfo[i].address = i;
127 		sc->devinfo[i].default_address = 0;
128 	}
129 
130 	/* Reset ADB bus */
131 	adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL);
132 	DELAY(1500);
133 
134 	/* Enumerate bus */
135 	next_free = 8;
136 
137 	for (i = 1; i <= 7; i++) {
138 	    int8_t first_relocated = -1;
139 	    int reply = 0;
140 
141 	    do {
142 		reply = adb_send_raw_packet_sync(dev,i,
143 			    ADB_COMMAND_TALK,3,0,NULL);
144 
145 		if (reply) {
146 			/* If we got a response, relocate to next_free */
147 			r3 = sc->devinfo[i].register3;
148 			r3 &= 0xf000;
149 			r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
150 			r3 |= 0x00fe;
151 
152 			adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
153 			    sizeof(uint16_t),(u_char *)(&r3));
154 
155 			adb_send_raw_packet_sync(dev,next_free,
156 			    ADB_COMMAND_TALK,3,0,NULL);
157 
158 			sc->devinfo[next_free].default_address = i;
159 			if (first_relocated < 0)
160 				first_relocated = next_free;
161 
162 			next_free++;
163 		} else if (first_relocated > 0) {
164 			/* Collisions removed, relocate first device back */
165 
166 			r3 = sc->devinfo[i].register3;
167 			r3 &= 0xf000;
168 			r3 |= ((uint16_t)(i) & 0x000f) << 8;
169 
170 			adb_send_raw_packet_sync(dev,first_relocated,
171 			    ADB_COMMAND_LISTEN,3,
172 			    sizeof(uint16_t),(u_char *)(&r3));
173 			adb_send_raw_packet_sync(dev,i,
174 			    ADB_COMMAND_TALK,3,0,NULL);
175 
176 			sc->devinfo[i].default_address = i;
177 			sc->devinfo[(int)(first_relocated)].default_address = 0;
178 			break;
179 		}
180 	    } while (reply);
181 	}
182 
183 	for (i = 0; i < 16; i++) {
184 		if (sc->devinfo[i].default_address) {
185 			sc->children[i] = device_add_child(dev, NULL, -1);
186 			device_set_ivars(sc->children[i], &sc->devinfo[i]);
187 		}
188 	}
189 
190 	bus_generic_attach(dev);
191 
192 	config_intrhook_disestablish(&sc->enum_hook);
193 }
194 
195 static int adb_bus_detach(device_t dev)
196 {
197 	struct adb_softc *sc = device_get_softc(dev);
198 
199 	mtx_destroy(&sc->sc_sync_mtx);
200 
201 	return (bus_generic_detach(dev));
202 }
203 
204 
205 static void
206 adb_probe_nomatch(device_t dev, device_t child)
207 {
208 	struct adb_devinfo *dinfo;
209 
210 	if (bootverbose) {
211 		dinfo = device_get_ivars(child);
212 
213 		device_printf(dev,"ADB %s at device %d (no driver attached)\n",
214 		    adb_device_string[dinfo->default_address],dinfo->address);
215 	}
216 }
217 
218 u_int
219 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
220     u_char *data)
221 {
222 	struct adb_softc *sc = device_get_softc(dev);
223 	u_char addr = command >> 4;
224 
225 	if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
226 		memcpy(&sc->devinfo[addr].register3,data,2);
227 		sc->devinfo[addr].handler_id = data[1];
228 	}
229 
230 	if (sc->sync_packet == command)  {
231 		memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
232 		atomic_store_rel_int(&sc->packet_reply,len + 1);
233 	}
234 
235 	if (sc->children[addr] != NULL) {
236 		ADB_RECEIVE_PACKET(sc->children[addr],status,
237 			(command & 0x0f) >> 2,command & 0x03,len,data);
238 	}
239 
240 	return (0);
241 }
242 
243 static int
244 adb_print_child(device_t dev, device_t child)
245 {
246 	struct adb_devinfo *dinfo;
247 	int retval = 0;
248 
249 	dinfo = device_get_ivars(child);
250 
251 	retval += bus_print_child_header(dev,child);
252 	printf(" at device %d",dinfo->address);
253 	retval += bus_print_child_footer(dev, child);
254 
255 	return (retval);
256 }
257 
258 u_int
259 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
260 {
261 	u_char command_byte = 0;
262 	struct adb_devinfo *dinfo;
263 	struct adb_softc *sc;
264 
265 	sc = device_get_softc(device_get_parent(dev));
266 	dinfo = device_get_ivars(dev);
267 
268 	command_byte |= dinfo->address << 4;
269 	command_byte |= command << 2;
270 	command_byte |= reg;
271 
272 	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
273 
274 	return (0);
275 }
276 
277 u_int
278 adb_set_autopoll(device_t dev, u_char enable)
279 {
280 	struct adb_devinfo *dinfo;
281 	struct adb_softc *sc;
282 	uint16_t mod = 0;
283 
284 	sc = device_get_softc(device_get_parent(dev));
285 	dinfo = device_get_ivars(dev);
286 
287 	mod = enable << dinfo->address;
288 	if (enable) {
289 		sc->autopoll_mask |= mod;
290 	} else {
291 		mod = ~mod;
292 		sc->autopoll_mask &= mod;
293 	}
294 
295 	ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
296 
297 	return (0);
298 }
299 
300 uint8_t
301 adb_get_device_type(device_t dev)
302 {
303 	struct adb_devinfo *dinfo;
304 
305 	dinfo = device_get_ivars(dev);
306 	return (dinfo->default_address);
307 }
308 
309 uint8_t
310 adb_get_device_handler(device_t dev)
311 {
312 	struct adb_devinfo *dinfo;
313 
314 	dinfo = device_get_ivars(dev);
315 	return (dinfo->handler_id);
316 }
317 
318 static int
319 adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
320     uint8_t reg, int len, u_char *data)
321 {
322 	u_char command_byte = 0;
323 	struct adb_softc *sc;
324 	int result = -1;
325 	int i = 0;
326 
327 	sc = device_get_softc(dev);
328 
329 	command_byte |= to << 4;
330 	command_byte |= command << 2;
331 	command_byte |= reg;
332 
333 	/* Wait if someone else has a synchronous request pending */
334 	mtx_lock(&sc->sc_sync_mtx);
335 
336 	sc->packet_reply = 0;
337 	sc->sync_packet = command_byte;
338 
339 	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
340 
341 	while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
342 		/*
343 		 * Maybe the command got lost? Try resending and polling the
344 		 * controller.
345 		 */
346 		if (i > 40)
347 			ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
348 			    len, data, 1);
349 
350 		DELAY(100);
351 		i++;
352 	}
353 
354 	result = sc->packet_reply - 1;
355 
356 	/* Clear packet sync */
357 	sc->packet_reply = 0;
358 	sc->sync_packet = 0xffff; /* We can't match a 16 bit value */
359 
360 	mtx_unlock(&sc->sc_sync_mtx);
361 
362 	return (result);
363 }
364 
365 uint8_t
366 adb_set_device_handler(device_t dev, uint8_t newhandler)
367 {
368 	struct adb_softc *sc;
369 	struct adb_devinfo *dinfo;
370 	uint16_t newr3;
371 
372 	dinfo = device_get_ivars(dev);
373 	sc = device_get_softc(device_get_parent(dev));
374 
375 	newr3 = dinfo->register3 & 0xff00;
376 	newr3 |= (uint16_t)(newhandler);
377 
378 	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
379 	    ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3));
380 	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
381 	    ADB_COMMAND_TALK, 3, 0, NULL);
382 
383 	return (dinfo->handler_id);
384 }
385 
386 uint8_t
387 adb_read_register(device_t dev, u_char reg,
388     size_t *len, void *data)
389 {
390 	struct adb_softc *sc;
391 	struct adb_devinfo *dinfo;
392 	size_t orig_len;
393 
394 	dinfo = device_get_ivars(dev);
395 	sc = device_get_softc(device_get_parent(dev));
396 
397 	orig_len = *len;
398 
399 	mtx_lock(&sc->sc_sync_mtx);
400 
401 	*len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
402 	           ADB_COMMAND_TALK, reg, 0, NULL);
403 
404 	if (*len > 0)
405 		memcpy(data,sc->syncreg,*len);
406 
407 	mtx_unlock(&sc->sc_sync_mtx);
408 
409 	return ((*len > 0) ? 0 : -1);
410 }
411 
412