Statistics
| Branch: | Revision:

root / hw / adb.c @ 5ea3c2b4

History | View | Annotate | Download (11.9 kB)

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 "hw.h"
25
#include "ppc_mac.h"
26
#include "console.h"
27

    
28
/* debug ADB */
29
//#define DEBUG_ADB
30

    
31
#ifdef DEBUG_ADB
32
#define ADB_DPRINTF(fmt, ...) \
33
do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
34
#else
35
#define ADB_DPRINTF(fmt, ...)
36
#endif
37

    
38
/* ADB commands */
39
#define ADB_BUSRESET                0x00
40
#define ADB_FLUSH               0x01
41
#define ADB_WRITEREG                0x08
42
#define ADB_READREG                0x0c
43

    
44
/* ADB device commands */
45
#define ADB_CMD_SELF_TEST                0xff
46
#define ADB_CMD_CHANGE_ID                0xfe
47
#define ADB_CMD_CHANGE_ID_AND_ACT        0xfd
48
#define ADB_CMD_CHANGE_ID_AND_ENABLE        0x00
49

    
50
/* ADB default device IDs (upper 4 bits of ADB command byte) */
51
#define ADB_DONGLE        1
52
#define ADB_KEYBOARD        2
53
#define ADB_MOUSE        3
54
#define ADB_TABLET        4
55
#define ADB_MODEM        5
56
#define ADB_MISC        7
57

    
58
/* error codes */
59
#define ADB_RET_NOTPRESENT (-2)
60

    
61
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
62
{
63
    ADBDevice *d;
64
    int devaddr, cmd, i;
65

    
66
    cmd = buf[0] & 0xf;
67
    if (cmd == ADB_BUSRESET) {
68
        for(i = 0; i < s->nb_devices; i++) {
69
            d = &s->devices[i];
70
            if (d->devreset) {
71
                d->devreset(d);
72
            }
73
        }
74
        return 0;
75
    }
76
    devaddr = buf[0] >> 4;
77
    for(i = 0; i < s->nb_devices; i++) {
78
        d = &s->devices[i];
79
        if (d->devaddr == devaddr) {
80
            return d->devreq(d, obuf, buf, len);
81
        }
82
    }
83
    return ADB_RET_NOTPRESENT;
84
}
85

    
86
/* XXX: move that to cuda ? */
87
int adb_poll(ADBBusState *s, uint8_t *obuf)
88
{
89
    ADBDevice *d;
90
    int olen, i;
91
    uint8_t buf[1];
92

    
93
    olen = 0;
94
    for(i = 0; i < s->nb_devices; i++) {
95
        if (s->poll_index >= s->nb_devices)
96
            s->poll_index = 0;
97
        d = &s->devices[s->poll_index];
98
        buf[0] = ADB_READREG | (d->devaddr << 4);
99
        olen = adb_request(s, obuf + 1, buf, 1);
100
        /* if there is data, we poll again the same device */
101
        if (olen > 0) {
102
            obuf[0] = buf[0];
103
            olen++;
104
            break;
105
        }
106
        s->poll_index++;
107
    }
108
    return olen;
109
}
110

    
111
ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
112
                               ADBDeviceRequest *devreq,
113
                               ADBDeviceReset *devreset,
114
                               void *opaque)
115
{
116
    ADBDevice *d;
117
    if (s->nb_devices >= MAX_ADB_DEVICES)
118
        return NULL;
119
    d = &s->devices[s->nb_devices++];
120
    d->bus = s;
121
    d->devaddr = devaddr;
122
    d->devreq = devreq;
123
    d->devreset = devreset;
124
    d->opaque = opaque;
125
    qemu_register_reset((QEMUResetHandler *)devreset, d);
126
    return d;
127
}
128

    
129
/***************************************************************/
130
/* Keyboard ADB device */
131

    
132
typedef struct KBDState {
133
    uint8_t data[128];
134
    int rptr, wptr, count;
135
} KBDState;
136

    
137
static const uint8_t pc_to_adb_keycode[256] = {
138
  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
139
 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
140
  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
141
 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
142
 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
143
 84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
144
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
145
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
146
  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
147
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
148
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
149
  0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
150
  0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
151
 61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
152
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
153
  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
154
};
155

    
156
static void adb_kbd_put_keycode(void *opaque, int keycode)
157
{
158
    ADBDevice *d = opaque;
159
    KBDState *s = d->opaque;
160

    
161
    if (s->count < sizeof(s->data)) {
162
        s->data[s->wptr] = keycode;
163
        if (++s->wptr == sizeof(s->data))
164
            s->wptr = 0;
165
        s->count++;
166
    }
167
}
168

    
169
static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
170
{
171
    static int ext_keycode;
172
    KBDState *s = d->opaque;
173
    int adb_keycode, keycode;
174
    int olen;
175

    
176
    olen = 0;
177
    for(;;) {
178
        if (s->count == 0)
179
            break;
180
        keycode = s->data[s->rptr];
181
        if (++s->rptr == sizeof(s->data))
182
            s->rptr = 0;
183
        s->count--;
184

    
185
        if (keycode == 0xe0) {
186
            ext_keycode = 1;
187
        } else {
188
            if (ext_keycode)
189
                adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
190
            else
191
                adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
192
            obuf[0] = adb_keycode | (keycode & 0x80);
193
            /* NOTE: could put a second keycode if needed */
194
            obuf[1] = 0xff;
195
            olen = 2;
196
            ext_keycode = 0;
197
            break;
198
        }
199
    }
200
    return olen;
201
}
202

    
203
static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
204
                           const uint8_t *buf, int len)
