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