16b10e573SMarc-André Lureau /*
26b10e573SMarc-André Lureau * QEMU Baum Braille Device
36b10e573SMarc-André Lureau *
41ef7c96eSSamuel Thibault * Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault
56b10e573SMarc-André Lureau *
66b10e573SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
76b10e573SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
86b10e573SMarc-André Lureau * in the Software without restriction, including without limitation the rights
96b10e573SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
106b10e573SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
116b10e573SMarc-André Lureau * furnished to do so, subject to the following conditions:
126b10e573SMarc-André Lureau *
136b10e573SMarc-André Lureau * The above copyright notice and this permission notice shall be included in
146b10e573SMarc-André Lureau * all copies or substantial portions of the Software.
156b10e573SMarc-André Lureau *
166b10e573SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176b10e573SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186b10e573SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
196b10e573SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
206b10e573SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216b10e573SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
226b10e573SMarc-André Lureau * THE SOFTWARE.
236b10e573SMarc-André Lureau */
240b8fa32fSMarkus Armbruster
256b10e573SMarc-André Lureau #include "qemu/osdep.h"
266b10e573SMarc-André Lureau #include "qapi/error.h"
276b10e573SMarc-André Lureau #include "chardev/char.h"
28db725815SMarkus Armbruster #include "qemu/main-loop.h"
290b8fa32fSMarkus Armbruster #include "qemu/module.h"
306b10e573SMarc-André Lureau #include "qemu/timer.h"
316b10e573SMarc-André Lureau #include "hw/usb.h"
326b10e573SMarc-André Lureau #include "ui/console.h"
336b10e573SMarc-André Lureau #include <brlapi.h>
346b10e573SMarc-André Lureau #include <brlapi_constants.h>
356b10e573SMarc-André Lureau #include <brlapi_keycodes.h>
36db1015e9SEduardo Habkost #include "qom/object.h"
376b10e573SMarc-André Lureau
386b10e573SMarc-André Lureau #if 0
396b10e573SMarc-André Lureau #define DPRINTF(fmt, ...) \
406b10e573SMarc-André Lureau printf(fmt, ## __VA_ARGS__)
416b10e573SMarc-André Lureau #else
426b10e573SMarc-André Lureau #define DPRINTF(fmt, ...)
436b10e573SMarc-André Lureau #endif
446b10e573SMarc-André Lureau
456b10e573SMarc-André Lureau #define ESC 0x1B
466b10e573SMarc-André Lureau
476b10e573SMarc-André Lureau #define BAUM_REQ_DisplayData 0x01
486b10e573SMarc-André Lureau #define BAUM_REQ_GetVersionNumber 0x05
496b10e573SMarc-André Lureau #define BAUM_REQ_GetKeys 0x08
506b10e573SMarc-André Lureau #define BAUM_REQ_SetMode 0x12
516b10e573SMarc-André Lureau #define BAUM_REQ_SetProtocol 0x15
526b10e573SMarc-André Lureau #define BAUM_REQ_GetDeviceIdentity 0x84
536b10e573SMarc-André Lureau #define BAUM_REQ_GetSerialNumber 0x8A
546b10e573SMarc-André Lureau
556b10e573SMarc-André Lureau #define BAUM_RSP_CellCount 0x01
566b10e573SMarc-André Lureau #define BAUM_RSP_VersionNumber 0x05
576b10e573SMarc-André Lureau #define BAUM_RSP_ModeSetting 0x11
586b10e573SMarc-André Lureau #define BAUM_RSP_CommunicationChannel 0x16
596b10e573SMarc-André Lureau #define BAUM_RSP_PowerdownSignal 0x17
606b10e573SMarc-André Lureau #define BAUM_RSP_HorizontalSensors 0x20
616b10e573SMarc-André Lureau #define BAUM_RSP_VerticalSensors 0x21
626b10e573SMarc-André Lureau #define BAUM_RSP_RoutingKeys 0x22
636b10e573SMarc-André Lureau #define BAUM_RSP_Switches 0x23
646b10e573SMarc-André Lureau #define BAUM_RSP_TopKeys 0x24
656b10e573SMarc-André Lureau #define BAUM_RSP_HorizontalSensor 0x25
666b10e573SMarc-André Lureau #define BAUM_RSP_VerticalSensor 0x26
676b10e573SMarc-André Lureau #define BAUM_RSP_RoutingKey 0x27
686b10e573SMarc-André Lureau #define BAUM_RSP_FrontKeys6 0x28
696b10e573SMarc-André Lureau #define BAUM_RSP_BackKeys6 0x29
706b10e573SMarc-André Lureau #define BAUM_RSP_CommandKeys 0x2B
716b10e573SMarc-André Lureau #define BAUM_RSP_FrontKeys10 0x2C
726b10e573SMarc-André Lureau #define BAUM_RSP_BackKeys10 0x2D
736b10e573SMarc-André Lureau #define BAUM_RSP_EntryKeys 0x33
746b10e573SMarc-André Lureau #define BAUM_RSP_JoyStick 0x34
756b10e573SMarc-André Lureau #define BAUM_RSP_ErrorCode 0x40
766b10e573SMarc-André Lureau #define BAUM_RSP_InfoBlock 0x42
776b10e573SMarc-André Lureau #define BAUM_RSP_DeviceIdentity 0x84
786b10e573SMarc-André Lureau #define BAUM_RSP_SerialNumber 0x8A
796b10e573SMarc-André Lureau #define BAUM_RSP_BluetoothName 0x8C
806b10e573SMarc-André Lureau
816b10e573SMarc-André Lureau #define BAUM_TL1 0x01
826b10e573SMarc-André Lureau #define BAUM_TL2 0x02
836b10e573SMarc-André Lureau #define BAUM_TL3 0x04
846b10e573SMarc-André Lureau #define BAUM_TR1 0x08
856b10e573SMarc-André Lureau #define BAUM_TR2 0x10
866b10e573SMarc-André Lureau #define BAUM_TR3 0x20
876b10e573SMarc-André Lureau
886b10e573SMarc-André Lureau #define BUF_SIZE 256
896b10e573SMarc-André Lureau
90f63a6e38SPhilippe Mathieu-Daudé #define X_MAX 84
91f63a6e38SPhilippe Mathieu-Daudé #define Y_MAX 1
92f63a6e38SPhilippe Mathieu-Daudé
93db1015e9SEduardo Habkost struct BaumChardev {
946b10e573SMarc-André Lureau Chardev parent;
956b10e573SMarc-André Lureau
966b10e573SMarc-André Lureau brlapi_handle_t *brlapi;
976b10e573SMarc-André Lureau int brlapi_fd;
986b10e573SMarc-André Lureau unsigned int x, y;
996b10e573SMarc-André Lureau bool deferred_init;
1006b10e573SMarc-André Lureau
1016b10e573SMarc-André Lureau uint8_t in_buf[BUF_SIZE];
1026b10e573SMarc-André Lureau uint8_t in_buf_used;
1036b10e573SMarc-André Lureau uint8_t out_buf[BUF_SIZE];
1046b10e573SMarc-André Lureau uint8_t out_buf_used, out_buf_ptr;
1056b10e573SMarc-André Lureau
1066b10e573SMarc-André Lureau QEMUTimer *cellCount_timer;
107db1015e9SEduardo Habkost };
108db1015e9SEduardo Habkost typedef struct BaumChardev BaumChardev;
1096b10e573SMarc-André Lureau
1106b10e573SMarc-André Lureau #define TYPE_CHARDEV_BRAILLE "chardev-braille"
1118110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(BaumChardev, BAUM_CHARDEV,
1128110fa1dSEduardo Habkost TYPE_CHARDEV_BRAILLE)
1136b10e573SMarc-André Lureau
1146b10e573SMarc-André Lureau /* Let's assume NABCC by default */
1156b10e573SMarc-André Lureau enum way {
1166b10e573SMarc-André Lureau DOTS2ASCII,
1176b10e573SMarc-André Lureau ASCII2DOTS
1186b10e573SMarc-André Lureau };
1196b10e573SMarc-André Lureau static const uint8_t nabcc_translation[2][256] = {
1206b10e573SMarc-André Lureau #ifndef BRLAPI_DOTS
1216b10e573SMarc-André Lureau #define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
1226b10e573SMarc-André Lureau ((d1?BRLAPI_DOT1:0)|\
1236b10e573SMarc-André Lureau (d2?BRLAPI_DOT2:0)|\
1246b10e573SMarc-André Lureau (d3?BRLAPI_DOT3:0)|\
1256b10e573SMarc-André Lureau (d4?BRLAPI_DOT4:0)|\
1266b10e573SMarc-André Lureau (d5?BRLAPI_DOT5:0)|\
1276b10e573SMarc-André Lureau (d6?BRLAPI_DOT6:0)|\
1286b10e573SMarc-André Lureau (d7?BRLAPI_DOT7:0)|\
1296b10e573SMarc-André Lureau (d8?BRLAPI_DOT8:0))
1306b10e573SMarc-André Lureau #endif
1316b10e573SMarc-André Lureau #define DO(dots, ascii) \
1326b10e573SMarc-André Lureau [DOTS2ASCII][dots] = ascii, \
1336b10e573SMarc-André Lureau [ASCII2DOTS][ascii] = dots
1346b10e573SMarc-André Lureau DO(0, ' '),
1356b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 0, 0), 'a'),
1366b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 0, 0), 'b'),
1376b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 0, 0), 'c'),
1386b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 0, 0), 'd'),
1396b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 0, 0), 'e'),
1406b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 0, 0), 'f'),
1416b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 0, 0), 'g'),
1426b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 0, 0), 'h'),
1436b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 0, 0), 'i'),
1446b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 0, 0), 'j'),
1456b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 0, 0), 'k'),
1466b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 0, 0), 'l'),
1476b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 0, 0), 'm'),
1486b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 0, 0), 'n'),
1496b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 0, 0), 'o'),
1506b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 0, 0), 'p'),
1516b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 0, 0), 'q'),
1526b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 0, 0), 'r'),
1536b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 0, 0), 's'),
1546b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 0, 0), 't'),
1556b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 0, 0), 'u'),
1566b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 0, 0), 'v'),
1576b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 0, 0), 'w'),
1586b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 0, 0), 'x'),
1596b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 0, 0), 'y'),
1606b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 0, 0), 'z'),
1616b10e573SMarc-André Lureau
1626b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 1, 0), 'A'),
1636b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 1, 0), 'B'),
1646b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 1, 0), 'C'),
1656b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 1, 0), 'D'),
1666b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 1, 0), 'E'),
1676b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 1, 0), 'F'),
1686b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 1, 0), 'G'),
1696b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 1, 0), 'H'),
1706b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 1, 0), 'I'),
1716b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 1, 0), 'J'),
1726b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 1, 0), 'K'),
1736b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 1, 0), 'L'),
1746b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 1, 0), 'M'),
1756b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 1, 0), 'N'),
1766b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 1, 0), 'O'),
1776b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 1, 0), 'P'),
1786b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 1, 0), 'Q'),
1796b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 1, 0), 'R'),
1806b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 1, 0), 'S'),
1816b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 1, 0), 'T'),
1826b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 1, 0), 'U'),
1836b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 1, 0), 'V'),
1846b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 1, 0), 'W'),
1856b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 1, 0), 'X'),
1866b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 1, 0), 'Y'),
1876b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 1, 0), 'Z'),
1886b10e573SMarc-André Lureau
1896b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 1, 0, 0), '0'),
1906b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 0, 0, 0), '1'),
1916b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 0, 0, 0), '2'),
1926b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 0, 0, 0), '3'),
1936b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 1, 0, 0), '4'),
1946b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 1, 0, 0), '5'),
1956b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 0, 0, 0), '6'),
1966b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 1, 0, 0), '7'),
1976b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 1, 0, 0), '8'),
1986b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 0, 0, 0), '9'),
1996b10e573SMarc-André Lureau
2006b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 1, 0, 0), '.'),
2016b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 1, 0, 0), '+'),
2026b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 1, 0, 0), '-'),
2036b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 1, 0, 0), '*'),
2046b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 0, 0, 0), '/'),
2056b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 1, 0, 0), '('),
2066b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 1, 0, 0), ')'),
2076b10e573SMarc-André Lureau
2086b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 1, 0, 0), '&'),
2096b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 1, 0, 0), '#'),
2106b10e573SMarc-André Lureau
2116b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 0, 0, 1, 0, 0), ','),
2126b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 1, 0, 0), ';'),
2136b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 1, 0, 0), ':'),
2146b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 1, 0, 0), '!'),
2156b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 1, 0, 0), '?'),
2166b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 0, 0, 0), '"'),
2176b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 0, 0, 0), '\''),
2186b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 0, 0), '`'),
2196b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 1, 0), '^'),
2206b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 0, 0), '~'),
2216b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 1, 0), '['),
2226b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 1, 0), ']'),
2236b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 0, 0), '{'),
2246b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 0, 0), '}'),
2256b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 1, 0, 0), '='),
2266b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 1, 0, 0), '<'),
2276b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 0, 0, 0), '>'),
2286b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 1, 0, 0), '$'),
2296b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 1, 0, 0), '%'),
2306b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 1, 0), '@'),
2316b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 0, 0), '|'),
2326b10e573SMarc-André Lureau DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 1, 0), '\\'),
2336b10e573SMarc-André Lureau DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 1, 0, 0), '_'),
2346b10e573SMarc-André Lureau };
2356b10e573SMarc-André Lureau
2366b10e573SMarc-André Lureau /* The guest OS has started discussing with us, finish initializing BrlAPI */
baum_deferred_init(BaumChardev * baum)2376b10e573SMarc-André Lureau static int baum_deferred_init(BaumChardev *baum)
2386b10e573SMarc-André Lureau {
2396b10e573SMarc-André Lureau int tty = BRLAPI_TTY_DEFAULT;
2406b10e573SMarc-André Lureau QemuConsole *con;
2416b10e573SMarc-André Lureau
2426b10e573SMarc-André Lureau if (baum->deferred_init) {
2436b10e573SMarc-André Lureau return 1;
2446b10e573SMarc-André Lureau }
2456b10e573SMarc-André Lureau
2466b10e573SMarc-André Lureau if (brlapi__getDisplaySize(baum->brlapi, &baum->x, &baum->y) == -1) {
2476b10e573SMarc-André Lureau brlapi_perror("baum: brlapi__getDisplaySize");
2486b10e573SMarc-André Lureau return 0;
2496b10e573SMarc-André Lureau }
250f63a6e38SPhilippe Mathieu-Daudé if (baum->y > Y_MAX) {
251f63a6e38SPhilippe Mathieu-Daudé baum->y = Y_MAX;
2521ef7c96eSSamuel Thibault }
253f63a6e38SPhilippe Mathieu-Daudé if (baum->x > X_MAX) {
254f63a6e38SPhilippe Mathieu-Daudé baum->x = X_MAX;
2551ef7c96eSSamuel Thibault }
2566b10e573SMarc-André Lureau
2576b10e573SMarc-André Lureau con = qemu_console_lookup_by_index(0);
2586b10e573SMarc-André Lureau if (con && qemu_console_is_graphic(con)) {
2596b10e573SMarc-André Lureau tty = qemu_console_get_window_id(con);
2606b10e573SMarc-André Lureau if (tty == -1)
2616b10e573SMarc-André Lureau tty = BRLAPI_TTY_DEFAULT;
2626b10e573SMarc-André Lureau }
2636b10e573SMarc-André Lureau
2646b10e573SMarc-André Lureau if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) {
2656b10e573SMarc-André Lureau brlapi_perror("baum: brlapi__enterTtyMode");
2666b10e573SMarc-André Lureau return 0;
2676b10e573SMarc-André Lureau }
2686b10e573SMarc-André Lureau baum->deferred_init = 1;
2696b10e573SMarc-André Lureau return 1;
2706b10e573SMarc-André Lureau }
2716b10e573SMarc-André Lureau
2726b10e573SMarc-André Lureau /* The serial port can receive more of our data */
baum_chr_accept_input(struct Chardev * chr)2736b10e573SMarc-André Lureau static void baum_chr_accept_input(struct Chardev *chr)
2746b10e573SMarc-André Lureau {
2756b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(chr);
2766b10e573SMarc-André Lureau int room, first;
2776b10e573SMarc-André Lureau
2786b10e573SMarc-André Lureau if (!baum->out_buf_used)
2796b10e573SMarc-André Lureau return;
2806b10e573SMarc-André Lureau room = qemu_chr_be_can_write(chr);
2816b10e573SMarc-André Lureau if (!room)
2826b10e573SMarc-André Lureau return;
2836b10e573SMarc-André Lureau if (room > baum->out_buf_used)
2846b10e573SMarc-André Lureau room = baum->out_buf_used;
2856b10e573SMarc-André Lureau
2866b10e573SMarc-André Lureau first = BUF_SIZE - baum->out_buf_ptr;
2876b10e573SMarc-André Lureau if (room > first) {
2886b10e573SMarc-André Lureau qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first);
2896b10e573SMarc-André Lureau baum->out_buf_ptr = 0;
2906b10e573SMarc-André Lureau baum->out_buf_used -= first;
2916b10e573SMarc-André Lureau room -= first;
2926b10e573SMarc-André Lureau }
2936b10e573SMarc-André Lureau qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room);
2946b10e573SMarc-André Lureau baum->out_buf_ptr += room;
2956b10e573SMarc-André Lureau baum->out_buf_used -= room;
2966b10e573SMarc-André Lureau }
2976b10e573SMarc-André Lureau
2986b10e573SMarc-André Lureau /* We want to send a packet */
baum_write_packet(BaumChardev * baum,const uint8_t * buf,int len)2996b10e573SMarc-André Lureau static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
3006b10e573SMarc-André Lureau {
3016b10e573SMarc-André Lureau Chardev *chr = CHARDEV(baum);
302*d34977d6SPhilippe Mathieu-Daudé g_autofree uint8_t *io_buf = g_malloc(1 + 2 * len);
303*d34977d6SPhilippe Mathieu-Daudé uint8_t *cur = io_buf;
3046b10e573SMarc-André Lureau int room;
3056b10e573SMarc-André Lureau *cur++ = ESC;
3066b10e573SMarc-André Lureau while (len--)
3076b10e573SMarc-André Lureau if ((*cur++ = *buf++) == ESC)
3086b10e573SMarc-André Lureau *cur++ = ESC;
3096b10e573SMarc-André Lureau room = qemu_chr_be_can_write(chr);
3106b10e573SMarc-André Lureau len = cur - io_buf;
3116b10e573SMarc-André Lureau if (len <= room) {
3126b10e573SMarc-André Lureau /* Fits */
3136b10e573SMarc-André Lureau qemu_chr_be_write(chr, io_buf, len);
3146b10e573SMarc-André Lureau } else {
3156b10e573SMarc-André Lureau int first;
3166b10e573SMarc-André Lureau uint8_t out;
3176b10e573SMarc-André Lureau /* Can't fit all, send what can be, and store the rest. */
3186b10e573SMarc-André Lureau qemu_chr_be_write(chr, io_buf, room);
3196b10e573SMarc-André Lureau len -= room;
3206b10e573SMarc-André Lureau cur = io_buf + room;
3216b10e573SMarc-André Lureau if (len > BUF_SIZE - baum->out_buf_used) {
3226b10e573SMarc-André Lureau /* Can't even store it, drop the previous data... */
3236b10e573SMarc-André Lureau assert(len <= BUF_SIZE);
3246b10e573SMarc-André Lureau baum->out_buf_used = 0;
3256b10e573SMarc-André Lureau baum->out_buf_ptr = 0;
3266b10e573SMarc-André Lureau }
3276b10e573SMarc-André Lureau out = baum->out_buf_ptr;
3286b10e573SMarc-André Lureau baum->out_buf_used += len;
3296b10e573SMarc-André Lureau first = BUF_SIZE - baum->out_buf_ptr;
3306b10e573SMarc-André Lureau if (len > first) {
3316b10e573SMarc-André Lureau memcpy(baum->out_buf + out, cur, first);
3326b10e573SMarc-André Lureau out = 0;
3336b10e573SMarc-André Lureau len -= first;
3346b10e573SMarc-André Lureau cur += first;
3356b10e573SMarc-André Lureau }
3366b10e573SMarc-André Lureau memcpy(baum->out_buf + out, cur, len);
3376b10e573SMarc-André Lureau }
3386b10e573SMarc-André Lureau }
3396b10e573SMarc-André Lureau
3406b10e573SMarc-André Lureau /* Called when the other end seems to have a wrong idea of our display size */
baum_cellCount_timer_cb(void * opaque)3416b10e573SMarc-André Lureau static void baum_cellCount_timer_cb(void *opaque)
3426b10e573SMarc-André Lureau {
3436b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(opaque);
3446b10e573SMarc-André Lureau uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
3456b10e573SMarc-André Lureau DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
3466b10e573SMarc-André Lureau baum_write_packet(baum, cell_count, sizeof(cell_count));
3476b10e573SMarc-André Lureau }
3486b10e573SMarc-André Lureau
3496b10e573SMarc-André Lureau /* Try to interpret a whole incoming packet */
baum_eat_packet(BaumChardev * baum,const uint8_t * buf,int len)3506b10e573SMarc-André Lureau static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
3516b10e573SMarc-André Lureau {
3526b10e573SMarc-André Lureau const uint8_t *cur = buf;
3536b10e573SMarc-André Lureau uint8_t req = 0;
3546b10e573SMarc-André Lureau
3556b10e573SMarc-André Lureau if (!len--)
3566b10e573SMarc-André Lureau return 0;
3576b10e573SMarc-André Lureau if (*cur++ != ESC) {
3586b10e573SMarc-André Lureau while (*cur != ESC) {
3596b10e573SMarc-André Lureau if (!len--)
3606b10e573SMarc-André Lureau return 0;
3616b10e573SMarc-André Lureau cur++;
3626b10e573SMarc-André Lureau }
3636b10e573SMarc-André Lureau DPRINTF("Dropped %td bytes!\n", cur - buf);
3646b10e573SMarc-André Lureau }
3656b10e573SMarc-André Lureau
3666b10e573SMarc-André Lureau #define EAT(c) do {\
3676b10e573SMarc-André Lureau if (!len--) \
3686b10e573SMarc-André Lureau return 0; \
3696b10e573SMarc-André Lureau if ((c = *cur++) == ESC) { \
3706b10e573SMarc-André Lureau if (!len--) \
3716b10e573SMarc-André Lureau return 0; \
3726b10e573SMarc-André Lureau if (*cur++ != ESC) { \
3736b10e573SMarc-André Lureau DPRINTF("Broken packet %#2x, tossing\n", req); \
3746b10e573SMarc-André Lureau if (timer_pending(baum->cellCount_timer)) { \
3756b10e573SMarc-André Lureau timer_del(baum->cellCount_timer); \
3766b10e573SMarc-André Lureau baum_cellCount_timer_cb(baum); \
3776b10e573SMarc-André Lureau } \
3786b10e573SMarc-André Lureau return (cur - 2 - buf); \
3796b10e573SMarc-André Lureau } \
3806b10e573SMarc-André Lureau } \
3816b10e573SMarc-André Lureau } while (0)
3826b10e573SMarc-André Lureau
3836b10e573SMarc-André Lureau EAT(req);
3846b10e573SMarc-André Lureau switch (req) {
3856b10e573SMarc-André Lureau case BAUM_REQ_DisplayData:
3866b10e573SMarc-André Lureau {
3871e3acd33SPhilippe Mathieu-Daudé uint8_t cells[X_MAX * Y_MAX], c;
3881e3acd33SPhilippe Mathieu-Daudé uint8_t text[X_MAX * Y_MAX];
3891e3acd33SPhilippe Mathieu-Daudé uint8_t zero[X_MAX * Y_MAX];
3906b10e573SMarc-André Lureau int cursor = BRLAPI_CURSOR_OFF;
3916b10e573SMarc-André Lureau int i;
3926b10e573SMarc-André Lureau
3936b10e573SMarc-André Lureau /* Allow 100ms to complete the DisplayData packet */
3946b10e573SMarc-André Lureau timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
3956b10e573SMarc-André Lureau NANOSECONDS_PER_SECOND / 10);
3966b10e573SMarc-André Lureau for (i = 0; i < baum->x * baum->y ; i++) {
3976b10e573SMarc-André Lureau EAT(c);
3986b10e573SMarc-André Lureau cells[i] = c;
3996b10e573SMarc-André Lureau if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
4006b10e573SMarc-André Lureau == (BRLAPI_DOT7|BRLAPI_DOT8)) {
4016b10e573SMarc-André Lureau cursor = i + 1;
4026b10e573SMarc-André Lureau c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
4036b10e573SMarc-André Lureau }
4046b10e573SMarc-André Lureau c = nabcc_translation[DOTS2ASCII][c];
4056b10e573SMarc-André Lureau if (!c) {
4066b10e573SMarc-André Lureau c = '?';
4076b10e573SMarc-André Lureau }
4086b10e573SMarc-André Lureau text[i] = c;
4096b10e573SMarc-André Lureau }
4106b10e573SMarc-André Lureau timer_del(baum->cellCount_timer);
4116b10e573SMarc-André Lureau
4121e3acd33SPhilippe Mathieu-Daudé memset(zero, 0, baum->x * baum->y);
4136b10e573SMarc-André Lureau
4146b10e573SMarc-André Lureau brlapi_writeArguments_t wa = {
4156b10e573SMarc-André Lureau .displayNumber = BRLAPI_DISPLAY_DEFAULT,
4166b10e573SMarc-André Lureau .regionBegin = 1,
4176b10e573SMarc-André Lureau .regionSize = baum->x * baum->y,
4186b10e573SMarc-André Lureau .text = (char *)text,
4196b10e573SMarc-André Lureau .textSize = baum->x * baum->y,
4206b10e573SMarc-André Lureau .andMask = zero,
4216b10e573SMarc-André Lureau .orMask = cells,
4226b10e573SMarc-André Lureau .cursor = cursor,
4236b10e573SMarc-André Lureau .charset = (char *)"ISO-8859-1",
4246b10e573SMarc-André Lureau };
4256b10e573SMarc-André Lureau
4266b10e573SMarc-André Lureau if (brlapi__write(baum->brlapi, &wa) == -1)
4276b10e573SMarc-André Lureau brlapi_perror("baum brlapi_write");
4286b10e573SMarc-André Lureau break;
4296b10e573SMarc-André Lureau }
4306b10e573SMarc-André Lureau case BAUM_REQ_SetMode:
4316b10e573SMarc-André Lureau {
4326b10e573SMarc-André Lureau uint8_t mode, setting;
4336b10e573SMarc-André Lureau DPRINTF("SetMode\n");
4346b10e573SMarc-André Lureau EAT(mode);
4356b10e573SMarc-André Lureau EAT(setting);
4366b10e573SMarc-André Lureau /* ignore */
4376b10e573SMarc-André Lureau break;
4386b10e573SMarc-André Lureau }
4396b10e573SMarc-André Lureau case BAUM_REQ_SetProtocol:
4406b10e573SMarc-André Lureau {
4416b10e573SMarc-André Lureau uint8_t protocol;
4426b10e573SMarc-André Lureau DPRINTF("SetProtocol\n");
4436b10e573SMarc-André Lureau EAT(protocol);
4446b10e573SMarc-André Lureau /* ignore */
4456b10e573SMarc-André Lureau break;
4466b10e573SMarc-André Lureau }
4476b10e573SMarc-André Lureau case BAUM_REQ_GetDeviceIdentity:
4486b10e573SMarc-André Lureau {
4496b10e573SMarc-André Lureau uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
4506b10e573SMarc-André Lureau 'B','a','u','m',' ','V','a','r','i','o' };
4516b10e573SMarc-André Lureau DPRINTF("GetDeviceIdentity\n");
4526b10e573SMarc-André Lureau identity[11] = '0' + baum->x / 10;
4536b10e573SMarc-André Lureau identity[12] = '0' + baum->x % 10;
4546b10e573SMarc-André Lureau baum_write_packet(baum, identity, sizeof(identity));
4556b10e573SMarc-André Lureau break;
4566b10e573SMarc-André Lureau }
4576b10e573SMarc-André Lureau case BAUM_REQ_GetVersionNumber:
4586b10e573SMarc-André Lureau {
4596b10e573SMarc-André Lureau uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
4606b10e573SMarc-André Lureau DPRINTF("GetVersionNumber\n");
4616b10e573SMarc-André Lureau baum_write_packet(baum, version, sizeof(version));
4626b10e573SMarc-André Lureau break;
4636b10e573SMarc-André Lureau }
4646b10e573SMarc-André Lureau case BAUM_REQ_GetSerialNumber:
4656b10e573SMarc-André Lureau {
4666b10e573SMarc-André Lureau uint8_t serial[] = { BAUM_RSP_SerialNumber,
4676b10e573SMarc-André Lureau '0','0','0','0','0','0','0','0' };
4686b10e573SMarc-André Lureau DPRINTF("GetSerialNumber\n");
4696b10e573SMarc-André Lureau baum_write_packet(baum, serial, sizeof(serial));
4706b10e573SMarc-André Lureau break;
4716b10e573SMarc-André Lureau }
4726b10e573SMarc-André Lureau case BAUM_REQ_GetKeys:
4736b10e573SMarc-André Lureau {
4746b10e573SMarc-André Lureau DPRINTF("Get%0#2x\n", req);
4756b10e573SMarc-André Lureau /* ignore */
4766b10e573SMarc-André Lureau break;
4776b10e573SMarc-André Lureau }
4786b10e573SMarc-André Lureau default:
4796b10e573SMarc-André Lureau DPRINTF("unrecognized request %0#2x\n", req);
4806b10e573SMarc-André Lureau do
4816b10e573SMarc-André Lureau if (!len--)
4826b10e573SMarc-André Lureau return 0;
4836b10e573SMarc-André Lureau while (*cur++ != ESC);
4846b10e573SMarc-André Lureau cur--;
4856b10e573SMarc-André Lureau break;
4866b10e573SMarc-André Lureau }
4876b10e573SMarc-André Lureau return cur - buf;
4886b10e573SMarc-André Lureau }
4896b10e573SMarc-André Lureau
4906b10e573SMarc-André Lureau /* The other end is writing some data. Store it and try to interpret */
baum_chr_write(Chardev * chr,const uint8_t * buf,int len)4916b10e573SMarc-André Lureau static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)
4926b10e573SMarc-André Lureau {
4936b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(chr);
4946b10e573SMarc-André Lureau int tocopy, cur, eaten, orig_len = len;
4956b10e573SMarc-André Lureau
4966b10e573SMarc-André Lureau if (!len)
4976b10e573SMarc-André Lureau return 0;
4986b10e573SMarc-André Lureau if (!baum->brlapi)
4996b10e573SMarc-André Lureau return len;
5006b10e573SMarc-André Lureau if (!baum_deferred_init(baum))
5016b10e573SMarc-André Lureau return len;
5026b10e573SMarc-André Lureau
5036b10e573SMarc-André Lureau while (len) {
5046b10e573SMarc-André Lureau /* Complete our buffer as much as possible */
5056b10e573SMarc-André Lureau tocopy = len;
5066b10e573SMarc-André Lureau if (tocopy > BUF_SIZE - baum->in_buf_used)
5076b10e573SMarc-André Lureau tocopy = BUF_SIZE - baum->in_buf_used;
5086b10e573SMarc-André Lureau
5096b10e573SMarc-André Lureau memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
5106b10e573SMarc-André Lureau baum->in_buf_used += tocopy;
5116b10e573SMarc-André Lureau buf += tocopy;
5126b10e573SMarc-André Lureau len -= tocopy;
5136b10e573SMarc-André Lureau
5146b10e573SMarc-André Lureau /* Interpret it as much as possible */
5156b10e573SMarc-André Lureau cur = 0;
5166b10e573SMarc-André Lureau while (cur < baum->in_buf_used &&
5176b10e573SMarc-André Lureau (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
5186b10e573SMarc-André Lureau cur += eaten;
5196b10e573SMarc-André Lureau
5206b10e573SMarc-André Lureau /* Shift the remainder */
5216b10e573SMarc-André Lureau if (cur) {
5226b10e573SMarc-André Lureau memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
5236b10e573SMarc-André Lureau baum->in_buf_used -= cur;
5246b10e573SMarc-André Lureau }
5256b10e573SMarc-André Lureau
5266b10e573SMarc-André Lureau /* And continue if any data left */
5276b10e573SMarc-André Lureau }
5286b10e573SMarc-André Lureau return orig_len;
5296b10e573SMarc-André Lureau }
5306b10e573SMarc-André Lureau
5316b10e573SMarc-André Lureau /* Send the key code to the other end */
baum_send_key(BaumChardev * baum,uint8_t type,uint8_t value)5326b10e573SMarc-André Lureau static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value)
5336b10e573SMarc-André Lureau {
5346b10e573SMarc-André Lureau uint8_t packet[] = { type, value };
5356b10e573SMarc-André Lureau DPRINTF("writing key %x %x\n", type, value);
5366b10e573SMarc-André Lureau baum_write_packet(baum, packet, sizeof(packet));
5376b10e573SMarc-André Lureau }
5386b10e573SMarc-André Lureau
baum_send_key2(BaumChardev * baum,uint8_t type,uint8_t value,uint8_t value2)5396b10e573SMarc-André Lureau static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
5406b10e573SMarc-André Lureau uint8_t value2)
5416b10e573SMarc-André Lureau {
5426b10e573SMarc-André Lureau uint8_t packet[] = { type, value, value2 };
5436b10e573SMarc-André Lureau DPRINTF("writing key %x %x\n", type, value);
5446b10e573SMarc-André Lureau baum_write_packet(baum, packet, sizeof(packet));
5456b10e573SMarc-André Lureau }
5466b10e573SMarc-André Lureau
5476b10e573SMarc-André Lureau /* We got some data on the BrlAPI socket */
baum_chr_read(void * opaque)5486b10e573SMarc-André Lureau static void baum_chr_read(void *opaque)
5496b10e573SMarc-André Lureau {
5506b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(opaque);
5516b10e573SMarc-André Lureau brlapi_keyCode_t code;
5526b10e573SMarc-André Lureau int ret;
5536b10e573SMarc-André Lureau if (!baum->brlapi)
5546b10e573SMarc-André Lureau return;
5556b10e573SMarc-André Lureau if (!baum_deferred_init(baum))
5566b10e573SMarc-André Lureau return;
5576b10e573SMarc-André Lureau while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
5586b10e573SMarc-André Lureau DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
5596b10e573SMarc-André Lureau /* Emulate */
5606b10e573SMarc-André Lureau switch (code & BRLAPI_KEY_TYPE_MASK) {
5616b10e573SMarc-André Lureau case BRLAPI_KEY_TYPE_CMD:
5626b10e573SMarc-André Lureau switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
5636b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_ROUTE:
5646b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
5656b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
5666b10e573SMarc-André Lureau break;
5676b10e573SMarc-André Lureau case 0:
5686b10e573SMarc-André Lureau switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
5696b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_FWINLT:
5706b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
5716b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5726b10e573SMarc-André Lureau break;
5736b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_FWINRT:
5746b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
5756b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5766b10e573SMarc-André Lureau break;
5776b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_LNUP:
5786b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
5796b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5806b10e573SMarc-André Lureau break;
5816b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_LNDN:
5826b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
5836b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5846b10e573SMarc-André Lureau break;
5856b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_TOP:
5866b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
5876b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5886b10e573SMarc-André Lureau break;
5896b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_BOT:
5906b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
5916b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5926b10e573SMarc-André Lureau break;
5936b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_TOP_LEFT:
5946b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
5956b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5966b10e573SMarc-André Lureau break;
5976b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_BOT_LEFT:
5986b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
5996b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6006b10e573SMarc-André Lureau break;
6016b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_HOME:
6026b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
6036b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6046b10e573SMarc-André Lureau break;
6056b10e573SMarc-André Lureau case BRLAPI_KEY_CMD_PREFMENU:
6066b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
6076b10e573SMarc-André Lureau baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6086b10e573SMarc-André Lureau break;
6096b10e573SMarc-André Lureau }
6106b10e573SMarc-André Lureau }
6116b10e573SMarc-André Lureau break;
6126b10e573SMarc-André Lureau case BRLAPI_KEY_TYPE_SYM:
6136b10e573SMarc-André Lureau {
6146b10e573SMarc-André Lureau brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK;
6156b10e573SMarc-André Lureau if (keysym < 0x100) {
6166b10e573SMarc-André Lureau uint8_t dots = nabcc_translation[ASCII2DOTS][keysym];
6176b10e573SMarc-André Lureau if (dots) {
6186b10e573SMarc-André Lureau baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots);
6196b10e573SMarc-André Lureau baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0);
6206b10e573SMarc-André Lureau }
6216b10e573SMarc-André Lureau }
6226b10e573SMarc-André Lureau break;
6236b10e573SMarc-André Lureau }
6246b10e573SMarc-André Lureau }
6256b10e573SMarc-André Lureau }
6266b10e573SMarc-André Lureau if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
6276b10e573SMarc-André Lureau brlapi_perror("baum: brlapi_readKey");
6286b10e573SMarc-André Lureau brlapi__closeConnection(baum->brlapi);
6296b10e573SMarc-André Lureau g_free(baum->brlapi);
6306b10e573SMarc-André Lureau baum->brlapi = NULL;
6316b10e573SMarc-André Lureau }
6326b10e573SMarc-André Lureau }
6336b10e573SMarc-André Lureau
char_braille_finalize(Object * obj)6346b10e573SMarc-André Lureau static void char_braille_finalize(Object *obj)
6356b10e573SMarc-André Lureau {
6366b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(obj);
6376b10e573SMarc-André Lureau
6386b10e573SMarc-André Lureau timer_free(baum->cellCount_timer);
6396b10e573SMarc-André Lureau if (baum->brlapi) {
6406b10e573SMarc-André Lureau brlapi__closeConnection(baum->brlapi);
6416b10e573SMarc-André Lureau g_free(baum->brlapi);
6426b10e573SMarc-André Lureau }
6436b10e573SMarc-André Lureau }
6446b10e573SMarc-André Lureau
baum_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)6456b10e573SMarc-André Lureau static void baum_chr_open(Chardev *chr,
6466b10e573SMarc-André Lureau ChardevBackend *backend,
6476b10e573SMarc-André Lureau bool *be_opened,
6486b10e573SMarc-André Lureau Error **errp)
6496b10e573SMarc-André Lureau {
6506b10e573SMarc-André Lureau BaumChardev *baum = BAUM_CHARDEV(chr);
6516b10e573SMarc-André Lureau brlapi_handle_t *handle;
6526b10e573SMarc-André Lureau
6536b10e573SMarc-André Lureau handle = g_malloc0(brlapi_getHandleSize());
6546b10e573SMarc-André Lureau baum->brlapi = handle;
6556b10e573SMarc-André Lureau
6566b10e573SMarc-André Lureau baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
6576b10e573SMarc-André Lureau if (baum->brlapi_fd == -1) {
6586b10e573SMarc-André Lureau error_setg(errp, "brlapi__openConnection: %s",
6596b10e573SMarc-André Lureau brlapi_strerror(brlapi_error_location()));
6606b10e573SMarc-André Lureau g_free(handle);
66198e87903SLiang Yan baum->brlapi = NULL;
6626b10e573SMarc-André Lureau return;
6636b10e573SMarc-André Lureau }
6646b10e573SMarc-André Lureau baum->deferred_init = 0;
6656b10e573SMarc-André Lureau
6666b10e573SMarc-André Lureau baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
6676b10e573SMarc-André Lureau
6686b10e573SMarc-André Lureau qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
6696b10e573SMarc-André Lureau }
6706b10e573SMarc-André Lureau
char_braille_class_init(ObjectClass * oc,void * data)6716b10e573SMarc-André Lureau static void char_braille_class_init(ObjectClass *oc, void *data)
6726b10e573SMarc-André Lureau {
6736b10e573SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
6746b10e573SMarc-André Lureau
6756b10e573SMarc-André Lureau cc->open = baum_chr_open;
6766b10e573SMarc-André Lureau cc->chr_write = baum_chr_write;
6776b10e573SMarc-André Lureau cc->chr_accept_input = baum_chr_accept_input;
6786b10e573SMarc-André Lureau }
6796b10e573SMarc-André Lureau
6806b10e573SMarc-André Lureau static const TypeInfo char_braille_type_info = {
6816b10e573SMarc-André Lureau .name = TYPE_CHARDEV_BRAILLE,
6826b10e573SMarc-André Lureau .parent = TYPE_CHARDEV,
6836b10e573SMarc-André Lureau .instance_size = sizeof(BaumChardev),
6846b10e573SMarc-André Lureau .instance_finalize = char_braille_finalize,
6856b10e573SMarc-André Lureau .class_init = char_braille_class_init,
6866b10e573SMarc-André Lureau };
687882273d9SGerd Hoffmann module_obj(TYPE_CHARDEV_BRAILLE);
6886b10e573SMarc-André Lureau
register_types(void)6896b10e573SMarc-André Lureau static void register_types(void)
6906b10e573SMarc-André Lureau {
6916b10e573SMarc-André Lureau type_register_static(&char_braille_type_info);
6926b10e573SMarc-André Lureau }
6936b10e573SMarc-André Lureau
6946b10e573SMarc-André Lureau type_init(register_types);
695