Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / drivers / adb_bus.c
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 }