xref: /netbsd/sys/arch/shark/shark/i8042.c (revision 3efe214b)
1 /*	$NetBSD: i8042.c,v 1.8 2021/09/16 22:19:10 andvar 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 
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: i8042.c,v 1.8 2021/09/16 22:19:10 andvar Exp $");
63 
64 #include <sys/param.h>
65 #include <sys/kernel.h>
66 #include <sys/systm.h>
67 #include <sys/bus.h>
68 #include <machine/kerndebug.h>
69 
70 #include <shark/shark/i8042reg.h>
71 /*
72 ** Global variables
73 */
74 
75 /* Variable to control which debugs printed.  No debug code gets
76 ** built into this driver unless KERN_DEBUG is defined in the config
77 ** file.
78 */
79 int i8042debug = KERN_DEBUG_WARNING | KERN_DEBUG_ERROR;
80 
81 /*
82 **++
83 **  FUNCTIONAL DESCRIPTION
84 **
85 **     i8042_flush
86 **
87 **     This routine waits until the input and output buffers
88 **     on the 8042 are empty, discarding any characters
89 **     in the input buffer.
90 **
91 **  FORMAL PARAMETERS:
92 **
93 **     iot    I/O tag for the mapped register space
94 **     ioh    I/O handle for the mapped register space
95 **
96 **  IMPLICIT INPUTS:
97 **
98 **     none.
99 **
100 **  IMPLICIT OUTPUTS:
101 **
102 **     none.
103 **
104 **  FUNCTION VALUE:
105 **
106 **     none.
107 **--
108 */
109 void
i8042_flush(bus_space_tag_t iot,bus_space_handle_t ioh)110 i8042_flush( bus_space_tag_t iot,
111              bus_space_handle_t ioh)
112 {
113     /* Wait until input and output buffers are empty */
114     (void)i8042_wait_output(iot,ioh);
115     while (i8042_wait_input(iot,ioh,I8042_ANY_DATA))
116     {
117         (void)bus_space_read_1(iot, ioh, KBDATAPO);
118     }
119     return;
120 } /* End i8042_flush */
121 
122 /*
123 **++
124 **  FUNCTIONAL DESCRIPTION:
125 **
126 **     i8042_wait_output
127 **
128 **     This function is boring.  It just waits until output
129 **     can be sent to the 8042 buffer.
130 **
131 **  FORMAL PARAMETERS:
132 **
133 **     iot    I/O tag for the mapped register space
134 **     ioh    I/O handle for the mapped register space
135 **
136 **  IMPLICIT INPUTS:
137 **
138 **     none.
139 **
140 **  IMPLICIT OUTPUTS:
141 **
142 **     none.
143 **
144 **  FUNCTION VALUE:
145 **
146 **   0 - Timed out waiting to send output.
147 **   1 - Can now send output to the 8042.
148 **--
149 */
150 int
i8042_wait_output(bus_space_tag_t iot,bus_space_handle_t ioh)151 i8042_wait_output( bus_space_tag_t    iot,
152                    bus_space_handle_t ioh )
153 {
154     register u_int     count;
155     int                retValue = 0;
156 
157     for (count = I8042_WAIT_THRESHOLD; count; count--)
158     {
159         /* Check if output buffer empty */
160         if ((bus_space_read_1(iot, ioh, KBSTATPO) & KBS_IBF) == 0)
161         {
162             retValue = 1;
163 	    break;
164         }
165     }
166     return (retValue);
167 } /* End i8042_wait_output */
168 
169 
170 /*
171 **++
172 **  FUNCTIONAL DESCRIPTION:
173 **
174 **     i8042_wait_input
175 **
176 **     This function waits until input is available to be read from
177 **     the 8042 output buffer.
178 **
179 **  FORMAL PARAMETERS:
180 **
181 **     iot    I/O tag for the mapped register space
182 **     ioh    I/O handle for the mapped register space
183 **     type   Type of input to wait for (auxiliary, keyboard or any).
184 **
185 **  IMPLICIT INPUTS:
186 **
187 **     none.
188 **
189 **  IMPLICIT OUTPUTS:
190 **
191 **     none.
192 **
193 **  FUNCTION VALUE:
194 **
195 **   0 - Timed out waiting for input
196 **   1 - Input available to be read
197 **--
198 */
199 int
i8042_wait_input(bus_space_tag_t iot,bus_space_handle_t ioh,u_char type)200 i8042_wait_input(bus_space_tag_t    iot,
201                  bus_space_handle_t ioh,
202                  u_char             type)
203 {
204     register u_int     count;
205     register u_char    status;
206     int                retValue = 0;
207 
208     for (count = I8042_WAIT_THRESHOLD; count; count--)
209     {
210         /* Check if there is a character to be read */
211         status = bus_space_read_1(iot, ioh, KBSTATPO);
212         if (((status & type) == type) ||
213             ((type == I8042_ANY_DATA) && (status & KBS_DIB)))
214         {
215             retValue = 1;
216 	    break;
217         }
218 	I8042_DELAY;
219     }
220     KERN_DEBUG(i8042debug, KERN_DEBUG_INFO,
221 	       ("i8042_wait_input: returning : %s\n\tlast status : 0x%x\n",
222 		retValue ? "Found Data" : "Exceeded Wait Threshold",
223 		status));
224 
225     return (retValue);
226 } /* End i8042_wait_input */
227 
228 
229 /*
230 **++
231 **  FUNCTIONAL DESCRIPTION:
232 **
233 **     i8042_cmd
234 **
235 **    This function sends a command to the 8042 device or the auxiliary
236 **    device hanging off it. The command is retried a
237 **    number of times if a resend response is received.
238 **
239 **  FORMAL PARAMETERS:
240 **
241 **     iot               I/O tag for the mapped register space
242 **     ioh               I/O handle for the mapped register space
243 **     auxCmd            An indication of what type of command this is.
244 **     checkResponse     A switch indicating whether to read a result after
245 **                       executing the command and compare ot with
246 **                       "responseExpected".
247 **     responseExpected  Only valid if "checkResponse" is non-zero.  This
248 **                       is compared with the data value read after the
249 **                       command has been executed.
250 **     value             Command to send to the device selected by "auxCmd".
251 **
252 **  IMPLICIT INPUTS:
253 **
254 **     none.
255 **
256 **  IMPLICIT OUTPUTS:
257 **
258 **     none.
259 **
260 **  FUNCTION VALUE:
261 **
262 **   0 - Failed to send command or receive acknowledgement for it
263 **   1 - Command sent and responded to successfully.
264 **--
265 */
266 int
i8042_cmd(bus_space_tag_t iot,bus_space_handle_t ioh,u_char auxCmd,u_char checkResponse,u_char responseExpected,u_char value)267 i8042_cmd(bus_space_tag_t    iot,
268           bus_space_handle_t ioh,
269           u_char             auxCmd,
270           u_char             checkResponse,
271           u_char             responseExpected,
272           u_char             value)
273 {
274     u_int              retries;
275     register u_char    c = 0;
276     int                status;
277 
278     /* Assume failure
279     */
280     status = 0;
281 
282     for (retries = I8042_RETRIES;
283          i8042_wait_output(iot,ioh) && retries;
284          retries--)
285     {
286         if (auxCmd == I8042_AUX_CMD)
287         {
288             /* Setup to write command to auxiliary device
289             */
290             bus_space_write_1(iot, ioh, KBCMDPO, KBC_AUXWRITE);
291             /* Write actual command to selected device
292             */
293             if (i8042_wait_output(iot,ioh))
294             {
295                 bus_space_write_1(iot, ioh, KBOUTPO, value);
296             }
297             else
298             {
299                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
300                      ("i8042_cmd: failed aux device request of 0x%x\n",
301                       value));
302                 break;
303             }
304         }
305         else if (auxCmd == I8042_CMD)
306         {
307             /* Write command to keyboard controller requested.
308             */
309             bus_space_write_1(iot, ioh, KBCMDPO, value);
310         }
311         else if (auxCmd == I8042_KBD_CMD)
312         {
313             /* Write a command to actual keyboard H/W device.
314             */
315             bus_space_write_1(iot, ioh, KBOUTPO, value);
316         }
317         else if (auxCmd == I8042_WRITE_CCB)
318         {
319             /* Write 8042 Controller Command Byte requested
320             */
321             bus_space_write_1(iot, ioh, KBCMDPO, K_LDCMDBYTE);
322             /* Write actual command to selected device
323             */
324             if (i8042_wait_output(iot,ioh))
325             {
326                 bus_space_write_1(iot, ioh, KBOUTPO, value);
327             }
328             else
329             {
330                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
331                            ("i8042_cmd: failed controller command byte "
332                             "write request of 0x%x\n",
333                             value));
334                 break;
335             }
336         }
337         else
338         {
339             KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
340                        ("i8042_cmd: invalid device identifier of 0x%x\n",
341                         auxCmd));
342             break;
343         }
344 
345         /* Does anyone need to check the result of this command ?
346         */
347         if (checkResponse == I8042_CHECK_RESPONSE)
348         {
349             /* get response from device and check if
350             ** successful.
351             */
352             if (i8042_wait_input(iot,ioh,I8042_ANY_DATA))
353             {
354                 c = bus_space_read_1(iot, ioh, KBDATAPO);
355                 if (c == responseExpected)
356                 {
357                     /* Successful command so we're outa here
358                     */
359                     status = 1;
360                     break;
361                 }
362                 else if (c == KBR_RESEND)
363                 {
364                     /* Hmm response was try again so lets.
365                     */
366                     KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
367                                ("i8042_cmd: resend of 0x%x\n", value));
368                 }
369                 else
370                 {
371                     /* response was nothing we expected so we're
372                     ** outa here.
373                     */
374                     KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
375                          ("i8042_cmd: unexpected response 0x%x\n", c));
376                     break;
377                 }
378             } /* End If able to get response from device */
379             else
380             {
381                 /* Timmed out waiting for a response .... maybe we
382                 ** weren't meant to get one ??
383                 */
384                 KERN_DEBUG(i8042debug, KERN_DEBUG_WARNING,
385                            ("i8042_cmd: no response to command 0x%x\n",
386                             value));
387                 break;
388             }
389         } /* End if need to check for response */
390         else
391         {
392             /* Not requested to check for response and we did send the
393             ** command so I guess we were successful :-)
394             */
395             status = 1;
396             break;
397         }
398     } /* End loop for several retries if needed a response */
399     /* Diagnostic output on command value, result and status returned
400     */
401     KERN_DEBUG(i8042debug, KERN_DEBUG_INFO,
402                ("i8042_cmd: %s Device : Command 0x%x: %s:\n\t "
403                 "Check Value 0x%x: "
404                 "Response Value 0x%x: Status being returned 0x%x\n",
405                 (auxCmd == I8042_AUX_CMD) ? "Auxiliary" : "Keyboard",
406                 value,
407                 (checkResponse == I8042_CHECK_RESPONSE) ?
408                          "Checking response" : "NOT checking response",
409                 responseExpected, c, status));
410 
411     return (status);
412 } /* End i8042_cmd */
413 
414 
415