xref: /netbsd/sys/arch/shark/shark/i8042.c (revision bf9ec67e)
1 /*	$NetBSD: i8042.c,v 1.1 2002/02/10 01:58:04 thorpej Exp $	*/
2 
3 /*
4  * Copyright 1997
5  * Digital Equipment Corporation. All rights reserved.
6  *
7  * This software is furnished under license and may be used and
8  * copied only in accordance with the following terms and conditions.
9  * Subject to these conditions, you may download, copy, install,
10  * use, modify and distribute this software in source and/or binary
11  * form. No title or ownership is transferred hereby.
12  *
13  * 1) Any source code used, modified or distributed must reproduce
14  *    and retain this copyright notice and list of conditions as
15  *    they appear in the source file.
16  *
17  * 2) No right is granted to use any trade name, trademark, or logo of
18  *    Digital Equipment Corporation. Neither the "Digital Equipment
19  *    Corporation" name nor any trademark or logo of Digital Equipment
20  *    Corporation may be used to endorse or promote products derived
21  *    from this software without the prior written permission of
22  *    Digital Equipment Corporation.
23  *
24  * 3) This software is provided "AS-IS" and any express or implied
25  *    warranties, including but not limited to, any implied warranties
26  *    of merchantability, fitness for a particular purpose, or
27  *    non-infringement are disclaimed. In no event shall DIGITAL be
28  *    liable for any damages whatsoever, and in particular, DIGITAL
29  *    shall not be liable for special, indirect, consequential, or
30  *    incidental damages or damages for lost profits, loss of
31  *    revenue or loss of use, whether such damages arise in contract,
32  *    negligence, tort, under statute, in equity, at law or otherwise,
33  *    even if advised of the possibility of such damage.
34  */
35 
36 /*
37 **++
38 **
39 **  FACILITY:
40 **
41 **    8042 controller functions.
42 **
43 **  ABSTRACT:
44 **
45 **    This file contains routines to access the 8042 keyboard microprocessor.
46 **    It hopefully allows a level of abstraction which will permit
47 **    simplification of keyboard and mouse drivers which have to share the
48 **    same registers when talking to the 8042.
49 **
50 **  AUTHORS:
51 **
52 **    John Court, Digital Equipment Corporation.
53 **
54 **  CREATION DATE:
55 **
56 **    16/4/1997
57 **
58 **--
59 */
60 #include <sys/param.h>
61 #include <sys/kernel.h>
62 #include <sys/systm.h>
63 #include <machine/kerndebug.h>
64 
65 #include <machine/bus.h>
66 #include <shark/shark/i8042reg.h>
67 /*
68 ** Global variables
69 */
70 
71 /* Variable to control which debugs printed.  No debug code gets
72 ** built into this driver unless KERN_DEBUG is defined in the config
73 ** file.
74 */
75 int i8042debug = KERN_DEBUG_WARNING | KERN_DEBUG_ERROR;
76 
77 /*
78 **++
79 **  FUNCTIONAL DESCRIPTION
80 **
81 **     i8042_flush
82 **
83 **     This routine waits until the input and output buffers
84 **     on the 8042 are empty, discarding any characters
85 **     in the input buffer.
86 **
87 **  FORMAL PARAMETERS:
88 **
89 **     iot    I/O tag for the mapped register space
90 **     ioh    I/O handle for the mapped register space
91 **
92 **  IMPLICIT INPUTS:
93 **
94 **     none.
95 **
96 **  IMPLICIT OUTPUTS:
97 **
98 **     none.
99 **
100 **  FUNCTION VALUE:
101 **
102 **     none.
103 **--
104 */
105 void
106 i8042_flush( bus_space_tag_t iot,
107              bus_space_handle_t ioh)
108 {
109     /* Wait until input and output buffers are empty */
110     (void)i8042_wait_output(iot,ioh);
111     while (i8042_wait_input(iot,ioh,I8042_ANY_DATA))
112     {
113         (void)bus_space_read_1(iot, ioh, KBDATAPO);
114     }
115     return;
116 } /* End i8042_flush */
117 
118 /*
119 **++
120 **  FUNCTIONAL DESCRIPTION:
121 **
122 **     i8042_wait_output
123 **
124 **     This function is boring.  It just waits until output
125 **     can be sent to the 8042 buffer.
126 **
127 **  FORMAL PARAMETERS:
128 **
129 **     iot    I/O tag for the mapped register space
130 **     ioh    I/O handle for the mapped register space
131 **
132 **  IMPLICIT INPUTS:
133 **
134 **     none.
135 **
136 **  IMPLICIT OUTPUTS:
137 **
138 **     none.
139 **
140 **  FUNCTION VALUE:
141 **
142 **   0 - Timed out waiting to send output.
143 **   1 - Can now send output to the 8042.
144 **--
145 */
146 int
147 i8042_wait_output( bus_space_tag_t    iot,
148                    bus_space_handle_t ioh )
149 {
150     register u_int     count;
151     int                retValue = 0;
152 
153     for (count = I8042_WAIT_THRESHOLD; count; count--)
154     {
155         /* Check if output buffer empty */
156         if ((bus_space_read_1(iot, ioh, KBSTATPO) & KBS_IBF) == 0)
157         {
158             retValue = 1;
159 	    break;
160         }
161     }
162     return (retValue);
163 } /* End i8042_wait_output */
164 
165 
166 /*
167 **++
168 **  FUNCTIONAL DESCRIPTION:
169 **
170 **     i8042_wait_input
171 **
172 **     This function waits until input is available to be read from
173 **     the 8042 output buffer.
174 **
175 **  FORMAL PARAMETERS:
176 **
177 **     iot    I/O tag for the mapped register space
178 **     ioh    I/O handle for the mapped register space
179 **     type   Type of input to wait for (auxiliary, keyboard or any).
180 **
181 **  IMPLICIT INPUTS:
182 **
183 **     none.
184 **
185 **  IMPLICIT OUTPUTS:
186 **
187 **     none.
188 **
189 **  FUNCTION VALUE:
190 **
191 **   0 - Timed out waiting for input
192 **   1 - Input available to be read
193 **--
194 */
195 int
196 i8042_wait_input(bus_space_tag_t    iot,
197                  bus_space_handle_t ioh,
198                  u_char             type)
199 {
200     register u_int     count;
201     register u_char    status;
202     int                retValue = 0;
203 
204     for (count = I8042_WAIT_THRESHOLD; count; count--)
205     {
206         /* Check if there is a character to be read */
207         status = bus_space_read_1(iot, ioh, KBSTATPO);
208         if (((status & type) == type) ||
209             ((type == I8042_ANY_DATA) && (status & KBS_DIB)))
210         {
211             retValue = 1;
212 	    break;
213         }
214 	I8042_DELAY;
215     }
216     KERN_DEBUG(i8042debug, KERN_DEBUG_INFO,
217 	       ("i8042_wait_input: returning : %s\n\tlast status : 0x%x\n",
218 		retValue ? "Found Data" : "Exceeded Wait Threshold",
219 		status));
220 
221     return (retValue);
222 } /* End i8042_wait_input */
223 
224 
225 /*
226 **++
227 **  FUNCTIONAL DESCRIPTION:
228 **
229 **     i8042_cmd
230 **
231 **    This function sends a command to the 8042 device or the auxiliary
232 **    device hanging off it. The command is retried a
233 **    number of times if a resend response is received.
234 **
235 **  FORMAL PARAMETERS:
236 **
237 **     iot               I/O tag for the mapped register space
238 **     ioh               I/O handle for the mapped register space
239 **     auxCmd            An indication of what type of command this is.
240 **     checkResponse     A switch indicating whether to read a result after
241 **                       executing the command and compare ot with
242 **                       "responseExpected".
243 **     responseExpected  Only valid if "checkResponse" is non-zero.  This
244 **                       is compared with the data value read after the
245 **                       command has been executed.
246 **     value             Command to send to the device selected by "auxCmd".
247 **
248 **  IMPLICIT INPUTS:
249 **
250 **     none.
251 **
252 **  IMPLICIT OUTPUTS:
253 **
254 **     none.
255 **
256 **  FUNCTION VALUE:
257 **
258 **   0 - Failed to send command or receive acknowledgement for it
259 **   1 - Command sent and responded to successfully.
260 **--
261 */
262 int
263 i8042_cmd(bus_space_tag_t    iot,
264           bus_space_handle_t ioh,
265           u_char             auxCmd,
266           u_char             checkResponse,
267           u_char             responseExpected,
268           u_char             value)
269 {
270     u_int              retries;
271     register u_char    c = NULL;
272     int                status;
273 
274     /* Assume failure
275     */
276     status = 0;
277 
278     for (retries = I8042_RETRIES;
279          i8042_wait_output(iot,ioh) && retries;
280          retries--)
281     {
282         if (auxCmd == I8042_AUX_CMD)
283         {
284             /* Setup to write command to auxiliary device
285             */
286             bus_space_write_1(iot, ioh, KBCMDPO, KBC_AUXWRITE);
287             /* Write actual command to selected device
288             */
289             if (i8042_wait_output(iot,ioh))
290             {
291                 bus_space_write_1(iot, ioh, KBOUTPO, value);
292             }
293             else
294             {
295                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
296                      ("i8042_cmd: failed aux device request of 0x%x\n",
297                       value));
298                 break;
299             }
300         }
301         else if (auxCmd == I8042_CMD)
302         {
303             /* Write command to keyboard controller requested.
304             */
305             bus_space_write_1(iot, ioh, KBCMDPO, value);
306         }
307         else if (auxCmd == I8042_KBD_CMD)
308         {
309             /* Write a command to actual keyboard H/W device.
310             */
311             bus_space_write_1(iot, ioh, KBOUTPO, value);
312         }
313         else if (auxCmd == I8042_WRITE_CCB)
314         {
315             /* Write 8042 Controller Command Byte requested
316             */
317             bus_space_write_1(iot, ioh, KBCMDPO, K_LDCMDBYTE);
318             /* Write actual command to selected device
319             */
320             if (i8042_wait_output(iot,ioh))
321             {
322                 bus_space_write_1(iot, ioh, KBOUTPO, value);
323             }
324             else
325             {
326                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
327                            ("i8042_cmd: failed contoller command byte "
328                             "write request of 0x%x\n",
329                             value));
330                 break;
331             }
332         }
333         else
334         {
335             KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
336                        ("i8042_cmd: invalid device identifier of 0x%x\n",
337                         auxCmd));
338             break;
339         }
340 
341         /* Does anyone need to check the result of this command ?
342         */
343         if (checkResponse == I8042_CHECK_RESPONSE)
344         {
345             /* get response from device and check if
346             ** successfull.
347             */
348             if (i8042_wait_input(iot,ioh,I8042_ANY_DATA))
349             {
350                 c = bus_space_read_1(iot, ioh, KBDATAPO);
351                 if (c == responseExpected)
352                 {
353                     /* Successfull command so we're outa here
354                     */
355                     status = 1;
356                     break;
357                 }
358                 else if (c == KBR_RESEND)
359                 {
360                     /* Hmm response was try again so lets.
361                     */
362                     KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
363                                ("i8042_cmd: resend of 0x%x\n", value));
364                 }
365                 else
366                 {
367                     /* response was nothing we expected so we're
368                     ** outa here.
369                     */
370                     KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
371                          ("i8042_cmd: unexpected response 0x%x\n", c));
372                     break;
373                 }
374             } /* End If able to get response from device */
375             else
376             {
377                 /* Timmed out waiting for a response .... maybe we
378                 ** weren't meant to get one ??
379                 */
380                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
381                            ("i8042_cmd: no response to command 0x%x\n",
382                             value));
383                 break;
384             }
385         } /* End if need to check for response */
386         else
387         {
388             /* Not requested to check for response and we did send the
389             ** command so I guess we were successfull :-)
390             */
391             status = 1;
392             break;
393         }
394     } /* End loop for several retries if needed a response */
395     /* Diagnostic output on command value, result and status returned
396     */
397     KERN_DEBUG(i8042debug, KERN_DEBUG_INFO,
398                ("i8042_cmd: %s Device : Command 0x%x: %s:\n\t "
399                 "Check Value 0x%x: "
400                 "Response Value 0x%x: Status being returned 0x%x\n",
401                 (auxCmd == I8042_AUX_CMD) ? "Auxiliary" : "Keyboard",
402                 value,
403                 (checkResponse == I8042_CHECK_RESPONSE) ?
404                          "Checking response" : "NOT checking response",
405                 responseExpected, c, status));
406 
407     return (status);
408 } /* End i8042_cmd */
409 
410 
411