1 /* Keyboard driver for PCs and ATs. */ 2 #include <minix/drivers.h> 3 #include <minix/input.h> 4 #include <minix/inputdriver.h> 5 6 #include "pckbd.h" 7 8 /* 9 * Data that is to be sent to the keyboard. Each byte is ACKed by the keyboard. 10 * This is currently somewhat overpowered for its only purpose: setting LEDs. 11 */ 12 static struct kbdout { 13 unsigned char buf[KBD_OUT_BUFSZ]; 14 int offset; 15 int avail; 16 int expect_ack; 17 } kbdout; 18 19 static int kbd_watchdog_set = 0; 20 static int kbd_alive = 1; 21 static minix_timer_t tmr_kbd_wd; 22 23 static int irq_hook_id = -1; 24 static int aux_irq_hook_id = -1; 25 26 static int kbd_state = 0; 27 28 static unsigned char aux_bytes[3]; 29 static unsigned char aux_state = 0; 30 static int aux_counter = 0; 31 static int aux_available = 0; 32 33 static void pckbd_leds(unsigned int); 34 static void pckbd_intr(unsigned int); 35 static void pckbd_alarm(clock_t); 36 37 static struct inputdriver pckbd_tab = { 38 .idr_leds = pckbd_leds, 39 .idr_intr = pckbd_intr, 40 .idr_alarm = pckbd_alarm 41 }; 42 43 /* 44 * The watchdog timer function, implementing all but the actual reset. 45 */ 46 static void 47 kbd_watchdog(minix_timer_t *UNUSED(tmrp)) 48 { 49 kbd_watchdog_set = 0; 50 if (!kbdout.avail) 51 return; /* Watchdog is no longer needed */ 52 53 if (!kbd_alive) 54 printf("PCKBD: watchdog should reset keyboard\n"); 55 kbd_alive = 0; 56 57 set_timer(&tmr_kbd_wd, sys_hz(), kbd_watchdog, 0); 58 59 kbd_watchdog_set = 1; 60 } 61 62 /* 63 * Send queued data to the keyboard. 64 */ 65 static void 66 kbd_send(void) 67 { 68 u32_t sb; 69 int r; 70 71 if (!kbdout.avail) 72 return; 73 if (kbdout.expect_ack) 74 return; 75 76 if ((r = sys_inb(KB_STATUS, &sb)) != OK) 77 printf("PCKBD: send sys_inb() failed (1): %d\n", r); 78 79 if (sb & (KB_OUT_FULL | KB_IN_FULL)) { 80 printf("PCKBD: not sending (1): sb = 0x%x\n", sb); 81 return; 82 } 83 micro_delay(KBC_IN_DELAY); 84 if ((r = sys_inb(KB_STATUS, &sb)) != OK) 85 printf("PCKBD: send sys_inb() failed (2): %d\n", r); 86 if (sb & (KB_OUT_FULL | KB_IN_FULL)) { 87 printf("PCKBD: not sending (2): sb = 0x%x\n", sb); 88 return; 89 } 90 91 /* Okay, buffer is really empty */ 92 if ((r = sys_outb(KEYBD, kbdout.buf[kbdout.offset])) != OK) 93 printf("PCKBD: send sys_outb() failed: %d\n", r); 94 kbdout.offset++; 95 kbdout.avail--; 96 kbdout.expect_ack = 1; 97 98 kbd_alive = 1; 99 if (kbd_watchdog_set) { 100 /* Set a watchdog timer for one second. */ 101 set_timer(&tmr_kbd_wd, sys_hz(), kbd_watchdog, 0); 102 103 kbd_watchdog_set = 1; 104 } 105 } 106 107 /* 108 * Try to obtain input from the keyboard. 109 */ 110 static int 111 scan_keyboard(unsigned char *bp, int *isauxp) 112 { 113 u32_t b, sb; 114 int r; 115 116 if ((r = sys_inb(KB_STATUS, &sb)) != OK) { 117 printf("PCKBD: scan sys_inb() failed (1): %d\n", r); 118 return FALSE; 119 } 120 if (!(sb & KB_OUT_FULL)) { 121 if (kbdout.avail && !kbdout.expect_ack) 122 kbd_send(); 123 return FALSE; 124 } 125 if ((r = sys_inb(KEYBD, &b)) != OK) { 126 printf("PCKBD: scan sys_inb() failed (2): %d\n", r); 127 return FALSE; 128 } 129 if (!(sb & 0x40) && b == KB_ACK && kbdout.expect_ack) { 130 kbdout.expect_ack = 0; 131 micro_delay(KBC_IN_DELAY); 132 kbd_send(); 133 return FALSE; 134 } 135 if (bp) 136 *bp = b; 137 if (isauxp) 138 *isauxp = !!(sb & KB_AUX_BYTE); 139 if (kbdout.avail && !kbdout.expect_ack) { 140 micro_delay(KBC_IN_DELAY); 141 kbd_send(); 142 } 143 return TRUE; 144 } 145 146 /* 147 * Wait until the controller is ready. Return TRUE on success, FALSE on 148 * timeout. Since this may discard input, only use during initialization. 149 */ 150 static int 151 kb_wait(void) 152 { 153 spin_t spin; 154 u32_t status; 155 int r, isaux; 156 unsigned char byte; 157 158 SPIN_FOR(&spin, KBC_WAIT_TIME) { 159 if ((r = sys_inb(KB_STATUS, &status)) != OK) 160 printf("PCKBD: wait sys_inb() failed: %d\n", r); 161 if (status & KB_OUT_FULL) 162 (void) scan_keyboard(&byte, &isaux); 163 if (!(status & (KB_IN_FULL | KB_OUT_FULL))) 164 return TRUE; /* wait until ready */ 165 } 166 167 printf("PCKBD: wait timeout\n"); 168 return FALSE; 169 } 170 171 /* 172 * Set the LEDs on the caps, num, and scroll lock keys. 173 */ 174 static void 175 set_leds(unsigned char ledmask) 176 { 177 if (kbdout.avail == 0) 178 kbdout.offset = 0; 179 if (kbdout.offset + kbdout.avail + 2 > KBD_OUT_BUFSZ) { 180 /* 181 * The output buffer is full. Ignore this command. Reset the 182 * ACK flag. 183 */ 184 kbdout.expect_ack = 0; 185 } else { 186 kbdout.buf[kbdout.offset+kbdout.avail] = LED_CODE; 187 kbdout.buf[kbdout.offset+kbdout.avail+1] = ledmask; 188 kbdout.avail += 2; 189 } 190 if (!kbdout.expect_ack) 191 kbd_send(); 192 } 193 194 /* 195 * Send a command to the keyboard. 196 */ 197 static void 198 kbc_cmd0(int cmd) 199 { 200 int r; 201 202 kb_wait(); 203 if ((r = sys_outb(KB_COMMAND, cmd)) != OK) 204 printf("PCKBD: cmd0 sys_outb() failed: %d\n", r); 205 } 206 207 /* 208 * Send a command to the keyboard, including data. 209 */ 210 static void 211 kbc_cmd1(int cmd, int data) 212 { 213 int r; 214 215 kb_wait(); 216 if ((r = sys_outb(KB_COMMAND, cmd)) != OK) 217 printf("PCKBD: cmd1 sys_outb() failed (1): %d\n", r); 218 kb_wait(); 219 if ((r = sys_outb(KEYBD, data)) != OK) 220 printf("PCKBD: cmd1 sys_outb() failed (2): %d\n", r); 221 } 222 223 /* 224 * Wait at most one second for a byte from the keyboard or the controller. 225 */ 226 static int 227 kbc_read(void) 228 { 229 u32_t byte, status; 230 spin_t spin; 231 int r; 232 233 SPIN_FOR(&spin, KBC_READ_TIME) { 234 if ((r = sys_inb(KB_STATUS, &status)) != OK) 235 printf("PCKBD: read sys_inb() failed (1): %d\n", r); 236 if (status & KB_OUT_FULL) { 237 micro_delay(KBC_IN_DELAY); 238 if ((r = sys_inb(KEYBD, &byte)) != OK) 239 printf("PCKBD: read sys_inb() failed (2): " 240 "%d\n", r); 241 if (status & KB_AUX_BYTE) 242 printf("PCKBD: read got aux 0x%x\n", byte); 243 return byte; 244 } 245 } 246 247 panic("kbc_read failed to complete"); 248 } 249 250 /* 251 * Initialize the keyboard hardware. 252 */ 253 static int 254 kb_init(void) 255 { 256 int r, ccb; 257 258 /* Disable the keyboard and AUX. */ 259 kbc_cmd0(KBC_DI_KBD); 260 kbc_cmd0(KBC_DI_AUX); 261 262 /* Discard leftover keystroke. */ 263 scan_keyboard(NULL, NULL); 264 265 /* Get the current configuration byte. */ 266 kbc_cmd0(KBC_RD_RAM_CCB); 267 ccb = kbc_read(); 268 269 /* If bit 5 is clear, it is a single channel controler for sure.. */ 270 aux_available = (ccb & 0x10); 271 272 /* Execute Controller Self Test. */ 273 kbc_cmd0(0xAA); 274 r = kbc_read(); 275 if (r != 0x55){ 276 printf("PCKBD: Controller self-test failed.\n"); 277 return EGENERIC; 278 } 279 280 /* Set interrupt handler and enable keyboard IRQ. */ 281 irq_hook_id = KEYBOARD_IRQ; /* id to be returned on interrupt */ 282 r = sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id); 283 if (r != OK) 284 panic("Couldn't set keyboard IRQ policy: %d", r); 285 if ((r = sys_irqenable(&irq_hook_id)) != OK) 286 panic("Couldn't enable keyboard IRQs: %d", r); 287 288 /* Activate IRQ bit for the keyboard. */ 289 ccb |= 0x1; 290 291 if (aux_available != 0) { 292 /* Set AUX interrupt handler and enable AUX IRQ. */ 293 aux_irq_hook_id = KBD_AUX_IRQ; /* id to be returned on interrupt */ 294 r = sys_irqsetpolicy(KBD_AUX_IRQ, IRQ_REENABLE, &aux_irq_hook_id); 295 if (r != OK) 296 panic("Couldn't set AUX IRQ policy: %d", r); 297 if ((r = sys_irqenable(&aux_irq_hook_id)) != OK) 298 panic("Couldn't enable AUX IRQs: %d", r); 299 300 /* Activate IRQ for AUX. */ 301 ccb |= 0x2; 302 } 303 304 /* Enable interrupt(s). */ 305 kbc_cmd1(KBC_WR_RAM_CCB, ccb); 306 307 /* Re-enable the keyboard device. */ 308 kbc_cmd0(KBC_EN_KBD); 309 310 if (aux_available != 0) { 311 /* Enable the AUX device. */ 312 kbc_cmd0(KBC_EN_AUX); 313 kbc_cmd1(0xD4, 0xF6); 314 kbc_cmd1(0xD4, 0xF4); 315 } 316 317 /* Set the initial LED state. */ 318 kb_wait(); 319 320 set_leds(0); 321 return OK; 322 } 323 324 /* 325 * Process a keyboard scancode. 326 */ 327 static void 328 kbd_process(unsigned char scode) 329 { 330 int press, index, page, code; 331 332 press = !(scode & SCAN_RELEASE) ? INPUT_PRESS : INPUT_RELEASE; 333 index = scode & ~SCAN_RELEASE; 334 335 switch (kbd_state) { 336 case 1: 337 page = scanmap_escaped[index].page; 338 code = scanmap_escaped[index].code; 339 break; 340 case 2: 341 kbd_state = (index == SCAN_CTRL) ? 3 : 0; 342 return; 343 case 3: 344 if (index == SCAN_NUMLOCK) { 345 page = INPUT_PAGE_KEY; 346 code = INPUT_KEY_PAUSE; 347 break; 348 } 349 /* FALLTHROUGH */ 350 default: 351 switch (scode) { 352 case SCAN_EXT0: 353 kbd_state = 1; 354 return; 355 case SCAN_EXT1: 356 kbd_state = 2; 357 return; 358 } 359 page = scanmap_normal[index].page; 360 code = scanmap_normal[index].code; 361 break; 362 } 363 364 if (page) 365 inputdriver_send_event(FALSE /*mouse*/, page, code, press, 0); 366 367 kbd_state = 0; 368 } 369 370 /* 371 * Process an auxiliary (mouse) scancode. 372 */ 373 static void 374 kbdaux_process(unsigned char scode) 375 { 376 u32_t delta; 377 int i; 378 379 if (aux_counter == 0 && !(scode & 0x08)) 380 return; /* resync */ 381 382 aux_bytes[aux_counter++] = scode; 383 384 if (aux_counter < 3) 385 return; /* need more first */ 386 387 aux_counter = 0; 388 389 /* Send an event for each button state change. */ 390 for (i = 0; i < 3; i++) { 391 if ((aux_state ^ aux_bytes[0]) & (1 << i)) { 392 aux_state ^= (1 << i); 393 394 inputdriver_send_event(TRUE /*mouse*/, 395 INPUT_PAGE_BUTTON, INPUT_BUTTON_1 + i, 396 !!(aux_state & (1 << i)), 0); 397 } 398 } 399 400 /* Send an event for each relative mouse movement, X and/or Y. */ 401 for (i = 0; i < 2; i++) { 402 delta = aux_bytes[1 + i]; 403 if (delta != 0) { 404 if (aux_bytes[0] & (0x10 << i)) 405 delta |= 0xFFFFFF00; /* make signed */ 406 407 inputdriver_send_event(TRUE /*mouse*/, INPUT_PAGE_GD, 408 !i ? INPUT_GD_X : INPUT_GD_Y, delta, 409 INPUT_FLAG_REL); 410 } 411 } 412 } 413 414 /* 415 * Set keyboard LEDs. 416 */ 417 static void 418 pckbd_leds(unsigned int leds) 419 { 420 unsigned char b; 421 422 b = 0; 423 if (leds & (1 << INPUT_LED_NUMLOCK)) b |= LED_NUM_LOCK; 424 if (leds & (1 << INPUT_LED_CAPSLOCK)) b |= LED_CAPS_LOCK; 425 if (leds & (1 << INPUT_LED_SCROLLLOCK)) b |= LED_SCROLL_LOCK; 426 427 set_leds(b); 428 } 429 430 /* 431 * Process a keyboard interrupt. 432 */ 433 static void 434 pckbd_intr(unsigned int UNUSED(mask)) 435 { 436 unsigned char scode; 437 int isaux; 438 439 /* Fetch a character from the keyboard hardware and acknowledge it. */ 440 if (!scan_keyboard(&scode, &isaux)) 441 return; 442 443 if (!isaux) { 444 /* A keyboard key press or release. */ 445 kbd_process(scode); 446 } else { 447 /* A mouse event. */ 448 kbdaux_process(scode); 449 } 450 } 451 452 /* 453 * Process a timer signal. 454 */ 455 static void 456 pckbd_alarm(clock_t stamp) 457 { 458 expire_timers(stamp); 459 } 460 461 /* 462 * Initialize the driver. 463 */ 464 static int 465 pckbd_init(int UNUSED(type), sef_init_info_t *UNUSED(info)) 466 { 467 int flags = INPUT_DEV_KBD; 468 /* Initialize the watchdog timer. */ 469 init_timer(&tmr_kbd_wd); 470 471 /* Initialize the keyboard. */ 472 int r; 473 if((r = kb_init())!=OK){ 474 return r; 475 } 476 477 /* Announce the driver's presence. */ 478 if (aux_available != 0) 479 flags |= INPUT_DEV_MOUSE; 480 inputdriver_announce(flags); 481 482 return OK; 483 } 484 485 /* 486 * Set callback routines and let SEF initialize. 487 */ 488 static void 489 pckbd_startup(void) 490 { 491 sef_setcb_init_fresh(pckbd_init); 492 493 sef_startup(); 494 } 495 496 /* 497 * PC keyboard/mouse driver task. 498 */ 499 int 500 main(void) 501 { 502 pckbd_startup(); 503 504 inputdriver_task(&pckbd_tab); 505 506 return 0; 507 } 508