2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2008 Nathan Whitehorn
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/module.h>
36 #include <sys/kernel.h>
38 #include <machine/bus.h>
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);
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);
55 static char *adb_device_string[] = {
56 "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
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),
69 DEVMETHOD(bus_probe_nomatch, adb_probe_nomatch),
70 DEVMETHOD(bus_print_child, adb_print_child),
75 driver_t adb_driver = {
78 sizeof(struct adb_softc),
81 devclass_t adb_devclass;
84 adb_bus_probe(device_t dev)
86 device_set_desc(dev, "Apple Desktop Bus");
91 adb_bus_attach(device_t dev)
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;
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.
103 if (config_intrhook_establish(&sc->enum_hook) != 0)
110 adb_bus_enumerate(void *xdev)
112 device_t dev = (device_t)xdev;
114 struct adb_softc *sc = device_get_softc(dev);
115 uint8_t i, next_free;
119 sc->parent = device_get_parent(dev);
121 sc->packet_reply = 0;
122 sc->autopoll_mask = 0;
123 sc->sync_packet = 0xffff;
125 /* Initialize devinfo */
126 for (i = 0; i < 16; i++) {
127 sc->devinfo[i].address = i;
128 sc->devinfo[i].default_address = 0;
132 adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
138 for (i = 1; i <= 7; i++) {
139 int8_t first_relocated = -1;
143 reply = adb_send_raw_packet_sync(dev,i,
144 ADB_COMMAND_TALK,3,0,NULL,NULL);
147 /* If we got a response, relocate to next_free */
148 r3 = sc->devinfo[i].register3;
150 r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
153 adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
154 sizeof(uint16_t),(u_char *)(&r3),NULL);
156 adb_send_raw_packet_sync(dev,next_free,
157 ADB_COMMAND_TALK,3,0,NULL,NULL);
159 sc->devinfo[next_free].default_address = i;
160 if (first_relocated < 0)
161 first_relocated = next_free;
164 } else if (first_relocated > 0) {
165 /* Collisions removed, relocate first device back */
167 r3 = sc->devinfo[i].register3;
169 r3 |= ((uint16_t)(i) & 0x000f) << 8;
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);
177 sc->devinfo[i].default_address = i;
178 sc->devinfo[(int)(first_relocated)].default_address = 0;
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]);
191 bus_generic_attach(dev);
193 config_intrhook_disestablish(&sc->enum_hook);
196 static int adb_bus_detach(device_t dev)
198 return (bus_generic_detach(dev));
203 adb_probe_nomatch(device_t dev, device_t child)
205 struct adb_devinfo *dinfo;
208 dinfo = device_get_ivars(child);
210 device_printf(dev,"ADB %s at device %d (no driver attached)\n",
211 adb_device_string[dinfo->default_address],dinfo->address);
216 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
219 struct adb_softc *sc = device_get_softc(dev);
220 u_char addr = command >> 4;
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];
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);
233 if (sc->children[addr] != NULL) {
234 ADB_RECEIVE_PACKET(sc->children[addr],status,
235 (command & 0x0f) >> 2,command & 0x03,len,data);
242 adb_print_child(device_t dev, device_t child)
244 struct adb_devinfo *dinfo;
247 dinfo = device_get_ivars(child);
249 retval += bus_print_child_header(dev,child);
250 printf(" at device %d",dinfo->address);
251 retval += bus_print_child_footer(dev, child);
257 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
259 u_char command_byte = 0;
260 struct adb_devinfo *dinfo;
261 struct adb_softc *sc;
263 sc = device_get_softc(device_get_parent(dev));
264 dinfo = device_get_ivars(dev);
266 command_byte |= dinfo->address << 4;
267 command_byte |= command << 2;
270 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
276 adb_set_autopoll(device_t dev, u_char enable)
278 struct adb_devinfo *dinfo;
279 struct adb_softc *sc;
282 sc = device_get_softc(device_get_parent(dev));
283 dinfo = device_get_ivars(dev);
285 mod = enable << dinfo->address;
287 sc->autopoll_mask |= mod;
290 sc->autopoll_mask &= mod;
293 ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
299 adb_get_device_type(device_t dev)
301 struct adb_devinfo *dinfo;
303 dinfo = device_get_ivars(dev);
304 return (dinfo->default_address);
308 adb_get_device_handler(device_t dev)
310 struct adb_devinfo *dinfo;
312 dinfo = device_get_ivars(dev);
313 return (dinfo->handler_id);
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)
320 u_char command_byte = 0;
321 struct adb_softc *sc;
325 sc = device_get_softc(dev);
327 command_byte |= to << 4;
328 command_byte |= command << 2;
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);
335 sc->packet_reply = 0;
336 sc->sync_packet = command_byte;
338 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
340 while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
342 * Maybe the command got lost? Try resending and polling the
346 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
349 tsleep(sc, 0, "ADB sync", hz/10);
353 result = sc->packet_reply - 1;
355 if (reply != NULL && result > 0)
356 memcpy(reply,sc->syncreg,result);
358 /* Clear packet sync */
359 sc->packet_reply = 0;
362 * We can't match a value beyond 8 bits, so set sync_packet to
363 * 0xffff to avoid collisions.
365 atomic_set_int(&sc->sync_packet, 0xffff);
371 adb_set_device_handler(device_t dev, uint8_t newhandler)
373 struct adb_softc *sc;
374 struct adb_devinfo *dinfo;
377 dinfo = device_get_ivars(dev);
378 sc = device_get_softc(device_get_parent(dev));
380 newr3 = dinfo->register3 & 0xff00;
381 newr3 |= (uint16_t)(newhandler);
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);
388 return (dinfo->handler_id);
392 adb_read_register(device_t dev, u_char reg, void *data)
394 struct adb_softc *sc;
395 struct adb_devinfo *dinfo;
398 dinfo = device_get_ivars(dev);
399 sc = device_get_softc(device_get_parent(dev));
401 result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
402 ADB_COMMAND_TALK, reg, 0, NULL, data);
408 adb_write_register(device_t dev, u_char reg, size_t len, void *data)
410 struct adb_softc *sc;
411 struct adb_devinfo *dinfo;
414 dinfo = device_get_ivars(dev);
415 sc = device_get_softc(device_get_parent(dev));
417 result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
418 ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
420 result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
421 ADB_COMMAND_TALK, reg, 0, NULL, NULL);