adb_bus.c revision 184473
155682Smarkm/*- 2233294Sstas * Copyright (C) 2008 Nathan Whitehorn 355682Smarkm * All rights reserved. 455682Smarkm * 5233294Sstas * Redistribution and use in source and binary forms, with or without 655682Smarkm * modification, are permitted provided that the following conditions 755682Smarkm * are met: 855682Smarkm * 1. Redistributions of source code must retain the above copyright 9233294Sstas * notice, this list of conditions and the following disclaimer. 1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer in the 12233294Sstas * documentation and/or other materials provided with the distribution. 1355682Smarkm * 1455682Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1555682Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16233294Sstas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1755682Smarkm * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1855682Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1955682Smarkm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20233294Sstas * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2155682Smarkm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2255682Smarkm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2355682Smarkm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2455682Smarkm * 2555682Smarkm * $FreeBSD: head/sys/dev/adb/adb_bus.c 184473 2008-10-30 15:27:13Z nwhitehorn $ 2655682Smarkm */ 2755682Smarkm 2855682Smarkm#include <sys/cdefs.h> 2955682Smarkm#include <sys/param.h> 3055682Smarkm#include <sys/systm.h> 3155682Smarkm#include <sys/module.h> 3255682Smarkm#include <sys/bus.h> 3355682Smarkm#include <sys/conf.h> 3455682Smarkm#include <sys/kernel.h> 3555682Smarkm 3655682Smarkm#include <machine/bus.h> 3755682Smarkm 38233294Sstas#include <vm/vm.h> 3955682Smarkm#include <vm/pmap.h> 4055682Smarkm 4155682Smarkm#include "adb.h" 4255682Smarkm#include "adbvar.h" 43 44static int adb_bus_probe(device_t dev); 45static int adb_bus_attach(device_t dev); 46static int adb_bus_detach(device_t dev); 47static void adb_bus_enumerate(void *xdev); 48static void adb_probe_nomatch(device_t dev, device_t child); 49static int adb_print_child(device_t dev, device_t child); 50 51static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data); 52 53static char *adb_device_string[] = { 54 "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" 55}; 56 57static 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 73driver_t adb_driver = { 74 "adb", 75 adb_bus_methods, 76 sizeof(struct adb_softc), 77}; 78 79devclass_t adb_devclass; 80 81static int 82adb_bus_probe(device_t dev) 83{ 84 device_set_desc(dev, "Apple Desktop Bus"); 85 return (0); 86} 87 88static int 89adb_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 107static void 108adb_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 122 mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE); 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); 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); 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)); 154 155 adb_send_raw_packet_sync(dev,next_free, 156 ADB_COMMAND_TALK,3,0,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)); 173 adb_send_raw_packet_sync(dev,i, 174 ADB_COMMAND_TALK,3,0,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 192 config_intrhook_disestablish(&sc->enum_hook); 193} 194 195static int adb_bus_detach(device_t dev) 196{ 197 struct adb_softc *sc = device_get_softc(dev); 198 199 mtx_destroy(&sc->sc_sync_mtx); 200 201 return (bus_generic_detach(dev)); 202} 203 204 205static void 206adb_probe_nomatch(device_t dev, device_t child) 207{ 208 struct adb_devinfo *dinfo; 209 210 if (bootverbose) { 211 dinfo = device_get_ivars(child); 212 213 device_printf(dev,"ADB %s at device %d (no driver attached)\n", 214 adb_device_string[dinfo->default_address],dinfo->address); 215 } 216} 217 218u_int 219adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 220 u_char *data) 221{ 222 struct adb_softc *sc = device_get_softc(dev); 223 u_char addr = command >> 4; 224 225 if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { 226 memcpy(&sc->devinfo[addr].register3,data,2); 227 sc->devinfo[addr].handler_id = data[1]; 228 } 229 230 if (sc->sync_packet == command) { 231 memcpy(sc->syncreg,data,(len > 8) ? 8 : len); 232 atomic_store_rel_int(&sc->packet_reply,len + 1); 233 } 234 235 if (sc->children[addr] != NULL) { 236 ADB_RECEIVE_PACKET(sc->children[addr],status, 237 (command & 0x0f) >> 2,command & 0x03,len,data); 238 } 239 240 return (0); 241} 242 243static int 244adb_print_child(device_t dev, device_t child) 245{ 246 struct adb_devinfo *dinfo; 247 int retval = 0; 248 249 dinfo = device_get_ivars(child); 250 251 retval += bus_print_child_header(dev,child); 252 printf(" at device %d",dinfo->address); 253 retval += bus_print_child_footer(dev, child); 254 255 return (retval); 256} 257 258u_int 259adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data) 260{ 261 u_char command_byte = 0; 262 struct adb_devinfo *dinfo; 263 struct adb_softc *sc; 264 265 sc = device_get_softc(device_get_parent(dev)); 266 dinfo = device_get_ivars(dev); 267 268 command_byte |= dinfo->address << 4; 269 command_byte |= command << 2; 270 command_byte |= reg; 271 272 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 273 274 return (0); 275} 276 277u_int 278adb_set_autopoll(device_t dev, u_char enable) 279{ 280 struct adb_devinfo *dinfo; 281 struct adb_softc *sc; 282 uint16_t mod = 0; 283 284 sc = device_get_softc(device_get_parent(dev)); 285 dinfo = device_get_ivars(dev); 286 287 mod = enable << dinfo->address; 288 if (enable) { 289 sc->autopoll_mask |= mod; 290 } else { 291 mod = ~mod; 292 sc->autopoll_mask &= mod; 293 } 294 295 ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask); 296 297 return (0); 298} 299 300uint8_t 301adb_get_device_type(device_t dev) 302{ 303 struct adb_devinfo *dinfo; 304 305 dinfo = device_get_ivars(dev); 306 return (dinfo->default_address); 307} 308 309uint8_t 310adb_get_device_handler(device_t dev) 311{ 312 struct adb_devinfo *dinfo; 313 314 dinfo = device_get_ivars(dev); 315 return (dinfo->handler_id); 316} 317 318static int 319adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 320 uint8_t reg, int len, u_char *data) 321{ 322 u_char command_byte = 0; 323 struct adb_softc *sc; 324 int result = -1; 325 int i = 0; 326 327 sc = device_get_softc(dev); 328 329 command_byte |= to << 4; 330 command_byte |= command << 2; 331 command_byte |= reg; 332 333 /* Wait if someone else has a synchronous request pending */ 334 mtx_lock(&sc->sc_sync_mtx); 335 336 sc->packet_reply = 0; 337 sc->sync_packet = command_byte; 338 339 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 340 341 while (!atomic_fetchadd_int(&sc->packet_reply,0)) { 342 /* 343 * Maybe the command got lost? Try resending and polling the 344 * controller. 345 */ 346 if (i > 40) 347 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 348 len, data, 1); 349 350 DELAY(100); 351 i++; 352 } 353 354 result = sc->packet_reply - 1; 355 356 /* Clear packet sync */ 357 sc->packet_reply = 0; 358 sc->sync_packet = 0xffff; /* We can't match a 16 bit value */ 359 360 mtx_unlock(&sc->sc_sync_mtx); 361 362 return (result); 363} 364 365uint8_t 366adb_set_device_handler(device_t dev, uint8_t newhandler) 367{ 368 struct adb_softc *sc; 369 struct adb_devinfo *dinfo; 370 uint16_t newr3; 371 372 dinfo = device_get_ivars(dev); 373 sc = device_get_softc(device_get_parent(dev)); 374 375 newr3 = dinfo->register3 & 0xff00; 376 newr3 |= (uint16_t)(newhandler); 377 378 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 379 ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3)); 380 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 381 ADB_COMMAND_TALK, 3, 0, NULL); 382 383 return (dinfo->handler_id); 384} 385 386uint8_t 387adb_read_register(device_t dev, u_char reg, 388 size_t *len, void *data) 389{ 390 struct adb_softc *sc; 391 struct adb_devinfo *dinfo; 392 size_t orig_len; 393 394 dinfo = device_get_ivars(dev); 395 sc = device_get_softc(device_get_parent(dev)); 396 397 orig_len = *len; 398 399 mtx_lock(&sc->sc_sync_mtx); 400 401 *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 402 ADB_COMMAND_TALK, reg, 0, NULL); 403 404 if (*len > 0) 405 memcpy(data,sc->syncreg,*len); 406 407 mtx_unlock(&sc->sc_sync_mtx); 408 409 return ((*len > 0) ? 0 : -1); 410} 411 412