Index: head/sys/dev/adb/adb.h =================================================================== --- head/sys/dev/adb/adb.h (revision 185723) +++ head/sys/dev/adb/adb.h (revision 185724) @@ -1,78 +1,78 @@ /*- * Copyright (C) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _POWERPC_ADB_H_ #define _POWERPC_ADB_H_ #include "adb_hb_if.h" #include "adb_if.h" enum { ADB_COMMAND_FLUSH = 0, ADB_COMMAND_LISTEN = 2, ADB_COMMAND_TALK = 3, }; enum { ADB_DEVICE_DONGLE = 0x01, ADB_DEVICE_KEYBOARD = 0x02, ADB_DEVICE_MOUSE = 0x03, ADB_DEVICE_TABLET = 0x04, ADB_DEVICE_MODEM = 0x05, ADB_DEVICE_MISC = 0x07 }; struct adb_devinfo { uint8_t address; uint8_t default_address; uint8_t handler_id; uint16_t register3; }; /* Pass packets down through the bus manager */ u_int adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data); u_int adb_set_autopoll(device_t dev, u_char enable); /* Pass packets up from the interface */ u_int adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, u_char *data); uint8_t adb_get_device_type(device_t dev); uint8_t adb_get_device_handler(device_t dev); uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler); -uint8_t adb_read_register(device_t dev, u_char reg, size_t *len, void *data); +size_t adb_read_register(device_t dev, u_char reg, void *data); /* Bits for implementing ADB host bus adapters */ extern devclass_t adb_devclass; extern driver_t adb_driver; #endif Index: head/sys/dev/adb/adb_bus.c =================================================================== --- head/sys/dev/adb/adb_bus.c (revision 185723) +++ head/sys/dev/adb/adb_bus.c (revision 185724) @@ -1,411 +1,404 @@ /*- * Copyright (C) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include "adb.h" #include "adbvar.h" static int adb_bus_probe(device_t dev); static int adb_bus_attach(device_t dev); static int adb_bus_detach(device_t dev); static void adb_bus_enumerate(void *xdev); static void adb_probe_nomatch(device_t dev, device_t child); static int adb_print_child(device_t dev, device_t child); -static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data); +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); static char *adb_device_string[] = { "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" }; static device_method_t adb_bus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, adb_bus_probe), DEVMETHOD(device_attach, adb_bus_attach), DEVMETHOD(device_detach, adb_bus_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus Interface */ DEVMETHOD(bus_probe_nomatch, adb_probe_nomatch), DEVMETHOD(bus_print_child, adb_print_child), { 0, 0 }, }; driver_t adb_driver = { "adb", adb_bus_methods, sizeof(struct adb_softc), }; devclass_t adb_devclass; static int adb_bus_probe(device_t dev) { device_set_desc(dev, "Apple Desktop Bus"); return (0); } static int adb_bus_attach(device_t dev) { struct adb_softc *sc = device_get_softc(dev); sc->enum_hook.ich_func = adb_bus_enumerate; sc->enum_hook.ich_arg = dev; /* * We should wait until interrupts are enabled to try to probe * the bus. Enumerating the ADB involves receiving packets, * which works best with interrupts enabled. */ if (config_intrhook_establish(&sc->enum_hook) != 0) return (ENOMEM); return (0); } static void adb_bus_enumerate(void *xdev) { device_t dev = (device_t)xdev; struct adb_softc *sc = device_get_softc(dev); uint8_t i, next_free; uint16_t r3; sc->sc_dev = dev; sc->parent = device_get_parent(dev); sc->packet_reply = 0; sc->autopoll_mask = 0; + sc->sync_packet = 0xffff; - mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE); - /* Initialize devinfo */ for (i = 0; i < 16; i++) { sc->devinfo[i].address = i; sc->devinfo[i].default_address = 0; } /* Reset ADB bus */ - adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL); + adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL); DELAY(1500); /* Enumerate bus */ next_free = 8; for (i = 1; i <= 7; i++) { int8_t first_relocated = -1; int reply = 0; do { reply = adb_send_raw_packet_sync(dev,i, - ADB_COMMAND_TALK,3,0,NULL); + ADB_COMMAND_TALK,3,0,NULL,NULL); if (reply) { /* If we got a response, relocate to next_free */ r3 = sc->devinfo[i].register3; r3 &= 0xf000; r3 |= ((uint16_t)(next_free) & 0x000f) << 8; r3 |= 0x00fe; adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3, - sizeof(uint16_t),(u_char *)(&r3)); + sizeof(uint16_t),(u_char *)(&r3),NULL); adb_send_raw_packet_sync(dev,next_free, - ADB_COMMAND_TALK,3,0,NULL); + ADB_COMMAND_TALK,3,0,NULL,NULL); sc->devinfo[next_free].default_address = i; if (first_relocated < 0) first_relocated = next_free; next_free++; } else if (first_relocated > 0) { /* Collisions removed, relocate first device back */ r3 = sc->devinfo[i].register3; r3 &= 0xf000; r3 |= ((uint16_t)(i) & 0x000f) << 8; adb_send_raw_packet_sync(dev,first_relocated, ADB_COMMAND_LISTEN,3, - sizeof(uint16_t),(u_char *)(&r3)); + sizeof(uint16_t),(u_char *)(&r3),NULL); adb_send_raw_packet_sync(dev,i, - ADB_COMMAND_TALK,3,0,NULL); + ADB_COMMAND_TALK,3,0,NULL,NULL); sc->devinfo[i].default_address = i; sc->devinfo[(int)(first_relocated)].default_address = 0; break; } } while (reply); } for (i = 0; i < 16; i++) { if (sc->devinfo[i].default_address) { sc->children[i] = device_add_child(dev, NULL, -1); device_set_ivars(sc->children[i], &sc->devinfo[i]); } } bus_generic_attach(dev); config_intrhook_disestablish(&sc->enum_hook); } static int adb_bus_detach(device_t dev) { - struct adb_softc *sc = device_get_softc(dev); - - mtx_destroy(&sc->sc_sync_mtx); - return (bus_generic_detach(dev)); } static void adb_probe_nomatch(device_t dev, device_t child) { struct adb_devinfo *dinfo; if (bootverbose) { dinfo = device_get_ivars(child); device_printf(dev,"ADB %s at device %d (no driver attached)\n", adb_device_string[dinfo->default_address],dinfo->address); } } u_int adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, u_char *data) { struct adb_softc *sc = device_get_softc(dev); u_char addr = command >> 4; if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { memcpy(&sc->devinfo[addr].register3,data,2); sc->devinfo[addr].handler_id = data[1]; } if (sc->sync_packet == command) { memcpy(sc->syncreg,data,(len > 8) ? 8 : len); atomic_store_rel_int(&sc->packet_reply,len + 1); + wakeup(sc); } if (sc->children[addr] != NULL) { ADB_RECEIVE_PACKET(sc->children[addr],status, (command & 0x0f) >> 2,command & 0x03,len,data); } return (0); } static int adb_print_child(device_t dev, device_t child) { struct adb_devinfo *dinfo; int retval = 0; dinfo = device_get_ivars(child); retval += bus_print_child_header(dev,child); printf(" at device %d",dinfo->address); retval += bus_print_child_footer(dev, child); return (retval); } u_int adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data) { u_char command_byte = 0; struct adb_devinfo *dinfo; struct adb_softc *sc; sc = device_get_softc(device_get_parent(dev)); dinfo = device_get_ivars(dev); command_byte |= dinfo->address << 4; command_byte |= command << 2; command_byte |= reg; ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); return (0); } u_int adb_set_autopoll(device_t dev, u_char enable) { struct adb_devinfo *dinfo; struct adb_softc *sc; uint16_t mod = 0; sc = device_get_softc(device_get_parent(dev)); dinfo = device_get_ivars(dev); mod = enable << dinfo->address; if (enable) { sc->autopoll_mask |= mod; } else { mod = ~mod; sc->autopoll_mask &= mod; } ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask); return (0); } uint8_t adb_get_device_type(device_t dev) { struct adb_devinfo *dinfo; dinfo = device_get_ivars(dev); return (dinfo->default_address); } uint8_t adb_get_device_handler(device_t dev) { struct adb_devinfo *dinfo; dinfo = device_get_ivars(dev); return (dinfo->handler_id); } static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, - uint8_t reg, int len, u_char *data) + uint8_t reg, int len, u_char *data, u_char *reply) { u_char command_byte = 0; struct adb_softc *sc; int result = -1; - int i = 0; + int i = 1; sc = device_get_softc(dev); command_byte |= to << 4; command_byte |= command << 2; command_byte |= reg; /* Wait if someone else has a synchronous request pending */ - mtx_lock(&sc->sc_sync_mtx); + while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte)) + tsleep(sc, 0, "ADB sync", hz/10); sc->packet_reply = 0; sc->sync_packet = command_byte; ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); while (!atomic_fetchadd_int(&sc->packet_reply,0)) { /* * Maybe the command got lost? Try resending and polling the * controller. */ - if (i > 40) + if (i % 40 == 0) ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); - DELAY(100); + tsleep(sc, 0, "ADB sync", hz/10); i++; } result = sc->packet_reply - 1; + if (reply != NULL && result > 0) + memcpy(reply,sc->syncreg,result); + /* Clear packet sync */ sc->packet_reply = 0; - sc->sync_packet = 0xffff; /* We can't match a 16 bit value */ - mtx_unlock(&sc->sc_sync_mtx); + /* + * We can't match a value beyond 8 bits, so set sync_packet to + * 0xffff to avoid collisions. + */ + atomic_set_int(&sc->sync_packet, 0xffff); return (result); } uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler) { struct adb_softc *sc; struct adb_devinfo *dinfo; uint16_t newr3; dinfo = device_get_ivars(dev); sc = device_get_softc(device_get_parent(dev)); newr3 = dinfo->register3 & 0xff00; newr3 |= (uint16_t)(newhandler); + adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, + 3, sizeof(uint16_t), (u_char *)(&newr3), NULL); adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, - ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3)); - adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, - ADB_COMMAND_TALK, 3, 0, NULL); + ADB_COMMAND_TALK, 3, 0, NULL, NULL); return (dinfo->handler_id); } -uint8_t -adb_read_register(device_t dev, u_char reg, - size_t *len, void *data) +size_t +adb_read_register(device_t dev, u_char reg, void *data) { struct adb_softc *sc; struct adb_devinfo *dinfo; - size_t orig_len; + size_t result; dinfo = device_get_ivars(dev); sc = device_get_softc(device_get_parent(dev)); - orig_len = *len; + result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, + ADB_COMMAND_TALK, reg, 0, NULL, data); - mtx_lock(&sc->sc_sync_mtx); - - *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, - ADB_COMMAND_TALK, reg, 0, NULL); - - if (*len > 0) - memcpy(data,sc->syncreg,*len); - - mtx_unlock(&sc->sc_sync_mtx); - - return ((*len > 0) ? 0 : -1); + return (result); } Index: head/sys/dev/adb/adb_kbd.c =================================================================== --- head/sys/dev/adb/adb_kbd.c (revision 185723) +++ head/sys/dev/adb/adb_kbd.c (revision 185724) @@ -1,692 +1,688 @@ /*- * Copyright (C) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include "opt_kbd.h" #include #include #include #include #include "adb.h" #define KBD_DRIVER_NAME "akbd" #define AKBD_EMULATE_ATKBD 1 static int adb_kbd_probe(device_t dev); static int adb_kbd_attach(device_t dev); static int adb_kbd_detach(device_t dev); static void akbd_repeat(void *xsc); static u_int adb_kbd_receive_packet(device_t dev, u_char status, u_char command, u_char reg, int len, u_char *data); struct adb_kbd_softc { keyboard_t sc_kbd; device_t sc_dev; struct mtx sc_mutex; struct cv sc_cv; int sc_mode; int sc_state; int have_led_control; uint8_t buffer[8]; volatile int buffers; struct callout sc_repeater; int sc_repeatstart; int sc_repeatcontinue; uint8_t last_press; }; static device_method_t adb_kbd_methods[] = { /* Device interface */ DEVMETHOD(device_probe, adb_kbd_probe), DEVMETHOD(device_attach, adb_kbd_attach), DEVMETHOD(device_detach, adb_kbd_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* ADB interface */ DEVMETHOD(adb_receive_packet, adb_kbd_receive_packet), { 0, 0 } }; static driver_t adb_kbd_driver = { "akbd", adb_kbd_methods, sizeof(struct adb_kbd_softc), }; static devclass_t adb_kbd_devclass; DRIVER_MODULE(akbd, adb, adb_kbd_driver, adb_kbd_devclass, 0, 0); static const uint8_t adb_to_at_scancode_map[128] = { 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 0, 48, 16, 17, 18, 19, 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, 15, 57, 41, 14, 0, 1, 29, 0, 42, 58, 56, 97, 98, 100, 95, 0, 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 91, 89, 0, 74, 13, 0, 0, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73, 0, 0, 0, 63, 64, 65, 61, 66, 67, 0, 87, 0, 105, 0, 70, 0, 68, 0, 88, 0, 107, 102, 94, 96, 103, 62, 99, 60, 101, 59, 54, 93, 90, 0, 0 }; /* keyboard driver declaration */ static int akbd_configure(int flags); static kbd_probe_t akbd_probe; static kbd_init_t akbd_init; static kbd_term_t akbd_term; static kbd_intr_t akbd_interrupt; static kbd_test_if_t akbd_test_if; static kbd_enable_t akbd_enable; static kbd_disable_t akbd_disable; static kbd_read_t akbd_read; static kbd_check_t akbd_check; static kbd_read_char_t akbd_read_char; static kbd_check_char_t akbd_check_char; static kbd_ioctl_t akbd_ioctl; static kbd_lock_t akbd_lock; static kbd_clear_state_t akbd_clear_state; static kbd_get_state_t akbd_get_state; static kbd_set_state_t akbd_set_state; static kbd_poll_mode_t akbd_poll; keyboard_switch_t akbdsw = { akbd_probe, akbd_init, akbd_term, akbd_interrupt, akbd_test_if, akbd_enable, akbd_disable, akbd_read, akbd_check, akbd_read_char, akbd_check_char, akbd_ioctl, akbd_lock, akbd_clear_state, akbd_get_state, akbd_set_state, genkbd_get_fkeystr, akbd_poll, genkbd_diag, }; KEYBOARD_DRIVER(akbd, akbdsw, akbd_configure); static int adb_kbd_probe(device_t dev) { uint8_t type; type = adb_get_device_type(dev); if (type != ADB_DEVICE_KEYBOARD) return (ENXIO); switch(adb_get_device_handler(dev)) { case 1: device_set_desc(dev,"Apple Standard Keyboard"); break; case 2: device_set_desc(dev,"Apple Extended Keyboard"); break; case 4: device_set_desc(dev,"Apple ISO Keyboard"); break; case 5: device_set_desc(dev,"Apple Extended ISO Keyboard"); break; case 8: device_set_desc(dev,"Apple Keyboard II"); break; case 9: device_set_desc(dev,"Apple ISO Keyboard II"); break; case 12: device_set_desc(dev,"PowerBook Keyboard"); break; case 13: device_set_desc(dev,"PowerBook ISO Keyboard"); break; case 24: device_set_desc(dev,"PowerBook Extended Keyboard"); break; case 27: device_set_desc(dev,"Apple Design Keyboard"); break; case 195: device_set_desc(dev,"PowerBook G3 Keyboard"); break; case 196: device_set_desc(dev,"iBook Keyboard"); break; default: device_set_desc(dev,"ADB Keyboard"); break; } return (0); } static int ms_to_ticks(int ms) { if (hz > 1000) return ms*(hz/1000); return ms/(1000/hz); } static int adb_kbd_attach(device_t dev) { struct adb_kbd_softc *sc; keyboard_switch_t *sw; sw = kbd_get_switch(KBD_DRIVER_NAME); if (sw == NULL) { return ENXIO; } sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_mode = K_RAW; sc->sc_state = 0; sc->have_led_control = 0; sc->buffers = 0; /* Try stepping forward to the extended keyboard protocol */ adb_set_device_handler(dev,3); mtx_init(&sc->sc_mutex,KBD_DRIVER_NAME,MTX_DEF,0); cv_init(&sc->sc_cv,KBD_DRIVER_NAME); callout_init(&sc->sc_repeater, 0); #ifdef AKBD_EMULATE_ATKBD kbd_init_struct(&sc->sc_kbd, KBD_DRIVER_NAME, KB_101, 0, 0, 0, 0); kbd_set_maps(&sc->sc_kbd, &key_map, &accent_map, fkey_tab, sizeof(fkey_tab) / sizeof(fkey_tab[0])); #else #error ADB raw mode not implemented #endif KBD_FOUND_DEVICE(&sc->sc_kbd); KBD_PROBE_DONE(&sc->sc_kbd); KBD_INIT_DONE(&sc->sc_kbd); KBD_CONFIG_DONE(&sc->sc_kbd); (*sw->enable)(&sc->sc_kbd); kbd_register(&sc->sc_kbd); #ifdef KBD_INSTALL_CDEV if (kbd_attach(&sc->sc_kbd)) { adb_kbd_detach(dev); return ENXIO; } #endif - adb_set_autopoll(dev,1); - - /* Check (asynchronously) if we can read out the LED state from + /* Check if we can read out the LED state from this keyboard by reading the key state register */ - adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL); + if (adb_read_register(dev, 2, NULL) == 2) + sc->have_led_control = 1; + adb_set_autopoll(dev,1); + return (0); } static int adb_kbd_detach(device_t dev) { struct adb_kbd_softc *sc; keyboard_t *kbd; sc = device_get_softc(dev); adb_set_autopoll(dev,0); callout_stop(&sc->sc_repeater); mtx_lock(&sc->sc_mutex); kbd = kbd_get_keyboard(kbd_find_keyboard(KBD_DRIVER_NAME, device_get_unit(dev))); kbdd_disable(kbd); #ifdef KBD_INSTALL_CDEV kbd_detach(kbd); #endif kbdd_term(kbd); mtx_unlock(&sc->sc_mutex); mtx_destroy(&sc->sc_mutex); cv_destroy(&sc->sc_cv); return (0); } static u_int adb_kbd_receive_packet(device_t dev, u_char status, u_char command, u_char reg, int len, u_char *data) { struct adb_kbd_softc *sc; sc = device_get_softc(dev); if (command != ADB_COMMAND_TALK) return 0; - - if (reg == 2 && len == 2) { - sc->have_led_control = 1; - return 0; - } if (reg != 0 || len != 2) return (0); mtx_lock(&sc->sc_mutex); if ((data[0] & 0x7f) == 57 && sc->buffers < 7) { /* Fake the down/up cycle for caps lock */ sc->buffer[sc->buffers++] = data[0] & 0x7f; sc->buffer[sc->buffers++] = (data[0] & 0x7f) | (1 << 7); } else { sc->buffer[sc->buffers++] = data[0]; } if (sc->buffer[sc->buffers-1] < 0xff) sc->last_press = sc->buffer[sc->buffers-1]; if ((data[1] & 0x7f) == 57 && sc->buffers < 7) { /* Fake the down/up cycle for caps lock */ sc->buffer[sc->buffers++] = data[1] & 0x7f; sc->buffer[sc->buffers++] = (data[1] & 0x7f) | (1 << 7); } else { sc->buffer[sc->buffers++] = data[1]; } if (sc->buffer[sc->buffers-1] < 0xff) sc->last_press = sc->buffer[sc->buffers-1]; /* Stop any existing key repeating */ callout_stop(&sc->sc_repeater); /* Schedule a repeat callback on keydown */ if (!(sc->last_press & (1 << 7))) { callout_reset(&sc->sc_repeater, ms_to_ticks(sc->sc_kbd.kb_delay1), akbd_repeat, sc); } mtx_unlock(&sc->sc_mutex); cv_broadcast(&sc->sc_cv); if (KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) { sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd, KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg); } return (0); } static void akbd_repeat(void *xsc) { struct adb_kbd_softc *sc = xsc; int notify_kbd = 0; /* Fake an up/down key repeat so long as we have the free buffers */ mtx_lock(&sc->sc_mutex); if (sc->buffers < 7) { sc->buffer[sc->buffers++] = sc->last_press | (1 << 7); sc->buffer[sc->buffers++] = sc->last_press; notify_kbd = 1; } mtx_unlock(&sc->sc_mutex); if (notify_kbd && KBD_IS_ACTIVE(&sc->sc_kbd) && KBD_IS_BUSY(&sc->sc_kbd)) { sc->sc_kbd.kb_callback.kc_func(&sc->sc_kbd, KBDIO_KEYINPUT, sc->sc_kbd.kb_callback.kc_arg); } /* Reschedule the callout */ callout_reset(&sc->sc_repeater, ms_to_ticks(sc->sc_kbd.kb_delay2), akbd_repeat, sc); } static int akbd_configure(int flags) { return 0; } static int akbd_probe(int unit, void *arg, int flags) { return 0; } static int akbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) { return 0; } static int akbd_term(keyboard_t *kbd) { return 0; } static int akbd_interrupt(keyboard_t *kbd, void *arg) { return 0; } static int akbd_test_if(keyboard_t *kbd) { return 0; } static int akbd_enable(keyboard_t *kbd) { KBD_ACTIVATE(kbd); return (0); } static int akbd_disable(keyboard_t *kbd) { struct adb_kbd_softc *sc; sc = (struct adb_kbd_softc *)(kbd); callout_stop(&sc->sc_repeater); KBD_DEACTIVATE(kbd); return (0); } static int akbd_read(keyboard_t *kbd, int wait) { return (0); } static int akbd_check(keyboard_t *kbd) { struct adb_kbd_softc *sc; if (!KBD_IS_ACTIVE(kbd)) return (FALSE); sc = (struct adb_kbd_softc *)(kbd); mtx_lock(&sc->sc_mutex); if (sc->buffers > 0) { mtx_unlock(&sc->sc_mutex); return (TRUE); } mtx_unlock(&sc->sc_mutex); return (FALSE); } static u_int akbd_read_char(keyboard_t *kbd, int wait) { struct adb_kbd_softc *sc; uint8_t adb_code, final_scancode; int i; sc = (struct adb_kbd_softc *)(kbd); mtx_lock(&sc->sc_mutex); if (!sc->buffers && wait) cv_wait(&sc->sc_cv,&sc->sc_mutex); if (!sc->buffers) { mtx_unlock(&sc->sc_mutex); return (0); } adb_code = sc->buffer[0]; for (i = 1; i < sc->buffers; i++) sc->buffer[i-1] = sc->buffer[i]; sc->buffers--; mtx_unlock(&sc->sc_mutex); #ifdef AKBD_EMULATE_ATKBD final_scancode = adb_to_at_scancode_map[adb_code & 0x7f]; final_scancode |= adb_code & 0x80; #else final_scancode = adb_code; #endif return (final_scancode); } static int akbd_check_char(keyboard_t *kbd) { if (!KBD_IS_ACTIVE(kbd)) return (FALSE); return (akbd_check(kbd)); } static int set_typematic(keyboard_t *kbd, int code) { /* These numbers are in microseconds, so convert to ticks */ static int delays[] = { 250, 500, 750, 1000 }; static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 68, 76, 84, 92, 100, 110, 118, 126, 136, 152, 168, 184, 200, 220, 236, 252, 272, 304, 336, 368, 400, 440, 472, 504 }; if (code & ~0x7f) return EINVAL; kbd->kb_delay1 = delays[(code >> 5) & 3]; kbd->kb_delay2 = rates[code & 0x1f]; return 0; } static int akbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data) { struct adb_kbd_softc *sc; uint16_t r2; int error; sc = (struct adb_kbd_softc *)(kbd); error = 0; switch (cmd) { case KDGKBMODE: *(int *)data = sc->sc_mode; break; case KDSKBMODE: switch (*(int *)data) { case K_XLATE: if (sc->sc_mode != K_XLATE) { /* make lock key state and LED state match */ sc->sc_state &= ~LOCK_MASK; sc->sc_state |= KBD_LED_VAL(kbd); } /* FALLTHROUGH */ case K_RAW: case K_CODE: if (sc->sc_mode != *(int *)data) sc->sc_mode = *(int *)data; break; default: error = EINVAL; break; } break; case KDGETLED: *(int *)data = KBD_LED_VAL(kbd); break; case KDSKBSTATE: if (*(int *)data & ~LOCK_MASK) { error = EINVAL; break; } sc->sc_state &= ~LOCK_MASK; sc->sc_state |= *(int *)data; /* FALLTHROUGH */ case KDSETLED: KBD_LED_VAL(kbd) = *(int *)data; if (!sc->have_led_control) break; r2 = (~0 & 0x04) | 3; if (*(int *)data & NLKED) r2 &= ~1; if (*(int *)data & CLKED) r2 &= ~2; if (*(int *)data & SLKED) r2 &= ~4; adb_send_packet(sc->sc_dev,ADB_COMMAND_LISTEN,2, sizeof(uint16_t),(u_char *)&r2); break; case KDGKBSTATE: *(int *)data = sc->sc_state & LOCK_MASK; break; case KDSETREPEAT: if (!KBD_HAS_DEVICE(kbd)) return 0; if (((int *)data)[1] < 0) return EINVAL; if (((int *)data)[0] < 0) return EINVAL; else if (((int *)data)[0] == 0) /* fastest possible value */ kbd->kb_delay1 = 200; else kbd->kb_delay1 = ((int *)data)[0]; kbd->kb_delay2 = ((int *)data)[1]; break; case KDSETRAD: error = set_typematic(kbd, *(int *)data); break; case PIO_KEYMAP: case PIO_KEYMAPENT: case PIO_DEADKEYMAP: default: return (genkbd_commonioctl(kbd, cmd, data)); } return (error); } static int akbd_lock(keyboard_t *kbd, int lock) { return (0); } static void akbd_clear_state(keyboard_t *kbd) { } static int akbd_get_state(keyboard_t *kbd, void *buf, size_t len) { return (0); } static int akbd_set_state(keyboard_t *kbd, void *buf, size_t len) { return (0); } static int akbd_poll(keyboard_t *kbd, int on) { return (0); } static int akbd_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: kbd_add_driver(&akbd_kbd_driver); break; case MOD_UNLOAD: kbd_delete_driver(&akbd_kbd_driver); break; default: return (EOPNOTSUPP); } return (0); } DEV_MODULE(akbd, akbd_modevent, NULL); Index: head/sys/dev/adb/adb_mouse.c =================================================================== --- head/sys/dev/adb/adb_mouse.c (revision 185723) +++ head/sys/dev/adb/adb_mouse.c (revision 185724) @@ -1,555 +1,555 @@ /*- * Copyright (C) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "adb.h" #define CDEV_GET_SOFTC(x) devclass_get_softc(adb_mouse_devclass, minor(x) & 0x1f) static int adb_mouse_probe(device_t dev); static int adb_mouse_attach(device_t dev); static int adb_mouse_detach(device_t dev); static d_open_t ams_open; static d_close_t ams_close; static d_read_t ams_read; static d_ioctl_t ams_ioctl; static d_poll_t ams_poll; static u_int adb_mouse_receive_packet(device_t dev, u_char status, u_char command, u_char reg, int len, u_char *data); struct adb_mouse_softc { device_t sc_dev; struct mtx sc_mtx; struct cv sc_cv; int flags; #define AMS_EXTENDED 0x1 #define AMS_TOUCHPAD 0x2 uint16_t dpi; mousehw_t hw; mousemode_t mode; u_char id[4]; int buttons; int last_buttons; int xdelta, ydelta; int8_t packet[8]; size_t packet_read_len; struct cdev *cdev; struct selinfo rsel; }; static device_method_t adb_mouse_methods[] = { /* Device interface */ DEVMETHOD(device_probe, adb_mouse_probe), DEVMETHOD(device_attach, adb_mouse_attach), DEVMETHOD(device_detach, adb_mouse_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* ADB interface */ DEVMETHOD(adb_receive_packet, adb_mouse_receive_packet), { 0, 0 } }; static driver_t adb_mouse_driver = { "ams", adb_mouse_methods, sizeof(struct adb_mouse_softc), }; static devclass_t adb_mouse_devclass; DRIVER_MODULE(ams, adb, adb_mouse_driver, adb_mouse_devclass, 0, 0); static struct cdevsw ams_cdevsw = { .d_version = D_VERSION, .d_flags = 0, .d_open = ams_open, .d_close = ams_close, .d_read = ams_read, .d_ioctl = ams_ioctl, .d_poll = ams_poll, .d_name = "ams", }; static int adb_mouse_probe(device_t dev) { uint8_t type; type = adb_get_device_type(dev); if (type != ADB_DEVICE_MOUSE) return (ENXIO); device_set_desc(dev,"ADB Mouse"); return (0); } static int adb_mouse_attach(device_t dev) { struct adb_mouse_softc *sc; char *description = "Unknown Pointing Device"; size_t r1_len; u_char r1[8]; sc = device_get_softc(dev); sc->sc_dev = dev; mtx_init(&sc->sc_mtx,"ams",MTX_DEF,0); cv_init(&sc->sc_cv,"ams"); sc->flags = 0; sc->hw.buttons = 2; sc->hw.iftype = MOUSE_IF_UNKNOWN; sc->hw.type = MOUSE_UNKNOWN; sc->hw.model = sc->hw.hwid = 0; sc->mode.protocol = MOUSE_PROTO_SYSMOUSE; sc->mode.rate = -1; sc->mode.resolution = 100; sc->mode.accelfactor = 0; sc->mode.level = 0; sc->mode.packetsize = 5; sc->buttons = 0; sc->last_buttons = 0; sc->packet_read_len = 0; /* Try to switch to extended protocol */ adb_set_device_handler(dev,4); switch(adb_get_device_handler(dev)) { case 1: sc->mode.resolution = 100; break; case 2: sc->mode.resolution = 200; break; case 4: - adb_read_register(dev,1,&r1_len,r1); + r1_len = adb_read_register(dev,1,r1); if (r1_len < 8) break; sc->flags |= AMS_EXTENDED; memcpy(&sc->hw.hwid,r1,4); sc->mode.resolution = (r1[4] << 8) | r1[5]; switch (r1[6]) { case 0: sc->hw.type = MOUSE_PAD; description = "Tablet"; break; case 1: sc->hw.type = MOUSE_MOUSE; description = "Mouse"; break; case 2: sc->hw.type = MOUSE_TRACKBALL; description = "Trackball"; break; case 3: sc->flags |= AMS_TOUCHPAD; sc->hw.type = MOUSE_PAD; description = "Touchpad"; break; } sc->hw.buttons = r1[7]; device_printf(dev,"%d-button %d-dpi %s\n", sc->hw.buttons, sc->mode.resolution,description); /* * Check for one of MacAlly's non-compliant 2-button mice. * These claim to speak the extended mouse protocol, but * instead speak the standard protocol and only when their * handler is set to 0x42. */ if (sc->hw.hwid == 0x4b4f4954) { adb_set_device_handler(dev,0x42); if (adb_get_device_handler(dev) == 0x42) { device_printf(dev, "MacAlly 2-Button Mouse\n"); sc->flags &= ~AMS_EXTENDED; } } break; } sc->cdev = make_dev(&ams_cdevsw, device_get_unit(dev), UID_ROOT, GID_OPERATOR, 0644, "ams%d", device_get_unit(dev)); adb_set_autopoll(dev,1); return (0); } static int adb_mouse_detach(device_t dev) { struct adb_mouse_softc *sc; adb_set_autopoll(dev,0); sc = device_get_softc(dev); destroy_dev(sc->cdev); mtx_destroy(&sc->sc_mtx); cv_destroy(&sc->sc_cv); return (0); } static u_int adb_mouse_receive_packet(device_t dev, u_char status, u_char command, u_char reg, int len, u_char *data) { struct adb_mouse_softc *sc; int i = 0; int xdelta, ydelta; int buttons; sc = device_get_softc(dev); if (command != ADB_COMMAND_TALK || reg != 0 || len < 2) return (0); ydelta = data[0] & 0x7f; xdelta = data[1] & 0x7f; buttons = 0; buttons |= !(data[0] & 0x80); buttons |= !(data[1] & 0x80) << 1; if (sc->flags & AMS_EXTENDED) { for (i = 2; i < len && i < 5; i++) { xdelta |= (data[i] & 0x07) << (3*i + 1); ydelta |= (data[i] & 0x70) << (3*i - 3); buttons |= !(data[i] & 0x08) << (2*i - 2); buttons |= !(data[i] & 0x80) << (2*i - 1); } } else { len = 2; /* Ignore extra data */ } /* Do sign extension as necessary */ if (xdelta & (0x40 << 3*(len-2))) xdelta |= 0xffffffc0 << 3*(len - 2); if (ydelta & (0x40 << 3*(len-2))) ydelta |= 0xffffffc0 << 3*(len - 2); /* * Some mice report high-numbered buttons on the wrong button number, * so set the highest-numbered real button as pressed if there are * mysterious high-numbered ones set. * * Don't do this for touchpads, because touchpads also trigger * high button events when they are touched. */ if (buttons & ~((1 << sc->hw.buttons) - 1) && !(sc->flags & AMS_TOUCHPAD)) { buttons |= 1 << (sc->hw.buttons - 1); } buttons &= (1 << sc->hw.buttons) - 1; mtx_lock(&sc->sc_mtx); /* Add in our new deltas, and take into account Apple's opposite meaning for Y axis motion */ sc->xdelta += xdelta; sc->ydelta -= ydelta; sc->buttons = buttons; mtx_unlock(&sc->sc_mtx); cv_broadcast(&sc->sc_cv); selwakeuppri(&sc->rsel, PZERO); return (0); } static int ams_open(struct cdev *dev, int flag, int fmt, struct thread *p) { struct adb_mouse_softc *sc; sc = CDEV_GET_SOFTC(dev); if (sc == NULL) return (ENXIO); mtx_lock(&sc->sc_mtx); sc->packet_read_len = 0; sc->xdelta = 0; sc->ydelta = 0; sc->buttons = 0; mtx_unlock(&sc->sc_mtx); return (0); } static int ams_close(struct cdev *dev, int flag, int fmt, struct thread *p) { struct adb_mouse_softc *sc; sc = CDEV_GET_SOFTC(dev); cv_broadcast(&sc->sc_cv); selwakeuppri(&sc->rsel, PZERO); return (0); } static int ams_poll(struct cdev *dev, int events, struct thread *p) { struct adb_mouse_softc *sc; sc = CDEV_GET_SOFTC(dev); if (sc == NULL) return (EIO); if (events & (POLLIN | POLLRDNORM)) { mtx_lock(&sc->sc_mtx); if (sc->xdelta == 0 && sc->ydelta == 0 && sc->buttons == sc->last_buttons) { selrecord(p, &sc->rsel); events = 0; } else { events &= (POLLIN | POLLRDNORM); } mtx_unlock(&sc->sc_mtx); } return events; } static int ams_read(struct cdev *dev, struct uio *uio, int flag) { struct adb_mouse_softc *sc; size_t len; int8_t outpacket[8]; int error; sc = CDEV_GET_SOFTC(dev); if (sc == NULL) return (EIO); if (uio->uio_resid <= 0) return (0); mtx_lock(&sc->sc_mtx); if (!sc->packet_read_len) { if (sc->xdelta == 0 && sc->ydelta == 0 && sc->buttons == sc->last_buttons) { if (flag & O_NONBLOCK) { mtx_unlock(&sc->sc_mtx); return EWOULDBLOCK; } /* Otherwise, block on new data */ error = cv_wait_sig(&sc->sc_cv, &sc->sc_mtx); if (error) { mtx_unlock(&sc->sc_mtx); return (error); } } sc->packet[0] = 1 << 7; sc->packet[0] |= (!(sc->buttons & 1)) << 2; sc->packet[0] |= (!(sc->buttons & 4)) << 1; sc->packet[0] |= (!(sc->buttons & 2)); if (sc->xdelta > 127) { sc->packet[1] = 127; sc->packet[3] = sc->xdelta - 127; } else if (sc->xdelta < -127) { sc->packet[1] = -127; sc->packet[3] = sc->xdelta + 127; } else { sc->packet[1] = sc->xdelta; sc->packet[3] = 0; } if (sc->ydelta > 127) { sc->packet[2] = 127; sc->packet[4] = sc->ydelta - 127; } else if (sc->ydelta < -127) { sc->packet[2] = -127; sc->packet[4] = sc->ydelta + 127; } else { sc->packet[2] = sc->ydelta; sc->packet[4] = 0; } /* No Z movement */ sc->packet[5] = 0; sc->packet[6] = 0; sc->packet[7] = ~((uint8_t)(sc->buttons >> 3)) & 0x7f; sc->last_buttons = sc->buttons; sc->xdelta = 0; sc->ydelta = 0; sc->packet_read_len = sc->mode.packetsize; } len = (sc->packet_read_len > uio->uio_resid) ? uio->uio_resid : sc->packet_read_len; memcpy(outpacket,sc->packet + (sc->mode.packetsize - sc->packet_read_len),len); sc->packet_read_len -= len; mtx_unlock(&sc->sc_mtx); uiomove(outpacket,len,uio); return (0); } static int ams_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *p) { struct adb_mouse_softc *sc; mousemode_t mode; sc = CDEV_GET_SOFTC(dev); if (sc == NULL) return (EIO); switch (cmd) { case MOUSE_GETHWINFO: *(mousehw_t *)addr = sc->hw; break; case MOUSE_GETMODE: *(mousemode_t *)addr = sc->mode; break; case MOUSE_SETMODE: mode = *(mousemode_t *)addr; addr = (caddr_t)&mode.level; /* Fallthrough */ case MOUSE_SETLEVEL: if (*(int *)addr == -1) break; else if (*(int *)addr == 1) { sc->mode.level = 1; sc->mode.packetsize = 8; break; } else if (*(int *)addr == 0) { sc->mode.level = 0; sc->mode.packetsize = 5; break; } return EINVAL; case MOUSE_GETLEVEL: *(int *)addr = sc->mode.level; break; case MOUSE_GETSTATUS: { mousestatus_t *status = (mousestatus_t *) addr; mtx_lock(&sc->sc_mtx); status->button = sc->buttons; status->obutton = sc->last_buttons; status->flags = status->button ^ status->obutton; if (sc->xdelta != 0 || sc->ydelta) status->flags |= MOUSE_POSCHANGED; if (status->button != status->obutton) status->flags |= MOUSE_BUTTONSCHANGED; status->dx = sc->xdelta; status->dy = sc->ydelta; status->dz = 0; sc->xdelta = 0; sc->ydelta = 0; sc->last_buttons = sc->buttons; mtx_unlock(&sc->sc_mtx); break; } default: return ENOTTY; } return (0); } Index: head/sys/dev/adb/adbvar.h =================================================================== --- head/sys/dev/adb/adbvar.h (revision 185723) +++ head/sys/dev/adb/adbvar.h (revision 185724) @@ -1,55 +1,54 @@ /*- * Copyright (C) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _POWERPC_ADBVAR_H_ #define _POWERPC_ADBVAR_H_ #include "adb.h" enum { ADB_COMMAND_BUS_RESET = 0 }; struct adb_softc { device_t sc_dev; device_t parent; struct intr_config_hook enum_hook; - struct mtx sc_sync_mtx; volatile int sync_packet; volatile int packet_reply; uint16_t autopoll_mask; uint8_t syncreg[8]; device_t children[16]; struct adb_devinfo devinfo[16]; }; #endif /* _POWERPC_ADBVAR_H_ */ Index: head/sys/powerpc/powermac/cuda.c =================================================================== --- head/sys/powerpc/powermac/cuda.c (revision 185723) +++ head/sys/powerpc/powermac/cuda.c (revision 185724) @@ -1,631 +1,704 @@ /*- * Copyright (c) 2006 Michael Lorenz * Copyright 2008 by Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cudavar.h" #include "viareg.h" /* * MacIO interface */ static int cuda_probe(device_t); static int cuda_attach(device_t); static int cuda_detach(device_t); -static u_int cuda_adb_send(device_t dev, u_char command_byte, int len, +static u_int cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, u_char poll); -static u_int cuda_adb_autopoll(device_t dev, uint16_t mask); -static void cuda_poll(device_t dev); +static u_int cuda_adb_autopoll(device_t dev, uint16_t mask); +static void cuda_poll(device_t dev); +static void cuda_send_inbound(struct cuda_softc *sc); +static void cuda_send_outbound(struct cuda_softc *sc); static device_method_t cuda_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cuda_probe), DEVMETHOD(device_attach, cuda_attach), DEVMETHOD(device_detach, cuda_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* bus interface, for ADB root */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), /* ADB bus interface */ DEVMETHOD(adb_hb_send_raw_packet, cuda_adb_send), DEVMETHOD(adb_hb_controller_poll, cuda_poll), DEVMETHOD(adb_hb_set_autopoll_mask, cuda_adb_autopoll), { 0, 0 }, }; static driver_t cuda_driver = { "cuda", cuda_methods, sizeof(struct cuda_softc), }; static devclass_t cuda_devclass; DRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0); DRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0); +MALLOC_DEFINE(M_CUDA, "cuda", "CUDA packet queue"); + static void cuda_intr(void *arg); static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset); static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value); static void cuda_idle(struct cuda_softc *); static void cuda_tip(struct cuda_softc *); static void cuda_clear_tip(struct cuda_softc *); static void cuda_in(struct cuda_softc *); static void cuda_out(struct cuda_softc *); static void cuda_toggle_ack(struct cuda_softc *); static void cuda_ack_off(struct cuda_softc *); static int cuda_intr_state(struct cuda_softc *); static int cuda_probe(device_t dev) { const char *type = ofw_bus_get_type(dev); if (strcmp(type, "via-cuda") != 0) return (ENXIO); device_set_desc(dev, CUDA_DEVSTR); return (0); } static int cuda_attach(device_t dev) { struct cuda_softc *sc; volatile int i; uint8_t reg; phandle_t node,child; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_memrid = 0; sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_memrid, RF_ACTIVE); if (sc->sc_memr == NULL) { device_printf(dev, "Could not alloc mem resource!\n"); return (ENXIO); } sc->sc_irqrid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, RF_ACTIVE); if (sc->sc_irq == NULL) { device_printf(dev, "could not allocate interrupt\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) { device_printf(dev, "could not setup interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq); return (ENXIO); } mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE); sc->sc_sent = 0; sc->sc_received = 0; sc->sc_waiting = 0; sc->sc_polling = 0; sc->sc_state = CUDA_NOTREADY; - sc->sc_error = 0; sc->sc_autopoll = 0; + STAILQ_INIT(&sc->sc_inq); + STAILQ_INIT(&sc->sc_outq); + /* Init CUDA */ reg = cuda_read_reg(sc, vDirB); reg |= 0x30; /* register B bits 4 and 5: outputs */ cuda_write_reg(sc, vDirB, reg); reg = cuda_read_reg(sc, vDirB); reg &= 0xf7; /* register B bit 3: input */ cuda_write_reg(sc, vDirB, reg); reg = cuda_read_reg(sc, vACR); reg &= ~vSR_OUT; /* make sure SR is set to IN */ cuda_write_reg(sc, vACR, reg); cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10); sc->sc_state = CUDA_IDLE; /* used by all types of hardware */ cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */ cuda_idle(sc); /* reset ADB */ /* Reset CUDA */ i = cuda_read_reg(sc, vSR); /* clear interrupt */ cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */ cuda_idle(sc); /* reset state to idle */ DELAY(150); cuda_tip(sc); /* signal start of frame */ DELAY(150); cuda_toggle_ack(sc); DELAY(150); cuda_clear_tip(sc); DELAY(150); cuda_idle(sc); /* back to idle state */ i = cuda_read_reg(sc, vSR); /* clear interrupt */ cuda_write_reg(sc, vIER, 0x84); /* ints ok now */ /* Initialize child buses (ADB) */ node = ofw_bus_get_node(dev); for (child = OF_child(node); child != 0; child = OF_peer(child)) { char name[32]; memset(name, 0, sizeof(name)); OF_getprop(child, "name", name, sizeof(name)); if (bootverbose) device_printf(dev, "CUDA child <%s>\n",name); if (strncmp(name, "adb", 4) == 0) { sc->adb_bus = device_add_child(dev,"adb",-1); } } return (bus_generic_attach(dev)); } static int cuda_detach(device_t dev) { struct cuda_softc *sc; sc = device_get_softc(dev); bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq); bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr); mtx_destroy(&sc->sc_mutex); return (bus_generic_detach(dev)); } static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset) { return (bus_read_1(sc->sc_memr, offset)); } static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value) { bus_write_1(sc->sc_memr, offset, value); } static void cuda_idle(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vBufB); reg |= (vPB4 | vPB5); cuda_write_reg(sc, vBufB, reg); } static void cuda_tip(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vBufB); reg &= ~vPB5; cuda_write_reg(sc, vBufB, reg); } static void cuda_clear_tip(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vBufB); reg |= vPB5; cuda_write_reg(sc, vBufB, reg); } static void cuda_in(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vACR); reg &= ~vSR_OUT; cuda_write_reg(sc, vACR, reg); } static void cuda_out(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vACR); reg |= vSR_OUT; cuda_write_reg(sc, vACR, reg); } static void cuda_toggle_ack(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vBufB); reg ^= vPB4; cuda_write_reg(sc, vBufB, reg); } static void cuda_ack_off(struct cuda_softc *sc) { uint8_t reg; reg = cuda_read_reg(sc, vBufB); reg |= vPB4; cuda_write_reg(sc, vBufB, reg); } static int cuda_intr_state(struct cuda_softc *sc) { return ((cuda_read_reg(sc, vBufB) & vPB3) == 0); } static int cuda_send(void *cookie, int poll, int length, uint8_t *msg) { struct cuda_softc *sc = cookie; device_t dev = sc->sc_dev; + struct cuda_packet *pkt; if (sc->sc_state == CUDA_NOTREADY) - return -1; + return (-1); mtx_lock(&sc->sc_mutex); - if (sc->sc_state != CUDA_IDLE) { - if (sc->sc_waiting == 0) { - sc->sc_waiting = 1; - } else { - mtx_unlock(&sc->sc_mutex); - return -1; - } + pkt = malloc(sizeof(struct cuda_packet), M_CUDA, M_WAITOK); + pkt->len = length - 1; + pkt->type = msg[0]; + memcpy(pkt->data, &msg[1], pkt->len); + + STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q); + + /* + * If we already are sending a packet, we should bail now that this + * one has been added to the queue. + */ + + if (sc->sc_waiting) { + mtx_unlock(&sc->sc_mutex); + return (0); } - sc->sc_error = 0; - memcpy(sc->sc_out, msg, length); - sc->sc_out_length = length; + cuda_send_outbound(sc); + mtx_unlock(&sc->sc_mutex); + + if (sc->sc_polling || poll || cold) + cuda_poll(dev); + + return (0); +} + +static void +cuda_send_outbound(struct cuda_softc *sc) +{ + struct cuda_packet *pkt; + + mtx_assert(&sc->sc_mutex, MA_OWNED); + + pkt = STAILQ_FIRST(&sc->sc_outq); + if (pkt == NULL) + return; + + sc->sc_out_length = pkt->len + 1; + memcpy(sc->sc_out, &pkt->type, pkt->len + 1); sc->sc_sent = 0; - if (sc->sc_waiting != 1) { - DELAY(150); + free(pkt, M_CUDA); + STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q); + + sc->sc_waiting = 1; + + cuda_poll(sc->sc_dev); + + DELAY(150); + + if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc)) { sc->sc_state = CUDA_OUT; cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[0]); cuda_ack_off(sc); cuda_tip(sc); } - sc->sc_waiting = 1; - mtx_unlock(&sc->sc_mutex); +} - if (sc->sc_polling || poll || cold) { - cuda_poll(dev); +static void +cuda_send_inbound(struct cuda_softc *sc) +{ + device_t dev; + struct cuda_packet *pkt; + + dev = sc->sc_dev; + + mtx_lock(&sc->sc_mutex); + + while ((pkt = STAILQ_FIRST(&sc->sc_inq)) != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_inq, pkt_q); + + mtx_unlock(&sc->sc_mutex); + + /* check if we have a handler for this message */ + switch (pkt->type) { + case CUDA_ADB: + if (pkt->len > 2) { + adb_receive_raw_packet(sc->adb_bus, + pkt->data[0],pkt->data[1], + pkt->len - 2,&pkt->data[2]); + } else { + adb_receive_raw_packet(sc->adb_bus, + pkt->data[0],pkt->data[1],0,NULL); + } + break; + case CUDA_PSEUDO: + mtx_lock(&sc->sc_mutex); + if (pkt->data[0] == CMD_AUTOPOLL) + sc->sc_autopoll = 1; + mtx_unlock(&sc->sc_mutex); + break; + case CUDA_ERROR: + /* + * CUDA will throw errors if we miss a race between + * sending and receiving packets. This is already + * handled when we abort packet output to handle + * this packet in cuda_intr(). Thus, we ignore + * these messages. + */ + break; + default: + device_printf(dev,"unknown CUDA command %d\n", + pkt->type); + break; + } + + free(pkt,M_CUDA); + + mtx_lock(&sc->sc_mutex); } - return 0; + mtx_unlock(&sc->sc_mutex); } static void cuda_poll(device_t dev) { struct cuda_softc *sc = device_get_softc(dev); if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc) && !sc->sc_waiting) return; - if ((cuda_read_reg(sc, vIFR) & vSR_INT) == vSR_INT) - cuda_intr(dev); + cuda_intr(dev); } static void cuda_intr(void *arg) { device_t dev; struct cuda_softc *sc; - int i, ending, type, restart_send; + int i, ending, restart_send, process_inbound; uint8_t reg; dev = (device_t)arg; sc = device_get_softc(dev); mtx_lock(&sc->sc_mutex); restart_send = 0; + process_inbound = 0; reg = cuda_read_reg(sc, vIFR); + if ((reg & vSR_INT) != vSR_INT) { + mtx_unlock(&sc->sc_mutex); + return; + } + cuda_write_reg(sc, vIFR, 0x7f); /* Clear interrupt */ switch_start: switch (sc->sc_state) { case CUDA_IDLE: /* * This is an unexpected packet, so grab the first (dummy) * byte, set up the proper vars, and tell the chip we are * starting to receive the packet by setting the TIP bit. */ sc->sc_in[1] = cuda_read_reg(sc, vSR); if (cuda_intr_state(sc) == 0) { /* must have been a fake start */ if (sc->sc_waiting) { /* start over */ DELAY(150); sc->sc_state = CUDA_OUT; sc->sc_sent = 0; cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[1]); cuda_ack_off(sc); cuda_tip(sc); } break; } cuda_in(sc); cuda_tip(sc); sc->sc_received = 1; sc->sc_state = CUDA_IN; break; case CUDA_IN: sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR); ending = 0; if (sc->sc_received > 255) { /* bitch only once */ if (sc->sc_received == 256) { device_printf(dev,"input overflow\n"); ending = 1; } } else sc->sc_received++; - if (sc->sc_received > 3) { - if ((sc->sc_in[3] == CMD_IIC) && - (sc->sc_received > (sc->sc_i2c_read_len + 4))) { - ending = 1; - } - } - /* intr off means this is the last byte (end of frame) */ if (cuda_intr_state(sc) == 0) { ending = 1; } else { cuda_toggle_ack(sc); } if (ending == 1) { /* end of message? */ - sc->sc_in[0] = sc->sc_received - 1; + struct cuda_packet *pkt; /* reset vars and signal the end of this frame */ cuda_idle(sc); - /* check if we have a handler for this message */ - type = sc->sc_in[1]; + /* Queue up the packet */ + pkt = malloc(sizeof(struct cuda_packet), M_CUDA, + M_WAITOK); - switch (type) { - case CUDA_ADB: - if (sc->sc_received > 4) { - adb_receive_raw_packet(sc->adb_bus, - sc->sc_in[2],sc->sc_in[3], - sc->sc_received - 4,&sc->sc_in[4]); - } else { - adb_receive_raw_packet(sc->adb_bus, - sc->sc_in[2],sc->sc_in[3],0,NULL); - } - break; - case CUDA_PSEUDO: - if (sc->sc_in[3] == CMD_AUTOPOLL) - sc->sc_autopoll = 1; - break; - case CUDA_ERROR: - device_printf(dev,"CUDA Error\n"); - sc->sc_error = 1; - break; - default: - device_printf(dev,"unknown CUDA command %d\n", - type); - break; - } + pkt->len = sc->sc_received - 2; + pkt->type = sc->sc_in[1]; + memcpy(pkt->data, &sc->sc_in[2], pkt->len); + STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q); + sc->sc_state = CUDA_IDLE; - sc->sc_received = 0; + process_inbound = 1; /* * If there is something waiting to be sent out, * set everything up and send the first byte. */ if (sc->sc_waiting == 1) { DELAY(1500); /* required */ sc->sc_sent = 0; sc->sc_state = CUDA_OUT; /* * If the interrupt is on, we were too slow * and the chip has already started to send * something to us, so back out of the write * and start a read cycle. */ if (cuda_intr_state(sc)) { cuda_in(sc); cuda_idle(sc); sc->sc_sent = 0; sc->sc_state = CUDA_IDLE; sc->sc_received = 0; DELAY(150); goto switch_start; } + /* * If we got here, it's ok to start sending * so load the first byte and tell the chip * we want to send. */ cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_ack_off(sc); cuda_tip(sc); } } break; case CUDA_OUT: i = cuda_read_reg(sc, vSR); /* reset SR-intr in IFR */ sc->sc_sent++; if (cuda_intr_state(sc)) { /* ADB intr low during write */ cuda_in(sc); /* make sure SR is set to IN */ cuda_idle(sc); sc->sc_sent = 0; /* must start all over */ sc->sc_state = CUDA_IDLE; /* new state */ sc->sc_received = 0; sc->sc_waiting = 1; /* must retry when done with * read */ DELAY(150); goto switch_start; /* process next state right * now */ break; } if (sc->sc_out_length == sc->sc_sent) { /* check for done */ - sc->sc_waiting = 0; /* done writing */ sc->sc_state = CUDA_IDLE; /* signal bus is idle */ cuda_in(sc); cuda_idle(sc); } else { /* send next byte */ cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_toggle_ack(sc); /* signal byte ready to * shift */ } break; case CUDA_NOTREADY: break; default: break; } mtx_unlock(&sc->sc_mutex); + + if (process_inbound) + cuda_send_inbound(sc); + + mtx_lock(&sc->sc_mutex); + /* If we have another packet waiting, set it up */ + if (!sc->sc_waiting && sc->sc_state == CUDA_IDLE) + cuda_send_outbound(sc); + + mtx_unlock(&sc->sc_mutex); + } static u_int -cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, u_char poll) +cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, + u_char poll) { struct cuda_softc *sc = device_get_softc(dev); - int i; uint8_t packet[16]; + int i; /* construct an ADB command packet and send it */ packet[0] = CUDA_ADB; packet[1] = command_byte; for (i = 0; i < len; i++) packet[i + 2] = data[i]; - if (poll) - cuda_poll(dev); - cuda_send(sc, poll, len + 2, packet); - if (poll) - cuda_poll(dev); - - return 0; + return (0); } static u_int cuda_adb_autopoll(device_t dev, uint16_t mask) { struct cuda_softc *sc = device_get_softc(dev); uint8_t cmd[] = {CUDA_PSEUDO, CMD_AUTOPOLL, mask != 0}; mtx_lock(&sc->sc_mutex); if (cmd[2] == sc->sc_autopoll) { mtx_unlock(&sc->sc_mutex); - return 0; + return (0); } - while (sc->sc_state != CUDA_IDLE) - mtx_sleep(dev,&sc->sc_mutex,0,"cuda",1); - sc->sc_autopoll = -1; - cuda_send(sc, 0, 3, cmd); + cuda_send(sc, 1, 3, cmd); mtx_unlock(&sc->sc_mutex); - - return 0; + + return (0); } Index: head/sys/powerpc/powermac/cudavar.h =================================================================== --- head/sys/powerpc/powermac/cudavar.h (revision 185723) +++ head/sys/powerpc/powermac/cudavar.h (revision 185724) @@ -1,94 +1,106 @@ /*- * Copyright (c) 2006 Michael Lorenz * Copyright (c) 2008 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ * */ #ifndef _POWERPC_CUDAVAR_H_ #define _POWERPC_CUDAVAR_H_ #define CUDA_DEVSTR "Apple CUDA I/O Controller" /* Cuda addresses */ #define CUDA_ADB 0 #define CUDA_PSEUDO 1 #define CUDA_ERROR 2 /* error codes? */ #define CUDA_TIMER 3 #define CUDA_POWER 4 #define CUDA_IIC 5 /* XXX ??? */ #define CUDA_PMU 6 #define CUDA_ADB_QUERY 7 /* Cuda commands */ #define CMD_AUTOPOLL 1 #define CMD_READ_RTC 3 #define CMD_WRITE_RTC 9 #define CMD_POWEROFF 10 #define CMD_RESET 17 #define CMD_IIC 34 /* Cuda state codes */ #define CUDA_NOTREADY 0x1 /* has not been initialized yet */ #define CUDA_IDLE 0x2 /* the bus is currently idle */ #define CUDA_OUT 0x3 /* sending out a command */ #define CUDA_IN 0x4 /* receiving data */ #define CUDA_POLLING 0x5 /* polling - II only */ +struct cuda_packet { + uint8_t len; + uint8_t type; + + uint8_t data[253]; + STAILQ_ENTRY(cuda_packet) pkt_q; +}; + +STAILQ_HEAD(cuda_pktq, cuda_packet); + struct cuda_softc { device_t sc_dev; int sc_memrid; struct resource *sc_memr; int sc_irqrid; struct resource *sc_irq; void *sc_ih; struct mtx sc_mutex; device_t adb_bus; - int sc_node; - volatile int sc_state; - int sc_waiting; - int sc_polling; - int sc_sent; - int sc_out_length; - int sc_received; - int sc_iic_done; - int sc_error; - volatile int sc_autopoll; + int sc_node; + volatile int sc_state; + int sc_waiting; + int sc_polling; + int sc_iic_done; + volatile int sc_autopoll; int sc_i2c_read_len; /* internal buffers */ - uint8_t sc_in[256]; - uint8_t sc_out[256]; + uint8_t sc_in[256]; + uint8_t sc_out[256]; + int sc_sent; + int sc_out_length; + int sc_received; + + struct cuda_pktq sc_inq; + struct cuda_pktq sc_outq; }; #endif /* _POWERPC_CUDAVAR_H_ */