205
{
206
    KBDState *s = d->opaque;
207
    int cmd, reg, olen;
208

    
209
    if ((buf[0] & 0x0f) == ADB_FLUSH) {
210
        /* flush keyboard fifo */
211
        s->wptr = s->rptr = s->count = 0;
212
        return 0;
213
    }
214

    
215
    cmd = buf[0] & 0xc;
216
    reg = buf[0] & 0x3;
217
    olen = 0;
218
    switch(cmd) {
219
    case ADB_WRITEREG:
220
        switch(reg) {
221
        case 2:
222
            /* LED status */
223
            break;
224
        case 3:
225
            switch(buf[2]) {
226
            case ADB_CMD_SELF_TEST:
227
                break;
228
            case ADB_CMD_CHANGE_ID:
229
            case ADB_CMD_CHANGE_ID_AND_ACT:
230
            case ADB_CMD_CHANGE_ID_AND_ENABLE:
231
                d->devaddr = buf[1] & 0xf;
232
                break;
233
            default:
234
                /* XXX: check this */
235
                d->devaddr = buf[1] & 0xf;
236
                d->handler = buf[2];
237
                break;
238
            }
239
        }
240
        break;
241
    case ADB_READREG:
242
        switch(reg) {
243
        case 0:
244
            olen = adb_kbd_poll(d, obuf);
245
            break;
246
        case 1:
247
            break;
248
        case 2:
249
            obuf[0] = 0x00; /* XXX: check this */
250
            obuf[1] = 0x07; /* led status */
251
            olen = 2;
252
            break;
253
        case 3:
254
            obuf[0] = d->handler;
255
            obuf[1] = d->devaddr;
256
            olen = 2;
257
            break;
258
        }
259
        break;
260
    }
261
    return olen;
262
}
263

    
264
static const VMStateDescription vmstate_adb_kbd = {
265
    .name = "adb_kbd",
266
    .version_id = 1,
267
    .minimum_version_id = 1,
268
    .minimum_version_id_old = 1,
269
    .fields      = (VMStateField[]) {
270
        VMSTATE_BUFFER(data, KBDState),
271
        VMSTATE_INT32(rptr, KBDState),
272
        VMSTATE_INT32(wptr, KBDState),
273
        VMSTATE_INT32(count, KBDState),
274
        VMSTATE_END_OF_LIST()
275
    }
276
};
277

    
278
static int adb_kbd_reset(ADBDevice *d)
279
{
280
    KBDState *s = d->opaque;
281

    
282
    d->handler = 1;
283
    d->devaddr = ADB_KEYBOARD;
284
    memset(s, 0, sizeof(KBDState));
285

    
286
    return 0;
287
}
288

    
289
void adb_kbd_init(ADBBusState *bus)
290
{
291
    ADBDevice *d;
292
    KBDState *s;
293
    s = qemu_mallocz(sizeof(KBDState));
294
    d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
295
                            adb_kbd_reset, s);
296
    qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
297
    vmstate_register(NULL, -1, &vmstate_adb_kbd, s);
298
}
299

    
300
/***************************************************************/
301
/* Mouse ADB device */
302

    
303
typedef struct MouseState {
304
    int buttons_state, last_buttons_state;
305
    int dx, dy, dz;
306
} MouseState;
307

    
308
static void adb_mouse_event(void *opaque,
309
                            int dx1, int dy1, int dz1, int buttons_state)
