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