1f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* 2f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Minimalistic braille device kernel support. 3f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * 4f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * By default, shows console messages on the braille device. 5f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Pressing Insert switches to VC browsing. 6f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * 7f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org> 8f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * 9f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * This program is free software ; you can redistribute it and/or modify 10f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * it under the terms of the GNU General Public License as published by 11f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * the Free Software Foundation ; either version 2 of the License, or 12f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * (at your option) any later version. 13f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * 14f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * This program is distributed in the hope that it will be useful, 15f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * but WITHOUT ANY WARRANTY ; without even the implied warranty of 16f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * GNU General Public License for more details. 18f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * 19f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * You should have received a copy of the GNU General Public License 20f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * along with the program ; if not, write to the Free Software 21f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault */ 23f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 24f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/kernel.h> 25f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/module.h> 26f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/moduleparam.h> 27f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/console.h> 28f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/notifier.h> 29f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 30f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/selection.h> 31f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/vt_kern.h> 32f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/consolemap.h> 33f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 34f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/keyboard.h> 35f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/kbd_kern.h> 36f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#include <linux/input.h> 37f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 38f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel ThibaultMODULE_AUTHOR("samuel.thibault@ens-lyon.org"); 39f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel ThibaultMODULE_DESCRIPTION("braille device"); 40f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel ThibaultMODULE_LICENSE("GPL"); 41f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 42f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* 43f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Braille device support part. 44f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault */ 45f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 46f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* Emit various sounds */ 4790ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool sound; 48f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultmodule_param(sound, bool, 0); 49f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel ThibaultMODULE_PARM_DESC(sound, "emit sounds"); 50f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 51f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic void beep(unsigned int freq) 52f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 53f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (sound) 54f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault kd_mksound(freq, HZ/10); 55f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 56f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 57f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* mini console */ 58f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define WIDTH 40 59f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define BRAILLE_KEY KEY_INSERT 60f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic u16 console_buf[WIDTH]; 61f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int console_cursor; 62f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 63f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* mini view of VC */ 64f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int vc_x, vc_y, lastvc_x, lastvc_y; 65f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 66f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* show console ? (or show VC) */ 67f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int console_show = 1; 68f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* pending newline ? */ 69f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int console_newline = 1; 70f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int lastVC = -1; 71f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 72f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic struct console *braille_co; 73f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 74f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* Very VisioBraille-specific */ 75f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic void braille_write(u16 *buf) 76f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 77f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault static u16 lastwrite[WIDTH]; 78f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c; 79f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault u16 out; 80f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault int i; 81f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 82f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (!braille_co) 83f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return; 84f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 85f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf))) 86f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return; 87f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault memcpy(lastwrite, buf, WIDTH * sizeof(*buf)); 88f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 89f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define SOH 1 90f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define STX 2 91f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define ETX 2 92f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define EOT 4 93f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault#define ENQ 5 94f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault data[0] = STX; 95f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault data[1] = '>'; 96f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault csum ^= '>'; 97f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault c = &data[2]; 98f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault for (i = 0; i < WIDTH; i++) { 99f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault out = buf[i]; 100f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (out >= 0x100) 101f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault out = '?'; 102f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else if (out == 0x00) 103f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault out = ' '; 104f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault csum ^= out; 105f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (out <= 0x05) { 106f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault *c++ = SOH; 107f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault out |= 0x40; 108f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 109f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault *c++ = out; 110f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 111f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 112f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (csum <= 0x05) { 113f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault *c++ = SOH; 114f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault csum |= 0x40; 115f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 116f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault *c++ = csum; 117f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault *c++ = ETX; 118f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 119f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_co->write(braille_co, data, c - data); 120f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 121f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 122f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* Follow the VC cursor*/ 123f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic void vc_follow_cursor(struct vc_data *vc) 124f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 125f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = vc->vc_x - (vc->vc_x % WIDTH); 126f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y = vc->vc_y; 127f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault lastvc_x = vc->vc_x; 128f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault lastvc_y = vc->vc_y; 129f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 130f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 131f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* Maybe the VC cursor moved, if so follow it */ 132f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic void vc_maybe_cursor_moved(struct vc_data *vc) 133f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 134f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y) 135f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_follow_cursor(vc); 136f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 137f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 138f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* Show portion of VC at vc_x, vc_y */ 139f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic void vc_refresh(struct vc_data *vc) 140f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 141f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault u16 buf[WIDTH]; 142f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault int i; 143f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 144f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault for (i = 0; i < WIDTH; i++) { 145f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault u16 glyph = screen_glyph(vc, 146f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 2 * (vc_x + i) + vc_y * vc->vc_size_row); 147f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault buf[i] = inverse_translate(vc, glyph, 1); 148f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 149f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_write(buf); 150f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 151f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 152f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* 153f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Link to keyboard 154f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault */ 155f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 156f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int keyboard_notifier_call(struct notifier_block *blk, 157f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned long code, void *_param) 158f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 159f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault struct keyboard_notifier_param *param = _param; 160f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault struct vc_data *vc = param->vc; 161f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault int ret = NOTIFY_OK; 162f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 163f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (!param->down) 164f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return ret; 165f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 166f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault switch (code) { 167f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KBD_KEYCODE: 168f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_show) { 169f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (param->value == BRAILLE_KEY) { 170f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_show = 0; 171f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(880); 172f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_maybe_cursor_moved(vc); 173f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_refresh(vc); 174f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault ret = NOTIFY_STOP; 175f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 176f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else { 177f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault ret = NOTIFY_STOP; 178f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault switch (param->value) { 179f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_INSERT: 180f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(440); 181f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_show = 1; 182f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault lastVC = -1; 183f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_write(console_buf); 184f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 185f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_LEFT: 186f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc_x > 0) { 187f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x -= WIDTH; 188f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc_x < 0) 189f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = 0; 190f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else if (vc_y >= 1) { 191f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(880); 192f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y--; 193f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = vc->vc_cols-WIDTH; 194f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else 195f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(220); 196f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 197f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_RIGHT: 198f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc_x + WIDTH < vc->vc_cols) { 199f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x += WIDTH; 200f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else if (vc_y + 1 < vc->vc_rows) { 201f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(880); 202f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y++; 203f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = 0; 204f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else 205f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(220); 206f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 207f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_DOWN: 208f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc_y + 1 < vc->vc_rows) 209f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y++; 210f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else 211f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(220); 212f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 213f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_UP: 214f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc_y >= 1) 215f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y--; 216f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else 217f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(220); 218f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 219f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_HOME: 220f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_follow_cursor(vc); 221f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 222f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_PAGEUP: 223f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = 0; 224f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y = 0; 225f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 226f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KEY_PAGEDOWN: 227f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_x = 0; 228f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_y = vc->vc_rows-1; 229f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 230f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault default: 231f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault ret = NOTIFY_OK; 232f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 233f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 234f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (ret == NOTIFY_STOP) 235f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_refresh(vc); 236f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 237f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 238f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KBD_POST_KEYSYM: 239f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault { 240f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned char type = KTYP(param->value) - 0xf0; 241f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (type == KT_SPEC) { 242f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned char val = KVAL(param->value); 243f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault int on_off = -1; 244f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 245f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault switch (val) { 246f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KVAL(K_CAPS): 247079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox on_off = vt_get_leds(fg_console, VC_CAPSLOCK); 248f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 249f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KVAL(K_NUM): 250079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox on_off = vt_get_leds(fg_console, VC_NUMLOCK); 251f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 252f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KVAL(K_HOLD): 253079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox on_off = vt_get_leds(fg_console, VC_SCROLLOCK); 254f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 255f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 256f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (on_off == 1) 257f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(880); 258f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else if (on_off == 0) 259f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault beep(440); 260f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 261f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 262f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KBD_UNBOUND_KEYCODE: 263f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KBD_UNICODE: 264f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case KBD_KEYSYM: 265f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault /* Unused */ 266f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 267f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 268f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return ret; 269f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 270f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 271f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic struct notifier_block keyboard_notifier_block = { 272f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault .notifier_call = keyboard_notifier_call, 273f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault}; 274f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 275f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic int vt_notifier_call(struct notifier_block *blk, 276f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned long code, void *_param) 277f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 278f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault struct vt_notifier_param *param = _param; 279f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault struct vc_data *vc = param->vc; 280f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault switch (code) { 281f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case VT_ALLOCATE: 282f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 283f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case VT_DEALLOCATE: 284f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 285f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case VT_WRITE: 286f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault { 287f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault unsigned char c = param->c; 288f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc->vc_num != fg_console) 289f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 290f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault switch (c) { 291f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\b': 292f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case 127: 293f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_cursor > 0) { 294f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_cursor--; 295f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_buf[console_cursor] = ' '; 296f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 297f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 298f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\n': 299f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\v': 300f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\f': 301f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\r': 302f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_newline = 1; 303f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 304f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case '\t': 305f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault c = ' '; 306f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault /* Fallthrough */ 307f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault default: 308f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (c < 32) 309f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault /* Ignore other control sequences */ 310f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 311f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_newline) { 312f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault memset(console_buf, 0, sizeof(console_buf)); 313f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_cursor = 0; 314f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_newline = 0; 315f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 316f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_cursor == WIDTH) 317f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault memmove(console_buf, &console_buf[1], 318f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault (WIDTH-1) * sizeof(*console_buf)); 319f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else 320f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_cursor++; 321f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_buf[console_cursor-1] = c; 322f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 323f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 324f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_show) 325f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_write(console_buf); 326f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault else { 327f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_maybe_cursor_moved(vc); 328f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_refresh(vc); 329f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 330f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 331f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 332f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault case VT_UPDATE: 333f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault /* Maybe a VT switch, flush */ 334f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console_show) { 335f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (vc->vc_num != lastVC) { 336f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault lastVC = vc->vc_num; 337f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault memset(console_buf, 0, sizeof(console_buf)); 338f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_cursor = 0; 339f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_write(console_buf); 340f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 341f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } else { 342f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_maybe_cursor_moved(vc); 343f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault vc_refresh(vc); 344f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 345f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault break; 346f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 347f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return NOTIFY_OK; 348f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 349f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 350f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultstatic struct notifier_block vt_notifier_block = { 351f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault .notifier_call = vt_notifier_call, 352f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault}; 353f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 354f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault/* 355f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault * Called from printk.c when console=brl is given 356f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault */ 357f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 358f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultint braille_register_console(struct console *console, int index, 359f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault char *console_options, char *braille_options) 360f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 361f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault int ret; 362bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches 363bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches if (!(console->flags & CON_BRL)) 364bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches return 0; 365f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (!console_options) 366f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault /* Only support VisioBraille for now */ 367f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console_options = "57600o8"; 368f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (braille_co) 369f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return -ENODEV; 370f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (console->setup) { 371f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault ret = console->setup(console, console_options); 372f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (ret != 0) 373f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return ret; 374f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault } 375f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console->flags |= CON_ENABLED; 376f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault console->index = index; 377f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_co = console; 378c0c9209ddd96bc4f1d70a8b9958710671e076080Pascal Terjan register_keyboard_notifier(&keyboard_notifier_block); 379c0c9209ddd96bc4f1d70a8b9958710671e076080Pascal Terjan register_vt_notifier(&vt_notifier_block); 380bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches return 1; 381f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 382f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault 383f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibaultint braille_unregister_console(struct console *console) 384f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault{ 385f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault if (braille_co != console) 386f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault return -EINVAL; 387bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches if (!(console->flags & CON_BRL)) 388bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches return 0; 389c0c9209ddd96bc4f1d70a8b9958710671e076080Pascal Terjan unregister_keyboard_notifier(&keyboard_notifier_block); 390c0c9209ddd96bc4f1d70a8b9958710671e076080Pascal Terjan unregister_vt_notifier(&vt_notifier_block); 391f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault braille_co = NULL; 392bbeddf52adc1b4207674ab88686cbbe58c24f721Joe Perches return 1; 393f7511d5f66f01fc451747b24e79f3ada7a3af9afSamuel Thibault} 394