]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/adb/adb_bus.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / 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 devclass_t adb_devclass;
82
83 static int
84 adb_bus_probe(device_t dev)
85 {
86         device_set_desc(dev, "Apple Desktop Bus");
87         return (0);
88 }
89
90 static int
91 adb_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
109 static void
110 adb_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
196 static int adb_bus_detach(device_t dev)
197 {
198         return (bus_generic_detach(dev));
199 }
200
201 static void
202 adb_probe_nomatch(device_t dev, device_t child)
203 {
204         struct adb_devinfo *dinfo;
205
206         if (bootverbose) {
207                 dinfo = device_get_ivars(child);
208
209                 device_printf(dev,"ADB %s at device %d (no driver attached)\n",
210                     adb_device_string[dinfo->default_address],dinfo->address);
211         }
212 }
213
214 u_int
215 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 
216     u_char *data) 
217 {
218         struct adb_softc *sc = device_get_softc(dev);
219         u_char addr = command >> 4;
220
221         if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
222                 memcpy(&sc->devinfo[addr].register3,data,2);
223                 sc->devinfo[addr].handler_id = data[1];
224         }
225
226         if (sc->sync_packet == command)  {
227                 memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
228                 atomic_store_rel_int(&sc->packet_reply,len + 1);
229                 wakeup(sc);
230         }
231
232         if (sc->children[addr] != NULL) {
233                 ADB_RECEIVE_PACKET(sc->children[addr],status,
234                         (command & 0x0f) >> 2,command & 0x03,len,data);
235         }
236
237         return (0);
238 }
239
240 static int
241 adb_print_child(device_t dev, device_t child)
242 {
243         struct adb_devinfo *dinfo;
244         int retval = 0;
245
246         dinfo = device_get_ivars(child);
247
248         retval += bus_print_child_header(dev,child);
249         printf(" at device %d",dinfo->address);
250         retval += bus_print_child_footer(dev, child);
251
252         return (retval);
253 }
254
255 u_int 
256 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
257 {
258         u_char command_byte = 0;
259         struct adb_devinfo *dinfo;
260         struct adb_softc *sc;
261
262         sc = device_get_softc(device_get_parent(dev));
263         dinfo = device_get_ivars(dev);
264
265         command_byte |= dinfo->address << 4;
266         command_byte |= command << 2;
267         command_byte |= reg;
268
269         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
270
271         return (0);
272 }
273
274 u_int
275 adb_set_autopoll(device_t dev, u_char enable) 
276 {
277         struct adb_devinfo *dinfo;
278         struct adb_softc *sc;
279         uint16_t mod = 0;
280
281         sc = device_get_softc(device_get_parent(dev));
282         dinfo = device_get_ivars(dev);
283
284         mod = enable << dinfo->address;
285         if (enable) {
286                 sc->autopoll_mask |= mod;
287         } else {
288                 mod = ~mod;
289                 sc->autopoll_mask &= mod;
290         }
291
292         ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
293
294         return (0);
295 }
296
297 uint8_t 
298 adb_get_device_type(device_t dev) 
299 {
300         struct adb_devinfo *dinfo;
301
302         dinfo = device_get_ivars(dev);
303         return (dinfo->default_address);
304 }
305
306 uint8_t 
307 adb_get_device_handler(device_t dev) 
308 {
309         struct adb_devinfo *dinfo;
310
311         dinfo = device_get_ivars(dev);
312         return (dinfo->handler_id);
313 }
314
315 static int 
316 adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 
317     uint8_t reg, int len, u_char *data, u_char *reply) 
318 {
319         u_char command_byte = 0;
320         struct adb_softc *sc;
321         int result = -1;
322         int i = 1;
323
324         sc = device_get_softc(dev);
325
326         command_byte |= to << 4;
327         command_byte |= command << 2;
328         command_byte |= reg;
329
330         /* Wait if someone else has a synchronous request pending */
331         while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
332                 tsleep(sc, 0, "ADB sync", hz/10);
333
334         sc->packet_reply = 0;
335         sc->sync_packet = command_byte;
336
337         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
338
339         while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
340                 /*
341                  * Maybe the command got lost? Try resending and polling the 
342                  * controller.
343                  */
344                 if (i % 40 == 0)
345                         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 
346                             len, data, 1);
347
348                 tsleep(sc, 0, "ADB sync", hz/10);
349                 i++;
350         }
351
352         result = sc->packet_reply - 1;
353
354         if (reply != NULL && result > 0)
355                 memcpy(reply,sc->syncreg,result);
356
357         /* Clear packet sync */
358         sc->packet_reply = 0;
359
360         /*
361          * We can't match a value beyond 8 bits, so set sync_packet to 
362          * 0xffff to avoid collisions.
363          */
364         atomic_set_int(&sc->sync_packet, 0xffff); 
365
366         return (result);
367 }
368
369 uint8_t 
370 adb_set_device_handler(device_t dev, uint8_t newhandler) 
371 {
372         struct adb_softc *sc;
373         struct adb_devinfo *dinfo;
374         uint16_t newr3;
375
376         dinfo = device_get_ivars(dev);
377         sc = device_get_softc(device_get_parent(dev));
378
379         newr3 = dinfo->register3 & 0xff00;
380         newr3 |= (uint16_t)(newhandler);
381
382         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, 
383             3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
384         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 
385             ADB_COMMAND_TALK, 3, 0, NULL, NULL);
386
387         return (dinfo->handler_id);
388 }
389
390 size_t 
391 adb_read_register(device_t dev, u_char reg, void *data) 
392 {
393         struct adb_softc *sc;
394         struct adb_devinfo *dinfo;
395         size_t result;
396
397         dinfo = device_get_ivars(dev);
398         sc = device_get_softc(device_get_parent(dev));
399
400         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
401                    ADB_COMMAND_TALK, reg, 0, NULL, data);
402
403         return (result);
404 }
405
406 size_t 
407 adb_write_register(device_t dev, u_char reg, size_t len, void *data) 
408 {
409         struct adb_softc *sc;
410         struct adb_devinfo *dinfo;
411         size_t result;
412
413         dinfo = device_get_ivars(dev);
414         sc = device_get_softc(device_get_parent(dev));
415
416         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
417                    ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
418
419         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
420                    ADB_COMMAND_TALK, reg, 0, NULL, NULL);
421
422         return (result);
423 }