From: miod Date: Wed, 25 Dec 2013 21:01:01 +0000 (+0000) Subject: Instead of deciding which iockbc port is the keyboard port, and which one is the X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=07eb5baf9161566c9a1a82efdaa97df238f53a8f;p=openbsd Instead of deciding which iockbc port is the keyboard port, and which one is the mouse port, depending upon the system time, match what the prom is doing and actually probe for a keyboard on both ports, and decide the first port with a keyboard is the keyboard port. If no keyboard is found, but a mouse is found, decide the keyboard port is the empty one. If no device is found, then we can try and pick the defaults, depending upon the system we are running on, as this used to be the case (i.e. coping with Fuel having keyboard on port 1 and mouse on port 0 when connecting devices according to the chassis' markings). This is necessary because different IO9 board revisions on Tezro come with different wirings, and we can not tell these boards apart. Discussed with "nullnilaki" (nullnilaki on gmail) who is the lucky owner of an Onyx 350 with correct wiring and a Tezro with inverted wiring. Tested on Octane and Fuel with all combinations of devices connected (mouse only, keyboard only, keyboard and mouse) in both ports, glass and serial console. XXX We probably want to allow for more pckbd attachment flexibility on non-x86 XXX platforms eventually (at least where the PS/2 slots are really independent, XXX so that we can attach pckbd to any port and better cope with human error XXX when connecting devices. --- diff --git a/sys/arch/sgi/dev/iockbc.c b/sys/arch/sgi/dev/iockbc.c index adc4f9627e2..7d11ae08f55 100644 --- a/sys/arch/sgi/dev/iockbc.c +++ b/sys/arch/sgi/dev/iockbc.c @@ -1,5 +1,6 @@ -/* $OpenBSD: iockbc.c,v 1.8 2012/08/10 17:49:31 shadchin Exp $ */ +/* $OpenBSD: iockbc.c,v 1.9 2013/12/25 21:01:01 miod Exp $ */ /* + * Copyright (c) 2013, Miodrag Vallat * Copyright (c) 2006, 2007, 2009 Joel Sing * * Permission to use, copy, modify, and distribute this software for any @@ -70,7 +71,11 @@ #include #include +#include #include +#include +#define KBC_DEVCMD_ACK KBR_ACK +#define KBC_DEVCMD_RESEND KBR_RESEND #include #include @@ -83,9 +88,6 @@ const char *iockbc_slot_names[] = { "kbd", "mouse" }; -#define KBC_DEVCMD_ACK 0xfa -#define KBC_DEVCMD_RESEND 0xfe - /* #define IOCKBC_DEBUG */ #ifdef IOCKBC_DEBUG #define DPRINTF(x...) do { printf(x); } while(0) @@ -153,11 +155,15 @@ struct pckbc_slotdata { #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL) -struct pckbc_internal iockbc_consdata; +enum iockbc_slottype { EMPTY, KBD, MOUSE }; + +static struct pckbc_internal iockbc_consdata; +static struct pckbc_slotdata iockbc_cons_slotdata; int iockbc_is_ioc_console(struct ioc_attach_args *); int iockbc_is_iof_console(struct iof_attach_args *); -void iockbc_attach_common(struct iockbc_softc *, bus_addr_t, int); +void iockbc_attach_common(struct iockbc_softc *, bus_addr_t, int, + const struct iockbc_reginfo *, const struct iockbc_reginfo *); void iockbc_start(struct pckbc_internal *, pckbc_slot_t); int iockbc_attach_slot(struct iockbc_softc *, pckbc_slot_t); void iockbc_init_slotdata(struct pckbc_slotdata *, @@ -174,6 +180,8 @@ int iockbc_poll_read(struct pckbc_internal *, pckbc_slot_t); int iockbc_poll_write(struct pckbc_internal *, pckbc_slot_t, int); void iockbc_process_input(struct pckbc_softc *, struct pckbc_internal *, int, uint); +enum iockbc_slottype + iockbc_probe_slot(struct pckbc_internal *, pckbc_slot_t); int iockbc_match(struct device *parent, void *cf, void *aux) @@ -189,7 +197,7 @@ iockbc_match(struct device *parent, void *cf, void *aux) * Register assignments */ -const struct iockbc_reginfo iockbc_ioc_normal[PCKBC_NSLOTS] = { +const struct iockbc_reginfo iockbc_ioc[PCKBC_NSLOTS] = { [PCKBC_KBD_SLOT] = { .rx = IOC3_KBC_KBD_RX, .tx = IOC3_KBC_KBD_TX, @@ -225,16 +233,6 @@ iockbc_ioc_attach(struct device *parent, struct device *self, void *aux) struct iockbc_softc *isc = (void*)self; struct ioc_attach_args *iaa = aux; - /* - * For some reason keyboard and mouse ports are inverted on Fuel. - */ - - if (ISSET(iaa->iaa_flags, IOC_FLAGS_OBIO) && - sys_config.system_type == SGI_IP35) - isc->reginfo = iockbc_ioc_inverted; - else - isc->reginfo = iockbc_ioc_normal; - /* Setup bus space mapping. */ isc->iot = iaa->iaa_memt; isc->ioh = iaa->iaa_memh; @@ -246,7 +244,8 @@ iockbc_ioc_attach(struct device *parent, struct device *self, void *aux) else printf(": unable to establish interrupt\n"); - iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_ioc_console(iaa)); + iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_ioc_console(iaa), + iockbc_ioc, iockbc_ioc_inverted); } #endif @@ -270,14 +269,27 @@ const struct iockbc_reginfo iockbc_iof[PCKBC_NSLOTS] = { } }; +const struct iockbc_reginfo iockbc_iof_inverted[PCKBC_NSLOTS] = { + [PCKBC_KBD_SLOT] = { + .rx = IOC4_KBC_AUX_RX, + .tx = IOC4_KBC_AUX_TX, + .cs = IOC4_KBC_CTRL_STATUS, + .busy = IOC3_KBC_STATUS_AUX_WRITE_PENDING + }, + [PCKBC_AUX_SLOT] = { + .rx = IOC4_KBC_KBD_RX, + .tx = IOC4_KBC_KBD_TX, + .cs = IOC4_KBC_CTRL_STATUS, + .busy = IOC3_KBC_STATUS_KBD_WRITE_PENDING + } +}; + void iockbc_iof_attach(struct device *parent, struct device *self, void *aux) { struct iockbc_softc *isc = (void*)self; struct iof_attach_args *iaa = aux; - isc->reginfo = iockbc_iof; - /* Setup bus space mapping. */ isc->iot = iaa->iaa_memt; isc->ioh = iaa->iaa_memh; @@ -289,7 +301,8 @@ iockbc_iof_attach(struct device *parent, struct device *self, void *aux) else printf(": unable to establish interrupt\n"); - iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_iof_console(iaa)); + iockbc_attach_common(isc, iaa->iaa_base, iockbc_is_iof_console(iaa), + iockbc_iof, iockbc_iof_inverted); } #endif @@ -331,7 +344,123 @@ iockbc_submatch(struct device *parent, void *match, void *aux) cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot) return (0); - return ((*cf->cf_attach->ca_match)(parent, cf, aux)); + return ((*cf->cf_attach->ca_match)(parent, cf, pa)); +} + +/* + * Figure out what kind of device is connected to the given slot, if any. + */ +enum iockbc_slottype +iockbc_probe_slot(struct pckbc_internal *t, pckbc_slot_t slot) +{ + int rc, i, tries; + + /* reset device */ + pckbc_flush(t, slot); + for (tries = 0; tries < 5; tries++) { + rc = iockbc_poll_write(t, slot, KBC_RESET); + if (rc < 0) { + DPRINTF(("%s: slot %d write failed\n", __func__, slot)); + return EMPTY; + } + for (i = 10; i != 0; i--) { + rc = iockbc_poll_read(t, slot); + if (rc >= 0) + break; + } + if (rc < 0) { + DPRINTF(("%s: slot %d no answer to reset\n", + __func__, slot)); + return EMPTY; + } + if (rc == KBC_DEVCMD_ACK) + break; + if (rc == KBC_DEVCMD_RESEND) + continue; + DPRINTF(("%s: slot %d bogus reset ack %02x\n", + __func__, slot, rc)); + return EMPTY; + } + + /* get answer byte */ + for (i = 10; i != 0; i--) { + rc = iockbc_poll_read(t, slot); + if (rc >= 0) + break; + } + if (rc < 0) { + DPRINTF(("%s: slot %d no answer to reset after ack\n", + __func__, slot)); + return EMPTY; + } + if (rc != KBR_RSTDONE) { + DPRINTF(("%s: slot %d bogus reset answer %02x\n", + __func__, slot, rc)); + return EMPTY; + } + /* mice send an extra byte */ + (void)iockbc_poll_read(t, slot); + + /* ask for device id */ + for (tries = 0; tries < 5; tries++) { + rc = iockbc_poll_write(t, slot, KBC_READID); + if (rc == -1) { + DPRINTF(("%s: slot %d write failed\n", __func__, slot)); + return EMPTY; + } + for (i = 10; i != 0; i--) { + rc = iockbc_poll_read(t, slot); + if (rc >= 0) + break; + } + if (rc < 0) { + DPRINTF(("%s: slot %d no answer to command\n", + __func__, slot)); + return EMPTY; + } + if (rc == KBC_DEVCMD_ACK) + break; + if (rc == KBC_DEVCMD_RESEND) + continue; + DPRINTF(("%s: slot %d bogus command ack %02x\n", + __func__, slot, rc)); + return EMPTY; + } + + /* get first answer byte */ + for (i = 10; i != 0; i--) { + rc = iockbc_poll_read(t, slot); + if (rc >= 0) + break; + } + if (rc < 0) { + DPRINTF(("%s: slot %d no answer to command after ack\n", + __func__, slot)); + return EMPTY; + } + + switch (rc) { + case KCID_KBD1: /* keyboard */ + /* get second answer byte */ + rc = iockbc_poll_read(t, slot); + if (rc < 0) { + DPRINTF(("%s: slot %d truncated keyboard answer\n", + __func__, slot)); + return EMPTY; + } + if (rc != KCID_KBD2) { + DPRINTF(("%s: slot %d unexpected keyboard answer" + " 0x%02x 0x%02x\n", __func__, slot, KCID_KBD1, rc)); + /* return EMPTY; */ + } + return KBD; + case KCID_MOUSE: /* mouse */ + return MOUSE; + default: + DPRINTF(("%s: slot %d unknown device answer 0x%02x\n", + __func__, slot, rc)); + return EMPTY; + } } int @@ -342,19 +471,11 @@ iockbc_attach_slot(struct iockbc_softc *isc, pckbc_slot_t slot) struct pckbc_attach_args pa; int found; - if (!t->t_slotdata[slot]) { - t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata), - M_DEVBUF, M_NOWAIT); - - if (t->t_slotdata[slot] == NULL) { - printf("Failed to allocate slot data!\n"); - return 0; - } - iockbc_init_slotdata(t->t_slotdata[slot], &isc->reginfo[slot]); - } + iockbc_init_slotdata(t->t_slotdata[slot], &isc->reginfo[slot]); pa.pa_tag = t; pa.pa_slot = slot; + found = (config_found_sm((struct device *)sc, &pa, iockbcprint, iockbc_submatch) != NULL); @@ -362,23 +483,30 @@ iockbc_attach_slot(struct iockbc_softc *isc, pckbc_slot_t slot) } void -iockbc_attach_common(struct iockbc_softc *isc, bus_addr_t addr, int console) +iockbc_attach_common(struct iockbc_softc *isc, bus_addr_t addr, int console, + const struct iockbc_reginfo *reginfo, + const struct iockbc_reginfo *reginfo_inverted) { struct pckbc_softc *sc = &isc->sc_pckbc; struct pckbc_internal *t; bus_addr_t cs; uint32_t csr; + pckbc_slot_t slot; if (console) { iockbc_consdata.t_sc = sc; - sc->id = &iockbc_consdata; + sc->id = t = &iockbc_consdata; isc->console = 1; + if (®info[PCKBC_KBD_SLOT] == iockbc_cons_slotdata.reginfo) + isc->reginfo = reginfo; + else + isc->reginfo = reginfo_inverted; } else { /* * Setup up controller: do not force pull clock and data lines * low, clamp clocks after three bytes received. */ - cs = isc->reginfo[0].cs; + cs = reginfo[PCKBC_KBD_SLOT].cs; csr = bus_space_read_4(isc->iot, isc->ioh, cs); csr &= ~(IOC3_KBC_CTRL_KBD_PULL_DATA_LOW | IOC3_KBC_CTRL_KBD_PULL_CLOCK_LOW | @@ -400,6 +528,62 @@ iockbc_attach_common(struct iockbc_softc *isc, bus_addr_t addr, int console) timeout_set(&t->t_cleanup, iockbc_cleanup, t); timeout_set(&t->t_poll, iockbc_poll, t); + + isc->reginfo = reginfo; + } + + for (slot = 0; slot < PCKBC_NSLOTS; slot++) { + if (t->t_slotdata[slot] == NULL) { + t->t_slotdata[slot] = + malloc(sizeof(struct pckbc_slotdata), + M_DEVBUF, M_WAITOK); + } + } + + if (!console) { + enum iockbc_slottype slottype; + int mouse_on_main = 0; + + /* + * Probe for a keyboard. If none is found at the regular + * keyboard port, but one is found at the mouse port, then + * it is likely that this particular system has both ports + * inverted (or incorrect labels on the chassis), unless + * this is a human error. In any case, try to get the + * keyboard to attach to the `keyboard' port and the + * pointing device to the `mouse' port. + */ + + for (slot = 0; slot < PCKBC_NSLOTS; slot++) { + iockbc_init_slotdata(t->t_slotdata[slot], + &isc->reginfo[slot]); + slottype = iockbc_probe_slot(t, slot); + if (slottype == KBD) + break; + if (slottype == MOUSE) + mouse_on_main = slot == PCKBC_KBD_SLOT; + } + if (slot == PCKBC_NSLOTS) { + /* + * We could not identify a keyboard. Let's assume + * none is connected; if a mouse has been found on + * the keyboard port and none on the aux port, the + * ports are likely to be inverted. + */ + if (mouse_on_main) + slot = PCKBC_AUX_SLOT; + else + slot = PCKBC_KBD_SLOT; + } + if (slot == PCKBC_AUX_SLOT) { + /* + * Either human error or inverted wiring; use + * the inverted port settings. + * iockbc_attach_slot() below will call + * iockbc_init_slotdata() again. + */ + isc->reginfo = reginfo_inverted; + } } /* @@ -969,7 +1153,6 @@ pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on) * Console support. */ -static struct pckbc_slotdata iockbc_cons_slotdata; static int iockbc_console; int @@ -978,7 +1161,9 @@ iockbc_cnattach() bus_space_tag_t iot = &sys_config.console_io; bus_space_handle_t ioh = (bus_space_handle_t)iot->bus_base; struct pckbc_internal *t = &iockbc_consdata; - const struct iockbc_reginfo *reginfo = NULL; + const struct iockbc_reginfo *reginfo = NULL, *reginfo_inverted; + enum iockbc_slottype slottype; + pckbc_slot_t slot; uint32_t csr; int is_ioc; int rc; @@ -987,14 +1172,13 @@ iockbc_cnattach() PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3); if (is_ioc) { #if NIOCKBC_IOC > 0 - if (sys_config.system_type == SGI_IP35) - reginfo = &iockbc_ioc_inverted[PCKBC_KBD_SLOT]; - else - reginfo = &iockbc_ioc_normal[PCKBC_KBD_SLOT]; + reginfo = iockbc_ioc; + reginfo_inverted = iockbc_ioc_inverted; #endif } else { #if NIOCKBC_IOF > 0 - reginfo = &iockbc_iof[PCKBC_KBD_SLOT]; + reginfo = iockbc_iof; + reginfo_inverted = iockbc_iof_inverted; #endif } if (reginfo == NULL) @@ -1021,7 +1205,47 @@ iockbc_cnattach() timeout_set(&t->t_cleanup, iockbc_cleanup, t); timeout_set(&t->t_poll, iockbc_poll, t); - iockbc_init_slotdata(&iockbc_cons_slotdata, reginfo); + /* + * Probe for a keyboard. There must be one connected, for the PROM + * would not have advertized glass console if none had been + * detected. + */ + + for (slot = 0; slot < PCKBC_NSLOTS; slot++) { + iockbc_init_slotdata(&iockbc_cons_slotdata, ®info[slot]); + t->t_slotdata[slot] = &iockbc_cons_slotdata; + slottype = iockbc_probe_slot(t, slot); + t->t_slotdata[slot] = NULL; + if (slottype == KBD) + break; + } + if (slot == PCKBC_NSLOTS) { + /* + * We could not identify a keyboard, but the PROM did; + * let's assume it's a fluke and assume it exists and + * is connected to the first connector. + */ + slot = PCKBC_KBD_SLOT; + /* + * For some reason keyboard and mouse ports are inverted on + * Fuel. They also are inverted on some IO9 boards, but + * we can't tell both IO9 flavour apart, yet. + */ + if (is_ioc && sys_config.system_type == SGI_IP35) + slot = PCKBC_AUX_SLOT; + } + + if (slot == PCKBC_AUX_SLOT) { + /* + * Either human error when plugging the keyboard, or the + * physical connectors on the chassis are inverted. + * Compensate by switching in software (pckbd relies upon + * being at PCKBC_KBD_SLOT). + */ + reginfo = reginfo_inverted; + } + + iockbc_init_slotdata(&iockbc_cons_slotdata, ®info[PCKBC_KBD_SLOT]); t->t_slotdata[PCKBC_KBD_SLOT] = &iockbc_cons_slotdata; rc = pckbd_cnattach(t); diff --git a/sys/dev/ic/i8042reg.h b/sys/dev/ic/i8042reg.h index 9bbd3a9c757..ef3ad189a22 100644 --- a/sys/dev/ic/i8042reg.h +++ b/sys/dev/ic/i8042reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i8042reg.h,v 1.7 2013/05/23 18:29:51 tobias Exp $ */ +/* $OpenBSD: i8042reg.h,v 1.8 2013/12/25 21:01:01 miod Exp $ */ /* $NetBSD: i8042reg.h,v 1.7 1998/01/18 14:41:37 drochner Exp $ */ #define KBSTATP 4 /* kbd controller status port (I) */ @@ -25,6 +25,7 @@ #define KBC_KBDTEST 0xab /* test keyboard port */ #define KBC_KBDDISABLE 0xad /* disable keyboard port */ #define KBC_KBDENABLE 0xae /* enable keyboard port */ +#define KBC_READID 0xf2 /* read device id */ #define KBC_PULSE0 0xfe /* pulse output bit 0 */ #define KBC_PULSE1 0xfd /* pulse output bit 1 */ #define KBC_PULSE2 0xfb /* pulse output bit 2 */ @@ -44,3 +45,7 @@ #define KC8_MENABLE 0x02 /* enable mouse interrupt */ #define KC8_KENABLE 0x01 /* enable keyboard interrupt */ #define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) + +#define KCID_KBD1 0xAB +#define KCID_KBD2 0x83 +#define KCID_MOUSE 0x00