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_be_can_write(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_be_write(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_be_write(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_be_can_write(baum->chr);
 254    len = cur - io_buf;
 255    if (len <= room) {
 256        /* Fits */
 257        qemu_chr_be_write(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_be_write(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/* Send the key code to the other end */
 472static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
 473    uint8_t packet[] = { type, value };
 474    DPRINTF("writing key %x %x\n", type, value);
 475    baum_write_packet(baum, packet, sizeof(packet));
 476}
 477
 478/* We got some data on the BrlAPI socket */
 479static void baum_chr_read(void *opaque)
 480{
 481    BaumDriverState *baum = opaque;
 482    brlapi_keyCode_t code;
 483    int ret;
 484    if (!baum->brlapi)
 485        return;
 486    while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
 487        DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
 488        /* Emulate */
 489        switch (code & BRLAPI_KEY_TYPE_MASK) {
 490        case BRLAPI_KEY_TYPE_CMD:
 491            switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
 492            case BRLAPI_KEY_CMD_ROUTE:
 493                baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
 494                baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
 495                break;
 496            case 0:
 497                switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
 498                case BRLAPI_KEY_CMD_FWINLT:
 499                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
 500                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 501                    break;
 502                case BRLAPI_KEY_CMD_FWINRT:
 503                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
 504                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 505                    break;
 506                case BRLAPI_KEY_CMD_LNUP:
 507                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
 508                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 509                    break;
 510                case BRLAPI_KEY_CMD_LNDN:
 511                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
 512                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 513                    break;
 514                case BRLAPI_KEY_CMD_TOP:
 515                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
 516                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 517                    break;
 518                case BRLAPI_KEY_CMD_BOT:
 519                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
 520                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 521                    break;
 522                case BRLAPI_KEY_CMD_TOP_LEFT:
 523                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
 524                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 525                    break;
 526                case BRLAPI_KEY_CMD_BOT_LEFT:
 527                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
 528                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 529                    break;
 530                case BRLAPI_KEY_CMD_HOME:
 531                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
 532                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 533                    break;
 534                case BRLAPI_KEY_CMD_PREFMENU:
 535                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
 536                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
 537                    break;
 538                }
 539            }
 540            break;
 541        case BRLAPI_KEY_TYPE_SYM:
 542            break;
 543        }
 544    }
 545    if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
 546        brlapi_perror("baum: brlapi_readKey");
 547        brlapi__closeConnection(baum->brlapi);
 548        g_free(baum->brlapi);
 549        baum->brlapi = NULL;
 550    }
 551}
 552
 553static void baum_close(struct CharDriverState *chr)
 554{
 555    BaumDriverState *baum = chr->opaque;
 556
 557    qemu_free_timer(baum->cellCount_timer);
 558    if (baum->brlapi) {
 559        brlapi__closeConnection(baum->brlapi);
 560        g_free(baum->brlapi);
 561    }
 562    g_free(baum);
 563}
 564
 565CharDriverState *chr_baum_init(QemuOpts *opts)
 566{
 567    BaumDriverState *baum;
 568    CharDriverState *chr;
 569    brlapi_handle_t *handle;
 570#ifdef CONFIG_SDL
 571    SDL_SysWMinfo info;
 572#endif
 573    int tty;
 574
 575    baum = g_malloc0(sizeof(BaumDriverState));
 576    baum->chr = chr = g_malloc0(sizeof(CharDriverState));
 577
 578    chr->opaque = baum;
 579    chr->chr_write = baum_write;
 580    chr->chr_accept_input = baum_accept_input;
 581    chr->chr_close = baum_close;
 582
 583    handle = g_malloc0(brlapi_getHandleSize());
 584    baum->brlapi = handle;
 585
 586    baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
 587    if (baum->brlapi_fd == -1) {
 588        brlapi_perror("baum_init: brlapi_openConnection");
 589        goto fail_handle;
 590    }
 591
 592    baum->cellCount_timer = qemu_new_timer_ns(vm_clock, baum_cellCount_timer_cb, baum);
 593
 594    if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
 595        brlapi_perror("baum_init: brlapi_getDisplaySize");
 596        goto fail;
 597    }
 598
 599#ifdef CONFIG_SDL
 600    memset(&info, 0, sizeof(info));
 601    SDL_VERSION(&info.version);
 602    if (SDL_GetWMInfo(&info))
 603        tty = info.info.x11.wmwindow;
 604    else
 605#endif
 606        tty = BRLAPI_TTY_DEFAULT;
 607
 608    if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
 609        brlapi_perror("baum_init: brlapi_enterTtyMode");
 610        goto fail;
 611    }
 612
 613    qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
 614
 615    qemu_chr_generic_open(chr);
 616
 617    return chr;
 618
 619fail:
 620    qemu_free_timer(baum->cellCount_timer);
 621    brlapi__closeConnection(handle);
 622fail_handle:
 623    g_free(handle);
 624    g_free(chr);
 625    g_free(baum);
 626    return NULL;
 627}
 628