qemu/hw/adb.c
<<
>>
Prefs
   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, ...) \
  33do { 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
  61int 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 ? */
  87int 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
 111ADBDevice *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    d->devreset(d);
 127    return d;
 128}
 129
 130/***************************************************************/
 131/* Keyboard ADB device */
 132
 133typedef struct KBDState {
 134    uint8_t data[128];
 135    int rptr, wptr, count;
 136} KBDState;
 137
 138static const uint8_t pc_to_adb_keycode[256] = {
 139  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
 140 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
 141  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
 142 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
 143 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
 144 84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
 145  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 146  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 147  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
 148  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
 149  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
 150  0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
 151  0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
 152 61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
 153  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 154  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 155};
 156
 157static void adb_kbd_put_keycode(void *opaque, int keycode)
 158{
 159    ADBDevice *d = opaque;
 160    KBDState *s = d->opaque;
 161
 162    if (s->count < sizeof(s->data)) {
 163        s->data[s->wptr] = keycode;
 164        if (++s->wptr == sizeof(s->data))
 165            s->wptr = 0;
 166        s->count++;
 167    }
 168}
 169
 170static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
 171{
 172    static int ext_keycode;
 173    KBDState *s = d->opaque;
 174    int adb_keycode, keycode;
 175    int olen;
 176
 177    olen = 0;
 178    for(;;) {
 179        if (s->count == 0)
 180            break;
 181        keycode = s->data[s->rptr];
 182        if (++s->rptr == sizeof(s->data))
 183            s->rptr = 0;
 184        s->count--;
 185
 186        if (keycode == 0xe0) {
 187            ext_keycode = 1;
 188        } else {
 189            if (ext_keycode)
 190                adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
 191            else
 192                adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
 193            obuf[0] = adb_keycode | (keycode & 0x80);
 194            /* NOTE: could put a second keycode if needed */
 195            obuf[1] = 0xff;
 196            olen = 2;
 197            ext_keycode = 0;
 198            break;
 199        }
 200    }
 201    return olen;
 202}
 203
 204static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
 205                           const uint8_t *buf, int len)
 206{
 207    KBDState *s = d->opaque;
 208    int cmd, reg, olen;
 209
 210    if ((buf[0] & 0x0f) == ADB_FLUSH) {
 211        /* flush keyboard fifo */
 212        s->wptr = s->rptr = s->count = 0;
 213        return 0;
 214    }
 215
 216    cmd = buf[0] & 0xc;
 217    reg = buf[0] & 0x3;
 218    olen = 0;
 219    switch(cmd) {
 220    case ADB_WRITEREG:
 221        switch(reg) {
 222        case 2:
 223            /* LED status */
 224            break;
 225        case 3:
 226            switch(buf[2]) {
 227            case ADB_CMD_SELF_TEST:
 228                break;
 229            case ADB_CMD_CHANGE_ID:
 230            case ADB_CMD_CHANGE_ID_AND_ACT:
 231            case ADB_CMD_CHANGE_ID_AND_ENABLE:
 232                d->devaddr = buf[1] & 0xf;
 233                break;
 234            default:
 235                /* XXX: check this */
 236                d->devaddr = buf[1] & 0xf;
 237                d->handler = buf[2];
 238                break;
 239            }
 240        }
 241        break;
 242    case ADB_READREG:
 243        switch(reg) {
 244        case 0:
 245            olen = adb_kbd_poll(d, obuf);
 246            break;
 247        case 1:
 248            break;
 249        case 2:
 250            obuf[0] = 0x00; /* XXX: check this */
 251            obuf[1] = 0x07; /* led status */
 252            olen = 2;
 253            break;
 254        case 3:
 255            obuf[0] = d->handler;
 256            obuf[1] = d->devaddr;
 257            olen = 2;
 258            break;
 259        }
 260        break;
 261    }
 262    return olen;
 263}
 264
 265static void adb_kbd_save(QEMUFile *f, void *opaque)
 266{
 267    KBDState *s = (KBDState *)opaque;
 268
 269    qemu_put_buffer(f, s->data, sizeof(s->data));
 270    qemu_put_sbe32s(f, &s->rptr);
 271    qemu_put_sbe32s(f, &s->wptr);
 272    qemu_put_sbe32s(f, &s->count);
 273}
 274
 275static int adb_kbd_load(QEMUFile *f, void *opaque, int version_id)
 276{
 277    KBDState *s = (KBDState *)opaque;
 278
 279    if (version_id != 1)
 280        return -EINVAL;
 281
 282    qemu_get_buffer(f, s->data, sizeof(s->data));
 283    qemu_get_sbe32s(f, &s->rptr);
 284    qemu_get_sbe32s(f, &s->wptr);
 285    qemu_get_sbe32s(f, &s->count);
 286
 287    return 0;
 288}
 289
 290static int adb_kbd_reset(ADBDevice *d)
 291{
 292    KBDState *s = d->opaque;
 293
 294    d->handler = 1;
 295    d->devaddr = ADB_KEYBOARD;
 296    memset(s, 0, sizeof(KBDState));
 297
 298    return 0;
 299}
 300
 301void adb_kbd_init(ADBBusState *bus)
 302{
 303    ADBDevice *d;
 304    KBDState *s;
 305    s = qemu_mallocz(sizeof(KBDState));
 306    d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
 307                            adb_kbd_reset, s);
 308    qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
 309    register_savevm("adb_kbd", -1, 1, adb_kbd_save,
 310                    adb_kbd_load, s);
 311}
 312
 313/***************************************************************/
 314/* Mouse ADB device */
 315
 316typedef struct MouseState {
 317    int buttons_state, last_buttons_state;
 318    int dx, dy, dz;
 319} MouseState;
 320
 321static void adb_mouse_event(void *opaque,
 322                            int dx1, int dy1, int dz1, int buttons_state)
 323{
 324    ADBDevice *d = opaque;
 325    MouseState *s = d->opaque;
 326
 327    s->dx += dx1;
 328    s->dy += dy1;
 329    s->dz += dz1;
 330    s->buttons_state = buttons_state;
 331}
 332
 333
 334static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
 335{
 336    MouseState *s = d->opaque;
 337    int dx, dy;
 338
 339    if (s->last_buttons_state == s->buttons_state &&
 340        s->dx == 0 && s->dy == 0)
 341        return 0;
 342
 343    dx = s->dx;
 344    if (dx < -63)
 345        dx = -63;
 346    else if (dx > 63)
 347        dx = 63;
 348
 349    dy = s->dy;
 350    if (dy < -63)
 351        dy = -63;
 352    else if (dy > 63)
 353        dy = 63;
 354
 355    s->dx -= dx;
 356    s->dy -= dy;
 357    s->last_buttons_state = s->buttons_state;
 358
 359    dx &= 0x7f;
 360    dy &= 0x7f;
 361
 362    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
 363        dy |= 0x80;
 364    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
 365        dx |= 0x80;
 366
 367    obuf[0] = dy;
 368    obuf[1] = dx;
 369    return 2;
 370}
 371
 372static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
 373                             const uint8_t *buf, int len)
 374{
 375    MouseState *s = d->opaque;
 376    int cmd, reg, olen;
 377
 378    if ((buf[0] & 0x0f) == ADB_FLUSH) {
 379        /* flush mouse fifo */
 380        s->buttons_state = s->last_buttons_state;
 381        s->dx = 0;
 382        s->dy = 0;
 383        s->dz = 0;
 384        return 0;
 385    }
 386
 387    cmd = buf[0] & 0xc;
 388    reg = buf[0] & 0x3;
 389    olen = 0;
 390    switch(cmd) {
 391    case ADB_WRITEREG:
 392        ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
 393        switch(reg) {
 394        case 2:
 395            break;
 396        case 3:
 397            switch(buf[2]) {
 398            case ADB_CMD_SELF_TEST:
 399                break;
 400            case ADB_CMD_CHANGE_ID:
 401            case ADB_CMD_CHANGE_ID_AND_ACT:
 402            case ADB_CMD_CHANGE_ID_AND_ENABLE:
 403                d->devaddr = buf[1] & 0xf;
 404                break;
 405            default:
 406                /* XXX: check this */
 407                d->devaddr = buf[1] & 0xf;
 408                break;
 409            }
 410        }
 411        break;
 412    case ADB_READREG:
 413        switch(reg) {
 414        case 0:
 415            olen = adb_mouse_poll(d, obuf);
 416            break;
 417        case 1:
 418            break;
 419        case 3:
 420            obuf[0] = d->handler;
 421            obuf[1] = d->devaddr;
 422            olen = 2;
 423            break;
 424        }
 425        ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
 426                    obuf[0], obuf[1]);
 427        break;
 428    }
 429    return olen;
 430}
 431
 432static int adb_mouse_reset(ADBDevice *d)
 433{
 434    MouseState *s = d->opaque;
 435
 436    d->handler = 2;
 437    d->devaddr = ADB_MOUSE;
 438    memset(s, 0, sizeof(MouseState));
 439
 440    return 0;
 441}
 442
 443static void adb_mouse_save(QEMUFile *f, void *opaque)
 444{
 445    MouseState *s = (MouseState *)opaque;
 446
 447    qemu_put_sbe32s(f, &s->buttons_state);
 448    qemu_put_sbe32s(f, &s->last_buttons_state);
 449    qemu_put_sbe32s(f, &s->dx);
 450    qemu_put_sbe32s(f, &s->dy);
 451    qemu_put_sbe32s(f, &s->dz);
 452}
 453
 454static int adb_mouse_load(QEMUFile *f, void *opaque, int version_id)
 455{
 456    MouseState *s = (MouseState *)opaque;
 457
 458    if (version_id != 1)
 459        return -EINVAL;
 460
 461    qemu_get_sbe32s(f, &s->buttons_state);
 462    qemu_get_sbe32s(f, &s->last_buttons_state);
 463    qemu_get_sbe32s(f, &s->dx);
 464    qemu_get_sbe32s(f, &s->dy);
 465    qemu_get_sbe32s(f, &s->dz);
 466
 467    return 0;
 468}
 469
 470void adb_mouse_init(ADBBusState *bus)
 471{
 472    ADBDevice *d;
 473    MouseState *s;
 474
 475    s = qemu_mallocz(sizeof(MouseState));
 476    d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
 477                            adb_mouse_reset, s);
 478    qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse");
 479    register_savevm("adb_mouse", -1, 1, adb_mouse_save,
 480                    adb_mouse_load, s);
 481}
 482