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