1184299Snwhitehorn/*- 2184299Snwhitehorn * Copyright (C) 2008 Nathan Whitehorn 3184299Snwhitehorn * All rights reserved. 4184299Snwhitehorn * 5184299Snwhitehorn * Redistribution and use in source and binary forms, with or without 6184299Snwhitehorn * modification, are permitted provided that the following conditions 7184299Snwhitehorn * are met: 8184299Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9184299Snwhitehorn * notice, this list of conditions and the following disclaimer. 10184299Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11184299Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12184299Snwhitehorn * documentation and/or other materials provided with the distribution. 13184299Snwhitehorn * 14184299Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15184299Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16184299Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17184299Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18184299Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19184299Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20184299Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21184299Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22184299Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23184299Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24184299Snwhitehorn * 25184299Snwhitehorn * $FreeBSD$ 26184299Snwhitehorn */ 27184299Snwhitehorn 28184299Snwhitehorn#include <sys/cdefs.h> 29184299Snwhitehorn#include <sys/param.h> 30184299Snwhitehorn#include <sys/systm.h> 31184299Snwhitehorn#include <sys/module.h> 32184299Snwhitehorn#include <sys/bus.h> 33184299Snwhitehorn#include <sys/conf.h> 34184299Snwhitehorn#include <sys/kernel.h> 35184299Snwhitehorn 36184299Snwhitehorn#include <machine/bus.h> 37184299Snwhitehorn 38184299Snwhitehorn#include <vm/vm.h> 39184299Snwhitehorn#include <vm/pmap.h> 40184299Snwhitehorn 41184299Snwhitehorn#include "adb.h" 42184299Snwhitehorn#include "adbvar.h" 43184299Snwhitehorn 44184299Snwhitehornstatic int adb_bus_probe(device_t dev); 45184299Snwhitehornstatic int adb_bus_attach(device_t dev); 46184299Snwhitehornstatic int adb_bus_detach(device_t dev); 47184473Snwhitehornstatic void adb_bus_enumerate(void *xdev); 48184299Snwhitehornstatic void adb_probe_nomatch(device_t dev, device_t child); 49184299Snwhitehornstatic int adb_print_child(device_t dev, device_t child); 50184299Snwhitehorn 51185724Snwhitehornstatic 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); 52184299Snwhitehorn 53184299Snwhitehornstatic char *adb_device_string[] = { 54184299Snwhitehorn "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" 55184299Snwhitehorn}; 56184299Snwhitehorn 57184299Snwhitehornstatic device_method_t adb_bus_methods[] = { 58184299Snwhitehorn /* Device interface */ 59184299Snwhitehorn DEVMETHOD(device_probe, adb_bus_probe), 60184299Snwhitehorn DEVMETHOD(device_attach, adb_bus_attach), 61184299Snwhitehorn DEVMETHOD(device_detach, adb_bus_detach), 62184299Snwhitehorn DEVMETHOD(device_shutdown, bus_generic_shutdown), 63184299Snwhitehorn DEVMETHOD(device_suspend, bus_generic_suspend), 64184299Snwhitehorn DEVMETHOD(device_resume, bus_generic_resume), 65184299Snwhitehorn 66184299Snwhitehorn /* Bus Interface */ 67184299Snwhitehorn DEVMETHOD(bus_probe_nomatch, adb_probe_nomatch), 68184299Snwhitehorn DEVMETHOD(bus_print_child, adb_print_child), 69184299Snwhitehorn 70184299Snwhitehorn { 0, 0 }, 71184299Snwhitehorn}; 72184299Snwhitehorn 73184299Snwhitehorndriver_t adb_driver = { 74184299Snwhitehorn "adb", 75184299Snwhitehorn adb_bus_methods, 76184299Snwhitehorn sizeof(struct adb_softc), 77184299Snwhitehorn}; 78184299Snwhitehorn 79184299Snwhitehorndevclass_t adb_devclass; 80184299Snwhitehorn 81184299Snwhitehornstatic int 82184299Snwhitehornadb_bus_probe(device_t dev) 83184299Snwhitehorn{ 84184299Snwhitehorn device_set_desc(dev, "Apple Desktop Bus"); 85184299Snwhitehorn return (0); 86184299Snwhitehorn} 87184299Snwhitehorn 88184299Snwhitehornstatic int 89184299Snwhitehornadb_bus_attach(device_t dev) 90184299Snwhitehorn{ 91184299Snwhitehorn struct adb_softc *sc = device_get_softc(dev); 92184473Snwhitehorn sc->enum_hook.ich_func = adb_bus_enumerate; 93184473Snwhitehorn sc->enum_hook.ich_arg = dev; 94184473Snwhitehorn 95184473Snwhitehorn /* 96184473Snwhitehorn * We should wait until interrupts are enabled to try to probe 97184473Snwhitehorn * the bus. Enumerating the ADB involves receiving packets, 98184473Snwhitehorn * which works best with interrupts enabled. 99184473Snwhitehorn */ 100184473Snwhitehorn 101184473Snwhitehorn if (config_intrhook_establish(&sc->enum_hook) != 0) 102184473Snwhitehorn return (ENOMEM); 103184473Snwhitehorn 104184473Snwhitehorn return (0); 105184473Snwhitehorn} 106184473Snwhitehorn 107184473Snwhitehornstatic void 108184473Snwhitehornadb_bus_enumerate(void *xdev) 109184473Snwhitehorn{ 110184473Snwhitehorn device_t dev = (device_t)xdev; 111184473Snwhitehorn 112184473Snwhitehorn struct adb_softc *sc = device_get_softc(dev); 113184299Snwhitehorn uint8_t i, next_free; 114184299Snwhitehorn uint16_t r3; 115184299Snwhitehorn 116184299Snwhitehorn sc->sc_dev = dev; 117184299Snwhitehorn sc->parent = device_get_parent(dev); 118184299Snwhitehorn 119184299Snwhitehorn sc->packet_reply = 0; 120184299Snwhitehorn sc->autopoll_mask = 0; 121185724Snwhitehorn sc->sync_packet = 0xffff; 122184299Snwhitehorn 123184299Snwhitehorn /* Initialize devinfo */ 124184299Snwhitehorn for (i = 0; i < 16; i++) { 125184299Snwhitehorn sc->devinfo[i].address = i; 126184299Snwhitehorn sc->devinfo[i].default_address = 0; 127184299Snwhitehorn } 128184299Snwhitehorn 129184299Snwhitehorn /* Reset ADB bus */ 130185724Snwhitehorn adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL); 131184299Snwhitehorn DELAY(1500); 132184299Snwhitehorn 133184299Snwhitehorn /* Enumerate bus */ 134184299Snwhitehorn next_free = 8; 135184299Snwhitehorn 136184890Snwhitehorn for (i = 1; i <= 7; i++) { 137184299Snwhitehorn int8_t first_relocated = -1; 138184299Snwhitehorn int reply = 0; 139184299Snwhitehorn 140184299Snwhitehorn do { 141184299Snwhitehorn reply = adb_send_raw_packet_sync(dev,i, 142185724Snwhitehorn ADB_COMMAND_TALK,3,0,NULL,NULL); 143184299Snwhitehorn 144184299Snwhitehorn if (reply) { 145184299Snwhitehorn /* If we got a response, relocate to next_free */ 146184299Snwhitehorn r3 = sc->devinfo[i].register3; 147184299Snwhitehorn r3 &= 0xf000; 148184299Snwhitehorn r3 |= ((uint16_t)(next_free) & 0x000f) << 8; 149184299Snwhitehorn r3 |= 0x00fe; 150184299Snwhitehorn 151184299Snwhitehorn adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3, 152185724Snwhitehorn sizeof(uint16_t),(u_char *)(&r3),NULL); 153184299Snwhitehorn 154184299Snwhitehorn adb_send_raw_packet_sync(dev,next_free, 155185724Snwhitehorn ADB_COMMAND_TALK,3,0,NULL,NULL); 156184299Snwhitehorn 157184299Snwhitehorn sc->devinfo[next_free].default_address = i; 158184299Snwhitehorn if (first_relocated < 0) 159184299Snwhitehorn first_relocated = next_free; 160184299Snwhitehorn 161184299Snwhitehorn next_free++; 162184299Snwhitehorn } else if (first_relocated > 0) { 163184299Snwhitehorn /* Collisions removed, relocate first device back */ 164184299Snwhitehorn 165184299Snwhitehorn r3 = sc->devinfo[i].register3; 166184299Snwhitehorn r3 &= 0xf000; 167184299Snwhitehorn r3 |= ((uint16_t)(i) & 0x000f) << 8; 168184299Snwhitehorn 169184299Snwhitehorn adb_send_raw_packet_sync(dev,first_relocated, 170184299Snwhitehorn ADB_COMMAND_LISTEN,3, 171185724Snwhitehorn sizeof(uint16_t),(u_char *)(&r3),NULL); 172184299Snwhitehorn adb_send_raw_packet_sync(dev,i, 173185724Snwhitehorn ADB_COMMAND_TALK,3,0,NULL,NULL); 174184299Snwhitehorn 175184299Snwhitehorn sc->devinfo[i].default_address = i; 176184299Snwhitehorn sc->devinfo[(int)(first_relocated)].default_address = 0; 177184299Snwhitehorn break; 178184299Snwhitehorn } 179184299Snwhitehorn } while (reply); 180184299Snwhitehorn } 181184299Snwhitehorn 182184299Snwhitehorn for (i = 0; i < 16; i++) { 183184299Snwhitehorn if (sc->devinfo[i].default_address) { 184184299Snwhitehorn sc->children[i] = device_add_child(dev, NULL, -1); 185184299Snwhitehorn device_set_ivars(sc->children[i], &sc->devinfo[i]); 186184299Snwhitehorn } 187184299Snwhitehorn } 188184299Snwhitehorn 189184473Snwhitehorn bus_generic_attach(dev); 190184473Snwhitehorn 191184473Snwhitehorn config_intrhook_disestablish(&sc->enum_hook); 192184299Snwhitehorn} 193184299Snwhitehorn 194184299Snwhitehornstatic int adb_bus_detach(device_t dev) 195184299Snwhitehorn{ 196184299Snwhitehorn return (bus_generic_detach(dev)); 197184299Snwhitehorn} 198184299Snwhitehorn 199184299Snwhitehorn 200184299Snwhitehornstatic void 201184299Snwhitehornadb_probe_nomatch(device_t dev, device_t child) 202184299Snwhitehorn{ 203184299Snwhitehorn struct adb_devinfo *dinfo; 204184299Snwhitehorn 205184299Snwhitehorn if (bootverbose) { 206184299Snwhitehorn dinfo = device_get_ivars(child); 207184299Snwhitehorn 208184299Snwhitehorn device_printf(dev,"ADB %s at device %d (no driver attached)\n", 209184299Snwhitehorn adb_device_string[dinfo->default_address],dinfo->address); 210184299Snwhitehorn } 211184299Snwhitehorn} 212184299Snwhitehorn 213184299Snwhitehornu_int 214184299Snwhitehornadb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 215184299Snwhitehorn u_char *data) 216184299Snwhitehorn{ 217184299Snwhitehorn struct adb_softc *sc = device_get_softc(dev); 218184299Snwhitehorn u_char addr = command >> 4; 219184299Snwhitehorn 220184299Snwhitehorn if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { 221184299Snwhitehorn memcpy(&sc->devinfo[addr].register3,data,2); 222184299Snwhitehorn sc->devinfo[addr].handler_id = data[1]; 223184299Snwhitehorn } 224184299Snwhitehorn 225184299Snwhitehorn if (sc->sync_packet == command) { 226184299Snwhitehorn memcpy(sc->syncreg,data,(len > 8) ? 8 : len); 227184299Snwhitehorn atomic_store_rel_int(&sc->packet_reply,len + 1); 228185724Snwhitehorn wakeup(sc); 229184299Snwhitehorn } 230184299Snwhitehorn 231184299Snwhitehorn if (sc->children[addr] != NULL) { 232184299Snwhitehorn ADB_RECEIVE_PACKET(sc->children[addr],status, 233184299Snwhitehorn (command & 0x0f) >> 2,command & 0x03,len,data); 234184299Snwhitehorn } 235184299Snwhitehorn 236184299Snwhitehorn return (0); 237184299Snwhitehorn} 238184299Snwhitehorn 239184299Snwhitehornstatic int 240184299Snwhitehornadb_print_child(device_t dev, device_t child) 241184299Snwhitehorn{ 242184299Snwhitehorn struct adb_devinfo *dinfo; 243184299Snwhitehorn int retval = 0; 244184299Snwhitehorn 245184299Snwhitehorn dinfo = device_get_ivars(child); 246184299Snwhitehorn 247184299Snwhitehorn retval += bus_print_child_header(dev,child); 248184299Snwhitehorn printf(" at device %d",dinfo->address); 249184299Snwhitehorn retval += bus_print_child_footer(dev, child); 250184299Snwhitehorn 251184299Snwhitehorn return (retval); 252184299Snwhitehorn} 253184299Snwhitehorn 254184299Snwhitehornu_int 255184299Snwhitehornadb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data) 256184299Snwhitehorn{ 257184299Snwhitehorn u_char command_byte = 0; 258184299Snwhitehorn struct adb_devinfo *dinfo; 259184299Snwhitehorn struct adb_softc *sc; 260184299Snwhitehorn 261184299Snwhitehorn sc = device_get_softc(device_get_parent(dev)); 262184299Snwhitehorn dinfo = device_get_ivars(dev); 263184299Snwhitehorn 264184299Snwhitehorn command_byte |= dinfo->address << 4; 265184299Snwhitehorn command_byte |= command << 2; 266184299Snwhitehorn command_byte |= reg; 267184299Snwhitehorn 268184299Snwhitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 269184299Snwhitehorn 270184299Snwhitehorn return (0); 271184299Snwhitehorn} 272184299Snwhitehorn 273184299Snwhitehornu_int 274184299Snwhitehornadb_set_autopoll(device_t dev, u_char enable) 275184299Snwhitehorn{ 276184299Snwhitehorn struct adb_devinfo *dinfo; 277184299Snwhitehorn struct adb_softc *sc; 278184299Snwhitehorn uint16_t mod = 0; 279184299Snwhitehorn 280184299Snwhitehorn sc = device_get_softc(device_get_parent(dev)); 281184299Snwhitehorn dinfo = device_get_ivars(dev); 282184299Snwhitehorn 283184299Snwhitehorn mod = enable << dinfo->address; 284184299Snwhitehorn if (enable) { 285184299Snwhitehorn sc->autopoll_mask |= mod; 286184299Snwhitehorn } else { 287184299Snwhitehorn mod = ~mod; 288184299Snwhitehorn sc->autopoll_mask &= mod; 289184299Snwhitehorn } 290184299Snwhitehorn 291184299Snwhitehorn ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask); 292184299Snwhitehorn 293184299Snwhitehorn return (0); 294184299Snwhitehorn} 295184299Snwhitehorn 296184299Snwhitehornuint8_t 297184299Snwhitehornadb_get_device_type(device_t dev) 298184299Snwhitehorn{ 299184299Snwhitehorn struct adb_devinfo *dinfo; 300184299Snwhitehorn 301184299Snwhitehorn dinfo = device_get_ivars(dev); 302184299Snwhitehorn return (dinfo->default_address); 303184299Snwhitehorn} 304184299Snwhitehorn 305184299Snwhitehornuint8_t 306184299Snwhitehornadb_get_device_handler(device_t dev) 307184299Snwhitehorn{ 308184299Snwhitehorn struct adb_devinfo *dinfo; 309184299Snwhitehorn 310184299Snwhitehorn dinfo = device_get_ivars(dev); 311184299Snwhitehorn return (dinfo->handler_id); 312184299Snwhitehorn} 313184299Snwhitehorn 314184299Snwhitehornstatic int 315184299Snwhitehornadb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 316185724Snwhitehorn uint8_t reg, int len, u_char *data, u_char *reply) 317184299Snwhitehorn{ 318184299Snwhitehorn u_char command_byte = 0; 319184299Snwhitehorn struct adb_softc *sc; 320184299Snwhitehorn int result = -1; 321185724Snwhitehorn int i = 1; 322184299Snwhitehorn 323184299Snwhitehorn sc = device_get_softc(dev); 324184299Snwhitehorn 325184299Snwhitehorn command_byte |= to << 4; 326184299Snwhitehorn command_byte |= command << 2; 327184299Snwhitehorn command_byte |= reg; 328184299Snwhitehorn 329184299Snwhitehorn /* Wait if someone else has a synchronous request pending */ 330185724Snwhitehorn while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte)) 331185724Snwhitehorn tsleep(sc, 0, "ADB sync", hz/10); 332184299Snwhitehorn 333184299Snwhitehorn sc->packet_reply = 0; 334184299Snwhitehorn sc->sync_packet = command_byte; 335184299Snwhitehorn 336184299Snwhitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 337184299Snwhitehorn 338184299Snwhitehorn while (!atomic_fetchadd_int(&sc->packet_reply,0)) { 339184473Snwhitehorn /* 340184473Snwhitehorn * Maybe the command got lost? Try resending and polling the 341184473Snwhitehorn * controller. 342184473Snwhitehorn */ 343185724Snwhitehorn if (i % 40 == 0) 344184473Snwhitehorn ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 345184473Snwhitehorn len, data, 1); 346184299Snwhitehorn 347185724Snwhitehorn tsleep(sc, 0, "ADB sync", hz/10); 348184299Snwhitehorn i++; 349184299Snwhitehorn } 350184299Snwhitehorn 351184299Snwhitehorn result = sc->packet_reply - 1; 352184299Snwhitehorn 353185724Snwhitehorn if (reply != NULL && result > 0) 354185724Snwhitehorn memcpy(reply,sc->syncreg,result); 355185724Snwhitehorn 356184299Snwhitehorn /* Clear packet sync */ 357184299Snwhitehorn sc->packet_reply = 0; 358184299Snwhitehorn 359185724Snwhitehorn /* 360185724Snwhitehorn * We can't match a value beyond 8 bits, so set sync_packet to 361185724Snwhitehorn * 0xffff to avoid collisions. 362185724Snwhitehorn */ 363185724Snwhitehorn atomic_set_int(&sc->sync_packet, 0xffff); 364184299Snwhitehorn 365184299Snwhitehorn return (result); 366184299Snwhitehorn} 367184299Snwhitehorn 368184299Snwhitehornuint8_t 369184299Snwhitehornadb_set_device_handler(device_t dev, uint8_t newhandler) 370184299Snwhitehorn{ 371184299Snwhitehorn struct adb_softc *sc; 372184299Snwhitehorn struct adb_devinfo *dinfo; 373184299Snwhitehorn uint16_t newr3; 374184299Snwhitehorn 375184299Snwhitehorn dinfo = device_get_ivars(dev); 376184299Snwhitehorn sc = device_get_softc(device_get_parent(dev)); 377184299Snwhitehorn 378184299Snwhitehorn newr3 = dinfo->register3 & 0xff00; 379184299Snwhitehorn newr3 |= (uint16_t)(newhandler); 380184299Snwhitehorn 381185724Snwhitehorn adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, 382185724Snwhitehorn 3, sizeof(uint16_t), (u_char *)(&newr3), NULL); 383184299Snwhitehorn adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 384185724Snwhitehorn ADB_COMMAND_TALK, 3, 0, NULL, NULL); 385184299Snwhitehorn 386184299Snwhitehorn return (dinfo->handler_id); 387184299Snwhitehorn} 388184299Snwhitehorn 389185724Snwhitehornsize_t 390185724Snwhitehornadb_read_register(device_t dev, u_char reg, void *data) 391184299Snwhitehorn{ 392184299Snwhitehorn struct adb_softc *sc; 393184299Snwhitehorn struct adb_devinfo *dinfo; 394185724Snwhitehorn size_t result; 395184299Snwhitehorn 396184299Snwhitehorn dinfo = device_get_ivars(dev); 397184299Snwhitehorn sc = device_get_softc(device_get_parent(dev)); 398184299Snwhitehorn 399185724Snwhitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 400185724Snwhitehorn ADB_COMMAND_TALK, reg, 0, NULL, data); 401184299Snwhitehorn 402185724Snwhitehorn return (result); 403184299Snwhitehorn} 404184299Snwhitehorn 405199888Snwhitehornsize_t 406199888Snwhitehornadb_write_register(device_t dev, u_char reg, size_t len, void *data) 407199888Snwhitehorn{ 408199888Snwhitehorn struct adb_softc *sc; 409199888Snwhitehorn struct adb_devinfo *dinfo; 410199888Snwhitehorn size_t result; 411199888Snwhitehorn 412199888Snwhitehorn dinfo = device_get_ivars(dev); 413199888Snwhitehorn sc = device_get_softc(device_get_parent(dev)); 414199888Snwhitehorn 415199888Snwhitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 416199888Snwhitehorn ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL); 417199888Snwhitehorn 418199888Snwhitehorn result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 419199888Snwhitehorn ADB_COMMAND_TALK, reg, 0, NULL, NULL); 420199888Snwhitehorn 421199888Snwhitehorn return (result); 422199888Snwhitehorn} 423