📄 keyboard.c
字号:
* (And SCROLLOCK can also be set by the ioctl KDSETLED.)
*/
if (tty->stopped)
start_tty(tty);
else
stop_tty(tty);
}
#if 0
/* unused at present - and the VC_PAUSE bit is not used anywhere either */
static void pause(void)
{
chg_vc_kbd_mode(kbd,VC_PAUSE);
}
#endif
static void num(void)
{
if (vc_kbd_mode(kbd,VC_APPLIC)) {
applkey('P', 1);
return;
}
if (!rep) /* no autorepeat for numlock, ChN */
chg_vc_kbd_led(kbd,VC_NUMLOCK);
}
static void lastcons(void)
{
/* pressing alt-printscreen switches to the last used console, ChN */
want_console = last_console;
}
static void send_intr(void)
{
got_break = 1;
}
static void scrll_forw(void)
{
scrollfront(0);
}
static void scrll_back(void)
{
scrollback(0);
}
static void boot_it(void)
{
ctrl_alt_del();
}
static void compose(void)
{
dead_key_next = 1;
}
static void do_spec(unsigned char value, char up_flag)
{
typedef void (*fnp)(void);
fnp fn_table[] = {
NULL, enter, show_ptregs, show_mem,
show_state, send_intr, lastcons, caps_toggle,
num, hold, scrll_forw, scrll_back,
boot_it, caps_on, compose
};
if (up_flag)
return;
if (value >= SIZE(fn_table))
return;
if (!fn_table[value])
return;
fn_table[value]();
}
static void do_lowercase(unsigned char value, char up_flag)
{
printk("keyboard.c: do_lowercase was called - impossible\n");
}
static void do_self(unsigned char value, char up_flag)
{
if (up_flag)
return; /* no action, if this is a key release */
if (diacr)
value = handle_diacr(value);
if (dead_key_next) {
dead_key_next = 0;
diacr = value;
return;
}
put_queue(value);
}
#define A_GRAVE '`'
#define A_ACUTE '\''
#define A_CFLEX '^'
#define A_TILDE '~'
#define A_DIAER '"'
static unsigned char ret_diacr[] =
{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
/* If a dead key pressed twice, output a character corresponding to it, */
/* otherwise just remember the dead key. */
static void do_dead(unsigned char value, char up_flag)
{
if (up_flag)
return;
value = ret_diacr[value];
if (diacr == value) { /* pressed twice */
diacr = 0;
put_queue(value);
return;
}
diacr = value;
}
/* If space is pressed, return the character corresponding the pending */
/* dead key, otherwise try to combine the two. */
unsigned char handle_diacr(unsigned char ch)
{
int d = diacr;
int i;
diacr = 0;
if (ch == ' ')
return d;
for (i = 0; i < accent_table_size; i++)
if(accent_table[i].diacr == d && accent_table[i].base == ch)
return accent_table[i].result;
put_queue(d);
return ch;
}
static void do_cons(unsigned char value, char up_flag)
{
if (up_flag)
return;
want_console = value;
}
static void do_fn(unsigned char value, char up_flag)
{
if (up_flag)
return;
if (value < SIZE(func_table))
puts_queue(func_table[value]);
else
printk("do_fn called with value=%d\n", value);
}
static void do_pad(unsigned char value, char up_flag)
{
static char *pad_chars = "0123456789+-*/\015,.?";
static char *app_map = "pqrstuvwxylSRQMnn?";
if (up_flag)
return; /* no action, if this is a key release */
/* kludge... shift forces cursor/number keys */
if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
applkey(app_map[value], 1);
return;
}
if (!vc_kbd_led(kbd,VC_NUMLOCK))
switch (value) {
case KVAL(K_PCOMMA):
case KVAL(K_PDOT):
do_fn(KVAL(K_REMOVE), 0);
return;
case KVAL(K_P0):
do_fn(KVAL(K_INSERT), 0);
return;
case KVAL(K_P1):
do_fn(KVAL(K_SELECT), 0);
return;
case KVAL(K_P2):
do_cur(KVAL(K_DOWN), 0);
return;
case KVAL(K_P3):
do_fn(KVAL(K_PGDN), 0);
return;
case KVAL(K_P4):
do_cur(KVAL(K_LEFT), 0);
return;
case KVAL(K_P6):
do_cur(KVAL(K_RIGHT), 0);
return;
case KVAL(K_P7):
do_fn(KVAL(K_FIND), 0);
return;
case KVAL(K_P8):
do_cur(KVAL(K_UP), 0);
return;
case KVAL(K_P9):
do_fn(KVAL(K_PGUP), 0);
return;
case KVAL(K_P5):
applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
return;
}
put_queue(pad_chars[value]);
if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
put_queue(10);
}
static void do_cur(unsigned char value, char up_flag)
{
static char *cur_chars = "BDCA";
if (up_flag)
return;
applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
}
static void do_shift(unsigned char value, char up_flag)
{
int old_state = shift_state;
if (rep)
return;
/* kludge... */
if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT);
clr_vc_kbd_led(kbd, VC_CAPSLOCK);
}
if (up_flag) {
/* handle the case that two shift or control
keys are depressed simultaneously */
if (k_down[value])
k_down[value]--;
} else
k_down[value]++;
if (k_down[value])
shift_state |= (1 << value);
else
shift_state &= ~ (1 << value);
/* kludge */
if (up_flag && shift_state != old_state && npadch != -1) {
put_queue(npadch);
npadch = -1;
}
}
/* called after returning from RAW mode or when changing consoles -
recompute k_down[] and shift_state from key_down[] */
void compute_shiftstate(void)
{
int i, j, k, sym, val;
shift_state = 0;
for(i=0; i < SIZE(k_down); i++)
k_down[i] = 0;
for(i=0; i < SIZE(key_down); i++)
if(key_down[i]) { /* skip this word if not a single bit on */
k = (i<<5);
for(j=0; j<32; j++,k++)
if(test_bit(k, key_down)) {
sym = key_map[0][k];
if(KTYP(sym) == KT_SHIFT) {
val = KVAL(sym);
k_down[val]++;
shift_state |= (1<<val);
}
}
}
}
static void do_meta(unsigned char value, char up_flag)
{
if (up_flag)
return;
if (vc_kbd_mode(kbd, VC_META)) {
put_queue('\033');
put_queue(value);
} else
put_queue(value | 0x80);
}
static void do_ascii(unsigned char value, char up_flag)
{
if (up_flag)
return;
if (npadch == -1)
npadch = value;
else
npadch = (npadch * 10 + value) % 1000;
}
static void do_lock(unsigned char value, char up_flag)
{
if (up_flag || rep)
return;
chg_vc_kbd_lock(kbd, value);
}
/*
* send_data sends a character to the keyboard and waits
* for a acknowledge, possibly retrying if asked to. Returns
* the success status.
*/
static int send_data(unsigned char data)
{
int retries = 3;
int i;
do {
kb_wait();
acknowledge = 0;
resend = 0;
outb_p(data, 0x60);
for(i=0; i<0x20000; i++) {
inb_p(0x64); /* just as a delay */
if (acknowledge)
return 1;
if (resend)
break;
}
if (!resend)
return 0;
} while (retries-- > 0);
return 0;
}
/*
* This routine is the bottom half of the keyboard interrupt
* routine, and runs with all interrupts enabled. It does
* console changing, led setting and copy_to_cooked, which can
* take a reasonably long time.
*
* Aside from timing (which isn't really that important for
* keyboard interrupts as they happen often), using the software
* interrupt routines for this thing allows us to easily mask
* this when we don't want any of the above to happen. Not yet
* used, but this allows for easy and efficient race-condition
* prevention later on.
*/
static void kbd_bh(void * unused)
{
static unsigned char old_leds = 0xff;
unsigned char leds = kbd_table[fg_console].ledstate;
if (leds != old_leds) {
old_leds = leds;
if (!send_data(0xed) || !send_data(leds))
send_data(0xf4); /* re-enable kbd if any errors */
}
if (want_console >= 0) {
if (want_console != fg_console) {
last_console = fg_console;
change_console(want_console);
}
want_console = -1;
}
if (got_break) {
if (tty && !I_IGNBRK(tty)) {
if (I_BRKINT(tty)) {
flush_input(tty);
flush_output(tty);
if (tty->pgrp > 0)
kill_pg(tty->pgrp, SIGINT, 1);
} else {
cli();
if (LEFT(&tty->read_q) >= 2) {
set_bit(tty->read_q.head,
&tty->readq_flags);
put_queue(TTY_BREAK);
put_queue(0);
}
sti();
}
}
got_break = 0;
}
do_keyboard_interrupt();
cli();
if ((inb_p(0x64) & kbd_read_mask) == 0x01)
fake_keyboard_interrupt();
sti();
}
long no_idt[2] = {0, 0};
/*
* This routine reboots the machine by asking the keyboard
* controller to pulse the reset-line low. We try that for a while,
* and if it doesn't work, we do some other stupid things.
*/
void hard_reset_now(void)
{
int i, j;
extern unsigned long pg0[1024];
sti();
/* rebooting needs to touch the page at absolute addr 0 */
pg0[0] = 7;
*((unsigned short *)0x472) = 0x1234;
for (;;) {
for (i=0; i<100; i++) {
kb_wait();
for(j = 0; j < 100000 ; j++)
/* nothing */;
outb(0xfe,0x64); /* pulse reset low */
}
__asm__("\tlidt _no_idt");
}
}
unsigned long kbd_init(unsigned long kmem_start)
{
int i;
struct kbd_struct * kbd;
kbd = kbd_table + 0;
for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
kbd->ledstate = KBD_DEFLEDS;
kbd->default_ledstate = KBD_DEFLEDS;
kbd->lockstate = KBD_DEFLOCK;
kbd->modeflags = KBD_DEFMODE;
}
bh_base[KEYBOARD_BH].routine = kbd_bh;
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
mark_bh(KEYBOARD_BH);
return kmem_start;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -