diff options
author | Seth Goldberg <Seth.Goldberg@Sun.COM> | 2008-09-24 17:10:50 -0700 |
---|---|---|
committer | Seth Goldberg <Seth.Goldberg@Sun.COM> | 2008-09-24 17:10:50 -0700 |
commit | fbac63660cc7a6ccfe2042916ea594ac07d63fcb (patch) | |
tree | d0b82b1a773523b4f49e3dd3f5d71125632d90d6 /usr/src | |
parent | 0bb073995ac5a95bd35f2dd790df1ea3d8c2d507 (diff) | |
download | illumos-joyent-fbac63660cc7a6ccfe2042916ea594ac07d63fcb.tar.gz |
6751793 i8042 spews warnings if keyboard is not connected on DEBUG kernel
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/i8042.c | 119 | ||||
-rw-r--r-- | usr/src/uts/common/io/kb8042/kb8042.c | 16 |
2 files changed, 92 insertions, 43 deletions
diff --git a/usr/src/uts/common/io/i8042.c b/usr/src/uts/common/io/i8042.c index 9500395225..4e729bc4cb 100644 --- a/usr/src/uts/common/io/i8042.c +++ b/usr/src/uts/common/io/i8042.c @@ -154,7 +154,8 @@ struct i8042_port { */ boolean_t intercept_complete; boolean_t intr_intercept_enabled; - uint8_t intercept; + uint8_t intercept[2]; + uint8_t intercepted_byte; kcondvar_t intercept_cv; kmutex_t intercept_mutex; }; @@ -264,6 +265,10 @@ boolean_t i8042_force_interrupt_mode = B_FALSE; int max_wait_iterations = MAX_WAIT_ITERATIONS; +#ifdef DEBUG +int i8042_debug = 0; +#endif + /* * function prototypes for bus ops routines: */ @@ -1060,7 +1065,9 @@ i8042_intr(caddr_t arg) * that will signal the waiter, then exit the interrupt handler * without passing the byte to the child's interrupt handler. */ - if (port->intr_intercept_enabled && port->intercept == byte) { + if (port->intr_intercept_enabled && (port->intercept[0] == byte || + port->intercept[1] == byte)) { + port->intercepted_byte = byte; port->intr_intercept_enabled = B_FALSE; (void) ddi_intr_trigger_softint(global->intercept_sih, port); mutex_exit(&global->i8042_mutex); @@ -1304,6 +1311,60 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr) } /* + * Send the byte specified and wait for a reply -- either the retry response, + * or another response (assumed to be an acknowledgement). If the retry + * response is received within the timeout period, the initial byte is resent + * to the 8042. + */ +static int +i8042_do_intercept(ddi_acc_impl_t *handlep, struct i8042_port *port, + uint8_t *oaddr, uint8_t byte, uint8_t retry_response) +{ + int timedout = 0; + clock_t tval; + + /* + * Intercept the command response so that the 8042 interrupt handler + * does not call the port's interrupt handler. + */ + port->intercept_complete = B_FALSE; + port->intr_intercept_enabled = B_TRUE; + + /* Maximum time to wait: */ + tval = ddi_get_lbolt() + drv_usectohz(MAX_WAIT_ITERATIONS * + USECS_PER_WAIT); + + do { + i8042_put8_nolock(handlep, oaddr, byte); + + /* + * Wait for the command response + */ + while (!port->intercept_complete) { + if (cv_timedwait(&port->intercept_cv, + &port->intercept_mutex, tval) < 0 && + !port->intercept_complete) { + timedout = 1; + break; + } + } + + /* + * If the intercepted byte is the retry response, keep retrying + * until we time out, or until the success response is received. + */ + if (port->intercept_complete && + port->intercepted_byte == retry_response) + port->intercept_complete = B_FALSE; + + } while (!timedout && !port->intercept_complete); + + port->intr_intercept_enabled = B_FALSE; + + return (timedout); +} + +/* * The _rep_put8() operation is designed to allow child drivers to * execute commands that have responses or that have responses plus an * option byte. These commands need to be executed atomically with respect @@ -1311,12 +1372,14 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr) * when other child devices intersperse their commands while a command * to a different 8042-connected device is in flight). * - * haddr points to a buffer with either 2 or 3 bytes. Two bytes if a - * command is being sent for which we expect a response code (this function - * blocks until we either read that response code or until a timer expires). - * Three if the command requires a response and then an option byte. The - * option byte is only sent iff the response code expected is received before - * the timeout. + * haddr points to a buffer with either 3 or 4 bytes. Three bytes if a + * command (byte 0) is being sent for which we expect a response code (byte 1) + * (this function blocks until we either read a response code (or the retry + * code (byte 2)) or until a timer expires). + * Four if the command (byte 0) requires a response (byte 1) and then an + * option byte (byte 3). The option byte is only sent iff the response code + * expected is received before the timeout. As with the 3-byte request, byte + * 2 is the retry response. * * While this function may technically called in interrupt context, it may * block (depending on the IPL of the i8042 interrupt handler vs. the handler @@ -1337,7 +1400,6 @@ i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, uint8_t *daddr, int timedout = 0; boolean_t polled; ddi_acc_hdl_t *h; - clock_t tval; h = (ddi_acc_hdl_t *)handlep; @@ -1367,7 +1429,7 @@ i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, uint8_t *daddr, * Only support commands with MAX one parameter. The format of the * buffer supplied must be { <CMD>, <CMD_OK_RESPONSE>[, <PARAMETER>] } */ - if (repcount != 2 && repcount != 3) { + if (repcount != 3 && repcount != 4) { #ifdef DEBUG prom_printf("WARNING: i8042_rep_put8(): Invalid repetition " "count (%d)\n", (int)repcount); @@ -1391,42 +1453,27 @@ i8042_rep_put8(ddi_acc_impl_t *handlep, uint8_t *haddr, uint8_t *daddr, mutex_enter(&global->i8042_out_mutex); } - mutex_enter(&port->intercept_mutex); + /* Initialize the response and retry bytes from the caller */ + port->intercept[0] = haddr[1]; + port->intercept[1] = haddr[2]; - /* - * Intercept the command response so that the 8042 interrupt handler - * does not call the port's interrupt handler. - */ - port->intercept = haddr[1]; - port->intercept_complete = B_FALSE; - port->intr_intercept_enabled = B_TRUE; + mutex_enter(&port->intercept_mutex); - i8042_put8_nolock(handlep, oaddr, haddr[0]); + timedout = i8042_do_intercept(handlep, port, oaddr, haddr[0], haddr[2]); /* - * Wait for the command response + * If the first byte was processed before the timeout period, and + * there's an option byte, send it now. */ - tval = ddi_get_lbolt() + drv_usectohz(MAX_WAIT_ITERATIONS * - USECS_PER_WAIT); - - while (!port->intercept_complete) { - if (cv_timedwait(&port->intercept_cv, &port->intercept_mutex, - tval) < 0 && !port->intercept_complete) { - timedout = 1; - break; - } + if (!timedout && repcount == 4) { + timedout = i8042_do_intercept(handlep, port, oaddr, haddr[3], + haddr[2]); } - port->intr_intercept_enabled = B_FALSE; - mutex_exit(&port->intercept_mutex); - if (!timedout && repcount == 3) { - i8042_put8_nolock(handlep, oaddr, haddr[2]); - } - #ifdef DEBUG - if (timedout) + if (timedout && i8042_debug) prom_printf("WARNING: i8042_rep_put8(): timed out waiting for " "command response\n"); #endif diff --git a/usr/src/uts/common/io/kb8042/kb8042.c b/usr/src/uts/common/io/kb8042/kb8042.c index d8485567bf..819414838c 100644 --- a/usr/src/uts/common/io/kb8042/kb8042.c +++ b/usr/src/uts/common/io/kb8042/kb8042.c @@ -234,7 +234,7 @@ struct dev_ops kb8042_ops = { &cb_kb8042_ops, /* devo_cb_ops */ (struct bus_ops *)NULL, /* devo_bus_ops */ NULL, /* devo_power */ - ddi_quiesce_not_needed, /* devo_quiesce */ + ddi_quiesce_not_needed, /* devo_quiesce */ }; @@ -1325,7 +1325,7 @@ kb8042_streams_setled(struct kbtrans_hardware *hw, int led_state) static void kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled) { - uint8_t led_cmd[3]; + uint8_t led_cmd[4]; /* * KB_SET_LED and KB_ENABLE are special commands for which the nexus @@ -1344,13 +1344,14 @@ kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled) */ led_cmd[0] = KB_SET_LED; led_cmd[1] = KB_ACK; - led_cmd[2] = kb8042_xlate_leds(kb8042->leds.desired); + led_cmd[2] = KB_RESEND; + led_cmd[3] = kb8042_xlate_leds(kb8042->leds.desired); if (polled) { ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 3, 0); + kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 4, 0); } else { ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 3, 0); + kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 4, 0); } kb8042->leds.commanded = kb8042->leds.desired; @@ -1362,12 +1363,13 @@ kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled) */ led_cmd[0] = KB_ENABLE; led_cmd[1] = KB_ACK; + led_cmd[2] = KB_RESEND; if (polled) { ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 2, 0); + kb8042->addr + I8042_POLL_CMD_PLUS_PARAM, 3, 0); } else { ddi_rep_put8(kb8042->handle, &led_cmd[0], - kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 2, 0); + kb8042->addr + I8042_INT_CMD_PLUS_PARAM, 3, 0); } } else { /* All other commands use the "normal" virtual output port */ |