cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

baum.c (22875B)


      1/*
      2 * QEMU Baum Braille Device
      3 *
      4 * Copyright (c) 2008, 2010-2011, 2016-2017 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
     25#include "qemu/osdep.h"
     26#include "qapi/error.h"
     27#include "chardev/char.h"
     28#include "qemu/main-loop.h"
     29#include "qemu/module.h"
     30#include "qemu/timer.h"
     31#include "hw/usb.h"
     32#include "ui/console.h"
     33#include <brlapi.h>
     34#include <brlapi_constants.h>
     35#include <brlapi_keycodes.h>
     36#include "qom/object.h"
     37
     38#if 0
     39#define DPRINTF(fmt, ...) \
     40        printf(fmt, ## __VA_ARGS__)
     41#else
     42#define DPRINTF(fmt, ...)
     43#endif
     44
     45#define ESC 0x1B
     46
     47#define BAUM_REQ_DisplayData		0x01
     48#define BAUM_REQ_GetVersionNumber	0x05
     49#define BAUM_REQ_GetKeys		0x08
     50#define BAUM_REQ_SetMode		0x12
     51#define BAUM_REQ_SetProtocol		0x15
     52#define BAUM_REQ_GetDeviceIdentity	0x84
     53#define BAUM_REQ_GetSerialNumber	0x8A
     54
     55#define BAUM_RSP_CellCount		0x01
     56#define BAUM_RSP_VersionNumber		0x05
     57#define BAUM_RSP_ModeSetting		0x11
     58#define BAUM_RSP_CommunicationChannel	0x16
     59#define BAUM_RSP_PowerdownSignal	0x17
     60#define BAUM_RSP_HorizontalSensors	0x20
     61#define BAUM_RSP_VerticalSensors	0x21
     62#define BAUM_RSP_RoutingKeys		0x22
     63#define BAUM_RSP_Switches		0x23
     64#define BAUM_RSP_TopKeys		0x24
     65#define BAUM_RSP_HorizontalSensor	0x25
     66#define BAUM_RSP_VerticalSensor		0x26
     67#define BAUM_RSP_RoutingKey		0x27
     68#define BAUM_RSP_FrontKeys6		0x28
     69#define BAUM_RSP_BackKeys6		0x29
     70#define BAUM_RSP_CommandKeys		0x2B
     71#define BAUM_RSP_FrontKeys10		0x2C
     72#define BAUM_RSP_BackKeys10		0x2D
     73#define BAUM_RSP_EntryKeys		0x33
     74#define BAUM_RSP_JoyStick		0x34
     75#define BAUM_RSP_ErrorCode		0x40
     76#define BAUM_RSP_InfoBlock		0x42
     77#define BAUM_RSP_DeviceIdentity		0x84
     78#define BAUM_RSP_SerialNumber		0x8A
     79#define BAUM_RSP_BluetoothName		0x8C
     80
     81#define BAUM_TL1 0x01
     82#define BAUM_TL2 0x02
     83#define BAUM_TL3 0x04
     84#define BAUM_TR1 0x08
     85#define BAUM_TR2 0x10
     86#define BAUM_TR3 0x20
     87
     88#define BUF_SIZE 256
     89
     90struct BaumChardev {
     91    Chardev parent;
     92
     93    brlapi_handle_t *brlapi;
     94    int brlapi_fd;
     95    unsigned int x, y;
     96    bool deferred_init;
     97
     98    uint8_t in_buf[BUF_SIZE];
     99    uint8_t in_buf_used;
    100    uint8_t out_buf[BUF_SIZE];
    101    uint8_t out_buf_used, out_buf_ptr;
    102
    103    QEMUTimer *cellCount_timer;
    104};
    105typedef struct BaumChardev BaumChardev;
    106
    107#define TYPE_CHARDEV_BRAILLE "chardev-braille"
    108DECLARE_INSTANCE_CHECKER(BaumChardev, BAUM_CHARDEV,
    109                         TYPE_CHARDEV_BRAILLE)
    110
    111/* Let's assume NABCC by default */
    112enum way {
    113    DOTS2ASCII,
    114    ASCII2DOTS
    115};
    116static const uint8_t nabcc_translation[2][256] = {
    117#ifndef BRLAPI_DOTS
    118#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
    119    ((d1?BRLAPI_DOT1:0)|\
    120     (d2?BRLAPI_DOT2:0)|\
    121     (d3?BRLAPI_DOT3:0)|\
    122     (d4?BRLAPI_DOT4:0)|\
    123     (d5?BRLAPI_DOT5:0)|\
    124     (d6?BRLAPI_DOT6:0)|\
    125     (d7?BRLAPI_DOT7:0)|\
    126     (d8?BRLAPI_DOT8:0))
    127#endif
    128#define DO(dots, ascii) \
    129    [DOTS2ASCII][dots] = ascii, \
    130    [ASCII2DOTS][ascii] = dots
    131    DO(0, ' '),
    132    DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 0, 0), 'a'),
    133    DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 0, 0), 'b'),
    134    DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 0, 0), 'c'),
    135    DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 0, 0), 'd'),
    136    DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 0, 0), 'e'),
    137    DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 0, 0), 'f'),
    138    DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 0, 0), 'g'),
    139    DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 0, 0), 'h'),
    140    DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 0, 0), 'i'),
    141    DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 0, 0), 'j'),
    142    DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 0, 0), 'k'),
    143    DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 0, 0), 'l'),
    144    DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 0, 0), 'm'),
    145    DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 0, 0), 'n'),
    146    DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 0, 0), 'o'),
    147    DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 0, 0), 'p'),
    148    DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 0, 0), 'q'),
    149    DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 0, 0), 'r'),
    150    DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 0, 0), 's'),
    151    DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 0, 0), 't'),
    152    DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 0, 0), 'u'),
    153    DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 0, 0), 'v'),
    154    DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 0, 0), 'w'),
    155    DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 0, 0), 'x'),
    156    DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 0, 0), 'y'),
    157    DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 0, 0), 'z'),
    158
    159    DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 1, 0), 'A'),
    160    DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 1, 0), 'B'),
    161    DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 1, 0), 'C'),
    162    DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 1, 0), 'D'),
    163    DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 1, 0), 'E'),
    164    DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 1, 0), 'F'),
    165    DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 1, 0), 'G'),
    166    DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 1, 0), 'H'),
    167    DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 1, 0), 'I'),
    168    DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 1, 0), 'J'),
    169    DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 1, 0), 'K'),
    170    DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 1, 0), 'L'),
    171    DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 1, 0), 'M'),
    172    DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 1, 0), 'N'),
    173    DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 1, 0), 'O'),
    174    DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 1, 0), 'P'),
    175    DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 1, 0), 'Q'),
    176    DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 1, 0), 'R'),
    177    DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 1, 0), 'S'),
    178    DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 1, 0), 'T'),
    179    DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 1, 0), 'U'),
    180    DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 1, 0), 'V'),
    181    DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 1, 0), 'W'),
    182    DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 1, 0), 'X'),
    183    DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 1, 0), 'Y'),
    184    DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 1, 0), 'Z'),
    185
    186    DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 1, 0, 0), '0'),
    187    DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 0, 0, 0), '1'),
    188    DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 0, 0, 0), '2'),
    189    DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 0, 0, 0), '3'),
    190    DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 1, 0, 0), '4'),
    191    DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 1, 0, 0), '5'),
    192    DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 0, 0, 0), '6'),
    193    DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 1, 0, 0), '7'),
    194    DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 1, 0, 0), '8'),
    195    DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 0, 0, 0), '9'),
    196
    197    DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 1, 0, 0), '.'),
    198    DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 1, 0, 0), '+'),
    199    DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 1, 0, 0), '-'),
    200    DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 1, 0, 0), '*'),
    201    DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 0, 0, 0), '/'),
    202    DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 1, 0, 0), '('),
    203    DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 1, 0, 0), ')'),
    204
    205    DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 1, 0, 0), '&'),
    206    DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 1, 0, 0), '#'),
    207
    208    DO(BRLAPI_DOTS(0, 0, 0, 0, 0, 1, 0, 0), ','),
    209    DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 1, 0, 0), ';'),
    210    DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 1, 0, 0), ':'),
    211    DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 1, 0, 0), '!'),
    212    DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 1, 0, 0), '?'),
    213    DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 0, 0, 0), '"'),
    214    DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 0, 0, 0), '\''),
    215    DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 0, 0), '`'),
    216    DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 1, 0), '^'),
    217    DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 0, 0), '~'),
    218    DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 1, 0), '['),
    219    DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 1, 0), ']'),
    220    DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 0, 0), '{'),
    221    DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 0, 0), '}'),
    222    DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 1, 0, 0), '='),
    223    DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 1, 0, 0), '<'),
    224    DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 0, 0, 0), '>'),
    225    DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 1, 0, 0), '$'),
    226    DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 1, 0, 0), '%'),
    227    DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 1, 0), '@'),
    228    DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 0, 0), '|'),
    229    DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 1, 0), '\\'),
    230    DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 1, 0, 0), '_'),
    231};
    232
    233/* The guest OS has started discussing with us, finish initializing BrlAPI */
    234static int baum_deferred_init(BaumChardev *baum)
    235{
    236    int tty = BRLAPI_TTY_DEFAULT;
    237    QemuConsole *con;
    238
    239    if (baum->deferred_init) {
    240        return 1;
    241    }
    242
    243    if (brlapi__getDisplaySize(baum->brlapi, &baum->x, &baum->y) == -1) {
    244        brlapi_perror("baum: brlapi__getDisplaySize");
    245        return 0;
    246    }
    247    if (baum->y > 1) {
    248        baum->y = 1;
    249    }
    250    if (baum->x > 84) {
    251        baum->x = 84;
    252    }
    253
    254    con = qemu_console_lookup_by_index(0);
    255    if (con && qemu_console_is_graphic(con)) {
    256        tty = qemu_console_get_window_id(con);
    257        if (tty == -1)
    258            tty = BRLAPI_TTY_DEFAULT;
    259    }
    260
    261    if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) {
    262        brlapi_perror("baum: brlapi__enterTtyMode");
    263        return 0;
    264    }
    265    baum->deferred_init = 1;
    266    return 1;
    267}
    268
    269/* The serial port can receive more of our data */
    270static void baum_chr_accept_input(struct Chardev *chr)
    271{
    272    BaumChardev *baum = BAUM_CHARDEV(chr);
    273    int room, first;
    274
    275    if (!baum->out_buf_used)
    276        return;
    277    room = qemu_chr_be_can_write(chr);
    278    if (!room)
    279        return;
    280    if (room > baum->out_buf_used)
    281        room = baum->out_buf_used;
    282
    283    first = BUF_SIZE - baum->out_buf_ptr;
    284    if (room > first) {
    285        qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first);
    286        baum->out_buf_ptr = 0;
    287        baum->out_buf_used -= first;
    288        room -= first;
    289    }
    290    qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room);
    291    baum->out_buf_ptr += room;
    292    baum->out_buf_used -= room;
    293}
    294
    295/* We want to send a packet */
    296static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
    297{
    298    Chardev *chr = CHARDEV(baum);
    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(chr);
    306    len = cur - io_buf;
    307    if (len <= room) {
    308        /* Fits */
    309        qemu_chr_be_write(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(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    BaumChardev *baum = BAUM_CHARDEV(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(BaumChardev *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_chr_write(Chardev *chr, const uint8_t *buf, int len)
    488{
    489    BaumChardev *baum = BAUM_CHARDEV(chr);
    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(BaumChardev *baum, uint8_t type, uint8_t value)
    529{
    530    uint8_t packet[] = { type, value };
    531    DPRINTF("writing key %x %x\n", type, value);
    532    baum_write_packet(baum, packet, sizeof(packet));
    533}
    534
    535static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
    536                           uint8_t value2)
    537{
    538    uint8_t packet[] = { type, value, value2 };
    539    DPRINTF("writing key %x %x\n", type, value);
    540    baum_write_packet(baum, packet, sizeof(packet));
    541}
    542
    543/* We got some data on the BrlAPI socket */
    544static void baum_chr_read(void *opaque)
    545{
    546    BaumChardev *baum = BAUM_CHARDEV(opaque);
    547    brlapi_keyCode_t code;
    548    int ret;
    549    if (!baum->brlapi)
    550        return;
    551    if (!baum_deferred_init(baum))
    552        return;
    553    while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
    554        DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
    555        /* Emulate */
    556        switch (code & BRLAPI_KEY_TYPE_MASK) {
    557        case BRLAPI_KEY_TYPE_CMD:
    558            switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
    559            case BRLAPI_KEY_CMD_ROUTE:
    560                baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
    561                baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
    562                break;
    563            case 0:
    564                switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
    565                case BRLAPI_KEY_CMD_FWINLT:
    566                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
    567                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    568                    break;
    569                case BRLAPI_KEY_CMD_FWINRT:
    570                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
    571                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    572                    break;
    573                case BRLAPI_KEY_CMD_LNUP:
    574                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
    575                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    576                    break;
    577                case BRLAPI_KEY_CMD_LNDN:
    578                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
    579                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    580                    break;
    581                case BRLAPI_KEY_CMD_TOP:
    582                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
    583                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    584                    break;
    585                case BRLAPI_KEY_CMD_BOT:
    586                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
    587                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    588                    break;
    589                case BRLAPI_KEY_CMD_TOP_LEFT:
    590                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
    591                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    592                    break;
    593                case BRLAPI_KEY_CMD_BOT_LEFT:
    594                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
    595                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    596                    break;
    597                case BRLAPI_KEY_CMD_HOME:
    598                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
    599                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    600                    break;
    601                case BRLAPI_KEY_CMD_PREFMENU:
    602                    baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
    603                    baum_send_key(baum, BAUM_RSP_TopKeys, 0);
    604                    break;
    605                }
    606            }
    607            break;
    608        case BRLAPI_KEY_TYPE_SYM:
    609            {
    610                brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK;
    611                if (keysym < 0x100) {
    612                    uint8_t dots = nabcc_translation[ASCII2DOTS][keysym];
    613                    if (dots) {
    614                        baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots);
    615                        baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0);
    616                    }
    617                }
    618                break;
    619            }
    620        }
    621    }
    622    if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
    623        brlapi_perror("baum: brlapi_readKey");
    624        brlapi__closeConnection(baum->brlapi);
    625        g_free(baum->brlapi);
    626        baum->brlapi = NULL;
    627    }
    628}
    629
    630static void char_braille_finalize(Object *obj)
    631{
    632    BaumChardev *baum = BAUM_CHARDEV(obj);
    633
    634    timer_free(baum->cellCount_timer);
    635    if (baum->brlapi) {
    636        brlapi__closeConnection(baum->brlapi);
    637        g_free(baum->brlapi);
    638    }
    639}
    640
    641static void baum_chr_open(Chardev *chr,
    642                          ChardevBackend *backend,
    643                          bool *be_opened,
    644                          Error **errp)
    645{
    646    BaumChardev *baum = BAUM_CHARDEV(chr);
    647    brlapi_handle_t *handle;
    648
    649    handle = g_malloc0(brlapi_getHandleSize());
    650    baum->brlapi = handle;
    651
    652    baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
    653    if (baum->brlapi_fd == -1) {
    654        error_setg(errp, "brlapi__openConnection: %s",
    655                   brlapi_strerror(brlapi_error_location()));
    656        g_free(handle);
    657        baum->brlapi = NULL;
    658        return;
    659    }
    660    baum->deferred_init = 0;
    661
    662    baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
    663
    664    qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
    665}
    666
    667static void char_braille_class_init(ObjectClass *oc, void *data)
    668{
    669    ChardevClass *cc = CHARDEV_CLASS(oc);
    670
    671    cc->open = baum_chr_open;
    672    cc->chr_write = baum_chr_write;
    673    cc->chr_accept_input = baum_chr_accept_input;
    674}
    675
    676static const TypeInfo char_braille_type_info = {
    677    .name = TYPE_CHARDEV_BRAILLE,
    678    .parent = TYPE_CHARDEV,
    679    .instance_size = sizeof(BaumChardev),
    680    .instance_finalize = char_braille_finalize,
    681    .class_init = char_braille_class_init,
    682};
    683module_obj(TYPE_CHARDEV_BRAILLE);
    684
    685static void register_types(void)
    686{
    687    type_register_static(&char_braille_type_info);
    688}
    689
    690type_init(register_types);