|
|
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.