pc_keyb.c 5.4 KB

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