310
{
311
    ADBDevice *d = opaque;
312
    MouseState *s = d->opaque;
313

    
314
    s->dx += dx1;
315
    s->dy += dy1;
316
    s->dz += dz1;
317
    s->buttons_state = buttons_state;
318
}
319

    
320

    
321
static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
322
{
323
    MouseState *s = d->opaque;
324
    int dx, dy;
325

    
326
    if (s->last_buttons_state == s->buttons_state &&
327
        s->dx == 0 && s->dy == 0)
328
        return 0;
329

    
330
    dx = s->dx;
331
    if (dx < -63)
332
        dx = -63;
333
    else if (dx > 63)
334
        dx = 63;
335

    
336
    dy = s->dy;
337
    if (dy < -63)
338
        dy = -63;
339
    else if (dy > 63)
340
        dy = 63;
341

    
342
    s->dx -= dx;
343
    s->dy -= dy;
344
    s->last_buttons_state = s->buttons_state;
345

    
346
    dx &= 0x7f;
347
    dy &= 0x7f;
348

    
349
    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
350
        dy |= 0x80;
351
    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
352
        dx |= 0x80;
353

    
354
    obuf[0] = dy;
355
    obuf[1] = dx;
356
    return 2;
357
}
358

    
359
static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
360
                             const uint8_t *buf, int len)
361
{
362
    MouseState *s = d->opaque;
363
    int cmd, reg, olen;
364

    
365
    if ((buf[0] & 0x0f) == ADB_FLUSH) {
366
        /* flush mouse fifo */
367
        s->buttons_state = s->last_buttons_state;
368
        s->dx = 0;
369
        s->dy = 0;
370
        s->dz = 0;
371
        return 0;
372
    }
373

    
374
    cmd = buf[0] & 0xc;
375
    reg = buf[0] & 0x3;
376
    olen = 0;
377
    switch(cmd) {
378
    case ADB_WRITEREG:
379
        ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
380
        switch(reg) {
381
        case 2:
382
            break;
383
        case 3:
384
            switch(buf[2]) {
385
            case ADB_CMD_SELF_TEST:
386
                break;
387
            case ADB_CMD_CHANGE_ID:
388
            case ADB_CMD_CHANGE_ID_AND_ACT:
389
            case ADB_CMD_CHANGE_ID_AND_ENABLE:
390
                d->devaddr = buf[1] & 0xf;
391
                break;
392
            default:
393
                /* XXX: check this */
394
                d->devaddr = buf[1] & 0xf;
395
                break;
396
            }
397
        }
398
        break;
399
    case ADB_READREG:
400
        switch(reg) {
401
        case 0:
402
            olen = adb_mouse_poll(d, obuf);
403
            break;
404
        case 1:
405
            break;
406
        case 3:
407
            obuf[0] = d->handler;
408
            obuf[1] = d->devaddr;
409
            olen = 2;
410
            break;
411
        }
412
        ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
413
                    obuf[0], obuf[1]);
414
        break;
415
    }
416
    return olen;
417
}
418

    
419
static int adb_mouse_reset(ADBDevice *d)
420
{
421
    MouseState *s = d->opaque;
422

    
423
    d->handler = 2;
424
    d->devaddr = ADB_MOUSE;
425
    memset(s, 0, sizeof(MouseState));
426

    
427
    return 0;
428
}
429

    
430
static const VMStateDescription vmstate_adb_mouse = {
431
    .name = "adb_mouse",
432
    .version_id = 1,
433
    .minimum_version_id = 1,
434
    .minimum_version_id_old = 1,
435
    .fields      = (VMStateField[]) {
436
        VMSTATE_INT32(buttons_state, MouseState),
437
        VMSTATE_INT32(last_buttons_state, MouseState),
438
        VMSTATE_INT32(dx, MouseState),
439
        VMSTATE_INT32(dy, MouseState),
440
        VMSTATE_INT32(dz, MouseState),
441
        VMSTATE_END_OF_LIST()
442
    }
443
};
444

    
445
void adb_mouse_init(ADBBusState *bus)
446
{
447
    ADBDevice *d;
448
    MouseState *s;
449

    
450
    s = qemu_mallocz(sizeof(MouseState));
451
    d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
452
                            adb_mouse_reset, s);
453
    qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
454
    vmstate_register(NULL, -1, &vmstate_adb_mouse, s);
455
}