Commit 2e4d9fb126beba5177d9b58a6ecf2f2bfdb560ae

Authored by aurel32
1 parent 88cb0a02

Braille device support

(Samuel Thibault)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4173 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -57,6 +57,11 @@ OBJS+=scsi-generic.o
57 57 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o
58 58 OBJS+=sd.o ssi-sd.o
59 59  
  60 +ifdef CONFIG_BRLAPI
  61 +OBJS+= baum.o
  62 +LIBS+=-lbrlapi
  63 +endif
  64 +
60 65 ifdef CONFIG_WIN32
61 66 OBJS+=tap-win32.o
62 67 endif
... ...
Makefile.target
... ... @@ -658,7 +658,7 @@ main.o: CFLAGS+=-p
658 658 endif
659 659  
660 660 $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a
661   - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS)
  661 + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS)
662 662  
663 663 endif # !CONFIG_USER_ONLY
664 664  
... ...
configure
... ... @@ -286,6 +286,8 @@ for opt do
286 286 ;;
287 287 --disable-kqemu) kqemu="no"
288 288 ;;
  289 + --disable-brlapi) brlapi="no"
  290 + ;;
289 291 --enable-profiler) profiler="yes"
290 292 ;;
291 293 --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
... ... @@ -416,6 +418,7 @@ echo " --enable-alsa enable ALSA audio driver"
416 418 echo " --enable-esd enable EsoundD audio driver"
417 419 echo " --enable-fmod enable FMOD audio driver"
418 420 echo " --enable-dsound enable DirectSound audio driver"
  421 +echo " --disable-brlapi disable BrlAPI"
419 422 echo " --disable-vnc-tls disable TLS encryption for VNC server"
420 423 echo " --disable-curses disable curses output"
421 424 echo " --enable-system enable all system emulation targets"
... ... @@ -674,6 +677,20 @@ EOF
674 677 fi
675 678  
676 679 ##########################################
  680 +# BrlAPI probe
  681 +
  682 +if test -z "$brlapi" ; then
  683 + brlapi=no
  684 +cat > $TMPC << EOF
  685 +#include <brlapi.h>
  686 +int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); }
  687 +EOF
  688 + if $cc -o $TMPE ${OS_CFLAGS} $TMPC -lbrlapi 2> /tmp/qemu-$$-brlapi.log ; then
  689 + brlapi=yes
  690 + fi # brlapi compile test
  691 +fi # -z $brlapi
  692 +
  693 +##########################################
677 694 # curses probe
678 695  
679 696 if test "$curses" = "yes" ; then
... ... @@ -770,6 +787,7 @@ if test -n &quot;$sparc_cpu&quot;; then
770 787 echo "Target Sparc Arch $sparc_cpu"
771 788 fi
772 789 echo "kqemu support $kqemu"
  790 +echo "brlapi support $brlapi"
773 791 echo "Documentation $build_docs"
774 792 [ ! -z "$uname_release" ] && \
775 793 echo "uname -r $uname_release"
... ... @@ -1001,6 +1019,11 @@ if test &quot;$curses&quot; = &quot;yes&quot; ; then
1001 1019 echo "CONFIG_CURSES=yes" >> $config_mak
1002 1020 echo "CURSES_LIBS=-lcurses" >> $config_mak
1003 1021 fi
  1022 +if test "$brlapi" = "yes" ; then
  1023 + echo "CONFIG_BRLAPI=yes" >> $config_mak
  1024 + echo "#define CONFIG_BRLAPI 1" >> $config_h
  1025 + echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak
  1026 +fi
