adb_bus.c revision 184299
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: head/sys/dev/adb/adb_bus.c 184299 2008-10-26 19:37:38Z nwhitehorn $
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
44static int adb_bus_probe(device_t dev);
45static int adb_bus_attach(device_t dev);
46static int adb_bus_detach(device_t dev);
47static void adb_probe_nomatch(device_t dev, device_t child);
48static int adb_print_child(device_t dev, device_t child);
49
50static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data);
51
52static char *adb_device_string[] = {
53	"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
54};
55
56static 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
72driver_t adb_driver = {
73	"adb",
74	adb_bus_methods,
75	sizeof(struct adb_softc),
76};
77
78devclass_t adb_devclass;
79
80static int
81adb_bus_probe(device_t dev)
82{
83	device_set_desc(dev, "Apple Desktop Bus");
84	return (0);
85}
86
87static int
88adb_bus_attach(device_t dev)
89{
90	struct adb_softc *sc = device_get_softc(dev);
91	uint8_t i, next_free;
92	uint16_t r3;
93
94	sc->sc_dev = dev;
95	sc->parent = device_get_parent(dev);
96
97	sc->packet_reply = 0;
98	sc->autopoll_mask = 0;
99
100	mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE);
101
102	/* Initialize devinfo */
103	for (i = 0; i < 16; i++) {
104		sc->devinfo[i].address = i;
105		sc->devinfo[i].default_address = 0;
106	}
107
108	/* Reset ADB bus */
109	adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL);
110	DELAY(1500);
111
112	/* Enumerate bus */
113	next_free = 8;
114
115	for (i = 1; i < 7; i++) {
116	    int8_t first_relocated = -1;
117	    int reply = 0;
118
119	    do {
120		reply = adb_send_raw_packet_sync(dev,i,
121			    ADB_COMMAND_TALK,3,0,NULL);
122
123		if (reply) {
124			/* If we got a response, relocate to next_free */
125			r3 = sc->devinfo[i].register3;
126			r3 &= 0xf000;
127			r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
128			r3 |= 0x00fe;
129
130			adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
131			    sizeof(uint16_t),(u_char *)(&r3));
132
133			adb_send_raw_packet_sync(dev,next_free,
134			    ADB_COMMAND_TALK,3,0,NULL);
135
136			sc->devinfo[next_free].default_address = i;
137			if (first_relocated < 0)
138				first_relocated = next_free;
139
140			next_free++;
141		} else if (first_relocated > 0) {
142			/* Collisions removed, relocate first device back */
143
144			r3 = sc->devinfo[i].register3;
145			r3 &= 0xf000;
146			r3 |= ((uint16_t)(i) & 0x000f) << 8;
147
148			adb_send_raw_packet_sync(dev,first_relocated,
149			    ADB_COMMAND_LISTEN,3,
150			    sizeof(uint16_t),(u_char *)(&r3));
151			adb_send_raw_packet_sync(dev,i,
152			    ADB_COMMAND_TALK,3,0,NULL);
153
154			sc->devinfo[i].default_address = i;
155			sc->devinfo[(int)(first_relocated)].default_address = 0;
156			break;
157		}
158	    } while (reply);
159	}
160
161	for (i = 0; i < 16; i++) {
162		if (sc->devinfo[i].default_address) {
163			sc->children[i] = device_add_child(dev, NULL, -1);
164			device_set_ivars(sc->children[i], &sc->devinfo[i]);
165		}
166	}
167
168	return (bus_generic_attach(dev));
169}
170
171static int adb_bus_detach(device_t dev)
172{
173	struct adb_softc *sc = device_get_softc(dev);
174
175	mtx_destroy(&sc->sc_sync_mtx);
176
177	return (bus_generic_detach(dev));
178}
179
180
181static void
182adb_probe_nomatch(device_t dev, device_t child)
183{
184	struct adb_devinfo *dinfo;
185
186	if (bootverbose) {
187		dinfo = device_get_ivars(child);
188
189		device_printf(dev,"ADB %s at device %d (no driver attached)\n",
190		    adb_device_string[dinfo->default_address],dinfo->address);
191	}
192}
193
194u_int
195adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
196    u_char *data)
197{
198	struct adb_softc *sc = device_get_softc(dev);
199	u_char addr = command >> 4;
200
201	if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
202		memcpy(&sc->devinfo[addr].register3,data,2);
203		sc->devinfo[addr].handler_id = data[1];
204	}
205
206	if (sc->sync_packet == command)  {
207		memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
208		atomic_store_rel_int(&sc->packet_reply,len + 1);
209	}
210
211	if (sc->children[addr] != NULL) {
212		ADB_RECEIVE_PACKET(sc->children[addr],status,
213			(command & 0x0f) >> 2,command & 0x03,len,data);
214	}
215
216	return (0);
217}
218
219static int
220adb_print_child(device_t dev, device_t child)
221{
222	struct adb_devinfo *dinfo;
223	int retval = 0;
224
225	dinfo = device_get_ivars(child);
226
227	retval += bus_print_child_header(dev,child);
228	printf(" at device %d",dinfo->address);
229	retval += bus_print_child_footer(dev, child);
230
231	return (retval);
232}
233
234u_int
235adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
236{
237	u_char command_byte = 0;
238	struct adb_devinfo *dinfo;
239	struct adb_softc *sc;
240
241	sc = device_get_softc(device_get_parent(dev));
242	dinfo = device_get_ivars(dev);
243
244	command_byte |= dinfo->address << 4;
245	command_byte |= command << 2;
246	command_byte |= reg;
247
248	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
249
250	return (0);
251}
252
253u_int
254adb_set_autopoll(device_t dev, u_char enable)
255{
256	struct adb_devinfo *dinfo;
257	struct adb_softc *sc;
258	uint16_t mod = 0;
259
260	sc = device_get_softc(device_get_parent(dev));
261	dinfo = device_get_ivars(dev);
262
263	mod = enable << dinfo->address;
264	if (enable) {
265		sc->autopoll_mask |= mod;
266	} else {
267		mod = ~mod;
268		sc->autopoll_mask &= mod;
269	}
270
271	ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
272
273	return (0);
274}
275
276uint8_t
277adb_get_device_type(device_t dev)
278{
279	struct adb_devinfo *dinfo;
280
281	dinfo = device_get_ivars(dev);
282	return (dinfo->default_address);
283}
284
285uint8_t
286adb_get_device_handler(device_t dev)
287{
288	struct adb_devinfo *dinfo;
289
290	dinfo = device_get_ivars(dev);
291	return (dinfo->handler_id);
292}
293
294static int
295adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
296    uint8_t reg, int len, u_char *data)
297{
298	u_char command_byte = 0;
299	struct adb_softc *sc;
300	int result = -1;
301	int i = 0;
302
303	sc = device_get_softc(dev);
304
305	command_byte |= to << 4;
306	command_byte |= command << 2;
307	command_byte |= reg;
308
309	/* Wait if someone else has a synchronous request pending */
310	mtx_lock(&sc->sc_sync_mtx);
311
312	sc->packet_reply = 0;
313	sc->sync_packet = command_byte;
314
315	ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
316
317	while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
318		/* Sometimes CUDA controllers hang up during cold boots.
319		   Try poking them. */
320		if (i > 10)
321			ADB_HB_CONTROLLER_POLL(sc->parent);
322
323		DELAY(100);
324		i++;
325	}
326
327	result = sc->packet_reply - 1;
328
329	/* Clear packet sync */
330	sc->packet_reply = 0;
331	sc->sync_packet = 0xffff; /* We can't match a 16 bit value */
332
333	mtx_unlock(&sc->sc_sync_mtx);
334
335	return (result);
336}
337
338uint8_t
339adb_set_device_handler(device_t dev, uint8_t newhandler)
340{
341	struct adb_softc *sc;
342	struct adb_devinfo *dinfo;
343	uint16_t newr3;
344
345	dinfo = device_get_ivars(dev);
346	sc = device_get_softc(device_get_parent(dev));
347
348	newr3 = dinfo->register3 & 0xff00;
349	newr3 |= (uint16_t)(newhandler);
350
351	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
352	    ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3));
353	adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
354	    ADB_COMMAND_TALK, 3, 0, NULL);
355
356	return (dinfo->handler_id);
357}
358
359uint8_t
360adb_read_register(device_t dev, u_char reg,
361    size_t *len, void *data)
362{
363	struct adb_softc *sc;
364	struct adb_devinfo *dinfo;
365	size_t orig_len;
366
367	dinfo = device_get_ivars(dev);
368	sc = device_get_softc(device_get_parent(dev));
369
370	orig_len = *len;
371
372	mtx_lock(&sc->sc_sync_mtx);
373
374	*len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
375	           ADB_COMMAND_TALK, reg, 0, NULL);
376
377	if (*len > 0)
378		memcpy(data,sc->syncreg,*len);
379
380	mtx_unlock(&sc->sc_sync_mtx);
381
382	return ((*len > 0) ? 0 : -1);
383}
384
385