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