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