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