]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/dev/adb/adb_bus.c
Copy head to stable/8 as part of 8.0 Release cycle.
[FreeBSD/stable/8.git] / sys / dev / adb / adb_bus.c
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$
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 devclass_t adb_devclass;
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         newbus_xlock();
117         sc->sc_dev = dev;
118         sc->parent = device_get_parent(dev);
119
120         sc->packet_reply = 0;
121         sc->autopoll_mask = 0;
122         sc->sync_packet = 0xffff;
123
124         /* Initialize devinfo */
125         for (i = 0; i < 16; i++) {
126                 sc->devinfo[i].address = i;
127                 sc->devinfo[i].default_address = 0;
128         }
129         
130         /* Reset ADB bus */
131         adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
132         DELAY(1500);
133
134         /* Enumerate bus */
135         next_free = 8;
136
137         for (i = 1; i <= 7; i++) {
138             int8_t first_relocated = -1;
139             int reply = 0;
140
141             do {
142                 reply = adb_send_raw_packet_sync(dev,i,
143                             ADB_COMMAND_TALK,3,0,NULL,NULL);
144         
145                 if (reply) {
146                         /* If we got a response, relocate to next_free */
147                         r3 = sc->devinfo[i].register3;
148                         r3 &= 0xf000;
149                         r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
150                         r3 |= 0x00fe;
151
152                         adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
153                             sizeof(uint16_t),(u_char *)(&r3),NULL);
154
155                         adb_send_raw_packet_sync(dev,next_free,
156                             ADB_COMMAND_TALK,3,0,NULL,NULL);
157
158                         sc->devinfo[next_free].default_address = i;
159                         if (first_relocated < 0)
160                                 first_relocated = next_free;
161
162                         next_free++;
163                 } else if (first_relocated > 0) {
164                         /* Collisions removed, relocate first device back */
165
166                         r3 = sc->devinfo[i].register3;
167                         r3 &= 0xf000;
168                         r3 |= ((uint16_t)(i) & 0x000f) << 8;
169                         
170                         adb_send_raw_packet_sync(dev,first_relocated,
171                             ADB_COMMAND_LISTEN,3,
172                             sizeof(uint16_t),(u_char *)(&r3),NULL);
173                         adb_send_raw_packet_sync(dev,i,
174                             ADB_COMMAND_TALK,3,0,NULL,NULL);
175
176                         sc->devinfo[i].default_address = i;
177                         sc->devinfo[(int)(first_relocated)].default_address = 0;
178                         break;
179                 }
180             } while (reply);
181         }
182
183         for (i = 0; i < 16; i++) {
184                 if (sc->devinfo[i].default_address) {
185                         sc->children[i] = device_add_child(dev, NULL, -1);
186                         device_set_ivars(sc->children[i], &sc->devinfo[i]);
187                 }
188         }
189
190         bus_generic_attach(dev);
191         newbus_xunlock();
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
202 static void
203 adb_probe_nomatch(device_t dev, device_t child)
204 {
205         struct adb_devinfo *dinfo;
206
207         if (bootverbose) {
208                 dinfo = device_get_ivars(child);
209
210                 device_printf(dev,"ADB %s at device %d (no driver attached)\n",
211                     adb_device_string[dinfo->default_address],dinfo->address);
212         }
213 }
214
215 u_int
216 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 
217     u_char *data) 
218 {
219         struct adb_softc *sc = device_get_softc(dev);
220         u_char addr = command >> 4;
221
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];
225         }
226
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);
230                 wakeup(sc);
231         }
232
233         if (sc->children[addr] != NULL) {
234                 ADB_RECEIVE_PACKET(sc->children[addr],status,
235                         (command & 0x0f) >> 2,command & 0x03,len,data);
236         }
237         
238         return (0);
239 }
240
241 static int
242 adb_print_child(device_t dev, device_t child)
243 {
244         struct adb_devinfo *dinfo;
245         int retval = 0;
246         
247         dinfo = device_get_ivars(child);
248         
249         retval += bus_print_child_header(dev,child);
250         printf(" at device %d",dinfo->address);
251         retval += bus_print_child_footer(dev, child);
252
253         return (retval);
254 }
255
256 u_int 
257 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
258 {
259         u_char command_byte = 0;
260         struct adb_devinfo *dinfo;
261         struct adb_softc *sc;
262
263         sc = device_get_softc(device_get_parent(dev));
264         dinfo = device_get_ivars(dev);
265         
266         command_byte |= dinfo->address << 4;
267         command_byte |= command << 2;
268         command_byte |= reg;
269
270         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
271
272         return (0);
273 }
274
275 u_int
276 adb_set_autopoll(device_t dev, u_char enable) 
277 {
278         struct adb_devinfo *dinfo;
279         struct adb_softc *sc;
280         uint16_t mod = 0;
281
282         sc = device_get_softc(device_get_parent(dev));
283         dinfo = device_get_ivars(dev);
284         
285         mod = enable << dinfo->address;
286         if (enable) {
287                 sc->autopoll_mask |= mod;
288         } else {
289                 mod = ~mod;
290                 sc->autopoll_mask &= mod;
291         }
292
293         ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
294
295         return (0);
296 }
297
298 uint8_t 
299 adb_get_device_type(device_t dev) 
300 {
301         struct adb_devinfo *dinfo;
302
303         dinfo = device_get_ivars(dev);
304         return (dinfo->default_address);
305 }
306
307 uint8_t 
308 adb_get_device_handler(device_t dev) 
309 {
310         struct adb_devinfo *dinfo;
311
312         dinfo = device_get_ivars(dev);
313         return (dinfo->handler_id);
314 }
315
316 static int 
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) 
319 {
320         u_char command_byte = 0;
321         struct adb_softc *sc;
322         int result = -1;
323         int i = 1;
324
325         sc = device_get_softc(dev);
326         
327         command_byte |= to << 4;
328         command_byte |= command << 2;
329         command_byte |= reg;
330
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);
334
335         sc->packet_reply = 0;
336         sc->sync_packet = command_byte;
337
338         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
339
340         while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
341                 /*
342                  * Maybe the command got lost? Try resending and polling the 
343                  * controller.
344                  */
345                 if (i % 40 == 0)
346                         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 
347                             len, data, 1);
348
349                 tsleep(sc, 0, "ADB sync", hz/10);
350                 i++;
351         }
352
353         result = sc->packet_reply - 1;
354
355         if (reply != NULL && result > 0)
356                 memcpy(reply,sc->syncreg,result);
357
358         /* Clear packet sync */
359         sc->packet_reply = 0;
360
361         /*
362          * We can't match a value beyond 8 bits, so set sync_packet to 
363          * 0xffff to avoid collisions.
364          */
365         atomic_set_int(&sc->sync_packet, 0xffff); 
366
367         return (result);
368 }
369
370 uint8_t 
371 adb_set_device_handler(device_t dev, uint8_t newhandler) 
372 {
373         struct adb_softc *sc;
374         struct adb_devinfo *dinfo;
375         uint16_t newr3;
376
377         dinfo = device_get_ivars(dev);
378         sc = device_get_softc(device_get_parent(dev));
379
380         newr3 = dinfo->register3 & 0xff00;
381         newr3 |= (uint16_t)(newhandler);
382
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);
387
388         return (dinfo->handler_id);
389 }
390
391 size_t 
392 adb_read_register(device_t dev, u_char reg, void *data) 
393 {
394         struct adb_softc *sc;
395         struct adb_devinfo *dinfo;
396         size_t result;
397
398         dinfo = device_get_ivars(dev);
399         sc = device_get_softc(device_get_parent(dev));
400
401         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
402                    ADB_COMMAND_TALK, reg, 0, NULL, data);
403
404         return (result);
405 }
406