1004 1027  
1005 1028 # XXX: suppress that
1006 1029 if [ "$bsd" = "yes" ] ; then
... ...
hw/baum.c 0 → 100644
  1 +/*
  2 + * QEMU Baum Braille Device
  3 + *
  4 + * Copyright (c) 2008 Samuel Thibault
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "qemu-common.h"
  25 +#include "qemu-char.h"
  26 +#include "qemu-timer.h"
  27 +#include "usb.h"
  28 +#include <assert.h>
  29 +#include <brlapi.h>
  30 +#include <brlapi_constants.h>
  31 +#include <brlapi_keycodes.h>
  32 +#ifdef CONFIG_SDL
  33 +#include <SDL/SDL_syswm.h>
  34 +#endif
  35 +
  36 +#if 0
  37 +#define DPRINTF(fmt, ...) \
  38 + printf(fmt, ## __VA_ARGS__)
  39 +#else
  40 +#define DPRINTF(fmt, ...)
  41 +#endif
  42 +
  43 +#define ESC 0x1B
  44 +
  45 +#define BAUM_REQ_DisplayData 0x01
  46 +#define BAUM_REQ_GetVersionNumber 0x05
  47 +#define BAUM_REQ_GetKeys 0x08
  48 +#define BAUM_REQ_SetMode 0x12
  49 +#define BAUM_REQ_SetProtocol 0x15
  50 +#define BAUM_REQ_GetDeviceIdentity 0x84
  51 +#define BAUM_REQ_GetSerialNumber 0x8A
  52 +
  53 +#define BAUM_RSP_CellCount 0x01
  54 +#define BAUM_RSP_VersionNumber 0x05
  55 +#define BAUM_RSP_ModeSetting 0x11
  56 +#define BAUM_RSP_CommunicationChannel 0x16
  57 +#define BAUM_RSP_PowerdownSignal 0x17
  58 +#define BAUM_RSP_HorizontalSensors 0x20
  59 +#define BAUM_RSP_VerticalSensors 0x21
  60 +#define BAUM_RSP_RoutingKeys 0x22
  61 +#define BAUM_RSP_Switches 0x23
  62 +#define BAUM_RSP_TopKeys 0x24
  63 +#define BAUM_RSP_HorizontalSensor 0x25
  64 +#define BAUM_RSP_VerticalSensor 0x26
  65 +#define BAUM_RSP_RoutingKey 0x27
  66 +#define BAUM_RSP_FrontKeys6 0x28
  67 +#define BAUM_RSP_BackKeys6 0x29
  68 +#define BAUM_RSP_CommandKeys 0x2B
  69 +#define BAUM_RSP_FrontKeys10 0x2C
  70 +#define BAUM_RSP_BackKeys10 0x2D
  71 +#define BAUM_RSP_EntryKeys 0x33
  72 +#define BAUM_RSP_JoyStick 0x34
  73 +#define BAUM_RSP_ErrorCode 0x40
  74 +#define BAUM_RSP_InfoBlock 0x42
  75 +#define BAUM_RSP_DeviceIdentity 0x84
  76 +#define BAUM_RSP_SerialNumber 0x8A
  77 +#define BAUM_RSP_BluetoothName 0x8C
  78 +
  79 +#define BAUM_TL1 0x01
  80 +#define BAUM_TL2 0x02
  81 +#define BAUM_TL3 0x04
  82 +#define BAUM_TR1 0x08
  83 +#define BAUM_TR2 0x10
  84 +#define BAUM_TR3 0x20
  85 +
  86 +#define BUF_SIZE 256
  87 +
  88 +typedef struct {
  89 + CharDriverState *chr;
  90 +
  91 + brlapi_handle_t *brlapi;
  92 + int brlapi_fd;
  93 + int x, y;
  94 +
  95 + uint8_t in_buf[BUF_SIZE];
  96 + uint8_t in_buf_used;
  97 + uint8_t out_buf[BUF_SIZE];
  98 + uint8_t out_buf_used, out_buf_ptr;
  99 +
  100 + QEMUTimer *cellCount_timer;
  101 +} BaumDriverState;
  102 +
  103 +/* Let's assume NABCC by default */
  104 +static const uint8_t nabcc_translation[256] = {
  105 + [0] = ' ',
  106 +#ifndef BRLAPI_DOTS
  107 +#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
  108 + ((d1?BRLAPI_DOT1:0)|\
  109 + (d2?BRLAPI_DOT2:0)|\
  110 + (d3?BRLAPI_DOT3:0)|\
  111 + (d4?BRLAPI_DOT4:0)|\
  112 + (d5?BRLAPI_DOT5:0)|\
  113 + (d6?BRLAPI_DOT6:0)|\
  114 + (d7?BRLAPI_DOT7:0)|\
  115 + (d8?BRLAPI_DOT8:0))
  116 +#endif
  117 + [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a',
  118 + [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b',
  119 + [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c',
  120 + [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd',
  121 + [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e',
  122 + [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f',
  123 + [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g',
  124 + [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h',
  125 + [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i',
  126 + [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j',
  127 + [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k',
  128 + [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l',
  129 + [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm',
  130 + [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n',
  131 + [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o',
  132 + [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p',
  133 + [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q',
  134 + [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r',
  135 + [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's',
  136 + [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't',
  137 + [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u',
  138 + [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v',
  139 + [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w',
  140 + [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x',
  141 + [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y',
  142 + [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z',
  143 +
  144 + [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A',
  145 + [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B',
  146 + [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C',
  147 + [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D',
  148 + [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E',
  149 + [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F',
  150 + [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G',
  151 + [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H',
  152 + [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I',
  153 + [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J',
  154 + [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K',
  155 + [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L',
  156 + [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M',
  157 + [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N',
  158 + [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O',
  159 + [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P',
  160 + [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q',
  161 + [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R',
  162 + [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S',
  163 + [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T',
  164 + [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U',
  165 + [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V',
  166 + [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W',
  167 + [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X',
  168 + [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y',
  169 + [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z',
  170 +
  171 + [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0',
  172 + [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1',
  173 + [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2',
  174 + [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3',
  175 + [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4',
  176 + [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5',
  177 + [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6',
  178 + [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7',
  179 + [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8',
  180 + [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9',
  181 +
  182 + [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.',
  183 + [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+',
  184 + [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-',
  185 + [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*',
  186 + [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/',
  187 + [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(',
  188 + [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')',
  189 +
  190 + [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&',
  191 + [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#',
  192 +
  193 + [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',',
  194 + [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';',
  195 + [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':',
  196 + [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!',
  197 + [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?',
  198 + [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"',
  199 + [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'',
  200 + [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`',
  201 + [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^',
  202 + [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~',
  203 + [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[',
  204 + [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']',
  205 + [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{',
  206 + [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}',
  207 + [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=',
  208 + [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<',
  209 + [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>',
  210 + [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$',
  211 + [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%',
  212 + [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@',
  213 + [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|',
  214 + [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\',
  215 + [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_',
  216 +};
  217 +
  218 +/* The serial port can receive more of our data */
  219 +static void baum_accept_input(struct CharDriverState *chr)
  220 +{
  221 + BaumDriverState *baum = chr->opaque;
  222 + int room, first;
  223 +
  224 + if (!baum->out_buf_used)
  225 + return;
  226 + room = qemu_chr_can_read(chr);
  227 + if (!room)
  228 + return;
  229 + if (room > baum->out_buf_used)
  230 + room = baum->out_buf_used;
  231 +
  232 + first = BUF_SIZE - baum->out_buf_ptr;
  233 + if (room > first) {
  234 + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first);
  235 + baum->out_buf_ptr = 0;
  236 + baum->out_buf_used -= first;
  237 + room -= first;
  238 + }
  239 + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room);
  240 + baum->out_buf_ptr += room;
  241 + baum->out_buf_used -= room;
  242 +}
  243 +
  244 +/* We want to send a packet */
  245 +static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
  246 +{
  247 + uint8_t io_buf[1 + 2 * len], *cur = io_buf;
  248 + int room;
  249 + *cur++ = ESC;
  250 + while (len--)
  251 + if ((*cur++ = *buf++) == ESC)
  252 + *cur++ = ESC;
  253 + room = qemu_chr_can_read(baum->chr);
  254 + len = cur - io_buf;
  255 + if (len <= room) {
  256 + /* Fits */
  257 + qemu_chr_read(baum->chr, io_buf, len);
  258 + } else {
  259 + int first;
  260 + uint8_t out;
  261 + /* Can't fit all, send what can be, and store the rest. */
  262 + qemu_chr_read(baum->chr, io_buf, room);
  263 + len -= room;
  264 + cur = io_buf + room;
  265 + if (len > BUF_SIZE - baum->out_buf_used) {
  266 + /* Can't even store it, drop the previous data... */
  267 + assert(len <= BUF_SIZE);
  268 + baum->out_buf_used = 0;
  269 + baum->out_buf_ptr = 0;
  270 + }
  271 + out = baum->out_buf_ptr;
  272 + baum->out_buf_used += len;
  273 + first = BUF_SIZE - baum->out_buf_ptr;
  274 + if (len > first) {
  275 + memcpy(baum->out_buf + out, cur, first);
  276 + out = 0;
  277 + len -= first;
  278 + cur += first;
  279 + }
  280 + memcpy(baum->out_buf + out, cur, len);
  281 + }
  282 +}
  283 +
  284 +/* Called when the other end seems to have a wrong idea of our display size */
  285 +static void baum_cellCount_timer_cb(void *opaque)
  286 +{
  287 + BaumDriverState *baum = opaque;
  288 + uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
  289 + DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
  290 + baum_write_packet(baum, cell_count, sizeof(cell_count));
  291 +}
  292 +
  293 +/* Try to interpret a whole incoming packet */
  294 +static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
  295 +{
  296 + const uint8_t *cur = buf;
  297 + uint8_t req = 0;
  298 +
  299 + if (!len--)
  300 + return 0;
  301 + if (*cur++ != ESC) {
  302 + while (*cur != ESC) {
  303 + if (!len--)
  304 + return 0;
  305 + cur++;
  306 + }
  307 + DPRINTF("Dropped %d bytes!\n", cur - buf);
  308 + }
  309 +
  310 +#define EAT(c) do {\
  311 + if (!len--) \
  312 + return 0; \
  313 + if ((c = *cur++) == ESC) { \
  314 + if (!len--) \
  315 + return 0; \
  316 + if (*cur++ != ESC) { \
  317 + DPRINTF("Broken packet %#2x, tossing\n", req); \
  318 + if (qemu_timer_pending(baum->cellCount_timer)) { \
  319 + qemu_del_timer(baum->cellCount_timer); \
  320 + baum_cellCount_timer_cb(baum); \
  321 + } \
  322 + return (cur - 2 - buf); \
  323 + } \
  324 + } \
  325 +} while (0)
  326 +
  327 + EAT(req);
  328 + switch (req) {
  329 + case BAUM_REQ_DisplayData:
  330 + {
  331 + uint8_t cells[baum->x * baum->y], c;
  332 + uint8_t text[baum->x * baum->y];
  333 + uint8_t zero[baum->x * baum->y];
  334 + int cursor = BRLAPI_CURSOR_OFF;
  335 + int i;
  336 +
  337 + /* Allow 100ms to complete the DisplayData packet */
  338 + qemu_mod_timer(baum->cellCount_timer, qemu_get_clock(vm_clock) + ticks_per_sec / 10);
  339 + for (i = 0; i < baum->x * baum->y ; i++) {
  340 + EAT(c);
  341 + cells[i] = c;
  342 + if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
  343 + == (BRLAPI_DOT7|BRLAPI_DOT8)) {
  344 + cursor = i + 1;
  345 + c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
  346 + }
  347 + if (!(c = nabcc_translation[c]))
  348 + c = '?';
  349 + text[i] = c;
  350 + }
  351 + qemu_del_timer(baum->cellCount_timer);
  352 +
  353 + memset(zero, 0, sizeof(zero));
  354 +
  355 + brlapi_writeArguments_t wa = {
  356 + .displayNumber = BRLAPI_DISPLAY_DEFAULT,
  357 + .regionBegin = 1,
  358 + .regionSize = baum->x * baum->y,
  359 + .text = text,
  360 + .textSize = baum->x * baum->y,
  361 + .andMask = zero,
  362 + .orMask = cells,
  363 + .cursor = cursor,
  364 + .charset = "ISO-8859-1",
  365 + };
  366 +
  367 + if (brlapi__write(baum->brlapi, &wa) == -1)
  368 + brlapi_perror("baum brlapi_write");
  369 + break;
  370 + }
  371 + case BAUM_REQ_SetMode:
  372 + {
  373 + uint8_t mode, setting;
  374 + DPRINTF("SetMode\n");
  375 + EAT(mode);
  376 + EAT(setting);
  377 + /* ignore */
  378 + break;
  379 + }
  380 + case BAUM_REQ_SetProtocol:
  381 + {
  382 + uint8_t protocol;
  383 + DPRINTF("SetProtocol\n");
  384 + EAT(protocol);
  385 + /* ignore */
  386 + break;
  387 + }
  388 + case BAUM_REQ_GetDeviceIdentity:
  389 + {
  390 + uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
  391 + 'B','a','u','m',' ','V','a','r','i','o' };
  392 + DPRINTF("GetDeviceIdentity\n");
  393 + identity[11] = '0' + baum->x / 10;
  394 + identity[12] = '0' + baum->x % 10;
  395 + baum_write_packet(baum, identity, sizeof(identity));
  396 + break;
  397 + }
  398 + case BAUM_REQ_GetVersionNumber:
  399 + {
  400 + uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
  401 + DPRINTF("GetVersionNumber\n");
  402 + baum_write_packet(baum, version, sizeof(version));
  403 + break;
  404 + }
  405 + case BAUM_REQ_GetSerialNumber:
  406 + {
  407 + uint8_t serial[] = { BAUM_RSP_SerialNumber,
  408 + '0','0','0','0','0','0','0','0' };
  409 + DPRINTF("GetSerialNumber\n");
  410 + baum_write_packet(baum, serial, sizeof(serial));
  411 + break;
  412 + }
  413 + case BAUM_REQ_GetKeys:
  414 + {
  415 + DPRINTF("Get%0#2x\n", req);
  416 + /* ignore */
  417 + break;
  418 + }
  419 + default:
  420 + DPRINTF("unrecognized request %0#2x\n", req);
  421 + do
  422 + if (!len--)
  423 + return 0;
  424 + while (*cur++ != ESC);
  425 + cur--;
  426 + break;
  427 + }
  428 + return cur - buf;
  429 +}
  430 +
  431 +/* The other end is writing some data. Store it and try to interpret */
  432 +static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
  433 +{
  434 + BaumDriverState *baum = chr->opaque;
  435 + int tocopy, cur, eaten, orig_len = len;
  436 +
  437 + if (!len)
  438 + return 0;
  439 + if (!baum->brlapi)
  440 + return len;
  441 +
  442 + while (len) {
  443 + /* Complete our buffer as much as possible */
  444 + tocopy = len;
  445 + if (tocopy > BUF_SIZE - baum->in_buf_used)
  446 + tocopy = BUF_SIZE - baum->in_buf_used;
  447 +
  448 + memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
  449 + baum->in_buf_used += tocopy;
  450 + buf += tocopy;
  451 + len -= tocopy;
  452 +
  453 + /* Interpret it as much as possible */
  454 + cur = 0;
  455 + while (cur < baum->in_buf_used &&
  456 + (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
  457 + cur += eaten;
  458 +
  459 + /* Shift the remainder */
  460 + if (cur) {
  461 + memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
  462 + baum->in_buf_used -= cur;
  463 + }
  464 +
  465 + /* And continue if any data left */
  466 + }
  467 + return orig_len;
  468 +}
  469 +
  470 +/* The other end sent us some event */
  471 +static void baum_send_event(CharDriverState *chr, int event)
  472 +{
  473 + BaumDriverState *baum = chr->opaque;
  474 + switch (event) {
  475 + case CHR_EVENT_BREAK:
  476 + break;
  477 + case CHR_EVENT_RESET:
  478 + /* Reset state */
  479 + baum->in_buf_used = 0;
  480 + break;
  481 + }
  482 +}
  483 +
  484 +/* Send the key code to the other end */
  485 +static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
  486 + uint8_t packet[] = { type, value };
  487 + DPRINTF("writing key %x %x\n", type, value);
  488 + baum_write_packet(baum, packet, sizeof(packet));
  489 +}
  490 +
  491 +/* We got some data on the BrlAPI socket */
  492 +static void baum_chr_read(void *opaque)
  493 +{
  494 + BaumDriverState *baum = opaque;
  495 + brlapi_keyCode_t code;
  496 + int ret;
  497 + if (!baum->brlapi)
  498 + return;
  499 + while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
  500 + DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
  501 + /* Emulate */
  502 + switch (code & BRLAPI_KEY_TYPE_MASK) {
  503 + case BRLAPI_KEY_TYPE_CMD:
  504 + switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
  505 + case BRLAPI_KEY_CMD_ROUTE:
  506 + baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
  507 + baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
  508 + break;
  509 + case 0:
  510 + switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
  511 + case BRLAPI_KEY_CMD_FWINLT:
  512 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
  513 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  514 + break;
  515 + case BRLAPI_KEY_CMD_FWINRT:
  516 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
  517 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  518 + break;
  519 + case BRLAPI_KEY_CMD_LNUP:
  520 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
  521 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  522 + break;
  523 + case BRLAPI_KEY_CMD_LNDN:
  524 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
  525 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  526 + break;
  527 + case BRLAPI_KEY_CMD_TOP:
  528 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
  529 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  530 + break;
  531 + case BRLAPI_KEY_CMD_BOT:
  532 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
  533 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  534 + break;
  535 + case BRLAPI_KEY_CMD_TOP_LEFT:
  536 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
  537 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  538 + break;
  539 + case BRLAPI_KEY_CMD_BOT_LEFT:
  540 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
  541 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  542 + break;
  543 + case BRLAPI_KEY_CMD_HOME:
  544 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
  545 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  546 + break;
  547 + case BRLAPI_KEY_CMD_PREFMENU:
  548 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
  549 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  550 + break;
  551 + }
  552 + }
  553 + break;
  554 + case BRLAPI_KEY_TYPE_SYM:
  555 + break;
  556 + }
  557 + }
  558 + if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
  559 + brlapi_perror("baum: brlapi_readKey");
  560 + brlapi__closeConnection(baum->brlapi);
  561 + free(baum->brlapi);
  562 + baum->brlapi = NULL;
  563 + }
  564 +}
  565 +
  566 +CharDriverState *chr_baum_init(void)
  567 +{
  568 + BaumDriverState *baum;
  569 + CharDriverState *chr;
  570 + brlapi_handle_t *handle;
  571 +#ifdef CONFIG_SDL
  572 + SDL_SysWMinfo info;
  573 +#endif
  574 + int tty;
  575 +
  576 + baum = qemu_mallocz(sizeof(BaumDriverState));
  577 + if (!baum)
  578 + return NULL;
  579 +
  580 + baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
  581 + if (!chr)
  582 + goto fail_baum;
  583 +
  584 + chr->opaque = baum;
  585 + chr->chr_write = baum_write;
  586 + chr->chr_send_event = baum_send_event;
  587 + chr->chr_accept_input = baum_accept_input;
  588 +
  589 + handle = qemu_mallocz(brlapi_getHandleSize());
  590 + if (!handle)
  591 + goto fail_chr;
  592 + baum->brlapi = handle;
  593 +
  594 + baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
  595 + if (baum->brlapi_fd == -1) {
  596 + brlapi_perror("baum_init: brlapi_openConnection");
  597 + goto fail_handle;
  598 + }
  599 +
  600 + baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum);
  601 +
  602 + if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
  603 + brlapi_perror("baum_init: brlapi_getDisplaySize");
  604 + goto fail;
  605 + }
  606 +
  607 +#ifdef CONFIG_SDL
  608 + memset(&info, 0, sizeof(info));
  609 + SDL_VERSION(&info.version);
  610 + if (SDL_GetWMInfo(&info))
  611 + tty = info.info.x11.wmwindow;
  612 + else
  613 +#endif
  614 + tty = BRLAPI_TTY_DEFAULT;
  615 +
  616 + if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
  617 + brlapi_perror("baum_init: brlapi_enterTtyMode");
  618 + goto fail;
  619 + }
  620 +
  621 + qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
  622 +
  623 + qemu_chr_reset(chr);
  624 +
  625 + return chr;
  626 +
  627 +fail:
  628 + qemu_free_timer(baum->cellCount_timer);
  629 + brlapi__closeConnection(handle);
  630 +fail_handle:
  631 + free(handle);
  632 +fail_chr:
  633 + free(chr);
  634 +fail_baum:
  635 + free(baum);
  636 + return NULL;
  637 +}
  638 +
  639 +USBDevice *usb_baum_init(void)
  640 +{
  641 + /* USB Product ID of Super Vario 40 */
  642 + return usb_serial_init("productid=FE72:braille");
  643 +}
... ...
hw/baum.h 0 → 100644
  1 +/*
  2 + * QEMU Baum
  3 + *
  4 + * Copyright (c) 2008 Samuel Thibault
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/* usb device */
  26 +USBDevice *usb_baum_init(void);
  27 +
  28 +/* char device */
  29 +CharDriverState *chr_baum_init(void);
... ...
qemu-doc.texi
... ... @@ -546,6 +546,10 @@ Pass through the host device identified by vendor_id:product_id (Linux only).
546 546 Serial converter to host character device @var{dev}, see @code{-serial} for the
547 547 available devices.
548 548  
  549 +@item braille
  550 +Braille device. This will use BrlAPI to display the braille output on a real
  551 +or fake device.
  552 +
549 553 @end table
550 554  
551 555 @end table
... ... @@ -859,6 +863,10 @@ listening on port 4444 would be:
859 863 @item -serial mon:telnet::4444,server,nowait
860 864 @end table
861 865  
  866 +@item braille
  867 +Braille device. This will use BrlAPI to display the braille output on a real
  868 +or fake device.
  869 +
862 870 @end table
863 871  
864 872 @item -parallel @var{dev}
... ... @@ -1614,6 +1622,9 @@ usb_add serial:productid=FA00:tcp:192.168.0.2:4444
1614 1622 @end example
1615 1623 will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual
1616 1624 serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00).
  1625 +@item braille
  1626 +Braille device. This will use BrlAPI to display the braille output on a real
  1627 +or fake device.
1617 1628 @end table
1618 1629  
1619 1630 @node host_usb_devices
... ...
... ... @@ -28,6 +28,7 @@
28 28 #include "hw/pc.h"
29 29 #include "hw/audiodev.h"
30 30 #include "hw/isa.h"
  31 +#include "hw/baum.h"
31 32 #include "net.h"
32 33 #include "console.h"
33 34 #include "sysemu.h"
... ... @@ -3473,7 +3474,12 @@ CharDriverState *qemu_chr_open(const char *filename)
3473 3474 } else
3474 3475 if (strstart(filename, "file:", &p)) {
3475 3476 return qemu_chr_open_win_file_out(p);
3476   - }
  3477 + } else
  3478 +#endif
  3479 +#ifdef CONFIG_BRLAPI
  3480 + if (!strcmp(filename, "braille")) {
  3481 + return chr_baum_init();
  3482 + } else
3477 3483 #endif
3478 3484 {
3479 3485 return NULL;
... ... @@ -5281,6 +5287,10 @@ static int usb_device_add(const char *devname)
5281 5287 dev = usb_wacom_init();
5282 5288 } else if (strstart(devname, "serial:", &p)) {
5283 5289 dev = usb_serial_init(p);
  5290 +#ifdef CONFIG_BRLAPI
  5291 + } else if (!strcmp(devname, "braille")) {
  5292 + dev = usb_baum_init();
  5293 +#endif
5284 5294 } else {
5285 5295 return -1;
5286 5296 }
... ...