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