#include "type.h" #include "const.h" #include "protect.h" #include "string.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "proto.h" #include "keyboard.h" // #include "keymap.h" #include "x86.h" #include "stdio.h" #include "assert.h" #include "minix_keymap.h" #include "serialport.h" #include "memman.h" static int code_with_E0; static int shift_l; /* l shift state */ static int shift_r; /* r shift state */ static int alt_l; /* l alt state */ static int alt_r; /* r left state */ static int ctrl_l; /* l ctrl state */ static int ctrl_r; /* l ctrl state */ static int caps_lock; /* Caps Lock */ static int num_lock; /* Num Lock */ static int scroll_lock; /* Scroll Lock */ static int mouse_count; static u8 mouse_data[MOUSE_IN_BYTES]; static void set_leds(); static void set_mouse_leds(); static void kb_wait(); static void kbd_process(unsigned char scode); /* * Helper Procedures for PS/2 Mouse Operation * */ static void mouse_wait(u8 a_type) { int _time_out = 100000; if (a_type == 0) { while (_time_out--) if ((inb(PS2_PORT_CMD) & 1) == 1) return; return; } else { while (_time_out--) if ((inb(PS2_PORT_CMD) & 2) == 0) return; return; } } static void mouse_write(u8 a_write) { mouse_wait(1); // Wait to be able to send a command outb(PS2_PORT_CMD, PS2_CMD_2ND_OUT); // Tell the mouse we are sending a command mouse_wait(1); // Wait for the final part outb(PS2_PORT_DATA, a_write); // Finally write } // Get's response from mouse static u8 mouse_read() { mouse_wait(0); return inb(PS2_PORT_DATA); } static void mouse_set_rate(u8 rate) { mouse_write(0xf3); // set sample rate cmd assert(mouse_read() == PS2_ACK); mouse_write(rate); assert(mouse_read() == PS2_ACK); } static u8 mouse_get_id() { mouse_write(PS2_CMD_DATA_REPORT_DIS); assert(mouse_read() == PS2_ACK); mouse_write(PS2_CMD_GET_DEVICE); // report assert(mouse_read() == PS2_ACK); u8 device_type = mouse_read(); mouse_write(PS2_CMD_DATA_REPORT_ENB); assert(mouse_read() == PS2_ACK); return device_type; } static void set_mouse_leds() { kb_wait(); outb(KB_CMD, KBCMD_EN_MOUSE_INTFACE); kb_wait(); outb(KB_CMD, KEYCMD_SENDTO_MOUSE); kb_wait(); outb(KB_DATA, MOUSECMD_ENABLE); kb_wait(); outb(KB_CMD, KEYCMD_WRITE_MODE); kb_wait(); outb(KB_DATA, KBC_MODE); } void mouse_handler(int irq) { u8 scan_code = inb(PS2_PORT_DATA); static int aux_state = 0; int i; u32 pack; if (mouse_count == 0 && !(scan_code & 0x08)) return; // resync mouse_data[mouse_count++] = scan_code; if (mouse_count < 4) return; mouse_count = 0; for (i = 0; i < 3; i++) { pack = ISMOUSE | MOUSEBTN; if ((aux_state ^ mouse_data[0]) & (1 << i)) { aux_state ^= (1 << i); pack |= !!(aux_state & (1 << i)) ? MOUSEBTN_CLICK : MOUSEBTN_RELEASE; pack |= (1 << i); cur_ntty->recvbuf(cur_ntty, pack); } } pack = ISMOUSE | MOUSESCR; if ((signed char)mouse_data[3] > 0) { // actually it is 0x1 pack |= MOUSESCR_DOWN; cur_ntty->recvbuf(cur_ntty, pack); } else if ((signed char)mouse_data[3] < 0) { // actually it is 0xff pack |= MOUSESCR_UP; cur_ntty->recvbuf(cur_ntty, pack); } for (i = 0; i < 2; i++) { pack = mouse_data[1 + i]; if (pack != 0) { pack |= ISMOUSE | MOUSEPOS; if (mouse_data[0] & (0x10 << i)) pack |= MOUSEPOS_NEG; if (i == 1) pack |= MOUSEPOS_XY; cur_ntty->recvbuf(cur_ntty, pack); } } // kprintf("0x%02x 0x%02x 0x%02x 0x%02x\n", mouse_data[0], mouse_data[1], mouse_data[2], mouse_data[3]); } void init_mouse() { mouse_count = 0; put_irq_handler(MOUSE_IRQ, mouse_handler); enable_irq(MOUSE_IRQ); mouse_wait(1); outb(PS2_PORT_CMD, PS2_CMD_2ND_ENB); // Enable second PS/2 port mouse_wait(1); outb(PS2_PORT_CMD, PS2_CMD_READRAM); // Read "byte 0" from internal RAM mouse_wait(0); u8 _status = inb(PS2_PORT_DATA) | 0x2; // bit-1 <=> Second PS/2 port interrupt mouse_wait(1); outb(PS2_PORT_CMD, PS2_PORT_DATA); // Write next byte to "byte 0" of internal RAM mouse_wait(1); outb(PS2_PORT_DATA, _status); // Write back to internal RAM mouse_write(PS2_CMD_SET_DEFAULT); // Set Defaults assert(mouse_read() == PS2_ACK); mouse_write(PS2_CMD_DATA_REPORT_ENB); // Enable Data Reporting assert(mouse_read() == PS2_ACK); // Remember to read ACK, or it may block assert(mouse_get_id() == 0x00); // by init, id should be 0(standard ps/2 mouse) mouse_set_rate(200); mouse_set_rate(100); mouse_set_rate(80); // tricks to enable z-axis, from osdev assert(mouse_get_id() == 0x03); // z-axis enabled, id should be 3 (Mouse with scroll wheel) mouse_write(PS2_CMD_DATA_REPORT_ENB); assert(mouse_read() == PS2_ACK); set_mouse_leds(); } /** * Wait until the input buffer of 8042 is empty. */ static void kb_wait() /* 等待 8042 的输入缓冲区空 */ { u8 kb_stat; do { kb_stat = inb(KB_CMD); } while (kb_stat & 0x02); } static void kb_ack() { u8 kb_read; do { kb_read = inb(KB_DATA); } while (kb_read != KB_ACK); } /** * Set the leds according to: caps_lock, num_lock & scroll_lock. */ static void set_leds() { kb_wait(); outb(KB_CMD, KEYCMD_WRITE_MODE); kb_wait(); outb(KB_DATA, KBC_MODE); } void kb_handler(int irq) { u8 scan_code = inb(PS2_PORT_DATA); kbd_process(scan_code); // kprintf("kb"); }; void init_kb() { shift_l = shift_r = 0; alt_l = alt_r = 0; ctrl_l = ctrl_r = 0; caps_lock = 0; num_lock = 1; scroll_lock = 0; set_leds(); init_mouse(); put_irq_handler(KEYBOARD_IRQ, kb_handler); enable_irq(KEYBOARD_IRQ); } static u16 map_key(int code) { int caps, column; int shift = shift_l | shift_r; int alt = alt_l | alt_r; int ctrl = ctrl_l | ctrl_r; u16 *keyrow = minix_keymap[code]; caps = shift_l | shift_r; if (num_lock && (keyrow[0] & HASNUM)) caps = !caps; if (caps_lock && (keyrow[0] & HASCAPS)) caps = !caps; if (alt) { column = 2; if (ctrl || alt_r) column = 3; /* Ctrl + Alt == AltGr */ if (caps) column = 4; } else { column = 0; if (caps) column = 1; if (ctrl) column = 5; } return keyrow[column] & ~(HASNUM | HASCAPS); } static void kbd_process(unsigned char scode) { int press, index, page, code; static int kbd_state = 0; press = !(scode & SCAN_RELEASE) ? INPUT_PRESS : INPUT_RELEASE; index = scode & ~SCAN_RELEASE; switch (kbd_state) { case 1: page = scanmap_escaped[index].page; code = scanmap_escaped[index].code; break; case 2: kbd_state = (index == SCAN_CTRL) ? 3 : 0; return; case 3: if (index == SCAN_NUMLOCK) { page = INPUT_PAGE_KEY; code = INPUT_KEY_PAUSE; break; } /* FALLTHROUGH */ default: switch (scode) { case SCAN_EXT0: kbd_state = 1; return; case SCAN_EXT1: kbd_state = 2; return; } page = scanmap_normal[index].page; code = scanmap_normal[index].code; break; } if (page) { switch (code) { case INPUT_KEY_LEFT_SHIFT: shift_l = press; break; case INPUT_KEY_RIGHT_SHIFT: shift_r = press; break; case INPUT_KEY_LEFT_CTRL: ctrl_l = press; break; case INPUT_KEY_RIGHT_CTRL: ctrl_r = press; break; case INPUT_KEY_LEFT_ALT: alt_l = press; break; case INPUT_KEY_RIGHT_ALT: alt_r = press; break; case INPUT_KEY_NUM_LOCK: if (press){ num_lock = !num_lock; set_leds(); } break; case INPUT_KEY_CAPS_LOCK: if (press){ caps_lock = !caps_lock; set_leds(); } break; case INPUT_KEY_SCROLL_LOCK: if (press){ scroll_lock = !scroll_lock; set_leds(); } break; } // inputdriver_send_event(FALSE /*mouse*/, page, code, press, 0); if (press) cur_ntty->recvbuf(cur_ntty, map_key(code)); } kbd_state = 0; } static u32 kbdlock; #define LASTKEY(x) LAST(x, TTY_IN_BYTES) #define NEXTKEY(x) NEXT(x, TTY_IN_BYTES) // static u8 keybuf[3][TTY_IN_BYTES]; void ps2_tty_init(NTTY *tty) { static int _cnt = 0; assert(tty->driver_type == 1); assert(tty->input_buf); keyboard_buf *kbd = (keyboard_buf *)tty->input_buf; // kbd->buf = (void *)keybuf[_cnt++]; kbd->buf = (void*)K_PHY2LIN(do_kmalloc(TTY_IN_BYTES)); // kprintf("kbd buf: %p\n", kbd->buf); kbd->head = kbd->tail = kbd->readable = 0; kbd->len = 0; kbdlock = 0; } int ps2_tty_read(NTTY *tty, char *buf, int nr) { assert(tty->input_buf); keyboard_buf *kbd = (keyboard_buf *)tty->input_buf; int i = 0; while (1) { while (xchg(&kbdlock, 1) == 1) sys_yield(); if (kbd->readable) { break; } xchg(&kbdlock, 0); sys_yield(); } assert(kbd->buf); u8 *ibuf = kbd->buf; for (; i < nr && i < kbd->readable; ++i) { *buf ++ = ibuf[kbd->head]; // kprintf("[r]%p;", ibuf+kbd->head); kbd->head = NEXTKEY(kbd->head); } kbd->readable -= i; kbd->len -= i; xchg(&kbdlock, 0); return i; } void ps2_tty_flush(NTTY *tty) { disable_int(); assert(tty->input_buf); keyboard_buf *kbd = (keyboard_buf *)tty->input_buf; kbd->head = kbd->tail = kbd->len = kbd->readable = 0; enable_int(); } void ps2_tty_recvbuf(NTTY *tty, u32 key) { // kprintf("%x\n", key); // disable_int(); assert(tty->input_buf); keyboard_buf *kbd = (keyboard_buf *)tty->input_buf; u8* buf = kbd->buf; if (key & ISMOUSE) { if (key & MOUSESCR) { if (key & MOUSESCR_UP) { // kprintf("scroll up\n"); tty->ioctl(tty, 1, TTY_SCROLL_UP); } else { // kprintf("scroll down\n"); tty->ioctl(tty, 1, TTY_SCROLL_DOWN); } } else if (key & MOUSEBTN) { if ((key & MOUSEBTN_CLICK) && (key & MOUSEBTN_M)) { // kprintf("middle btn click %x\n", key); tty->ioctl(tty, 1, TTY_SCROLL_TOCUR); } } } else if (key & EXT) { switch (key) { case F1: case F2: case F3: case F4: case F5: case F6: case F7: case F8: case F9: case F10: case F11: case F12: { int conno = (key & 0xff) - (F1 & 0xff); if (conno < NR_CONSOLES) { // kprintf("select console %d\n", conno); tty->ioctl(tty, 2, conno); } break; } default: break; } } else { switch (key) { case '\r': case '\n': // escape ENTER while (xchg(&kbdlock, 1) == 1) sys_yield(); tty->write(tty, '\n'); buf[kbd->tail] = '\n'; kbd->len++; kbd->tail = NEXTKEY(kbd->tail); kbd->readable = CYCLE_SUB(kbd->head, kbd->tail, TTY_IN_BYTES); xchg(&kbdlock, 0); // kprintf("len=%d, h=%d, t=%d, rd=%d\n", kbd->len, kbd->head, kbd->tail, kbd->readable); break; case '\b': while (xchg(&kbdlock, 1) == 1) sys_yield(); if (kbd->len > kbd->readable) { // vga_tty_backspace(tty); tty->write(tty, '\b'); tty->write(tty, ' '); tty->write(tty, '\b'); kbd->len--; kbd->tail = LASTKEY(kbd->tail); } xchg(&kbdlock, 0); break; default: while (xchg(&kbdlock, 1) == 1); if ((key & 0xff) == 0) return; if (kbd->len == TTY_IN_BYTES - 1) return; // leave one space for ctrl ascii buf[kbd->tail] = (u8)(key & 0xff); // kprintf("%d %d %d", key & 0xff, kbd->tail, buf[kbd->tail]); kbd->len++; kbd->tail = NEXTKEY(kbd->tail); xchg(&kbdlock, 0); tty->write(tty, key); // kprintf("len=%d, h=%d, t=%d, rd=%d\n", kbd->len, kbd->head, kbd->tail, kbd->readable); break; } tty->ioctl(tty, IOCTL_CMD_TTY_FLUSH, 0); } // enable_int(); }