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