adb_bus.c revision 184299
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: head/sys/dev/adb/adb_bus.c 184299 2008-10-26 19:37:38Z nwhitehorn $ 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 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_probe_nomatch(device_t dev, device_t child); 48static int adb_print_child(device_t dev, device_t child); 49 50static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data); 51 52static char *adb_device_string[] = { 53 "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" 54}; 55 56static device_method_t adb_bus_methods[] = { 57 /* Device interface */ 58 DEVMETHOD(device_probe, adb_bus_probe), 59 DEVMETHOD(device_attach, adb_bus_attach), 60 DEVMETHOD(device_detach, adb_bus_detach), 61 DEVMETHOD(device_shutdown, bus_generic_shutdown), 62 DEVMETHOD(device_suspend, bus_generic_suspend), 63 DEVMETHOD(device_resume, bus_generic_resume), 64 65 /* Bus Interface */ 66 DEVMETHOD(bus_probe_nomatch, adb_probe_nomatch), 67 DEVMETHOD(bus_print_child, adb_print_child), 68 69 { 0, 0 }, 70}; 71 72driver_t adb_driver = { 73 "adb", 74 adb_bus_methods, 75 sizeof(struct adb_softc), 76}; 77 78devclass_t adb_devclass; 79 80static int 81adb_bus_probe(device_t dev) 82{ 83 device_set_desc(dev, "Apple Desktop Bus"); 84 return (0); 85} 86 87static int 88adb_bus_attach(device_t dev) 89{ 90 struct adb_softc *sc = device_get_softc(dev); 91 uint8_t i, next_free; 92 uint16_t r3; 93 94 sc->sc_dev = dev; 95 sc->parent = device_get_parent(dev); 96 97 sc->packet_reply = 0; 98 sc->autopoll_mask = 0; 99 100 mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE); 101 102 /* Initialize devinfo */ 103 for (i = 0; i < 16; i++) { 104 sc->devinfo[i].address = i; 105 sc->devinfo[i].default_address = 0; 106 } 107 108 /* Reset ADB bus */ 109 adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL); 110 DELAY(1500); 111 112 /* Enumerate bus */ 113 next_free = 8; 114 115 for (i = 1; i < 7; i++) { 116 int8_t first_relocated = -1; 117 int reply = 0; 118 119 do { 120 reply = adb_send_raw_packet_sync(dev,i, 121 ADB_COMMAND_TALK,3,0,NULL); 122 123 if (reply) { 124 /* If we got a response, relocate to next_free */ 125 r3 = sc->devinfo[i].register3; 126 r3 &= 0xf000; 127 r3 |= ((uint16_t)(next_free) & 0x000f) << 8; 128 r3 |= 0x00fe; 129 130 adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3, 131 sizeof(uint16_t),(u_char *)(&r3)); 132 133 adb_send_raw_packet_sync(dev,next_free, 134 ADB_COMMAND_TALK,3,0,NULL); 135 136 sc->devinfo[next_free].default_address = i; 137 if (first_relocated < 0) 138 first_relocated = next_free; 139 140 next_free++; 141 } else if (first_relocated > 0) { 142 /* Collisions removed, relocate first device back */ 143 144 r3 = sc->devinfo[i].register3; 145 r3 &= 0xf000; 146 r3 |= ((uint16_t)(i) & 0x000f) << 8; 147 148 adb_send_raw_packet_sync(dev,first_relocated, 149 ADB_COMMAND_LISTEN,3, 150 sizeof(uint16_t),(u_char *)(&r3)); 151 adb_send_raw_packet_sync(dev,i, 152 ADB_COMMAND_TALK,3,0,NULL); 153 154 sc->devinfo[i].default_address = i; 155 sc->devinfo[(int)(first_relocated)].default_address = 0; 156 break; 157 } 158 } while (reply); 159 } 160 161 for (i = 0; i < 16; i++) { 162 if (sc->devinfo[i].default_address) { 163 sc->children[i] = device_add_child(dev, NULL, -1); 164 device_set_ivars(sc->children[i], &sc->devinfo[i]); 165 } 166 } 167 168 return (bus_generic_attach(dev)); 169} 170 171static int adb_bus_detach(device_t dev) 172{ 173 struct adb_softc *sc = device_get_softc(dev); 174 175 mtx_destroy(&sc->sc_sync_mtx); 176 177 return (bus_generic_detach(dev)); 178} 179 180 181static void 182adb_probe_nomatch(device_t dev, device_t child) 183{ 184 struct adb_devinfo *dinfo; 185 186 if (bootverbose) { 187 dinfo = device_get_ivars(child); 188 189 device_printf(dev,"ADB %s at device %d (no driver attached)\n", 190 adb_device_string[dinfo->default_address],dinfo->address); 191 } 192} 193 194u_int 195adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 196 u_char *data) 197{ 198 struct adb_softc *sc = device_get_softc(dev); 199 u_char addr = command >> 4; 200 201 if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { 202 memcpy(&sc->devinfo[addr].register3,data,2); 203 sc->devinfo[addr].handler_id = data[1]; 204 } 205 206 if (sc->sync_packet == command) { 207 memcpy(sc->syncreg,data,(len > 8) ? 8 : len); 208 atomic_store_rel_int(&sc->packet_reply,len + 1); 209 } 210 211 if (sc->children[addr] != NULL) { 212 ADB_RECEIVE_PACKET(sc->children[addr],status, 213 (command & 0x0f) >> 2,command & 0x03,len,data); 214 } 215 216 return (0); 217} 218 219static int 220adb_print_child(device_t dev, device_t child) 221{ 222 struct adb_devinfo *dinfo; 223 int retval = 0; 224 225 dinfo = device_get_ivars(child); 226 227 retval += bus_print_child_header(dev,child); 228 printf(" at device %d",dinfo->address); 229 retval += bus_print_child_footer(dev, child); 230 231 return (retval); 232} 233 234u_int 235adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data) 236{ 237 u_char command_byte = 0; 238 struct adb_devinfo *dinfo; 239 struct adb_softc *sc; 240 241 sc = device_get_softc(device_get_parent(dev)); 242 dinfo = device_get_ivars(dev); 243 244 command_byte |= dinfo->address << 4; 245 command_byte |= command << 2; 246 command_byte |= reg; 247 248 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 249 250 return (0); 251} 252 253u_int 254adb_set_autopoll(device_t dev, u_char enable) 255{ 256 struct adb_devinfo *dinfo; 257 struct adb_softc *sc; 258 uint16_t mod = 0; 259 260 sc = device_get_softc(device_get_parent(dev)); 261 dinfo = device_get_ivars(dev); 262 263 mod = enable << dinfo->address; 264 if (enable) { 265 sc->autopoll_mask |= mod; 266 } else { 267 mod = ~mod; 268 sc->autopoll_mask &= mod; 269 } 270 271 ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask); 272 273 return (0); 274} 275 276uint8_t 277adb_get_device_type(device_t dev) 278{ 279 struct adb_devinfo *dinfo; 280 281 dinfo = device_get_ivars(dev); 282 return (dinfo->default_address); 283} 284 285uint8_t 286adb_get_device_handler(device_t dev) 287{ 288 struct adb_devinfo *dinfo; 289 290 dinfo = device_get_ivars(dev); 291 return (dinfo->handler_id); 292} 293 294static int 295adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 296 uint8_t reg, int len, u_char *data) 297{ 298 u_char command_byte = 0; 299 struct adb_softc *sc; 300 int result = -1; 301 int i = 0; 302 303 sc = device_get_softc(dev); 304 305 command_byte |= to << 4; 306 command_byte |= command << 2; 307 command_byte |= reg; 308 309 /* Wait if someone else has a synchronous request pending */ 310 mtx_lock(&sc->sc_sync_mtx); 311 312 sc->packet_reply = 0; 313 sc->sync_packet = command_byte; 314 315 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 316 317 while (!atomic_fetchadd_int(&sc->packet_reply,0)) { 318 /* Sometimes CUDA controllers hang up during cold boots. 319 Try poking them. */ 320 if (i > 10) 321 ADB_HB_CONTROLLER_POLL(sc->parent); 322 323 DELAY(100); 324 i++; 325 } 326 327 result = sc->packet_reply - 1; 328 329 /* Clear packet sync */ 330 sc->packet_reply = 0; 331 sc->sync_packet = 0xffff; /* We can't match a 16 bit value */ 332 333 mtx_unlock(&sc->sc_sync_mtx); 334 335 return (result); 336} 337 338uint8_t 339adb_set_device_handler(device_t dev, uint8_t newhandler) 340{ 341 struct adb_softc *sc; 342 struct adb_devinfo *dinfo; 343 uint16_t newr3; 344 345 dinfo = device_get_ivars(dev); 346 sc = device_get_softc(device_get_parent(dev)); 347 348 newr3 = dinfo->register3 & 0xff00; 349 newr3 |= (uint16_t)(newhandler); 350 351 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 352 ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3)); 353 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 354 ADB_COMMAND_TALK, 3, 0, NULL); 355 356 return (dinfo->handler_id); 357} 358 359uint8_t 360adb_read_register(device_t dev, u_char reg, 361 size_t *len, void *data) 362{ 363 struct adb_softc *sc; 364 struct adb_devinfo *dinfo; 365 size_t orig_len; 366 367 dinfo = device_get_ivars(dev); 368 sc = device_get_softc(device_get_parent(dev)); 369 370 orig_len = *len; 371 372 mtx_lock(&sc->sc_sync_mtx); 373 374 *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 375 ADB_COMMAND_TALK, reg, 0, NULL); 376 377 if (*len > 0) 378 memcpy(data,sc->syncreg,*len); 379 380 mtx_unlock(&sc->sc_sync_mtx); 381 382 return ((*len > 0) ? 0 : -1); 383} 384 385