qemu/hw/baum.c
<<
>>
Prefs
   1/*
   2 * QEMU Baum Braille Device
   3 *
   4 * Copyright (c) 2008 Samuel Thibault
   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 "qemu-common.h"
  25#include "qemu-char.h"
  26#include "qemu-timer.h"
  27#include "usb.h"
  28#include "baum.h"
  29#include <brlapi.h>
  30#include <brlapi_constants.h>
  31#include <brlapi_keycodes.h>
  32#ifdef CONFIG_SDL
  33#include <SDL_syswm.h>
  34#endif
  35
  36#if 0
  37#define DPRINTF(fmt, ...) \
  38        printf(fmt, ## __VA_ARGS__)
  39#else
  40#define DPRINTF(fmt, ...)
  41#endif
  42
  43#define ESC 0x1B
  44
  45#define BAUM_REQ_DisplayData            0x01
  46#define BAUM_REQ_GetVersionNumber       0x05
  47#define BAUM_REQ_GetKeys                0x08
  48#define BAUM_REQ_SetMode                0x12
  49#define BAUM_REQ_SetProtocol            0x15
  50#define BAUM_REQ_GetDeviceIdentity      0x84
  51#define BAUM_REQ_GetSerialNumber        0x8A
  52
  53#define BAUM_RSP_CellCount              0x01
  54#define BAUM_RSP_VersionNumber          0x05
  55#define BAUM_RSP_ModeSetting            0x11
  56#define BAUM_RSP_CommunicationChannel   0x16
  57#define BAUM_RSP_PowerdownSignal        0x17
  58#define BAUM_RSP_HorizontalSensors      0x20
  59#define BAUM_RSP_VerticalSensors        0x21
  60#define BAUM_RSP_RoutingKeys            0x22
  61#define BAUM_RSP_Switches               0x23
  62#define BAUM_RSP_TopKeys                0x24
  63#define BAUM_RSP_HorizontalSensor       0x25
  64#define BAUM_RSP_VerticalSensor         0x26
  65#define BAUM_RSP_RoutingKey             0x27
  66#define BAUM_RSP_FrontKeys6             0x28
  67#define BAUM_RSP_BackKeys6              0x29
  68#define BAUM_RSP_CommandKeys            0x2B
  69#define BAUM_RSP_FrontKeys10            0x2C
  70#define BAUM_RSP_BackKeys10             0x2D
  71#define BAUM_RSP_EntryKeys              0x33
  72#define BAUM_RSP_JoyStick               0x34
  73#define BAUM_RSP_ErrorCode              0x40
  74#define BAUM_RSP_InfoBlock              0x42
  75#define BAUM_RSP_DeviceIdentity         0x84
  76#define BAUM_RSP_SerialNumber           0x8A
  77#define BAUM_RSP_BluetoothName          0x8C
  78
  79#define BAUM_TL1 0x01
  80#define BAUM_TL2 0x02
  81#define BAUM_TL3 0x04
  82#define BAUM_TR1 0x08
  83#define BAUM_TR2 0x10
  84#define BAUM_TR3 0x20
  85
  86#define BUF_SIZE 256
  87
  88typedef struct {
  89    CharDriverState *chr;
  90
  91    brlapi_handle_t *brlapi;
  92    int brlapi_fd;
  93    unsigned int x, y;
  94
  95    uint8_t in_buf[BUF_SIZE];
  96    uint8_t in_buf_used;
  97    uint8_t out_buf[BUF_SIZE];
  98    uint8_t out_buf_used, out_buf_ptr;
  99
 100    QEMUTimer *cellCount_timer;
 101} BaumDriverState;
 102
 103/* Let's assume NABCC by default */
 104static const uint8_t nabcc_translation[256] = {
 105    [0] = ' ',
 106#ifndef BRLAPI_DOTS
 107#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
 108    ((d1?BRLAPI_DOT1:0)|\
 109     (d2?BRLAPI_DOT2:0)|\
 110     (d3?BRLAPI_DOT3:0)|\
 111     (d4?BRLAPI_DOT4:0)|\
 112     (d5?BRLAPI_DOT5:0)|\
 113     (d6?BRLAPI_DOT6:0)|\
 114     (d7?BRLAPI_DOT7:0)|\
 115     (d8?BRLAPI_DOT8:0))
 116#endif
 117    [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a',
 118    [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b',
 119    [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c',
 120    [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd',
 121    [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e',
 122    [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f',
 123    [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g',
 124    [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h',
 125    [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i',
 126    [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j',
 127    [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k',
 128    [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l',
 129    [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm',
 130    [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n',
 131    [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o',
 132    [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p',
 133    [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q',
 134    [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r',
 135    [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's',
 136    [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't',
 137    [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u',
 138    [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v',
 139    [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w',
 140    [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x',
 141    [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y',
 142    [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z',
 143
 144    [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A',
 145    [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B',
 146    [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C',
 147    [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D',
 148    [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E',
 149    [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F',
 150    [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G',
 151    [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H',
 152    [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I',
 153    [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J',
 154    [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K',
 155    [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L',
 156    [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M',
 157    [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N',
 158    [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O',
 159    [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P',
 160    [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q',
 161    [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R',
 162    [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S',
 163    [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T',
 164    [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U',
 165    [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V',
 166    [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W',
 167    [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X',
 168    [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y',
 169    [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z',
 170
 171    [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0',
 172    [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1',
 173    [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2',
 174    [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3',
 175    [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4',
 176    [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5',
 177    [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6',
 178    [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7',
 179    [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8',
 180    [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9',
 181
 182    [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.',
 183    [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+',
 184    [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-',
 185    [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*',
 186    [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/',
 187    [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(',
 188    [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')',
 189
 190    [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&',
 191    [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#',
 192
 193    [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',',
 194    [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';',
 195    [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':',
 196    [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!',
 197    [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?',
 198    [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"',
 199    [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'',
 200    [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`',
 201    [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^',
 202    [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~',
 203    [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[',
 204    [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']',
 205    [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{',
 206    [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}',
 207    [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=',
 208    [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<',
 209    [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>',
 210    [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$',
 211    [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%',
 212    [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@',
 213    [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|',
 214    [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\',
 215    [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_',
 216};
 217
 218/* The serial port can receive more of our data */
 219static void baum_accept_input(struct CharDriverState *chr)
 220{
 221    BaumDriverState *baum = chr->opaque;
 222    int room, first;
 223
 224    if (!baum->out_buf_used)
 225        return;
 226    room = qemu_chr_can_read(chr);
 227    if (!room)
 228        return;
 229    if (room > baum->out_buf_used)
 230        room = baum->out_buf_used;
 231
 232    first = BUF_SIZE - baum->out_buf_ptr;
 233    if (room > first) {
 234        qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first);
 235        baum->out_buf_ptr = 0;
 236        baum->out_buf_used -= first;
 237        room -= first;
 238    }
 239    qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room);
 240    baum->out_buf_ptr += room;
 241    baum->out_buf_used -= room;
 242}
 243
 244/* We want to send a packet */
 245static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 246{
 247    uint8_t io_buf[1 + 2 * len], *cur = io_buf;
 248    int room;
 249    *cur++ = ESC;
 250    while (len--)
 251        if ((*cur++ = *buf++) == ESC)
 252            *cur++ = ESC;
 253    room = qemu_chr_can_read(baum->chr);
 254    len = cur - io_buf;
 255    if (len <= room) {
 256        /* Fits */
 257        qemu_chr_read(baum->chr, io_buf, len);
 258    } else {
 259        int first;
 260        uint8_t out;
 261        /* Can't fit all, send what can be, and store the rest. */
 262        qemu_chr_read(baum->chr, io_buf, room);
 263        len -= room;
 264        cur = io_buf + room;
 265        if (len > BUF_SIZE - baum->out_buf_used) {
 266            /* Can't even store it, drop the previous data... */
 267            assert(len <= BUF_SIZE);
 268            baum->out_buf_used = 0;
 269            baum->out_buf_ptr = 0;
 270        }
 271        out = baum->out_buf_ptr;
 272        baum->out_buf_used += len;
 273        first = BUF_SIZE - baum->out_buf_ptr;
 274        if (len > first) {
 275            memcpy(baum->out_buf + out, cur, first);
 276            out = 0;
 277            len -= first;
 278            cur += first;
 279        }
 280        memcpy(baum->out_buf + out, cur, len);
 281    }
 282}
 283
 284/* Called when the other end seems to have a wrong idea of our display size */
 285static void baum_cellCount_timer_cb(void *opaque)
 286{
 287    BaumDriverState *baum = opaque;
 288    uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
 289    DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
 290    baum_write_packet(baum, cell_count, sizeof(cell_count));
 291}
 292
 293/* Try to interpret a whole incoming packet */
 294static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
 295{
 296    const uint8_t *cur = buf;
 297    uint8_t req = 0;
 298
 299    if (!len--)
 300        return 0;
 301    if (*cur++ != ESC) {
 302        while (*cur != ESC) {
 303            if (!len--)
 304                return 0;
 305            cur++;
 306        }
 307        DPRINTF("Dropped %d bytes!\n", cur - buf);
 308    }
 309
 310#define EAT(c) do {\
 311    if (!len--) \
 312        return 0; \
 313    if ((c = *cur++) == ESC) { \
 314        if (!len--) \
 315            return 0; \
 316        if (*cur++ != ESC) { \
 317            DPRINTF("Broken packet %#2x, tossing\n", req); \
 318                if (qemu_timer_pending(baum->cellCount_timer)) { \
 319                qemu_del_timer(baum->cellCount_timer); \
 320                baum_cellCount_timer_cb(baum); \
 321            } \
 322            return (cur - 2 - buf); \
 323        } \
 324    } \
 325} while (0)
 326
 327    EAT(req);
 328    switch (req) {
 329    case BAUM_REQ_DisplayData:
 330    {
 331        uint8_t cells[baum->x * baum->y], c;
 332        uint8_t text[baum->x * baum->y];
 333        uint8_t zero[baum->x * baum->y];
 334        int cursor = BRLAPI_CURSOR_OFF;
 335        int i;
 336
 337        /* Allow 100ms to complete the DisplayData packet */
 338        qemu_mod_timer(baum->cellCount_timer, qemu_get_clock_ns(vm_clock) +
 339                       get_ticks_per_sec() / 10);
 340        for (i = 0; i < baum->x * baum->y ; i++) {
 341            EAT(c);
 342            cells[i] = c;
 343            if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
 344                    == (BRLAPI_DOT7|BRLAPI_DOT8)) {
 345                cursor = i + 1;
 346                c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
 347            }
 348            if (!(c = nabcc_translation[c]))
 349                c = '?';
 350            text[i] = c;
 351        }
 352        qemu_del_timer(baum->cellCount_timer);
 353
 354        memset(zero, 0, sizeof(zero));
 355
 356        brlapi_writeArguments_t wa = {
 357            .displayNumber = BRLAPI_DISPLAY_DEFAULT,
 358            .regionBegin = 1,
 359            .regionSize = baum->x * baum->y,
 360            .text = (char *)text,
 361            .textSize = baum->x * baum->y,
 362            .andMask = zero,
 363            .orMask = cells,
 364            .cursor = cursor,
 365            .charset = (char *)"ISO-8859-1",
 366        };
 367
 368        if (brlapi__write(baum->brlapi, &wa) == -1)
 369            brlapi_perror("baum brlapi_write");
 370        break;
 371    }
 372    case BAUM_REQ_SetMode:
 373    {
 374        uint8_t mode, setting;
 375        DPRINTF("SetMode\n");
 376        EAT(mode);
 377        EAT(setting);
 378        /* ignore */
 379        break;
 380    }
 381    case BAUM_REQ_SetProtocol:
 382    {
 383        uint8_t protocol;
 384        DPRINTF("SetProtocol\n");
 385        EAT(protocol);
 386        /* ignore */
 387        break;
 388    }
 389    case BAUM_REQ_GetDeviceIdentity:
 390    {
 391        uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
 392            'B','a','u','m',' ','V','a','r','i','o' };
 393        DPRINTF("GetDeviceIdentity\n");
 394        identity[11] = '0' + baum->x / 10;
 395        identity[12] = '0' + baum->x % 10;
 396        baum_write_packet(baum, identity, sizeof(identity));
 397        break;
 398    }
 399    case BAUM_REQ_GetVersionNumber:
 400    {
 401        uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
 402        DPRINTF("GetVersionNumber\n");
 403        baum_write_packet(baum, version, sizeof(version));
 404        break;
 405    }
 406    case BAUM_REQ_GetSerialNumber:
 407    {
 408        uint8_t serial[] = { BAUM_RSP_SerialNumber,
 409            '0','0','0','0','0','0','0','0' };
 410        DPRINTF("GetSerialNumber\n");
 411        baum_write_packet(baum, serial, sizeof(serial));
 412        break;
 413    }
 414    case BAUM_REQ_GetKeys:
 415    {
 416        DPRINTF("Get%0#2x\n", req);
 417        /* ignore */
 418        break;
 419    }
 420    default:
 421        DPRINTF("unrecognized request %0#2x\n", req);
 422        do
 423            if (!len--)
 424                return 0;
 425        while (*cur++ != ESC);
 426        cur--;
 427        break;
 428    }
 429    return cur - buf;
 430}
 431
 432/* The other end is writing some data.  Store it and try to interpret */
 433static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
 434{
 435    BaumDriverState *baum = chr->opaque;
 436    int tocopy, cur, eaten, orig_len = len;
 437
 438    if (!len)
 439        return 0;
 440    if (!baum->brlapi)
 441        return len;
 442
 443    while (len) {
 444        /* Complete our buffer as much as possible */
 445        tocopy = len;
 446        if (tocopy > BUF_SIZE - baum->in_buf_used)
 447            tocopy = BUF_SIZE - baum->in_buf_used;
 448
 449        memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
 450        baum->in_buf_used += tocopy;
 451        buf += tocopy;
 452        len -= tocopy;
 453
 454        /* Interpret it as much as possible */
 455        cur = 0;
 456        while (cur < baum->in_buf_used &&
 457                (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
 458            cur += eaten;
 459
 460        /* Shift the remainder */
 461        if (cur) {
 462            memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
 463            baum->in_buf_used -= cur;
 464        }
 465
 466        /* And continue if any data left */
 467    }
 468    return orig_len;
 469}
 470
 471/* The other end sent us some event */
 472static void baum_send_event(CharDriverState *chr, int event)
 473{
 474    BaumDriverState *baum = chr->opaque;
 475    switch (event) {
 476    case CHR_EVENT_BREAK:
 477        break;
 478    case CHR_EVENT_OPENED:
 479        /* Reset state */
 480        baum->in_buf_used = 0;
 481        break;
 482    }
 483}
 484
 485/* Send the key code to the other end */
 486static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
 487    uint8_t packet[] = { type, value };
 488    DPRINTF("writing key %x %x\n", type, value);
 489    baum_write_packet(baum, packet, sizeof(packet));
 490}
 491
 492/* We got some data on the BrlAPI socket */
 493static void baum_chr_read(void *opaque)
 494{
 495    BaumDriverState *baum = opaque;
 496    brlapi_keyCode_t code;
 497    int ret;
 498    if (!baum->brlapi)
 499        return;
 500    while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
 501        DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
 502        /* Emulate */
 503        switch (code & BRLAPI_KEY_TYPE_MASK) {
 504        case BRLAPI_KEY_TYPE_CMD:
 505            switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
 506            case BRLAPI_KEY_CMD_ROUTE:
 507                baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
 508                baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
 509                break;
 510            case 0:
 511                switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
 512                case BRLAPI_KEY_CMD_FWINLT:
 513                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
 514                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 515                    break;
 516                case BRLAPI_KEY_CMD_FWINRT:
 517                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
 518                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 519                    break;
 520                case BRLAPI_KEY_CMD_LNUP:
 521                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
 522                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 523                    break;
 524                case BRLAPI_KEY_CMD_LNDN:
 525                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
 526                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 527                    break;
 528                case BRLAPI_KEY_CMD_TOP:
 529                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
 530                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 531                    break;
 532                case BRLAPI_KEY_CMD_BOT:
 533                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
 534                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 535                    break;
 536                case BRLAPI_KEY_CMD_TOP_LEFT:
 537                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
 538                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 539                    break;
 540                case BRLAPI_KEY_CMD_BOT_LEFT:
 541                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
 542                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 543                    break;
 544                case BRLAPI_KEY_CMD_HOME:
 545                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
 546                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 547                    break;
 548                case BRLAPI_KEY_CMD_PREFMENU:
 549                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
 550                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 551                    break;
 552                }
 553            }
 554            break;
 555        case BRLAPI_KEY_TYPE_SYM:
 556            break;
 557        }
 558    }
 559    if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
 560        brlapi_perror("baum: brlapi_readKey");
 561        brlapi__closeConnection(baum->brlapi);
 562        qemu_free(baum->brlapi);
 563        baum->brlapi = NULL;
 564    }
 565}
 566
 567static void baum_close(struct CharDriverState *chr)
 568{
 569    BaumDriverState *baum = chr->opaque;
 570
 571    qemu_free_timer(baum->cellCount_timer);
 572    if (baum->brlapi) {
 573        brlapi__closeConnection(baum->brlapi);
 574        qemu_free(baum->brlapi);
 575    }
 576    qemu_free(baum);
 577}
 578
 579int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
 580{
 581    BaumDriverState *baum;
 582    CharDriverState *chr;
 583    brlapi_handle_t *handle;
 584#ifdef CONFIG_SDL
 585    SDL_SysWMinfo info;
 586#endif
 587    int tty;
 588
 589    baum = qemu_mallocz(sizeof(BaumDriverState));
 590    baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
 591
 592    chr->opaque = baum;
 593    chr->chr_write = baum_write;
 594    chr->chr_send_event = baum_send_event;
 595    chr->chr_accept_input = baum_accept_input;
 596    chr->chr_close = baum_close;
 597
 598    handle = qemu_mallocz(brlapi_getHandleSize());
 599    baum->brlapi = handle;
 600
 601    baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
 602    if (baum->brlapi_fd == -1) {
 603        brlapi_perror("baum_init: brlapi_openConnection");
 604        goto fail_handle;
 605    }
 606
 607    baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum);
 608
 609    if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
 610        brlapi_perror("baum_init: brlapi_getDisplaySize");
 611        goto fail;
 612    }
 613
 614#ifdef CONFIG_SDL
 615    memset(&info, 0, sizeof(info));
 616    SDL_VERSION(&info.version);
 617    if (SDL_GetWMInfo(&info))
 618        tty = info.info.x11.wmwindow;
 619    else
 620#endif
 621        tty = BRLAPI_TTY_DEFAULT;
 622
 623    if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
 624        brlapi_perror("baum_init: brlapi_enterTtyMode");
 625        goto fail;
 626    }
 627
 628    qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
 629
 630    qemu_chr_generic_open(chr);
 631
 632    *_chr = chr;
 633    return 0;
 634
 635fail:
 636    qemu_free_timer(baum->cellCount_timer);
 637    brlapi__closeConnection(handle);
 638fail_handle:
 639    qemu_free(handle);
 640    qemu_free(chr);
 641    qemu_free(baum);
 642    return -EIO;
 643}
 644