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
46static int adb_bus_probe(device_t dev);
47static int adb_bus_attach(device_t dev);
48static int adb_bus_detach(device_t dev);
49static void adb_bus_enumerate(void *xdev);
50static void adb_probe_nomatch(device_t dev, device_t child);
51static int adb_print_child(device_t dev, device_t child);
52
53static 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
55static char *adb_device_string[] = {
56	"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
57};
58
59static 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
75driver_t adb_driver = {
76	"adb",
77	adb_bus_methods,
78	sizeof(struct adb_softc),
79};
80
81devclass_t adb_devclass;
82
83static int
84adb_bus_probe(device_t dev)
85{
86	device_set_desc(dev, "Apple Desktop Bus");
87	return (0);
88}
89
90static int
91adb_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
109static void
110adb_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
196static int adb_bus_detach(device_t dev)
197{
198	return (bus_generic_detach(dev));
199}
200
201
202static void
203adb_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
215u_int
216adb_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
241static int
242adb_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
256u_int
257adb_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
275u_int
276adb_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
298uint8_t
299adb_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
307uint8_t
308adb_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
316static int
317adb_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
370uint8_t
371adb_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
391size_t
392adb_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
407size_t
408adb_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