📄 kbd.c
字号:
#include <bios/types.h>#include <bios/time.h>#include <bios/pci.h>#include <bios/stdio.h>#include <bios/stdioint.h>#include <bios/timer.h>#define inb(r) pci_io_read_byte((r))#define outb(v,r) pci_io_write_byte((v),(r))/* * Keyboard Controller Registers */#define KBD_STATUS_REG 0x64 /* Status register (R) */#define KBD_CNTL_REG 0x64 /* Controller command register (W) */#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) *//* * Keyboard Controller Commands */#define KBD_CCMD_READ_MODE 0x20#define KBD_CCMD_WRITE_MODE 0x60#define KBD_CCMD_GET_VERSION 0xa1#define KBD_CCMD_MOUSE_DISABLE 0xa7#define KBD_CCMD_MOUSE_ENABLE 0xa8#define KBD_CCMD_TEST_MOUSE 0xa9#define KBD_CCMD_SELF_TEST 0xaa#define KBD_CCMD_KBD_TEST 0xab#define KBD_CCMD_KBD_DISABLE 0xad#define KBD_CCMD_KBD_ENABLE 0xae#define KBD_CCMD_WRITE_AUX_OBUF 0xd3#define KBD_CCMD_WRITE_MOUSE 0xd4/* * Keyboard Commands */#define KBD_CMD_SET_LEDS 0xed#define KBD_CMD_SET_RATE 0xf3#define KBD_CMD_ENABLE 0xf4#define KBD_CMD_DISABLE 0xf5#define KBD_CMD_RESET 0xff/* * Keyboard Replies */#define KBD_REPLY_POR 0xaa#define KBD_REPLY_ACK 0xfa#define KBD_REPLY_RESEND 0xfe/* * Status Register Bits */#define KBD_STAT_OBF 0x01#define KBD_STAT_IBF 0x02#define KBD_STAT_SELFTEST 0x04#define KBD_STAT_CMD 0x08#define KBD_STAT_UNLOCKED 0x10#define KBD_STAT_MOUSE_OBF 0x20#define KBD_STAT_GTO 0x40#define KBD_STAT_PERR 0x80/* * Controller mode register bits */#define KBD_MODE_KBD_INT 0x01#define KBD_MODE_MOUSE_INT 0x02#define KBD_MODE_SYS 0x04#define KBD_MODE_NO_KEYLOCK 0x08#define KBD_MODE_DISABLE_KBD 0x10#define KBD_MODE_DISABLE_MOUSE 0x20#define KBD_MODE_KCC 0x40#define KBD_MODE_RFU 0x80#define KBD_NO_DATA (-1)#define KBD_BAD_DATA (-2)static volatile unsigned char reply_expected;static volatile unsigned char acknowledge;static volatile unsigned char resend;static volatile unsigned char read_ch;static const char kbd_table[] = {/*00*/ 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,/*08*/ 0x37, 0x38, 0x39, 0x30, 0x2d, 0x3d, 0x7f, 0x09,/*10*/ 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69,/*18*/ 0x6f, 0x70, 0x5b, 0x5d, 0x0a, 0x00, 0x61, 0x73,/*20*/ 0x64, 0x66, 0x67, 0x68, 0x6a, 0x6b, 0x6c, 0x3b,/*28*/ 0x27, 0x60, 0x00, 0x5c, 0x7a, 0x78, 0x63, 0x76,/*30*/ 0x62, 0x6e, 0x6d, 0x2c, 0x2e, 0x2f, 0x00, 0x00,/*38*/ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*40*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*48*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,/*58*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*60*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*68*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*70*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,/*78*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};static void handle_scancode(int scancode, int up){ if (up) return; read_ch = kbd_table[scancode & 0x7f];}static int do_acknowledge(unsigned char scancode){ if (reply_expected) { switch (scancode) { case KBD_REPLY_ACK: acknowledge = 1; reply_expected = 0; return 0; case KBD_REPLY_RESEND: resend = 1; reply_expected = 0; return 0; default: break; } } return 1;}static unsigned char handle_kbd_event(void){ unsigned char status = inb(KBD_STATUS_REG); int work = 1000; while (status & KBD_STAT_OBF && work--) { unsigned char scancode; scancode = inb(KBD_DATA_REG); if (do_acknowledge(scancode)) handle_scancode(scancode, !(scancode & 0x80)); status = inb(KBD_STATUS_REG); } return status;}static void kb_wait(void){ int timeout = 10; do { unsigned char status = handle_kbd_event(); if (!(status & KBD_STAT_IBF)) return; wait_cs(1); } while (--timeout); printf("Keyboard timed out\n");}static int kbd_read_input(void){ int retval = KBD_NO_DATA; unsigned char status; status = inb(KBD_STATUS_REG); if (status & KBD_STAT_OBF) { unsigned char data = inb(KBD_DATA_REG); retval = data; if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) retval = KBD_BAD_DATA; } return retval;}static void kbd_clear_input(void){ int maxread = 100; /* Random number */ do { if (kbd_read_input() == KBD_NO_DATA) break; } while (--maxread);}static int kbd_wait_for_input(void){ long timeout = 100; do { int retval = kbd_read_input(); if (retval >= 0) return retval; wait_cs(1); } while (--timeout); return -1;}static void kbd_write(int address, int data){ kb_wait(); outb(data, address);}static int init_kbd_hw(void){ int status; /* * Test the keyboard interface. * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST); if (kbd_wait_for_input() != 0x55) { printf("Keyboard failed self test\n"); return 1; } /* * Perform a keyboard interface test. This causes the controller * to test the keyboard clock and data lines. The results of the * test are placed in the input buffer. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST); if (kbd_wait_for_input() != 0x00) { printf("Keyboard interface failed self test"); return 1; } /* * Enable the keyboard by allowing the keyboard clock to run. */ kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE); /* * Reset keyboard. If the read times out * then the assumption is that no keyboard is * plugged into the machine. * This defaults the keyboard to scan-code set 2. * * Set up to try again if the keyboard asks for RESEND. */ do { kbd_write(KBD_DATA_REG, KBD_CMD_RESET); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) { printf("Keyboard reset failed, no ACK: %02X\n", status); return 1; } } while (1); if (kbd_wait_for_input() != KBD_REPLY_POR) { printf("Keyboard reset failed, no POR\n"); return 1; } /* * Set keyboard controller mode. During this, the keyboard should be * in the disabled state. * * Set up to try again if the keyboard asks for RESEND. */ do { kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE); status = kbd_wait_for_input(); if (status == KBD_REPLY_ACK) break; if (status != KBD_REPLY_RESEND) { printf("Disable keyboard failed, no ACK: %02X\n", status); return 1; } } while (1); kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE); kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT|KBD_MODE_SYS|KBD_MODE_DISABLE_MOUSE|KBD_MODE_KCC); /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE); if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { /* * If the controller does not support conversion, * Set the keyboard to scan-code set 1. */ kbd_write(KBD_DATA_REG, 0xF0); kbd_wait_for_input(); kbd_write(KBD_DATA_REG, 0x01); kbd_wait_for_input(); } kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE); if (kbd_wait_for_input() != KBD_REPLY_ACK) { printf("Enable keyboard: no ACK\n"); return 1; } /* * Finally, set the typematic rate to maximum. */ kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE); if (kbd_wait_for_input() != KBD_REPLY_ACK) printf("Set rate: no ACK\n"); else { kbd_write(KBD_DATA_REG, 0x00); if (kbd_wait_for_input() != KBD_REPLY_ACK) printf("Set rate: no ACK\n"); } return 0;}int kbd_read(char *buffer, int nr){ int used = 0; do { handle_kbd_event(); if (read_ch) { buffer[used++] = read_ch; read_ch = 0; nr -= 1; } else if (timers[KEY_TIMER].status) break; } while (nr); return used;}void kbd_init(void){ /* flush any pending input */ kbd_clear_input(); if (!init_kbd_hw()) stdfn.read = kbd_read;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -