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