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