1b4dbc599SNathan Whitehorn /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4b4dbc599SNathan Whitehorn * Copyright (C) 2008 Nathan Whitehorn
5b4dbc599SNathan Whitehorn * All rights reserved.
6b4dbc599SNathan Whitehorn *
7b4dbc599SNathan Whitehorn * Redistribution and use in source and binary forms, with or without
8b4dbc599SNathan Whitehorn * modification, are permitted provided that the following conditions
9b4dbc599SNathan Whitehorn * are met:
10b4dbc599SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright
11b4dbc599SNathan Whitehorn * notice, this list of conditions and the following disclaimer.
12b4dbc599SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright
13b4dbc599SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the
14b4dbc599SNathan Whitehorn * documentation and/or other materials provided with the distribution.
15b4dbc599SNathan Whitehorn *
16b4dbc599SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17b4dbc599SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18b4dbc599SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19b4dbc599SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20b4dbc599SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21b4dbc599SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22b4dbc599SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23b4dbc599SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24b4dbc599SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25b4dbc599SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26b4dbc599SNathan Whitehorn */
27b4dbc599SNathan Whitehorn
28b4dbc599SNathan Whitehorn #include <sys/param.h>
29b4dbc599SNathan Whitehorn #include <sys/systm.h>
30b4dbc599SNathan Whitehorn #include <sys/module.h>
31b4dbc599SNathan Whitehorn #include <sys/bus.h>
32b4dbc599SNathan Whitehorn #include <sys/conf.h>
33b4dbc599SNathan Whitehorn #include <sys/kernel.h>
34b4dbc599SNathan Whitehorn
35b4dbc599SNathan Whitehorn #include <machine/bus.h>
36b4dbc599SNathan Whitehorn
37b4dbc599SNathan Whitehorn #include <vm/vm.h>
38b4dbc599SNathan Whitehorn #include <vm/pmap.h>
39b4dbc599SNathan Whitehorn
40b4dbc599SNathan Whitehorn #include "adb.h"
41b4dbc599SNathan Whitehorn #include "adbvar.h"
42b4dbc599SNathan Whitehorn
43b4dbc599SNathan Whitehorn static int adb_bus_probe(device_t dev);
44b4dbc599SNathan Whitehorn static int adb_bus_attach(device_t dev);
4501418697SNathan Whitehorn static void adb_bus_enumerate(void *xdev);
46b4dbc599SNathan Whitehorn static void adb_probe_nomatch(device_t dev, device_t child);
47b4dbc599SNathan Whitehorn static int adb_print_child(device_t dev, device_t child);
48b4dbc599SNathan Whitehorn
49582434bdSNathan Whitehorn 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);
50b4dbc599SNathan Whitehorn
51b4dbc599SNathan Whitehorn static char *adb_device_string[] = {
52b4dbc599SNathan Whitehorn "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
53b4dbc599SNathan Whitehorn };
54b4dbc599SNathan Whitehorn
55b4dbc599SNathan Whitehorn static device_method_t adb_bus_methods[] = {
56b4dbc599SNathan Whitehorn /* Device interface */
57b4dbc599SNathan Whitehorn DEVMETHOD(device_probe, adb_bus_probe),
58b4dbc599SNathan Whitehorn DEVMETHOD(device_attach, adb_bus_attach),
59d62d10ebSJohn Baldwin DEVMETHOD(device_detach, bus_generic_detach),
60b4dbc599SNathan Whitehorn DEVMETHOD(device_shutdown, bus_generic_shutdown),
61b4dbc599SNathan Whitehorn DEVMETHOD(device_suspend, bus_generic_suspend),
62b4dbc599SNathan Whitehorn DEVMETHOD(device_resume, bus_generic_resume),
63b4dbc599SNathan Whitehorn
64b4dbc599SNathan Whitehorn /* Bus Interface */
65b4dbc599SNathan Whitehorn DEVMETHOD(bus_probe_nomatch, adb_probe_nomatch),
66b4dbc599SNathan Whitehorn DEVMETHOD(bus_print_child, adb_print_child),
67b4dbc599SNathan Whitehorn
68b4dbc599SNathan Whitehorn { 0, 0 },
69b4dbc599SNathan Whitehorn };
70b4dbc599SNathan Whitehorn
71b4dbc599SNathan Whitehorn driver_t adb_driver = {
72b4dbc599SNathan Whitehorn "adb",
73b4dbc599SNathan Whitehorn adb_bus_methods,
74b4dbc599SNathan Whitehorn sizeof(struct adb_softc),
75b4dbc599SNathan Whitehorn };
76b4dbc599SNathan Whitehorn
77b4dbc599SNathan Whitehorn static int
adb_bus_probe(device_t dev)78b4dbc599SNathan Whitehorn adb_bus_probe(device_t dev)
79b4dbc599SNathan Whitehorn {
80b4dbc599SNathan Whitehorn device_set_desc(dev, "Apple Desktop Bus");
81b4dbc599SNathan Whitehorn return (0);
82b4dbc599SNathan Whitehorn }
83b4dbc599SNathan Whitehorn
84b4dbc599SNathan Whitehorn static int
adb_bus_attach(device_t dev)85b4dbc599SNathan Whitehorn adb_bus_attach(device_t dev)
86b4dbc599SNathan Whitehorn {
87b4dbc599SNathan Whitehorn struct adb_softc *sc = device_get_softc(dev);
8801418697SNathan Whitehorn sc->enum_hook.ich_func = adb_bus_enumerate;
8901418697SNathan Whitehorn sc->enum_hook.ich_arg = dev;
9001418697SNathan Whitehorn
9101418697SNathan Whitehorn /*
9201418697SNathan Whitehorn * We should wait until interrupts are enabled to try to probe
9301418697SNathan Whitehorn * the bus. Enumerating the ADB involves receiving packets,
9401418697SNathan Whitehorn * which works best with interrupts enabled.
9501418697SNathan Whitehorn */
9601418697SNathan Whitehorn
9701418697SNathan Whitehorn if (config_intrhook_establish(&sc->enum_hook) != 0)
9801418697SNathan Whitehorn return (ENOMEM);
9901418697SNathan Whitehorn
10001418697SNathan Whitehorn return (0);
10101418697SNathan Whitehorn }
10201418697SNathan Whitehorn
10301418697SNathan Whitehorn static void
adb_bus_enumerate(void * xdev)10401418697SNathan Whitehorn adb_bus_enumerate(void *xdev)
10501418697SNathan Whitehorn {
10601418697SNathan Whitehorn device_t dev = (device_t)xdev;
10701418697SNathan Whitehorn
10801418697SNathan Whitehorn struct adb_softc *sc = device_get_softc(dev);
109b4dbc599SNathan Whitehorn uint8_t i, next_free;
110b4dbc599SNathan Whitehorn uint16_t r3;
111b4dbc599SNathan Whitehorn
112b4dbc599SNathan Whitehorn sc->sc_dev = dev;
113b4dbc599SNathan Whitehorn sc->parent = device_get_parent(dev);
114b4dbc599SNathan Whitehorn
115b4dbc599SNathan Whitehorn sc->packet_reply = 0;
116b4dbc599SNathan Whitehorn sc->autopoll_mask = 0;
117582434bdSNathan Whitehorn sc->sync_packet = 0xffff;
118b4dbc599SNathan Whitehorn
119b4dbc599SNathan Whitehorn /* Initialize devinfo */
120b4dbc599SNathan Whitehorn for (i = 0; i < 16; i++) {
121b4dbc599SNathan Whitehorn sc->devinfo[i].address = i;
122b4dbc599SNathan Whitehorn sc->devinfo[i].default_address = 0;
123b4dbc599SNathan Whitehorn }
124b4dbc599SNathan Whitehorn
125b4dbc599SNathan Whitehorn /* Reset ADB bus */
126582434bdSNathan Whitehorn adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
127b4dbc599SNathan Whitehorn DELAY(1500);
128b4dbc599SNathan Whitehorn
129b4dbc599SNathan Whitehorn /* Enumerate bus */
130b4dbc599SNathan Whitehorn next_free = 8;
131b4dbc599SNathan Whitehorn
132669518d7SNathan Whitehorn for (i = 1; i <= 7; i++) {
133b4dbc599SNathan Whitehorn int8_t first_relocated = -1;
134b4dbc599SNathan Whitehorn int reply = 0;
135b4dbc599SNathan Whitehorn
136b4dbc599SNathan Whitehorn do {
137b4dbc599SNathan Whitehorn reply = adb_send_raw_packet_sync(dev,i,
138582434bdSNathan Whitehorn ADB_COMMAND_TALK,3,0,NULL,NULL);
139b4dbc599SNathan Whitehorn
140b4dbc599SNathan Whitehorn if (reply) {
141b4dbc599SNathan Whitehorn /* If we got a response, relocate to next_free */
142b4dbc599SNathan Whitehorn r3 = sc->devinfo[i].register3;
143b4dbc599SNathan Whitehorn r3 &= 0xf000;
144b4dbc599SNathan Whitehorn r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
145b4dbc599SNathan Whitehorn r3 |= 0x00fe;
146b4dbc599SNathan Whitehorn
147b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
148582434bdSNathan Whitehorn sizeof(uint16_t),(u_char *)(&r3),NULL);
149b4dbc599SNathan Whitehorn
150b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(dev,next_free,
151582434bdSNathan Whitehorn ADB_COMMAND_TALK,3,0,NULL,NULL);
152b4dbc599SNathan Whitehorn
153b4dbc599SNathan Whitehorn sc->devinfo[next_free].default_address = i;
154b4dbc599SNathan Whitehorn if (first_relocated < 0)
155b4dbc599SNathan Whitehorn first_relocated = next_free;
156b4dbc599SNathan Whitehorn
157b4dbc599SNathan Whitehorn next_free++;
158b4dbc599SNathan Whitehorn } else if (first_relocated > 0) {
159b4dbc599SNathan Whitehorn /* Collisions removed, relocate first device back */
160b4dbc599SNathan Whitehorn
161b4dbc599SNathan Whitehorn r3 = sc->devinfo[i].register3;
162b4dbc599SNathan Whitehorn r3 &= 0xf000;
163b4dbc599SNathan Whitehorn r3 |= ((uint16_t)(i) & 0x000f) << 8;
164b4dbc599SNathan Whitehorn
165b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(dev,first_relocated,
166b4dbc599SNathan Whitehorn ADB_COMMAND_LISTEN,3,
167582434bdSNathan Whitehorn sizeof(uint16_t),(u_char *)(&r3),NULL);
168b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(dev,i,
169582434bdSNathan Whitehorn ADB_COMMAND_TALK,3,0,NULL,NULL);
170b4dbc599SNathan Whitehorn
171b4dbc599SNathan Whitehorn sc->devinfo[i].default_address = i;
172b4dbc599SNathan Whitehorn sc->devinfo[(int)(first_relocated)].default_address = 0;
173b4dbc599SNathan Whitehorn break;
174b4dbc599SNathan Whitehorn }
175b4dbc599SNathan Whitehorn } while (reply);
176b4dbc599SNathan Whitehorn }
177b4dbc599SNathan Whitehorn
178b4dbc599SNathan Whitehorn for (i = 0; i < 16; i++) {
179b4dbc599SNathan Whitehorn if (sc->devinfo[i].default_address) {
1805b56413dSWarner Losh sc->children[i] = device_add_child(dev, NULL, DEVICE_UNIT_ANY);
181b4dbc599SNathan Whitehorn device_set_ivars(sc->children[i], &sc->devinfo[i]);
182b4dbc599SNathan Whitehorn }
183b4dbc599SNathan Whitehorn }
184b4dbc599SNathan Whitehorn
185*18250ec6SJohn Baldwin bus_attach_children(dev);
18601418697SNathan Whitehorn
18701418697SNathan Whitehorn config_intrhook_disestablish(&sc->enum_hook);
188b4dbc599SNathan Whitehorn }
189b4dbc599SNathan Whitehorn
190b4dbc599SNathan Whitehorn static void
adb_probe_nomatch(device_t dev,device_t child)191b4dbc599SNathan Whitehorn adb_probe_nomatch(device_t dev, device_t child)
192b4dbc599SNathan Whitehorn {
193b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
194b4dbc599SNathan Whitehorn
195b4dbc599SNathan Whitehorn if (bootverbose) {
196b4dbc599SNathan Whitehorn dinfo = device_get_ivars(child);
197b4dbc599SNathan Whitehorn
198b4dbc599SNathan Whitehorn device_printf(dev,"ADB %s at device %d (no driver attached)\n",
199b4dbc599SNathan Whitehorn adb_device_string[dinfo->default_address],dinfo->address);
200b4dbc599SNathan Whitehorn }
201b4dbc599SNathan Whitehorn }
202b4dbc599SNathan Whitehorn
203b4dbc599SNathan Whitehorn u_int
adb_receive_raw_packet(device_t dev,u_char status,u_char command,int len,u_char * data)204b4dbc599SNathan Whitehorn adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
205b4dbc599SNathan Whitehorn u_char *data)
206b4dbc599SNathan Whitehorn {
207b4dbc599SNathan Whitehorn struct adb_softc *sc = device_get_softc(dev);
208b4dbc599SNathan Whitehorn u_char addr = command >> 4;
209b4dbc599SNathan Whitehorn
210b4dbc599SNathan Whitehorn if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
211b4dbc599SNathan Whitehorn memcpy(&sc->devinfo[addr].register3,data,2);
212b4dbc599SNathan Whitehorn sc->devinfo[addr].handler_id = data[1];
213b4dbc599SNathan Whitehorn }
214b4dbc599SNathan Whitehorn
215b4dbc599SNathan Whitehorn if (sc->sync_packet == command) {
216b4dbc599SNathan Whitehorn memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
217b4dbc599SNathan Whitehorn atomic_store_rel_int(&sc->packet_reply,len + 1);
218582434bdSNathan Whitehorn wakeup(sc);
219b4dbc599SNathan Whitehorn }
220b4dbc599SNathan Whitehorn
221b4dbc599SNathan Whitehorn if (sc->children[addr] != NULL) {
222b4dbc599SNathan Whitehorn ADB_RECEIVE_PACKET(sc->children[addr],status,
223b4dbc599SNathan Whitehorn (command & 0x0f) >> 2,command & 0x03,len,data);
224b4dbc599SNathan Whitehorn }
225b4dbc599SNathan Whitehorn
226b4dbc599SNathan Whitehorn return (0);
227b4dbc599SNathan Whitehorn }
228b4dbc599SNathan Whitehorn
229b4dbc599SNathan Whitehorn static int
adb_print_child(device_t dev,device_t child)230b4dbc599SNathan Whitehorn adb_print_child(device_t dev, device_t child)
231b4dbc599SNathan Whitehorn {
232b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
233b4dbc599SNathan Whitehorn int retval = 0;
234b4dbc599SNathan Whitehorn
235b4dbc599SNathan Whitehorn dinfo = device_get_ivars(child);
236b4dbc599SNathan Whitehorn
237b4dbc599SNathan Whitehorn retval += bus_print_child_header(dev,child);
238b4dbc599SNathan Whitehorn printf(" at device %d",dinfo->address);
239b4dbc599SNathan Whitehorn retval += bus_print_child_footer(dev, child);
240b4dbc599SNathan Whitehorn
241b4dbc599SNathan Whitehorn return (retval);
242b4dbc599SNathan Whitehorn }
243b4dbc599SNathan Whitehorn
244b4dbc599SNathan Whitehorn u_int
adb_send_packet(device_t dev,u_char command,u_char reg,int len,u_char * data)245b4dbc599SNathan Whitehorn adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
246b4dbc599SNathan Whitehorn {
247b4dbc599SNathan Whitehorn u_char command_byte = 0;
248b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
249b4dbc599SNathan Whitehorn struct adb_softc *sc;
250b4dbc599SNathan Whitehorn
251b4dbc599SNathan Whitehorn sc = device_get_softc(device_get_parent(dev));
252b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
253b4dbc599SNathan Whitehorn
254b4dbc599SNathan Whitehorn command_byte |= dinfo->address << 4;
255b4dbc599SNathan Whitehorn command_byte |= command << 2;
256b4dbc599SNathan Whitehorn command_byte |= reg;
257b4dbc599SNathan Whitehorn
258b4dbc599SNathan Whitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
259b4dbc599SNathan Whitehorn
260b4dbc599SNathan Whitehorn return (0);
261b4dbc599SNathan Whitehorn }
262b4dbc599SNathan Whitehorn
263b4dbc599SNathan Whitehorn u_int
adb_set_autopoll(device_t dev,u_char enable)264b4dbc599SNathan Whitehorn adb_set_autopoll(device_t dev, u_char enable)
265b4dbc599SNathan Whitehorn {
266b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
267b4dbc599SNathan Whitehorn struct adb_softc *sc;
268b4dbc599SNathan Whitehorn uint16_t mod = 0;
269b4dbc599SNathan Whitehorn
270b4dbc599SNathan Whitehorn sc = device_get_softc(device_get_parent(dev));
271b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
272b4dbc599SNathan Whitehorn
273b4dbc599SNathan Whitehorn mod = enable << dinfo->address;
274b4dbc599SNathan Whitehorn if (enable) {
275b4dbc599SNathan Whitehorn sc->autopoll_mask |= mod;
276b4dbc599SNathan Whitehorn } else {
277b4dbc599SNathan Whitehorn mod = ~mod;
278b4dbc599SNathan Whitehorn sc->autopoll_mask &= mod;
279b4dbc599SNathan Whitehorn }
280b4dbc599SNathan Whitehorn
281b4dbc599SNathan Whitehorn ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
282b4dbc599SNathan Whitehorn
283b4dbc599SNathan Whitehorn return (0);
284b4dbc599SNathan Whitehorn }
285b4dbc599SNathan Whitehorn
286b4dbc599SNathan Whitehorn uint8_t
adb_get_device_type(device_t dev)287b4dbc599SNathan Whitehorn adb_get_device_type(device_t dev)
288b4dbc599SNathan Whitehorn {
289b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
290b4dbc599SNathan Whitehorn
291b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
292b4dbc599SNathan Whitehorn return (dinfo->default_address);
293b4dbc599SNathan Whitehorn }
294b4dbc599SNathan Whitehorn
295b4dbc599SNathan Whitehorn uint8_t
adb_get_device_handler(device_t dev)296b4dbc599SNathan Whitehorn adb_get_device_handler(device_t dev)
297b4dbc599SNathan Whitehorn {
298b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
299b4dbc599SNathan Whitehorn
300b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
301b4dbc599SNathan Whitehorn return (dinfo->handler_id);
302b4dbc599SNathan Whitehorn }
303b4dbc599SNathan Whitehorn
304b4dbc599SNathan Whitehorn 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)305b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
306582434bdSNathan Whitehorn uint8_t reg, int len, u_char *data, u_char *reply)
307b4dbc599SNathan Whitehorn {
308b4dbc599SNathan Whitehorn u_char command_byte = 0;
309b4dbc599SNathan Whitehorn struct adb_softc *sc;
310b4dbc599SNathan Whitehorn int result = -1;
311582434bdSNathan Whitehorn int i = 1;
312b4dbc599SNathan Whitehorn
313b4dbc599SNathan Whitehorn sc = device_get_softc(dev);
314b4dbc599SNathan Whitehorn
315b4dbc599SNathan Whitehorn command_byte |= to << 4;
316b4dbc599SNathan Whitehorn command_byte |= command << 2;
317b4dbc599SNathan Whitehorn command_byte |= reg;
318b4dbc599SNathan Whitehorn
319b4dbc599SNathan Whitehorn /* Wait if someone else has a synchronous request pending */
320582434bdSNathan Whitehorn while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
321582434bdSNathan Whitehorn tsleep(sc, 0, "ADB sync", hz/10);
322b4dbc599SNathan Whitehorn
323b4dbc599SNathan Whitehorn sc->packet_reply = 0;
324b4dbc599SNathan Whitehorn sc->sync_packet = command_byte;
325b4dbc599SNathan Whitehorn
326b4dbc599SNathan Whitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
327b4dbc599SNathan Whitehorn
328b4dbc599SNathan Whitehorn while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
32901418697SNathan Whitehorn /*
33001418697SNathan Whitehorn * Maybe the command got lost? Try resending and polling the
33101418697SNathan Whitehorn * controller.
33201418697SNathan Whitehorn */
333582434bdSNathan Whitehorn if (i % 40 == 0)
33401418697SNathan Whitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
33501418697SNathan Whitehorn len, data, 1);
336b4dbc599SNathan Whitehorn
337582434bdSNathan Whitehorn tsleep(sc, 0, "ADB sync", hz/10);
338b4dbc599SNathan Whitehorn i++;
339b4dbc599SNathan Whitehorn }
340b4dbc599SNathan Whitehorn
341b4dbc599SNathan Whitehorn result = sc->packet_reply - 1;
342b4dbc599SNathan Whitehorn
343582434bdSNathan Whitehorn if (reply != NULL && result > 0)
344582434bdSNathan Whitehorn memcpy(reply,sc->syncreg,result);
345582434bdSNathan Whitehorn
346b4dbc599SNathan Whitehorn /* Clear packet sync */
347b4dbc599SNathan Whitehorn sc->packet_reply = 0;
348b4dbc599SNathan Whitehorn
349582434bdSNathan Whitehorn /*
350582434bdSNathan Whitehorn * We can't match a value beyond 8 bits, so set sync_packet to
351582434bdSNathan Whitehorn * 0xffff to avoid collisions.
352582434bdSNathan Whitehorn */
353582434bdSNathan Whitehorn atomic_set_int(&sc->sync_packet, 0xffff);
354b4dbc599SNathan Whitehorn
355b4dbc599SNathan Whitehorn return (result);
356b4dbc599SNathan Whitehorn }
357b4dbc599SNathan Whitehorn
358b4dbc599SNathan Whitehorn uint8_t
adb_set_device_handler(device_t dev,uint8_t newhandler)359b4dbc599SNathan Whitehorn adb_set_device_handler(device_t dev, uint8_t newhandler)
360b4dbc599SNathan Whitehorn {
361b4dbc599SNathan Whitehorn struct adb_softc *sc;
362b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
363b4dbc599SNathan Whitehorn uint16_t newr3;
364b4dbc599SNathan Whitehorn
365b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
366b4dbc599SNathan Whitehorn sc = device_get_softc(device_get_parent(dev));
367b4dbc599SNathan Whitehorn
368b4dbc599SNathan Whitehorn newr3 = dinfo->register3 & 0xff00;
369b4dbc599SNathan Whitehorn newr3 |= (uint16_t)(newhandler);
370b4dbc599SNathan Whitehorn
371582434bdSNathan Whitehorn adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN,
372582434bdSNathan Whitehorn 3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
373b4dbc599SNathan Whitehorn adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
374582434bdSNathan Whitehorn ADB_COMMAND_TALK, 3, 0, NULL, NULL);
375b4dbc599SNathan Whitehorn
376b4dbc599SNathan Whitehorn return (dinfo->handler_id);
377b4dbc599SNathan Whitehorn }
378b4dbc599SNathan Whitehorn
379582434bdSNathan Whitehorn size_t
adb_read_register(device_t dev,u_char reg,void * data)380582434bdSNathan Whitehorn adb_read_register(device_t dev, u_char reg, void *data)
381b4dbc599SNathan Whitehorn {
382b4dbc599SNathan Whitehorn struct adb_softc *sc;
383b4dbc599SNathan Whitehorn struct adb_devinfo *dinfo;
384582434bdSNathan Whitehorn size_t result;
385b4dbc599SNathan Whitehorn
386b4dbc599SNathan Whitehorn dinfo = device_get_ivars(dev);
387b4dbc599SNathan Whitehorn sc = device_get_softc(device_get_parent(dev));
388b4dbc599SNathan Whitehorn
389582434bdSNathan Whitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
390582434bdSNathan Whitehorn ADB_COMMAND_TALK, reg, 0, NULL, data);
391b4dbc599SNathan Whitehorn
392582434bdSNathan Whitehorn return (result);
393b4dbc599SNathan Whitehorn }
394b4dbc599SNathan Whitehorn
395f697a802SNathan Whitehorn size_t
adb_write_register(device_t dev,u_char reg,size_t len,void * data)396f697a802SNathan Whitehorn adb_write_register(device_t dev, u_char reg, size_t len, void *data)
397f697a802SNathan Whitehorn {
398f697a802SNathan Whitehorn struct adb_softc *sc;
399f697a802SNathan Whitehorn struct adb_devinfo *dinfo;
400f697a802SNathan Whitehorn size_t result;
401f697a802SNathan Whitehorn
402f697a802SNathan Whitehorn dinfo = device_get_ivars(dev);
403f697a802SNathan Whitehorn sc = device_get_softc(device_get_parent(dev));
404f697a802SNathan Whitehorn
405f697a802SNathan Whitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
406f697a802SNathan Whitehorn ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
407f697a802SNathan Whitehorn
408f697a802SNathan Whitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
409f697a802SNathan Whitehorn ADB_COMMAND_TALK, reg, 0, NULL, NULL);
410f697a802SNathan Whitehorn
411f697a802SNathan Whitehorn return (result);
412f697a802SNathan Whitehorn }
413