|
|
1.1 ! root 1: /* ! 2: * ! 3: * Open Hack'Ware BIOS ADB bus support, ported to OpenBIOS ! 4: * ! 5: * Copyright (c) 2005 Jocelyn Mayer ! 6: * Copyright (c) 2005 Stefan Reinauer ! 7: * ! 8: * This program is free software; you can redistribute it and/or ! 9: * modify it under the terms of the GNU General Public License V2 ! 10: * as published by the Free Software Foundation ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA ! 20: */ ! 21: ! 22: #include "config.h" ! 23: #include "libopenbios/bindings.h" ! 24: #include "libc/vsprintf.h" ! 25: ! 26: #include "adb_bus.h" ! 27: #include "adb_kbd.h" ! 28: #include "adb_mouse.h" ! 29: ! 30: DECLARE_UNNAMED_NODE( adb, INSTALL_OPEN, sizeof(int)); ! 31: ! 32: static void ! 33: adb_initialize (int *idx) ! 34: { ! 35: phandle_t ph=get_cur_dev(); ! 36: ! 37: push_str("adb"); ! 38: fword("device-type"); ! 39: ! 40: set_property(ph, "compatible", "adb", 4); ! 41: set_int_property(ph, "#address-cells", 1); ! 42: set_int_property(ph, "#size-cells", 0); ! 43: } ! 44: ! 45: static void ! 46: adb_open(int *idx) ! 47: { ! 48: RET(-1); ! 49: } ! 50: ! 51: static void ! 52: adb_close(int *idx) ! 53: { ! 54: } ! 55: ! 56: NODE_METHODS( adb ) = { ! 57: { NULL, adb_initialize }, ! 58: { "open", adb_open }, ! 59: { "close", adb_close }, ! 60: }; ! 61: ! 62: adb_bus_t *adb_bus_new (void *host, ! 63: int (*req)(void *host, const uint8_t *snd_buf, ! 64: int len, uint8_t *rcv_buf)) ! 65: { ! 66: adb_bus_t *new; ! 67: ! 68: new = malloc(sizeof(adb_bus_t)); ! 69: if (new == NULL) ! 70: return NULL; ! 71: new->host = host; ! 72: new->req = req; ! 73: ! 74: return new; ! 75: } ! 76: ! 77: /* Check and relocate all ADB devices as suggested in ! 78: * ADB_manager Apple documentation ! 79: */ ! 80: ! 81: int adb_bus_init (char *path, adb_bus_t *bus) ! 82: { ! 83: char buf[64]; ! 84: uint8_t buffer[ADB_BUF_SIZE]; ! 85: uint8_t adb_addresses[16] = ! 86: { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, }; ! 87: adb_dev_t tmp_device, **cur; ! 88: int address; ! 89: int reloc = 0, next_free = 7; ! 90: int keep; ! 91: ! 92: snprintf(buf, sizeof(buf), "%s/adb", path); ! 93: REGISTER_NAMED_NODE( adb, buf); ! 94: /* Reset the bus */ ! 95: // ADB_DPRINTF("\n"); ! 96: adb_reset(bus); ! 97: cur = &bus->devices; ! 98: memset(&tmp_device, 0, sizeof(adb_dev_t)); ! 99: tmp_device.bus = bus; ! 100: for (address = 1; address < 8 && adb_addresses[reloc] > 0;) { ! 101: if (address == ADB_RES) { ! 102: /* Reserved */ ! 103: address++; ! 104: continue; ! 105: } ! 106: //ADB_DPRINTF("Check device on ADB address %d\n", address); ! 107: tmp_device.addr = address; ! 108: switch (adb_reg_get(&tmp_device, 3, buffer)) { ! 109: case 0: ! 110: //ADB_DPRINTF("No device on ADB address %d\n", address); ! 111: /* Register this address as free */ ! 112: if (adb_addresses[next_free] != 0) ! 113: adb_addresses[next_free++] = address; ! 114: /* Check next ADB address */ ! 115: address++; ! 116: break; ! 117: case 2: ! 118: /* One device answered : ! 119: * make it available and relocate it to a free address ! 120: */ ! 121: if (buffer[0] == ADB_CHADDR) { ! 122: /* device self test failed */ ! 123: ADB_DPRINTF("device on ADB address %d self-test failed " ! 124: "%02x %02x %02x\n", address, ! 125: buffer[0], buffer[1], buffer[2]); ! 126: keep = 0; ! 127: } else { ! 128: //ADB_DPRINTF("device on ADB address %d self-test OK\n", ! 129: // address); ! 130: keep = 1; ! 131: } ! 132: ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n", ! 133: address, adb_addresses[reloc], reloc); ! 134: buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc]; ! 135: if (keep == 1) ! 136: buffer[0] |= 0x20; ! 137: buffer[1] = ADB_CHADDR_NOCOLL; ! 138: if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) { ! 139: ADB_DPRINTF("ADB device relocation failed\n"); ! 140: return -1; ! 141: } ! 142: if (keep == 1) { ! 143: *cur = malloc(sizeof(adb_dev_t)); ! 144: if (*cur == NULL) { ! 145: return -1; ! 146: } ! 147: (*cur)->type = address; ! 148: (*cur)->bus = bus; ! 149: (*cur)->addr = adb_addresses[reloc++]; ! 150: /* Flush buffers */ ! 151: adb_flush(*cur); ! 152: switch ((*cur)->type) { ! 153: case ADB_PROTECT: ! 154: ADB_DPRINTF("Found one protected device\n"); ! 155: break; ! 156: case ADB_KEYBD: ! 157: ADB_DPRINTF("Found one keyboard on address %d\n", address); ! 158: adb_kbd_new(buf, *cur); ! 159: break; ! 160: case ADB_MOUSE: ! 161: ADB_DPRINTF("Found one mouse on address %d\n", address); ! 162: adb_mouse_new(buf, *cur); ! 163: break; ! 164: case ADB_ABS: ! 165: ADB_DPRINTF("Found one absolute positioning device\n"); ! 166: break; ! 167: case ADB_MODEM: ! 168: ADB_DPRINTF("Found one modem\n"); ! 169: break; ! 170: case ADB_RES: ! 171: ADB_DPRINTF("Found one ADB res device\n"); ! 172: break; ! 173: case ADB_MISC: ! 174: ADB_DPRINTF("Found one ADB misc device\n"); ! 175: break; ! 176: } ! 177: cur = &((*cur)->next); ! 178: } ! 179: break; ! 180: case 1: ! 181: case 3 ... 7: ! 182: /* SHOULD NOT HAPPEN : register 3 is always two bytes long */ ! 183: ADB_DPRINTF("Invalid returned len for ADB register 3\n"); ! 184: return -1; ! 185: case -1: ! 186: /* ADB ERROR */ ! 187: ADB_DPRINTF("error gettting ADB register 3\n"); ! 188: return -1; ! 189: } ! 190: } ! 191: ! 192: return 0; ! 193: } ! 194: ! 195: int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg, ! 196: uint8_t *buf, int len) ! 197: { ! 198: uint8_t adb_send[ADB_BUF_SIZE], adb_rcv[ADB_BUF_SIZE]; ! 199: ! 200: //ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len); ! 201: if (dev->bus == NULL || dev->bus->req == NULL) { ! 202: ADB_DPRINTF("ERROR: invalid bus !\n"); ! 203: for (;;); ! 204: } ! 205: /* Sanity checks */ ! 206: if (cmd != ADB_LISTEN && len != 0) { ! 207: /* No buffer transmitted but for LISTEN command */ ! 208: ADB_DPRINTF("in buffer for cmd %d\n", cmd); ! 209: return -1; ! 210: } ! 211: if (cmd == ADB_LISTEN && ((len < 2 || len > 8) || buf == NULL)) { ! 212: /* Need a buffer with a regular register size for LISTEN command */ ! 213: ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len); ! 214: return -1; ! 215: } ! 216: if ((cmd == ADB_TALK || cmd == ADB_LISTEN) && reg > 3) { ! 217: /* Need a valid register number for LISTEN and TALK commands */ ! 218: ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd, reg); ! 219: return -1; ! 220: } ! 221: switch (cmd) { ! 222: case ADB_SEND_RESET: ! 223: adb_send[0] = ADB_SEND_RESET; ! 224: break; ! 225: case ADB_FLUSH: ! 226: adb_send[0] = (dev->addr << 4) | ADB_FLUSH; ! 227: break; ! 228: case ADB_LISTEN: ! 229: memcpy(adb_send + 1, buf, len); ! 230: /* No break here */ ! 231: case ADB_TALK: ! 232: adb_send[0] = (dev->addr << 4) | cmd | reg; ! 233: break; ! 234: } ! 235: memset(adb_rcv, 0, ADB_BUF_SIZE); ! 236: len = (*dev->bus->req)(dev->bus->host, adb_send, len + 1, adb_rcv); ! 237: #ifdef DEBUG_ADB ! 238: //printk("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]); ! 239: #endif ! 240: switch (len) { ! 241: case 0: ! 242: /* No data */ ! 243: break; ! 244: case 2 ... 8: ! 245: /* Register transmitted */ ! 246: if (buf != NULL) ! 247: memcpy(buf, adb_rcv, len); ! 248: break; ! 249: default: ! 250: /* Should never happen */ ! 251: //ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len); ! 252: return -1; ! 253: } ! 254: //ADB_DPRINTF("retlen: %d\n", len); ! 255: ! 256: return len; ! 257: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.