1/* $NetBSD: i8042.c,v 1.5 2005/12/11 12:19:05 christos 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.5 2005/12/11 12:19:05 christos 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*/ 79int 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*/ 109void 110i8042_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*/ 150int 151i8042_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*/ 199int 200i8042_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*/ 266int 267i8042_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 contoller 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 /* Successfull 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