0.8.2-alt1
[qemu] / qemu / hw / adb.c
1 /*
2  * QEMU ADB support
3  * 
4  * Copyright (c) 2004 Fabrice Bellard
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25
26 /* ADB commands */
27 #define ADB_BUSRESET            0x00
28 #define ADB_FLUSH               0x01
29 #define ADB_WRITEREG            0x08
30 #define ADB_READREG             0x0c
31
32 /* ADB device commands */
33 #define ADB_CMD_SELF_TEST               0xff
34 #define ADB_CMD_CHANGE_ID               0xfe
35 #define ADB_CMD_CHANGE_ID_AND_ACT       0xfd
36 #define ADB_CMD_CHANGE_ID_AND_ENABLE    0x00
37
38 /* ADB default device IDs (upper 4 bits of ADB command byte) */
39 #define ADB_DONGLE      1
40 #define ADB_KEYBOARD    2
41 #define ADB_MOUSE       3
42 #define ADB_TABLET      4
43 #define ADB_MODEM       5
44 #define ADB_MISC        7
45
46 /* error codes */
47 #define ADB_RET_NOTPRESENT (-2)
48
49 int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
50 {
51     ADBDevice *d;
52     int devaddr, cmd, i;
53
54     cmd = buf[0] & 0xf;
55     if (cmd == ADB_BUSRESET) {
56         for(i = 0; i < s->nb_devices; i++) {
57             d = &s->devices[i];
58             if (d->devreset) {
59                 d->devreset(d);
60             }
61         }
62         return 0;
63     }
64     devaddr = buf[0] >> 4;
65     for(i = 0; i < s->nb_devices; i++) {
66         d = &s->devices[i];
67         if (d->devaddr == devaddr) {
68             return d->devreq(d, obuf, buf, len);
69         }
70     }
71     return ADB_RET_NOTPRESENT;
72 }
73
74 /* XXX: move that to cuda ? */
75 int adb_poll(ADBBusState *s, uint8_t *obuf)
76 {
77     ADBDevice *d;
78     int olen, i;
79     uint8_t buf[1];
80
81     olen = 0;
82     for(i = 0; i < s->nb_devices; i++) {
83         if (s->poll_index >= s->nb_devices)
84             s->poll_index = 0;
85         d = &s->devices[s->poll_index];
86         buf[0] = ADB_READREG | (d->devaddr << 4);
87         olen = adb_request(s, obuf + 1, buf, 1);
88         /* if there is data, we poll again the same device */
89         if (olen > 0) {
90             obuf[0] = buf[0];
91             olen++;
92             break;
93         }
94         s->poll_index++;
95     }
96     return olen;
97 }
98
99 ADBDevice *adb_register_device(ADBBusState *s, int devaddr, 
100                                ADBDeviceRequest *devreq, 
101                                ADBDeviceReset *devreset, 
102                                void *opaque)
103 {
104     ADBDevice *d;
105     if (s->nb_devices >= MAX_ADB_DEVICES)
106         return NULL;
107     d = &s->devices[s->nb_devices++];
108     d->bus = s;
109     d->devaddr = devaddr;
110     d->devreq = devreq;
111     d->devreset = devreset;
112     d->opaque = opaque;
113     return d;
114 }
115
116 /***************************************************************/
117 /* Keyboard ADB device */
118
119 typedef struct KBDState {
120     uint8_t data[128];
121     int rptr, wptr, count;
122 } KBDState;
123
124 static const uint8_t pc_to_adb_keycode[256] = {
125   0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
126  12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
127   2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
128  11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
129  97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
130  84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
131   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
132   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
133   0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
134   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
135   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
136   0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
137   0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
138  61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
139   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
140   0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
141 };
142
143 static void adb_kbd_put_keycode(void *opaque, int keycode)
144 {
145     ADBDevice *d = opaque;
146     KBDState *s = d->opaque;
147
148     if (s->count < sizeof(s->data)) {
149         s->data[s->wptr] = keycode;
150         if (++s->wptr == sizeof(s->data))
151             s->wptr = 0;
152         s->count++;
153     }
154 }
155
156 static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
157 {
158     static int ext_keycode;
159     KBDState *s = d->opaque;
160     int adb_keycode, keycode;
161     int olen;
162
163     olen = 0;
164     for(;;) {
165         if (s->count == 0)
166             break;
167         keycode = s->data[s->rptr];
168         if (++s->rptr == sizeof(s->data))
169             s->rptr = 0;
170         s->count--;
171
172         if (keycode == 0xe0) {
173             ext_keycode = 1;
174         } else {
175             if (ext_keycode)
176                 adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
177             else
178                 adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
179             obuf[0] = adb_keycode | (keycode & 0x80);
180             /* NOTE: could put a second keycode if needed */
181             obuf[1] = 0xff;
182             olen = 2;
183             ext_keycode = 0;
184             break;
185         }
186     }
187     return olen;
188 }
189
190 static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
191                            const uint8_t *buf, int len)
192 {
193     KBDState *s = d->opaque;
194     int cmd, reg, olen;
195
196     if ((buf[0] & 0x0f) == ADB_FLUSH) {
197         /* flush keyboard fifo */
198         s->wptr = s->rptr = s->count = 0;
199         return 0;
200     }
201
202     cmd = buf[0] & 0xc;
203     reg = buf[0] & 0x3;
204     olen = 0;
205     switch(cmd) {
206     case ADB_WRITEREG:
207         switch(reg) {
208         case 2:
209             /* LED status */
210             break;
211         case 3:
212             switch(buf[2]) {
213             case ADB_CMD_SELF_TEST:
214                 break;
215             case ADB_CMD_CHANGE_ID:
216             case ADB_CMD_CHANGE_ID_AND_ACT:
217             case ADB_CMD_CHANGE_ID_AND_ENABLE:
218                 d->devaddr = buf[1] & 0xf;
219                 break;
220             default:
221                 /* XXX: check this */
222                 d->devaddr = buf[1] & 0xf;
223                 d->handler = buf[2];
224                 break;
225             }
226         }
227         break;
228     case ADB_READREG:
229         switch(reg) {
230         case 0:
231             olen = adb_kbd_poll(d, obuf);
232             break;
233         case 1:
234             break;
235         case 2:
236             obuf[0] = 0x00; /* XXX: check this */
237             obuf[1] = 0x07; /* led status */
238             olen = 2;
239             break;
240         case 3:
241             obuf[0] = d->handler;
242             obuf[1] = d->devaddr;
243             olen = 2;
244             break;
245         }
246         break;
247     }
248     return olen;
249 }
250
251 static int adb_kbd_reset(ADBDevice *d)
252 {
253     KBDState *s = d->opaque;
254
255     d->handler = 1;
256     d->devaddr = ADB_KEYBOARD;
257     memset(s, 0, sizeof(KBDState));
258
259     return 0;
260 }
261
262 void adb_kbd_init(ADBBusState *bus)
263 {
264     ADBDevice *d;
265     KBDState *s;
266     s = qemu_mallocz(sizeof(KBDState));
267     d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
268                             adb_kbd_reset, s);
269     adb_kbd_reset(d);
270     qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
271 }
272
273 /***************************************************************/
274 /* Mouse ADB device */
275
276 typedef struct MouseState {
277     int buttons_state, last_buttons_state;
278     int dx, dy, dz;
279 } MouseState;
280
281 static void adb_mouse_event(void *opaque,
282                             int dx1, int dy1, int dz1, int buttons_state)
283 {
284     ADBDevice *d = opaque;
285     MouseState *s = d->opaque;
286
287     s->dx += dx1;
288     s->dy += dy1;
289     s->dz += dz1;
290     s->buttons_state = buttons_state;
291 }
292
293
294 static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
295 {
296     MouseState *s = d->opaque;
297     int dx, dy;
298
299     if (s->last_buttons_state == s->buttons_state &&
300         s->dx == 0 && s->dy == 0)
301         return 0;
302         
303     dx = s->dx;
304     if (dx < -63)
305         dx = -63;
306     else if (dx > 63)
307         dx = 63;
308     
309     dy = s->dy;
310     if (dy < -63)
311         dy = -63;
312     else if (dy > 63)
313         dy = 63;
314     
315     s->dx -= dx;
316     s->dy -= dy;
317     s->last_buttons_state = s->buttons_state;
318     
319     dx &= 0x7f;
320     dy &= 0x7f;
321     
322     if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
323         dy |= 0x80;
324     if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
325         dx |= 0x80;
326     
327     obuf[0] = dy;
328     obuf[1] = dx;
329     return 2;
330 }
331
332 static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
333                              const uint8_t *buf, int len)
334 {
335     MouseState *s = d->opaque;
336     int cmd, reg, olen;
337     
338     if ((buf[0] & 0x0f) == ADB_FLUSH) {
339         /* flush mouse fifo */
340         s->buttons_state = s->last_buttons_state;
341         s->dx = 0;
342         s->dy = 0;
343         s->dz = 0;
344         return 0;
345     }
346
347     cmd = buf[0] & 0xc;
348     reg = buf[0] & 0x3;
349     olen = 0;
350     switch(cmd) {
351     case ADB_WRITEREG:
352         switch(reg) {
353         case 2:
354             break;
355         case 3:
356             switch(buf[2]) {
357             case ADB_CMD_SELF_TEST:
358                 break;
359             case ADB_CMD_CHANGE_ID:
360             case ADB_CMD_CHANGE_ID_AND_ACT:
361             case ADB_CMD_CHANGE_ID_AND_ENABLE:
362                 d->devaddr = buf[1] & 0xf;
363                 break;
364             default:
365                 /* XXX: check this */
366                 d->devaddr = buf[1] & 0xf;
367                 break;
368             }
369         }
370         break;
371     case ADB_READREG:
372         switch(reg) {
373         case 0:
374             olen = adb_mouse_poll(d, obuf);
375             break;
376         case 1:
377             break;
378         case 3:
379             obuf[0] = d->handler;
380             obuf[1] = d->devaddr;
381             olen = 2;
382             break;
383         }
384         break;
385     }
386     return olen;
387 }
388
389 static int adb_mouse_reset(ADBDevice *d)
390 {
391     MouseState *s = d->opaque;
392
393     d->handler = 2;
394     d->devaddr = ADB_MOUSE;
395     memset(s, 0, sizeof(MouseState));
396
397     return 0;
398 }
399
400 void adb_mouse_init(ADBBusState *bus)
401 {
402     ADBDevice *d;
403     MouseState *s;
404
405     s = qemu_mallocz(sizeof(MouseState));
406     d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
407                             adb_mouse_reset, s);
408     adb_mouse_reset(d);
409     qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
410 }