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(vm_clock) + ticks_per_sec / 10);
 339        for (i = 0; i < baum->x * baum->y ; i++) {
 340            EAT(c);
 341            cells[i] = c;
 342            if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
 343                    == (BRLAPI_DOT7|BRLAPI_DOT8)) {
 344                cursor = i + 1;
 345                c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
 346            }
 347            if (!(c = nabcc_translation[c]))
 348                c = '?';
 349            text[i] = c;
 350        }
 351        qemu_del_timer(baum->cellCount_timer);
 352
 353        memset(zero, 0, sizeof(zero));
 354
 355        brlapi_writeArguments_t wa = {
 356            .displayNumber = BRLAPI_DISPLAY_DEFAULT,
 357            .regionBegin = 1,
 358            .regionSize = baum->x * baum->y,
 359            .text = (char *)text,
 360            .textSize = baum->x * baum->y,
 361            .andMask = zero,
 362            .orMask = cells,
 363            .cursor = cursor,
 364            .charset = (char *)"ISO-8859-1",
 365        };
 366
 367        if (brlapi__write(baum->brlapi, &wa) == -1)
 368            brlapi_perror("baum brlapi_write");
 369        break;
 370    }
 371    case BAUM_REQ_SetMode:
 372    {
 373        uint8_t mode, setting;
 374        DPRINTF("SetMode\n");
 375        EAT(mode);
 376        EAT(setting);
 377        /* ignore */
 378        break;
 379    }
 380    case BAUM_REQ_SetProtocol:
 381    {
 382        uint8_t protocol;
 383        DPRINTF("SetProtocol\n");
 384        EAT(protocol);
 385        /* ignore */
 386        break;
 387    }
 388    case BAUM_REQ_GetDeviceIdentity:
 389    {
 390        uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
 391            'B','a','u','m',' ','V','a','r','i','o' };
 392        DPRINTF("GetDeviceIdentity\n");
 393        identity[11] = '0' + baum->x / 10;
 394        identity[12] = '0' + baum->x % 10;
 395        baum_write_packet(baum, identity, sizeof(identity));
 396        break;
 397    }
 398    case BAUM_REQ_GetVersionNumber:
 399    {
 400        uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
 401        DPRINTF("GetVersionNumber\n");
 402        baum_write_packet(baum, version, sizeof(version));
 403        break;
 404    }
 405    case BAUM_REQ_GetSerialNumber:
 406    {
 407        uint8_t serial[] = { BAUM_RSP_SerialNumber,
 408            '0','0','0','0','0','0','0','0' };
 409        DPRINTF("GetSerialNumber\n");
 410        baum_write_packet(baum, serial, sizeof(serial));
 411        break;
 412    }
 413    case BAUM_REQ_GetKeys:
 414    {
 415        DPRINTF("Get%0#2x\n", req);
 416        /* ignore */
 417        break;
 418    }
 419    default:
 420        DPRINTF("unrecognized request %0#2x\n", req);
 421        do
 422            if (!len--)
 423                return 0;
 424        while (*cur++ != ESC);
 425        cur--;
 426        break;
 427    }
 428    return cur - buf;
 429}
 430
 431/* The other end is writing some data.  Store it and try to interpret */
 432static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
 433{
 434    BaumDriverState *baum = chr->opaque;
 435    int tocopy, cur, eaten, orig_len = len;
 436
 437    if (!len)
 438        return 0;
 439    if (!baum->brlapi)
 440        return len;
 441
 442    while (len) {
 443        /* Complete our buffer as much as possible */
 444        tocopy = len;
 445        if (tocopy > BUF_SIZE - baum->in_buf_used)
 446            tocopy = BUF_SIZE - baum->in_buf_used;
 447
 448        memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
 449        baum->in_buf_used += tocopy;
 450        buf += tocopy;
 451        len -= tocopy;
 452
 453        /* Interpret it as much as possible */
 454        cur = 0;
 455        while (cur < baum->in_buf_used &&
 456                (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
 457            cur += eaten;
 458
 459        /* Shift the remainder */
 460        if (cur) {
 461            memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
 462            baum->in_buf_used -= cur;
 463        }
 464
 465        /* And continue if any data left */
 466    }
 467    return orig_len;
 468}
 469
 470/* The other end sent us some event */
 471static void baum_send_event(CharDriverState *chr, int event)
 472{
 473    BaumDriverState *baum = chr->opaque;
 474    switch (event) {
 475    case CHR_EVENT_BREAK:
 476        break;
 477    case CHR_EVENT_RESET:
 478        /* Reset state */
 479        baum->in_buf_used = 0;
 480        break;
 481    }
 482}
 483
 484/* Send the key code to the other end */
 485static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
 486    uint8_t packet[] = { type, value };
 487    DPRINTF("writing key %x %x\n", type, value);
 488    baum_write_packet(baum, packet, sizeof(packet));
 489}
 490
 491/* We got some data on the BrlAPI socket */
 492static void baum_chr_read(void *opaque)
 493{
 494    BaumDriverState *baum = opaque;
 495    brlapi_keyCode_t code;
 496    int ret;
 497    if (!baum->brlapi)
 498        return;
 499    while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
 500        DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
 501        /* Emulate */
 502        switch (code & BRLAPI_KEY_TYPE_MASK) {
 503        case BRLAPI_KEY_TYPE_CMD:
 504            switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
 505            case BRLAPI_KEY_CMD_ROUTE:
 506                baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
 507                baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
 508                break;
 509            case 0:
 510                switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
 511                case BRLAPI_KEY_CMD_FWINLT:
 512                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
 513                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 514                    break;
 515                case BRLAPI_KEY_CMD_FWINRT:
 516                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
 517                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 518                    break;
 519                case BRLAPI_KEY_CMD_LNUP:
 520                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
 521                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 522                    break;
 523                case BRLAPI_KEY_CMD_LNDN:
 524                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
 525                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 526                    break;
 527                case BRLAPI_KEY_CMD_TOP:
 528                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
 529                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 530                    break;
 531                case BRLAPI_KEY_CMD_BOT:
 532                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
 533                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 534                    break;
 535                case BRLAPI_KEY_CMD_TOP_LEFT:
 536                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
 537                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 538                    break;
 539                case BRLAPI_KEY_CMD_BOT_LEFT:
 540                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
 541                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 542                    break;
 543                case BRLAPI_KEY_CMD_HOME:
 544                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
 545                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 546                    break;
 547                case BRLAPI_KEY_CMD_PREFMENU:
 548                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
 549                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 550                    break;
 551                }
 552            }
 553            break;
 554        case BRLAPI_KEY_TYPE_SYM:
 555            break;
 556        }
 557    }
 558    if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
 559        brlapi_perror("baum: brlapi_readKey");
 560        brlapi__closeConnection(baum->brlapi);
 561        free(baum->brlapi);
 562        baum->brlapi = NULL;
 563    }
 564}
 565
 566CharDriverState *chr_baum_init(void)
 567{
 568    BaumDriverState *baum;
 569    CharDriverState *chr;
 570    brlapi_handle_t *handle;
 571#ifdef CONFIG_SDL
 572    SDL_SysWMinfo info;
 573#endif
 574    int tty;
 575
 576    baum = qemu_mallocz(sizeof(BaumDriverState));
 577    baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
 578
 579    chr->opaque = baum;
 580    chr->chr_write = baum_write;
 581    chr->chr_send_event = baum_send_event;
 582    chr->chr_accept_input = baum_accept_input;
 583
 584    handle = qemu_mallocz(brlapi_getHandleSize());
 585    baum->brlapi = handle;
 586
 587    baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
 588    if (baum->brlapi_fd == -1) {
 589        brlapi_perror("baum_init: brlapi_openConnection");
 590        goto fail_handle;
 591    }
 592
 593    baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum);
 594
 595    if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
 596        brlapi_perror("baum_init: brlapi_getDisplaySize");
 597        goto fail;
 598    }
 599
 600#ifdef CONFIG_SDL
 601    memset(&info, 0, sizeof(info));
 602    SDL_VERSION(&info.version);
 603    if (SDL_GetWMInfo(&info))
 604        tty = info.info.x11.wmwindow;
 605    else
 606#endif
 607        tty = BRLAPI_TTY_DEFAULT;
 608
 609    if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
 610        brlapi_perror("baum_init: brlapi_enterTtyMode");
 611        goto fail;
 612    }
 613
 614    qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
 615
 616    qemu_chr_reset(chr);
 617
 618    return chr;
 619
 620fail:
 621    qemu_free_timer(baum->cellCount_timer);
 622    brlapi__closeConnection(handle);
 623fail_handle:
 624    free(handle);
 625    free(chr);
 626    free(baum);
 627    return NULL;
 628}
 629
 630USBDevice *usb_baum_init(void)
 631{
 632    /* USB Product ID of Super Vario 40 */
 633    return usb_serial_init("productid=FE72:braille");
 634}
 635