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