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