pc_keyb.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /***********************************************************************
  2. *
  3. * (C) Copyright 2004
  4. * DENX Software Engineering
  5. * Wolfgang Denk, wd@denx.de
  6. * All rights reserved.
  7. *
  8. * PS/2 keyboard driver
  9. *
  10. * Originally from linux source (drivers/char/pc_keyb.c)
  11. *
  12. ***********************************************************************/
  13. #include <common.h>
  14. #ifdef CONFIG_PS2KBD
  15. #include <keyboard.h>
  16. #include <pc_keyb.h>
  17. #undef KBG_DEBUG
  18. #ifdef KBG_DEBUG
  19. #define PRINTF(fmt,args...) printf (fmt ,##args)
  20. #else
  21. #define PRINTF(fmt,args...)
  22. #endif
  23. /*
  24. * This reads the keyboard status port, and does the
  25. * appropriate action.
  26. *
  27. */
  28. static unsigned char handle_kbd_event(void)
  29. {
  30. unsigned char status = kbd_read_status();
  31. unsigned int work = 10000;
  32. while ((--work > 0) && (status & KBD_STAT_OBF)) {
  33. unsigned char scancode;
  34. scancode = kbd_read_input();
  35. /* Error bytes must be ignored to make the
  36. Synaptics touchpads compaq use work */
  37. /* Ignore error bytes */
  38. if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
  39. if (status & KBD_STAT_MOUSE_OBF)
  40. ; /* not supported: handle_mouse_event(scancode); */
  41. else
  42. handle_scancode(scancode);
  43. }
  44. status = kbd_read_status();
  45. }
  46. if (!work)
  47. PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
  48. return status;
  49. }
  50. static int kbd_read_data(void)
  51. {
  52. int val;
  53. unsigned char status;
  54. val=-1;
  55. status = kbd_read_status();
  56. if (status & KBD_STAT_OBF) {
  57. val = kbd_read_input();
  58. if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
  59. val = -2;
  60. }
  61. return val;
  62. }
  63. static int kbd_wait_for_input(void)
  64. {
  65. unsigned long timeout;
  66. int val;
  67. timeout = KBD_TIMEOUT;
  68. val=kbd_read_data();
  69. while(val < 0) {
  70. if(timeout--==0)
  71. return -1;
  72. udelay(1000);
  73. val=kbd_read_data();
  74. }
  75. return val;
  76. }
  77. static int kb_wait(void)
  78. {
  79. unsigned long timeout = KBC_TIMEOUT * 10;
  80. do {
  81. unsigned char status = handle_kbd_event();
  82. if (!(status & KBD_STAT_IBF))
  83. return 0; /* ok */
  84. udelay(1000);
  85. timeout--;
  86. } while (timeout);
  87. return 1;
  88. }
  89. static void kbd_write_command_w(int data)
  90. {
  91. if(kb_wait())
  92. PRINTF("timeout in kbd_write_command_w\n");
  93. kbd_write_command(data);
  94. }
  95. static void kbd_write_output_w(int data)
  96. {
  97. if(kb_wait())
  98. PRINTF("timeout in kbd_write_output_w\n");
  99. kbd_write_output(data);
  100. }
  101. static void kbd_send_data(unsigned char data)
  102. {
  103. kbd_write_output_w(data);
  104. kbd_wait_for_input();
  105. }
  106. static char * kbd_initialize(void)
  107. {
  108. int status;
  109. /*
  110. * Test the keyboard interface.
  111. * This seems to be the only way to get it going.
  112. * If the test is successful a x55 is placed in the input buffer.
  113. */
  114. kbd_write_command_w(KBD_CCMD_SELF_TEST);
  115. if (kbd_wait_for_input() != 0x55)
  116. return "Kbd: failed self test";
  117. /*
  118. * Perform a keyboard interface test. This causes the controller
  119. * to test the keyboard clock and data lines. The results of the
  120. * test are placed in the input buffer.
  121. */
  122. kbd_write_command_w(KBD_CCMD_KBD_TEST);
  123. if (kbd_wait_for_input() != 0x00)
  124. return "Kbd: interface failed self test";
  125. /*
  126. * Enable the keyboard by allowing the keyboard clock to run.
  127. */
  128. kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
  129. /*
  130. * Reset keyboard. If the read times out
  131. * then the assumption is that no keyboard is
  132. * plugged into the machine.
  133. * This defaults the keyboard to scan-code set 2.
  134. *
  135. * Set up to try again if the keyboard asks for RESEND.
  136. */
  137. do {
  138. kbd_write_output_w(KBD_CMD_RESET);
  139. status = kbd_wait_for_input();
  140. if (status == KBD_REPLY_ACK)
  141. break;
  142. if (status != KBD_REPLY_RESEND) {
  143. PRINTF("status: %X\n",status);
  144. return "Kbd: reset failed, no ACK";
  145. }
  146. } while (1);
  147. if (kbd_wait_for_input() != KBD_REPLY_POR)
  148. return "Kbd: reset failed, no POR";
  149. /*
  150. * Set keyboard controller mode. During this, the keyboard should be
  151. * in the disabled state.
  152. *
  153. * Set up to try again if the keyboard asks for RESEND.
  154. */
  155. do {
  156. kbd_write_output_w(KBD_CMD_DISABLE);
  157. status = kbd_wait_for_input();
  158. if (status == KBD_REPLY_ACK)
  159. break;
  160. if (status != KBD_REPLY_RESEND)
  161. return "Kbd: disable keyboard: no ACK";
  162. } while (1);
  163. kbd_write_command_w(KBD_CCMD_WRITE_MODE);
  164. kbd_write_output_w(KBD_MODE_KBD_INT
  165. | KBD_MODE_SYS
  166. | KBD_MODE_DISABLE_MOUSE
  167. | KBD_MODE_KCC);
  168. /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
  169. kbd_write_command_w(KBD_CCMD_READ_MODE);
  170. if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
  171. /*
  172. * If the controller does not support conversion,
  173. * Set the keyboard to scan-code set 1.
  174. */
  175. kbd_write_output_w(0xF0);
  176. kbd_wait_for_input();
  177. kbd_write_output_w(0x01);
  178. kbd_wait_for_input();
  179. }
  180. kbd_write_output_w(KBD_CMD_ENABLE);
  181. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  182. return "Kbd: enable keyboard: no ACK";
  183. /*
  184. * Finally, set the typematic rate to maximum.
  185. */
  186. kbd_write_output_w(KBD_CMD_SET_RATE);
  187. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  188. return "Kbd: Set rate: no ACK";
  189. kbd_write_output_w(0x00);
  190. if (kbd_wait_for_input() != KBD_REPLY_ACK)
  191. return "Kbd: Set rate: no ACK";
  192. return NULL;
  193. }
  194. static void kbd_interrupt(void *dev_id)
  195. {
  196. handle_kbd_event();
  197. }
  198. /******************************************************************
  199. * Init
  200. ******************************************************************/
  201. int kbd_init_hw(void)
  202. {
  203. char* result;
  204. kbd_request_region();
  205. result=kbd_initialize();
  206. if (result==NULL) {
  207. PRINTF("AT Keyboard initialized\n");
  208. kbd_request_irq(kbd_interrupt);
  209. return (1);
  210. } else {
  211. printf("%s\n",result);
  212. return (-1);
  213. }
  214. }
  215. void pckbd_leds(unsigned char leds)
  216. {
  217. kbd_send_data(KBD_CMD_SET_LEDS);
  218. kbd_send_data(leds);
  219. }
  220. #endif /* CONFIG_PS2KBD */