123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- /*
- * Minimalistic braille device kernel support.
- *
- * By default, shows console messages on the braille device.
- * Pressing Insert switches to VC browsing.
- *
- * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org>
- *
- * This program is free software ; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with the program ; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/console.h>
- #include <linux/notifier.h>
- #include <linux/selection.h>
- #include <linux/vt_kern.h>
- #include <linux/consolemap.h>
- #include <linux/keyboard.h>
- #include <linux/kbd_kern.h>
- #include <linux/input.h>
- MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
- MODULE_DESCRIPTION("braille device");
- MODULE_LICENSE("GPL");
- /*
- * Braille device support part.
- */
- /* Emit various sounds */
- static bool sound;
- module_param(sound, bool, 0);
- MODULE_PARM_DESC(sound, "emit sounds");
- static void beep(unsigned int freq)
- {
- if (sound)
- kd_mksound(freq, HZ/10);
- }
- /* mini console */
- #define WIDTH 40
- #define BRAILLE_KEY KEY_INSERT
- static u16 console_buf[WIDTH];
- static int console_cursor;
- /* mini view of VC */
- static int vc_x, vc_y, lastvc_x, lastvc_y;
- /* show console ? (or show VC) */
- static int console_show = 1;
- /* pending newline ? */
- static int console_newline = 1;
- static int lastVC = -1;
- static struct console *braille_co;
- /* Very VisioBraille-specific */
- static void braille_write(u16 *buf)
- {
- static u16 lastwrite[WIDTH];
- unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
- u16 out;
- int i;
- if (!braille_co)
- return;
- if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
- return;
- memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
- #define SOH 1
- #define STX 2
- #define ETX 2
- #define EOT 4
- #define ENQ 5
- data[0] = STX;
- data[1] = '>';
- csum ^= '>';
- c = &data[2];
- for (i = 0; i < WIDTH; i++) {
- out = buf[i];
- if (out >= 0x100)
- out = '?';
- else if (out == 0x00)
- out = ' ';
- csum ^= out;
- if (out <= 0x05) {
- *c++ = SOH;
- out |= 0x40;
- }
- *c++ = out;
- }
- if (csum <= 0x05) {
- *c++ = SOH;
- csum |= 0x40;
- }
- *c++ = csum;
- *c++ = ETX;
- braille_co->write(braille_co, data, c - data);
- }
- /* Follow the VC cursor*/
- static void vc_follow_cursor(struct vc_data *vc)
- {
- vc_x = vc->vc_x - (vc->vc_x % WIDTH);
- vc_y = vc->vc_y;
- lastvc_x = vc->vc_x;
- lastvc_y = vc->vc_y;
- }
- /* Maybe the VC cursor moved, if so follow it */
- static void vc_maybe_cursor_moved(struct vc_data *vc)
- {
- if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
- vc_follow_cursor(vc);
- }
- /* Show portion of VC at vc_x, vc_y */
- static void vc_refresh(struct vc_data *vc)
- {
- u16 buf[WIDTH];
- int i;
- for (i = 0; i < WIDTH; i++) {
- u16 glyph = screen_glyph(vc,
- 2 * (vc_x + i) + vc_y * vc->vc_size_row);
- buf[i] = inverse_translate(vc, glyph, 1);
- }
- braille_write(buf);
- }
- /*
- * Link to keyboard
- */
- static int keyboard_notifier_call(struct notifier_block *blk,
- unsigned long code, void *_param)
- {
- struct keyboard_notifier_param *param = _param;
- struct vc_data *vc = param->vc;
- int ret = NOTIFY_OK;
- if (!param->down)
- return ret;
- switch (code) {
- case KBD_KEYCODE:
- if (console_show) {
- if (param->value == BRAILLE_KEY) {
- console_show = 0;
- beep(880);
- vc_maybe_cursor_moved(vc);
- vc_refresh(vc);
- ret = NOTIFY_STOP;
- }
- } else {
- ret = NOTIFY_STOP;
- switch (param->value) {
- case KEY_INSERT:
- beep(440);
- console_show = 1;
- lastVC = -1;
- braille_write(console_buf);
- break;
- case KEY_LEFT:
- if (vc_x > 0) {
- vc_x -= WIDTH;
- if (vc_x < 0)
- vc_x = 0;
- } else if (vc_y >= 1) {
- beep(880);
- vc_y--;
- vc_x = vc->vc_cols-WIDTH;
- } else
- beep(220);
- break;
- case KEY_RIGHT:
- if (vc_x + WIDTH < vc->vc_cols) {
- vc_x += WIDTH;
- } else if (vc_y + 1 < vc->vc_rows) {
- beep(880);
- vc_y++;
- vc_x = 0;
- } else
- beep(220);
- break;
- case KEY_DOWN:
- if (vc_y + 1 < vc->vc_rows)
- vc_y++;
- else
- beep(220);
- break;
- case KEY_UP:
- if (vc_y >= 1)
- vc_y--;
- else
- beep(220);
- break;
- case KEY_HOME:
- vc_follow_cursor(vc);
- break;
- case KEY_PAGEUP:
- vc_x = 0;
- vc_y = 0;
- break;
- case KEY_PAGEDOWN:
- vc_x = 0;
- vc_y = vc->vc_rows-1;
- break;
- default:
- ret = NOTIFY_OK;
- break;
- }
- if (ret == NOTIFY_STOP)
- vc_refresh(vc);
- }
- break;
- case KBD_POST_KEYSYM:
- {
- unsigned char type = KTYP(param->value) - 0xf0;
- if (type == KT_SPEC) {
- unsigned char val = KVAL(param->value);
- int on_off = -1;
- switch (val) {
- case KVAL(K_CAPS):
- on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
- break;
- case KVAL(K_NUM):
- on_off = vt_get_leds(fg_console, VC_NUMLOCK);
- break;
- case KVAL(K_HOLD):
- on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
- break;
- }
- if (on_off == 1)
- beep(880);
- else if (on_off == 0)
- beep(440);
- }
- }
- case KBD_UNBOUND_KEYCODE:
- case KBD_UNICODE:
- case KBD_KEYSYM:
- /* Unused */
- break;
- }
- return ret;
- }
- static struct notifier_block keyboard_notifier_block = {
- .notifier_call = keyboard_notifier_call,
- };
- static int vt_notifier_call(struct notifier_block *blk,
- unsigned long code, void *_param)
- {
- struct vt_notifier_param *param = _param;
- struct vc_data *vc = param->vc;
- switch (code) {
- case VT_ALLOCATE:
- break;
- case VT_DEALLOCATE:
- break;
- case VT_WRITE:
- {
- unsigned char c = param->c;
- if (vc->vc_num != fg_console)
- break;
- switch (c) {
- case '\b':
- case 127:
- if (console_cursor > 0) {
- console_cursor--;
- console_buf[console_cursor] = ' ';
- }
- break;
- case '\n':
- case '\v':
- case '\f':
- case '\r':
- console_newline = 1;
- break;
- case '\t':
- c = ' ';
- /* Fallthrough */
- default:
- if (c < 32)
- /* Ignore other control sequences */
- break;
- if (console_newline) {
- memset(console_buf, 0, sizeof(console_buf));
- console_cursor = 0;
- console_newline = 0;
- }
- if (console_cursor == WIDTH)
- memmove(console_buf, &console_buf[1],
- (WIDTH-1) * sizeof(*console_buf));
- else
- console_cursor++;
- console_buf[console_cursor-1] = c;
- break;
- }
- if (console_show)
- braille_write(console_buf);
- else {
- vc_maybe_cursor_moved(vc);
- vc_refresh(vc);
- }
- break;
- }
- case VT_UPDATE:
- /* Maybe a VT switch, flush */
- if (console_show) {
- if (vc->vc_num != lastVC) {
- lastVC = vc->vc_num;
- memset(console_buf, 0, sizeof(console_buf));
- console_cursor = 0;
- braille_write(console_buf);
- }
- } else {
- vc_maybe_cursor_moved(vc);
- vc_refresh(vc);
- }
- break;
- }
- return NOTIFY_OK;
- }
- static struct notifier_block vt_notifier_block = {
- .notifier_call = vt_notifier_call,
- };
- /*
- * Called from printk.c when console=brl is given
- */
- int braille_register_console(struct console *console, int index,
- char *console_options, char *braille_options)
- {
- int ret;
- if (!(console->flags & CON_BRL))
- return 0;
- if (!console_options)
- /* Only support VisioBraille for now */
- console_options = "57600o8";
- if (braille_co)
- return -ENODEV;
- if (console->setup) {
- ret = console->setup(console, console_options);
- if (ret != 0)
- return ret;
- }
- console->flags |= CON_ENABLED;
- console->index = index;
- braille_co = console;
- register_keyboard_notifier(&keyboard_notifier_block);
- register_vt_notifier(&vt_notifier_block);
- return 1;
- }
- int braille_unregister_console(struct console *console)
- {
- if (braille_co != console)
- return -EINVAL;
- if (!(console->flags & CON_BRL))
- return 0;
- unregister_keyboard_notifier(&keyboard_notifier_block);
- unregister_vt_notifier(&vt_notifier_block);
- braille_co = NULL;
- return 1;
- }
|