ps2kbd.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. * (C) Copyright 2002
  3. * John W. Linville, linville@tuxdriver.com
  4. *
  5. * Modified from code for support of MIP405 and PIP405 boards. Previous
  6. * copyright follows.
  7. *
  8. * (C) Copyright 2001
  9. * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
  10. *
  11. * See file CREDITS for list of people who contributed to this
  12. * project.
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27. * MA 02111-1307 USA
  28. *
  29. *
  30. * Source partly derived from:
  31. * linux/drivers/char/pc_keyb.c
  32. *
  33. *
  34. */
  35. #include <common.h>
  36. #include <asm/processor.h>
  37. #include <devices.h>
  38. #include "ps2kbd.h"
  39. unsigned char kbd_read_status(void);
  40. unsigned char kbd_read_input(void);
  41. void kbd_send_data(unsigned char data);
  42. void i8259_mask_irq(unsigned int irq);
  43. void i8259_unmask_irq(unsigned int irq);
  44. /* used only by send_data - set by keyboard_interrupt */
  45. #undef KBG_DEBUG
  46. #ifdef KBG_DEBUG
  47. #define PRINTF(fmt,args...) printf (fmt ,##args)
  48. #else
  49. #define PRINTF(fmt,args...)
  50. #endif
  51. #define KBD_STAT_KOBF 0x01
  52. #define KBD_STAT_IBF 0x02
  53. #define KBD_STAT_SYS 0x04
  54. #define KBD_STAT_CD 0x08
  55. #define KBD_STAT_LOCK 0x10
  56. #define KBD_STAT_MOBF 0x20
  57. #define KBD_STAT_TI_OUT 0x40
  58. #define KBD_STAT_PARERR 0x80
  59. #define KBD_INIT_TIMEOUT 2000 /* Timeout in ms for initializing the keyboard */
  60. #define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
  61. #define KBD_TIMEOUT 2000 /* Timeout in ms for keyboard command acknowledge */
  62. /*
  63. * Keyboard Controller Commands
  64. */
  65. #define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
  66. #define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
  67. #define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
  68. #define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
  69. #define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
  70. #define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
  71. #define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
  72. #define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
  73. #define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
  74. #define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
  75. #define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
  76. initiated by the auxiliary device */
  77. #define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
  78. /*
  79. * Keyboard Commands
  80. */
  81. #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
  82. #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
  83. #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
  84. #define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
  85. #define KBD_CMD_RESET 0xFF /* Reset */
  86. /*
  87. * Keyboard Replies
  88. */
  89. #define KBD_REPLY_POR 0xAA /* Power on reset */
  90. #define KBD_REPLY_ACK 0xFA /* Command ACK */
  91. #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
  92. /*
  93. * Status Register Bits
  94. */
  95. #define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
  96. #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
  97. #define KBD_STAT_SELFTEST 0x04 /* Self test successful */
  98. #define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
  99. #define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
  100. #define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
  101. #define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
  102. #define KBD_STAT_PERR 0x80 /* Parity error */
  103. #define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
  104. /*
  105. * Controller Mode Register Bits
  106. */
  107. #define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
  108. #define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
  109. #define KBD_MODE_SYS 0x04 /* The system flag (?) */
  110. #define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
  111. #define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
  112. #define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
  113. #define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
  114. #define KBD_MODE_RFU 0x80
  115. #define KDB_DATA_PORT 0x60
  116. #define KDB_COMMAND_PORT 0x64
  117. #define LED_SCR 0x01 /* scroll lock led */
  118. #define LED_CAP 0x04 /* caps lock led */
  119. #define LED_NUM 0x02 /* num lock led */
  120. #define KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
  121. static volatile char kbd_buffer[KBD_BUFFER_LEN];
  122. static volatile int in_pointer = 0;
  123. static volatile int out_pointer = 0;
  124. static unsigned char num_lock = 0;
  125. static unsigned char caps_lock = 0;
  126. static unsigned char scroll_lock = 0;
  127. static unsigned char shift = 0;
  128. static unsigned char ctrl = 0;
  129. static unsigned char alt = 0;
  130. static unsigned char e0 = 0;
  131. static unsigned char leds = 0;
  132. #define DEVNAME "ps2kbd"
  133. /* Simple translation table for the keys */
  134. static unsigned char kbd_plain_xlate[] = {
  135. 0xff,0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', /* 0x00 - 0x0f */
  136. 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\r',0xff, 'a', 's', /* 0x10 - 0x1f */
  137. 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`',0xff,'\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
  138. 'b', 'n', 'm', ',', '.', '/',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
  139. 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
  140. '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
  141. '\r',0xff,0xff
  142. };
  143. static unsigned char kbd_shift_xlate[] = {
  144. 0xff,0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', /* 0x00 - 0x0f */
  145. 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\r',0xff, 'A', 'S', /* 0x10 - 0x1f */
  146. 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
  147. 'B', 'N', 'M', '<', '>', '?',0xff,0xff,0xff, ' ',0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
  148. 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
  149. '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
  150. '\r',0xff,0xff
  151. };
  152. static unsigned char kbd_ctrl_xlate[] = {
  153. 0xff,0x1b, '1',0x00, '3', '4', '5',0x1E, '7', '8', '9', '0',0x1F, '=','\b','\t', /* 0x00 - 0x0f */
  154. 0x11,0x17,0x05,0x12,0x14,0x18,0x15,0x09,0x0f,0x10,0x1b,0x1d,'\n',0xff,0x01,0x13, /* 0x10 - 0x1f */
  155. 0x04,0x06,0x08,0x09,0x0a,0x0b,0x0c, ';','\'', '~',0x00,0x1c,0x1a,0x18,0x03,0x16, /* 0x20 - 0x2f */
  156. 0x02,0x0e,0x0d, '<', '>', '?',0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x30 - 0x3f */
  157. 0xff,0xff,0xff,0xff,0xff,0xff,0xff, '7', '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
  158. '2', '3', '0', '.',0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0x50 - 0x5F */
  159. '\r',0xff,0xff
  160. };
  161. /******************************************************************
  162. * Init
  163. ******************************************************************/
  164. int isa_kbd_init(void)
  165. {
  166. char* result;
  167. result=kbd_initialize();
  168. if (result != NULL)
  169. {
  170. result = kbd_initialize();
  171. }
  172. if(result==NULL) {
  173. printf("AT Keyboard initialized\n");
  174. irq_install_handler(KBD_INTERRUPT, (interrupt_handler_t *)kbd_interrupt, NULL);
  175. return (1);
  176. }
  177. else {
  178. printf("%s\n",result);
  179. return (-1);
  180. }
  181. }
  182. #ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
  183. extern int overwrite_console (void);
  184. #else
  185. int overwrite_console (void)
  186. {
  187. return (0);
  188. }
  189. #endif
  190. int drv_isa_kbd_init (void)
  191. {
  192. int error;
  193. device_t kbddev ;
  194. char *stdinname = getenv ("stdin");
  195. if(isa_kbd_init()==-1)
  196. return -1;
  197. memset (&kbddev, 0, sizeof(kbddev));
  198. strcpy(kbddev.name, DEVNAME);
  199. kbddev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
  200. kbddev.putc = NULL ;
  201. kbddev.puts = NULL ;
  202. kbddev.getc = kbd_getc ;
  203. kbddev.tstc = kbd_testc ;
  204. error = device_register (&kbddev);
  205. if(error==0) {
  206. /* check if this is the standard input device */
  207. if(strcmp(stdinname,DEVNAME)==0) {
  208. /* reassign the console */
  209. if(overwrite_console()) {
  210. return 1;
  211. }
  212. error=console_assign(stdin,DEVNAME);
  213. if(error==0)
  214. return 1;
  215. else
  216. return error;
  217. }
  218. return 1;
  219. }
  220. return error;
  221. }
  222. /******************************************************************
  223. * Queue handling
  224. ******************************************************************/
  225. /* puts character in the queue and sets up the in and out pointer */
  226. void kbd_put_queue(char data)
  227. {
  228. if((in_pointer+1)==KBD_BUFFER_LEN) {
  229. if(out_pointer==0) {
  230. return; /* buffer full */
  231. } else{
  232. in_pointer=0;
  233. }
  234. } else {
  235. if((in_pointer+1)==out_pointer)
  236. return; /* buffer full */
  237. in_pointer++;
  238. }
  239. kbd_buffer[in_pointer]=data;
  240. return;
  241. }
  242. /* test if a character is in the queue */
  243. int kbd_testc(void)
  244. {
  245. if(in_pointer==out_pointer)
  246. return(0); /* no data */
  247. else
  248. return(1);
  249. }
  250. /* gets the character from the queue */
  251. int kbd_getc(void)
  252. {
  253. char c;
  254. while(in_pointer==out_pointer);
  255. if((out_pointer+1)==KBD_BUFFER_LEN)
  256. out_pointer=0;
  257. else
  258. out_pointer++;
  259. c=kbd_buffer[out_pointer];
  260. return (int)c;
  261. }
  262. /* set LEDs */
  263. void kbd_set_leds(void)
  264. {
  265. if(caps_lock==0)
  266. leds&=~LED_CAP; /* switch caps_lock off */
  267. else
  268. leds|=LED_CAP; /* switch on LED */
  269. if(num_lock==0)
  270. leds&=~LED_NUM; /* switch LED off */
  271. else
  272. leds|=LED_NUM; /* switch on LED */
  273. if(scroll_lock==0)
  274. leds&=~LED_SCR; /* switch LED off */
  275. else
  276. leds|=LED_SCR; /* switch on LED */
  277. kbd_send_data(KBD_CMD_SET_LEDS);
  278. kbd_send_data(leds);
  279. }
  280. void handle_keyboard_event(unsigned char scancode)
  281. {
  282. unsigned char keycode;
  283. /* Convert scancode to keycode */
  284. PRINTF("scancode %x\n",scancode);
  285. if(scancode==0xe0) {
  286. e0=1; /* special charakters */
  287. return;
  288. }
  289. if(e0==1) {
  290. e0=0; /* delete flag */
  291. if(!( ((scancode&0x7F)==0x38)|| /* the right ctrl key */
  292. ((scancode&0x7F)==0x1D)|| /* the right alt key */
  293. ((scancode&0x7F)==0x35)|| /* the right '/' key */
  294. ((scancode&0x7F)==0x1C)|| /* the right enter key */
  295. ((scancode)==0x48)|| /* arrow up */
  296. ((scancode)==0x50)|| /* arrow down */
  297. ((scancode)==0x4b)|| /* arrow left */
  298. ((scancode)==0x4d))) /* arrow right */
  299. /* we swallow unknown e0 codes */
  300. return;
  301. }
  302. /* special cntrl keys */
  303. switch(scancode)
  304. {
  305. case 0x48:
  306. kbd_put_queue(27);
  307. kbd_put_queue(91);
  308. kbd_put_queue('A');
  309. return;
  310. case 0x50:
  311. kbd_put_queue(27);
  312. kbd_put_queue(91);
  313. kbd_put_queue('B');
  314. return;
  315. case 0x4b:
  316. kbd_put_queue(27);
  317. kbd_put_queue(91);
  318. kbd_put_queue('D');
  319. return;
  320. case 0x4D:
  321. kbd_put_queue(27);
  322. kbd_put_queue(91);
  323. kbd_put_queue('C');
  324. return;
  325. case 0x58: /* F12 key */
  326. if (ctrl == 1)
  327. {
  328. extern int console_changed;
  329. setenv("stdin", DEVNAME);
  330. setenv("stdout", "vga");
  331. console_changed = 1;
  332. }
  333. return;
  334. case 0x2A:
  335. case 0x36: /* shift pressed */
  336. shift=1;
  337. return; /* do nothing else */
  338. case 0xAA:
  339. case 0xB6: /* shift released */
  340. shift=0;
  341. return; /* do nothing else */
  342. case 0x38: /* alt pressed */
  343. alt=1;
  344. return; /* do nothing else */
  345. case 0xB8: /* alt released */
  346. alt=0;
  347. return; /* do nothing else */
  348. case 0x1d: /* ctrl pressed */
  349. ctrl=1;
  350. return; /* do nothing else */
  351. case 0x9d: /* ctrl released */
  352. ctrl=0;
  353. return; /* do nothing else */
  354. case 0x46: /* scrollock pressed */
  355. scroll_lock=~scroll_lock;
  356. kbd_set_leds();
  357. return; /* do nothing else */
  358. case 0x3A: /* capslock pressed */
  359. caps_lock=~caps_lock;
  360. kbd_set_leds();
  361. return;
  362. case 0x45: /* numlock pressed */
  363. num_lock=~num_lock;
  364. kbd_set_leds();
  365. return;
  366. case 0xC6: /* scroll lock released */
  367. case 0xC5: /* num lock released */
  368. case 0xBA: /* caps lock released */
  369. return; /* just swallow */
  370. }
  371. if((scancode&0x80)==0x80) /* key released */
  372. return;
  373. /* now, decide which table we need */
  374. if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
  375. PRINTF("unkown scancode %X\n",scancode);
  376. return; /* swallow it */
  377. }
  378. /* setup plain code first */
  379. keycode=kbd_plain_xlate[scancode];
  380. if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
  381. if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
  382. PRINTF("unkown caps-locked scancode %X\n",scancode);
  383. return; /* swallow it */
  384. }
  385. keycode=kbd_shift_xlate[scancode];
  386. if(keycode<'A') { /* we only want the alphas capital */
  387. keycode=kbd_plain_xlate[scancode];
  388. }
  389. }
  390. if(shift==1) { /* shift overwrites caps_lock */
  391. if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
  392. PRINTF("unkown shifted scancode %X\n",scancode);
  393. return; /* swallow it */
  394. }
  395. keycode=kbd_shift_xlate[scancode];
  396. }
  397. if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
  398. if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
  399. PRINTF("unkown ctrl scancode %X\n",scancode);
  400. return; /* swallow it */
  401. }
  402. keycode=kbd_ctrl_xlate[scancode];
  403. }
  404. /* check if valid keycode */
  405. if(keycode==0xff) {
  406. PRINTF("unkown scancode %X\n",scancode);
  407. return; /* swallow unknown codes */
  408. }
  409. kbd_put_queue(keycode);
  410. PRINTF("%x\n",keycode);
  411. }
  412. /*
  413. * This reads the keyboard status port, and does the
  414. * appropriate action.
  415. *
  416. */
  417. unsigned char handle_kbd_event(void)
  418. {
  419. unsigned char status = kbd_read_status();
  420. unsigned int work = 10000;
  421. while ((--work > 0) && (status & KBD_STAT_OBF)) {
  422. unsigned char scancode;
  423. scancode = kbd_read_input();
  424. /* Error bytes must be ignored to make the
  425. Synaptics touchpads compaq use work */
  426. /* Ignore error bytes */
  427. if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
  428. {
  429. if (status & KBD_STAT_MOUSE_OBF)
  430. ; /* not supported: handle_mouse_event(scancode); */
  431. else
  432. handle_keyboard_event(scancode);
  433. }
  434. status = kbd_read_status();
  435. }
  436. if (!work)
  437. PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
  438. return status;
  439. }
  440. /******************************************************************************
  441. * Lowlevel Part of keyboard section
  442. */
  443. unsigned char kbd_read_status(void)
  444. {
  445. return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
  446. }
  447. unsigned char kbd_read_input(void)
  448. {
  449. return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
  450. }
  451. void kbd_write_command(unsigned char cmd)
  452. {
  453. out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
  454. }
  455. void kbd_write_output(unsigned char data)
  456. {
  457. out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
  458. }
  459. int kbd_read_data(void)
  460. {
  461. int val;
  462. unsigned char status;
  463. val=-1;
  464. status = kbd_read_status();
  465. if (status & KBD_STAT_OBF) {
  466. val = kbd_read_input();
  467. if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
  468. val = -2;
  469. }
  470. return val;
  471. }
  472. int kbd_wait_for_input(void)
  473. {
  474. unsigned long timeout;
  475. int val;
  476. timeout = KBD_TIMEOUT;
  477. val=kbd_read_data();
  478. while(val < 0)
  479. {
  480. if(timeout--==0)
  481. return -1;
  482. udelay(1000);
  483. val=kbd_read_data();
  484. }
  485. return val;
  486. }
  487. int kb_wait(void)
  488. {
  489. unsigned long timeout = KBC_TIMEOUT * 10;
  490. do {
  491. unsigned char status = handle_kbd_event();
  492. if (!(status & KBD_STAT_IBF))
  493. return 0; /* ok */
  494. udelay(1000);
  495. timeout--;
  496. } while (timeout);
  497. return 1;
  498. }
  499. void kbd_write_command_w(int data)
  500. {
  501. if(kb_wait())
  502. PRINTF("timeout in kbd_write_command_w\n");
  503. kbd_write_command(data);
  504. }
  505. void kbd_write_output_w(int data)
  506. {
  507. if(kb_wait())
  508. PRINTF("timeout in kbd_write_output_w\n");
  509. kbd_write_output(data);
  510. }
  511. void kbd_send_data(unsigned char data)
  512. {
  513. unsigned char status;
  514. i8259_mask_irq(KBD_INTERRUPT); /* disable interrupt */
  515. kbd_write_output_w(data);
  516. status = kbd_wait_for_input();
  517. if (status == KBD_REPLY_ACK)
  518. i8259_unmask_irq(KBD_INTERRUPT); /* enable interrupt */
  519. }
  520. char * kbd_initialize(void)
  521. {
  522. int status;
  523. in_pointer = 0; /* delete in Buffer */
  524. out_pointer = 0;
  525. /*
  526. * Test the keyboard interface.
  527. * This seems to be the only way to get it going.
  528. * If the test is successful a x55 is placed in the input buffer.
  529. */
  530. kbd_write_command_w(KBD_CCMD_SELF_TEST);
  531. if (kbd_wait_for_input() != 0x55)
  532. return "Kbd: failed self test";
  533. /*
  534. * Perform a keyboard interface test. This causes the controller
  535. * to test the keyboard clock and data lines. The results of the
  536. * test are placed in the input buffer.
  537. */
  538. kbd_write_command_w(KBD_CCMD_KBD_TEST);
  539. if (kbd_wait_for_input() != 0x00)
  540. return "Kbd: interface failed self test";
  541. /*
  542. * Enable the keyboard by allowing the keyboard clock to run.
  543. */
  544. kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
  545. status = kbd_wait_for_input();
  546. /*
  547. * Reset keyboard. If the read times out
  548. * then the assumption is that no keyboard is
  549. * plugged into the machine.
  550. * This defaults the keyboard to scan-code set 2.
  551. *
  552. * Set up to try again if the keyboard asks for RESEND.
  553. */
  554. do {
  555. kbd_write_output_w(KBD_CMD_RESET);
  556. status = kbd_wait_for_input();
  557. if (status == KBD_REPLY_ACK)
  558. break;
  559. if (status != KBD_REPLY_RESEND)
  560. {
  561. PRINTF("status: %X\n",status);
  562. return "Kbd: reset failed, no ACK";
  563. }
  564. } while (1);
  565. if (kbd_wait_for_input() != KBD_REPLY_POR)
  566. return "Kbd: reset failed, no POR";
  567. /*
  568. * Set keyboard controller mode. During this, the keyboard should be
  569. * in the disabled state.
  570. *
  571. * Set up to try again if the keyboard asks for RESEND.
  572. */
  573. do {
  574. kbd_write_output_w(KBD_CMD_DISABLE);
  575. status = kbd_wait_for_input();
  576. if (status == KBD_REPLY_ACK)
  577. break;
  578. if (status != KBD_REPLY_RESEND)
  579. return "Kbd: disable keyboard: no ACK";
  580. } while (1);
  581. kbd_write_command_w(KBD_CCMD_WRITE_MODE);
  582. kbd_write_output_w(KBD_MODE_KBD_INT
  583. | KBD_MODE_SYS
  584. | KBD_MODE_DISABLE_MOUSE
  585. | KBD_MODE_KCC);
  586. /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
  587. kbd_write_command_w(KBD_CCMD_READ_MODE);
  588. if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
  589. /*
  590. * If the controller does not support conversion,
  591. * Set the keyboard to scan-code set 1.
  592. */
  593. kbd_write_output_w(0xF0);
  594. kbd_wait_for_input();
  595. kbd_write_output_w(0x01);
  596. kbd_wait_for_input();
  597. }
  598. kbd_write_output_w(KBD_CMD_ENABLE);
  599. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  600. return "Kbd: enable keyboard: no ACK";
  601. /*
  602. * Finally, set the typematic rate to maximum.
  603. */
  604. kbd_write_output_w(KBD_CMD_SET_RATE);
  605. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  606. return "Kbd: Set rate: no ACK";
  607. kbd_write_output_w(0x00);
  608. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  609. return "Kbd: Set rate: no ACK";
  610. return NULL;
  611. }
  612. void kbd_interrupt(void)
  613. {
  614. handle_kbd_event();
  615. }