LCOV - code coverage report
Current view: top level - dev/ic - pckbc.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 474 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: pckbc.c,v 1.50 2017/03/11 11:55:03 mpi Exp $ */
       2             : /* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1998
       6             :  *      Matthias Drochner.  All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      18             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      21             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include <sys/param.h>
      30             : #include <sys/systm.h>
      31             : #include <sys/timeout.h>
      32             : #include <sys/kernel.h>
      33             : #include <sys/device.h>
      34             : #include <sys/malloc.h>
      35             : #include <sys/errno.h>
      36             : #include <sys/queue.h>
      37             : 
      38             : #include <machine/bus.h>
      39             : #include <machine/cpu.h>
      40             : 
      41             : #include <dev/ic/i8042reg.h>
      42             : #include <dev/ic/pckbcvar.h>
      43             : 
      44             : #include "pckbd.h"
      45             : 
      46             : #if NPCKBD > 0
      47             : #include <dev/pckbc/pckbdvar.h>
      48             : #endif
      49             : 
      50             : #ifdef PCKBCDEBUG
      51             : #define DPRINTF(x...)   do { printf(x); } while (0);
      52             : #else
      53             : #define DPRINTF(x...)
      54             : #endif
      55             : 
      56             : /* descriptor for one device command */
      57             : struct pckbc_devcmd {
      58             :         TAILQ_ENTRY(pckbc_devcmd) next;
      59             :         int flags;
      60             : #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
      61             : #define KBC_CMDFLAG_SLOW 2
      62             :         u_char cmd[4];
      63             :         int cmdlen, cmdidx, retries;
      64             :         u_char response[4];
      65             :         int status, responselen, responseidx;
      66             : };
      67             : 
      68             : /* data per slave device */
      69             : struct pckbc_slotdata {
      70             :         int polling; /* don't read data port in interrupt handler */
      71             :         TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
      72             :         TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
      73             : #define NCMD 5
      74             :         struct pckbc_devcmd cmds[NCMD];
      75             : };
      76             : 
      77             : #define CMD_IN_QUEUE(q) (!TAILQ_EMPTY(&(q)->cmdqueue))
      78             : 
      79             : void pckbc_init_slotdata(struct pckbc_slotdata *);
      80             : int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t, int);
      81             : int pckbc_submatch_locators(struct device *, void *, void *);
      82             : int pckbc_submatch(struct device *, void *, void *);
      83             : int pckbcprint(void *, const char *);
      84             : 
      85             : struct pckbc_internal pckbc_consdata;
      86             : int pckbc_console_attached;
      87             : 
      88             : int pckbc_console;
      89             : static struct pckbc_slotdata pckbc_cons_slotdata;
      90             : 
      91             : static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
      92             : 
      93             : static int pckbc_get8042cmd(struct pckbc_internal *);
      94             : static int pckbc_put8042cmd(struct pckbc_internal *);
      95             : static int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t,
      96             :                                   u_char);
      97             : static void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t,
      98             :                                  struct pckbc_devcmd *);
      99             : 
     100             : void pckbc_cleanqueues(struct pckbc_internal *);
     101             : void pckbc_cleanqueue(struct pckbc_slotdata *);
     102             : void pckbc_cleanup(void *);
     103             : void pckbc_poll(void *);
     104             : int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
     105             : void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
     106             : int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *);
     107             : 
     108             : const char *pckbc_slot_names[] = { "kbd", "aux" };
     109             : 
     110             : #define KBC_DEVCMD_ACK          0xfa
     111             : #define KBC_DEVCMD_RESEND       0xfe
     112             : #define KBC_DEVCMD_BAT_DONE     0xaa
     113             : #define KBC_DEVCMD_BAT_FAIL     0xfc
     114             : 
     115             : #define KBD_DELAY       DELAY(8)
     116             : 
     117             : static inline int
     118           0 : pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
     119             : {
     120             :         u_int i;
     121             : 
     122           0 :         for (i = 100000; i; i--)
     123           0 :                 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
     124           0 :                         KBD_DELAY;
     125           0 :                         return (1);
     126             :                 }
     127           0 :         return (0);
     128           0 : }
     129             : 
     130             : int
     131           0 : pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
     132             : {
     133           0 :         if (!pckbc_wait_output(iot, ioh_c))
     134           0 :                 return (0);
     135           0 :         bus_space_write_1(iot, ioh_c, 0, val);
     136           0 :         return (1);
     137           0 : }
     138             : 
     139             : int
     140           0 : pckbc_poll_data1(bus_space_tag_t iot, bus_space_handle_t ioh_d,
     141             :     bus_space_handle_t ioh_c, pckbc_slot_t slot, int checkaux)
     142             : {
     143             :         int i;
     144             :         u_char stat;
     145             : 
     146             :         /* polls for ~100ms */
     147           0 :         for (i = 100; i; i--, delay(1000)) {
     148           0 :                 stat = bus_space_read_1(iot, ioh_c, 0);
     149           0 :                 if (stat & KBS_DIB) {
     150             :                         register u_char c;
     151             : 
     152           0 :                         KBD_DELAY;
     153           0 :                         CPU_BUSY_CYCLE();
     154           0 :                         c = bus_space_read_1(iot, ioh_d, 0);
     155           0 :                         if (checkaux && (stat & KBS_AUXDATA)) {
     156           0 :                                 if (slot != PCKBC_AUX_SLOT) {
     157             :                                         DPRINTF("lost aux 0x%x\n", c);
     158           0 :                                         continue;
     159             :                                 }
     160             :                         } else {
     161           0 :                                 if (slot == PCKBC_AUX_SLOT) {
     162             :                                         DPRINTF("lost kbd 0x%x\n", c);
     163           0 :                                         continue;
     164             :                                 }
     165             :                         }
     166           0 :                         return (c);
     167             :                 }
     168             :         }
     169           0 :         return (-1);
     170           0 : }
     171             : 
     172             : /*
     173             :  * Get the current command byte.
     174             :  */
     175             : static int
     176           0 : pckbc_get8042cmd(struct pckbc_internal *t)
     177             : {
     178           0 :         bus_space_tag_t iot = t->t_iot;
     179           0 :         bus_space_handle_t ioh_d = t->t_ioh_d;
     180           0 :         bus_space_handle_t ioh_c = t->t_ioh_c;
     181             :         int data;
     182             : 
     183           0 :         if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
     184           0 :                 return (0);
     185           0 :         data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
     186           0 :                                 t->t_haveaux);
     187           0 :         if (data == -1)
     188           0 :                 return (0);
     189           0 :         t->t_cmdbyte = data;
     190           0 :         return (1);
     191           0 : }
     192             : 
     193             : /*
     194             :  * Pass command byte to keyboard controller (8042).
     195             :  */
     196             : static int
     197           0 : pckbc_put8042cmd(struct pckbc_internal *t)
     198             : {
     199           0 :         bus_space_tag_t iot = t->t_iot;
     200           0 :         bus_space_handle_t ioh_d = t->t_ioh_d;
     201           0 :         bus_space_handle_t ioh_c = t->t_ioh_c;
     202             : 
     203           0 :         if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
     204           0 :                 return (0);
     205           0 :         if (!pckbc_wait_output(iot, ioh_c))
     206           0 :                 return (0);
     207           0 :         bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
     208           0 :         return (1);
     209           0 : }
     210             : 
     211             : static int
     212           0 : pckbc_send_devcmd(struct pckbc_internal *t, pckbc_slot_t slot, u_char val)
     213             : {
     214           0 :         bus_space_tag_t iot = t->t_iot;
     215           0 :         bus_space_handle_t ioh_d = t->t_ioh_d;
     216           0 :         bus_space_handle_t ioh_c = t->t_ioh_c;
     217             : 
     218           0 :         if (slot == PCKBC_AUX_SLOT) {
     219           0 :                 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
     220           0 :                         return (0);
     221             :         }
     222           0 :         if (!pckbc_wait_output(iot, ioh_c))
     223           0 :                 return (0);
     224           0 :         bus_space_write_1(iot, ioh_d, 0, val);
     225           0 :         return (1);
     226           0 : }
     227             : 
     228             : int
     229           0 : pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
     230             : {
     231           0 :         if (pckbc_console && !pckbc_console_attached &&
     232           0 :             pckbc_consdata.t_iot == iot &&
     233           0 :             pckbc_consdata.t_addr == addr)
     234           0 :                 return (1);
     235           0 :         return (0);
     236           0 : }
     237             : 
     238             : int
     239           0 : pckbc_submatch_locators(struct device *parent, void *match, void *aux)
     240             : {
     241           0 :         struct cfdata *cf = match;
     242           0 :         struct pckbc_attach_args *pa = aux;
     243             : 
     244           0 :         if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
     245           0 :             cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
     246           0 :                 return (0);
     247           0 :         return (1);
     248           0 : }
     249             : 
     250             : int
     251           0 : pckbc_submatch(struct device *parent, void *match, void *aux)
     252             : {
     253           0 :         struct cfdata *cf = match;
     254             : 
     255           0 :         if (pckbc_submatch_locators(parent, match, aux) == 0)
     256           0 :                 return (0);
     257           0 :         return ((*cf->cf_attach->ca_match)(parent, cf, aux));
     258           0 : }
     259             : 
     260             : int
     261           0 : pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot, int force)
     262             : {
     263           0 :         struct pckbc_internal *t = sc->id;
     264           0 :         struct pckbc_attach_args pa;
     265             :         int found;
     266             : 
     267           0 :         pa.pa_tag = t;
     268           0 :         pa.pa_slot = slot;
     269           0 :         found = (config_found_sm((struct device *)sc, &pa, pckbcprint,
     270           0 :             force ? pckbc_submatch_locators : pckbc_submatch) != NULL);
     271             : 
     272           0 :         if ((found || slot == PCKBC_AUX_SLOT) && !t->t_slotdata[slot]) {
     273           0 :                 t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata),
     274             :                                              M_DEVBUF, M_NOWAIT);
     275           0 :                 if (t->t_slotdata[slot] == NULL)
     276           0 :                         return 0;
     277           0 :                 pckbc_init_slotdata(t->t_slotdata[slot]);
     278             : 
     279           0 :                 if (!found && slot == PCKBC_AUX_SLOT) {
     280             :                         /*
     281             :                          * Some machines don't handle disabling the aux slot
     282             :                          * completely and still generate data when the mouse is
     283             :                          * moved, so setup a dummy interrupt handler to discard
     284             :                          * this slot's data.
     285             :                          */
     286           0 :                         pckbc_set_inputhandler(t, PCKBC_AUX_SLOT, NULL, sc,
     287             :                             NULL);
     288             :                         found = 1;
     289           0 :                 }
     290             :         }
     291           0 :         return (found);
     292           0 : }
     293             : 
     294             : void
     295           0 : pckbc_attach(struct pckbc_softc *sc, int flags)
     296             : {
     297             :         struct pckbc_internal *t;
     298             :         bus_space_tag_t iot;
     299             :         bus_space_handle_t ioh_d, ioh_c;
     300             :         int haskbd = 0, res;
     301             :         u_char cmdbits = 0;
     302             : 
     303           0 :         t = sc->id;
     304           0 :         iot = t->t_iot;
     305           0 :         ioh_d = t->t_ioh_d;
     306           0 :         ioh_c = t->t_ioh_c;
     307             : 
     308           0 :         if (pckbc_console == 0) {
     309           0 :                 timeout_set(&t->t_cleanup, pckbc_cleanup, t);
     310           0 :                 timeout_set(&t->t_poll, pckbc_poll, t);
     311           0 :         }
     312             : 
     313             :         /* flush */
     314           0 :         (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
     315             : 
     316             :         /* set initial cmd byte */
     317           0 :         if (!pckbc_put8042cmd(t)) {
     318             : #if defined(__i386__) || defined(__amd64__)
     319           0 :                 if (!ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) {
     320           0 :                         pckbc_release_console();
     321           0 :                         return;
     322             :                 }
     323             : #endif
     324           0 :                 printf("kbc: cmd word write error\n");
     325           0 :                 return;
     326             :         }
     327             : 
     328             : /*
     329             :  * XXX Don't check the keyboard port. There are broken keyboard controllers
     330             :  * which don't pass the test but work normally otherwise.
     331             :  */
     332             : #if 0
     333             :         /*
     334             :          * check kbd port ok
     335             :          */
     336             :         if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
     337             :                 return;
     338             :         res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
     339             : 
     340             :         /*
     341             :          * Normally, we should get a "0" here.
     342             :          * But there are keyboard controllers behaving differently.
     343             :          */
     344             :         if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
     345             : #ifdef PCKBCDEBUG
     346             :                 if (res != 0)
     347             :                         printf("kbc: returned %x on kbd slot test\n", res);
     348             : #endif
     349             :                 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) {
     350             :                         cmdbits |= KC8_KENABLE;
     351             :                         haskbd = 1;
     352             :                 }
     353             :         } else {
     354             :                 printf("kbc: kbd port test: %x\n", res);
     355             :                 return;
     356             :         }
     357             : #else
     358           0 :         if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) {
     359             :                 cmdbits |= KC8_KENABLE;
     360             :                 haskbd = 1;
     361           0 :         }
     362             : #endif /* 0 */
     363             : 
     364             :         /*
     365             :          * Check aux port ok.
     366             :          * Avoid KBC_AUXTEST because it hangs some older controllers
     367             :          * (eg UMC880?).
     368             :          */
     369           0 :         if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
     370           0 :                 printf("kbc: aux echo error 1\n");
     371           0 :                 goto nomouse;
     372             :         }
     373           0 :         if (!pckbc_wait_output(iot, ioh_c)) {
     374           0 :                 printf("kbc: aux echo error 2\n");
     375           0 :                 goto nomouse;
     376             :         }
     377           0 :         bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
     378           0 :         res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
     379             : 
     380           0 :         if (ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
     381             :                 /*
     382             :                  * The following code is necessary to find the aux port on the
     383             :                  * oqo-1 machine, among others.  However if confuses old
     384             :                  * (non-ps/2) keyboard controllers (at least UMC880x again).
     385             :                  */
     386           0 :                 if (res == -1) {
     387             :                         /* Read of aux echo timed out, try again */
     388           0 :                         if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
     389             :                                 goto nomouse;
     390           0 :                         if (!pckbc_wait_output(iot, ioh_c))
     391             :                                 goto nomouse;
     392           0 :                         bus_space_write_1(iot, ioh_d, 0, 0x5a);
     393           0 :                         res = pckbc_poll_data1(iot, ioh_d, ioh_c,
     394             :                             PCKBC_AUX_SLOT, 1);
     395             :                         DPRINTF("kbc: aux echo: %x\n", res);
     396           0 :                 }
     397             :         }
     398             : 
     399           0 :         if (res != -1) {
     400             :                 /*
     401             :                  * In most cases, the 0x5a gets echoed.
     402             :                  * Some old controllers (Gateway 2000 circa 1993)
     403             :                  * return 0xfe here.
     404             :                  * We are satisfied if there is anything in the
     405             :                  * aux output buffer.
     406             :                  */
     407             :                 DPRINTF("kbc: aux echo: %x\n", res);
     408           0 :                 t->t_haveaux = 1;
     409           0 :                 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT, 0))
     410           0 :                         cmdbits |= KC8_MENABLE;
     411             :         }
     412             : #ifdef PCKBCDEBUG
     413             :         else
     414             :                 printf("kbc: aux echo test failed\n");
     415             : #endif
     416             : 
     417             : #if defined(__i386__) || defined(__amd64__)
     418           0 :         if (haskbd == 0 && !ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) {
     419           0 :                 if (t->t_haveaux) {
     420           0 :                         if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 1))
     421           0 :                                 cmdbits |= KC8_KENABLE;
     422             :                 } else {
     423           0 :                         pckbc_release_console();
     424             :                 }
     425             :         }
     426             : #endif
     427             : 
     428             : nomouse:
     429             :         /* enable needed interrupts */
     430           0 :         t->t_cmdbyte |= cmdbits;
     431           0 :         if (!pckbc_put8042cmd(t))
     432           0 :                 printf("kbc: cmd word write error\n");
     433           0 : }
     434             : 
     435             : int
     436           0 : pckbcprint(void *aux, const char *pnp)
     437             : {
     438           0 :         struct pckbc_attach_args *pa = aux;
     439             : 
     440           0 :         if (!pnp)
     441           0 :                 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
     442           0 :         return (QUIET);
     443             : }
     444             : 
     445             : void
     446           0 : pckbc_release_console(void)
     447             : {
     448             : #if defined(__i386__) || defined(__amd64__)
     449             :         /*
     450             :          * If there is no keyboard present, yet we are the console,
     451             :          * we might be on a legacy-free PC where the PS/2 emulated
     452             :          * keyboard was elected as console, but went away as soon
     453             :          * as the USB controller drivers attached.
     454             :          *
     455             :          * In that case, we want to release ourselves from console
     456             :          * duties, unless we have been able to attach a mouse,
     457             :          * which would mean this is a real PS/2 controller
     458             :          * afterwards.
     459             :          */
     460           0 :         if (pckbc_console != 0) {
     461             :                 extern void wscn_input_init(int);
     462             : 
     463           0 :                 pckbc_console = 0;
     464           0 :                 wscn_input_init(1);
     465           0 :         }
     466             : #endif
     467           0 : }
     468             : 
     469             : void
     470           0 : pckbc_init_slotdata(struct pckbc_slotdata *q)
     471             : {
     472             :         int i;
     473           0 :         TAILQ_INIT(&q->cmdqueue);
     474           0 :         TAILQ_INIT(&q->freequeue);
     475             : 
     476           0 :         for (i = 0; i < NCMD; i++) {
     477           0 :                 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
     478             :         }
     479           0 :         q->polling = 0;
     480           0 : }
     481             : 
     482             : void
     483           0 : pckbc_flush(pckbc_tag_t self, pckbc_slot_t slot)
     484             : {
     485           0 :         struct pckbc_internal *t = self;
     486             : 
     487           0 :         (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
     488           0 :             slot, t->t_haveaux);
     489           0 : }
     490             : 
     491             : int
     492           0 : pckbc_poll_data(pckbc_tag_t self, pckbc_slot_t slot)
     493             : {
     494           0 :         struct pckbc_internal *t = self;
     495           0 :         struct pckbc_slotdata *q = t->t_slotdata[slot];
     496             :         int c;
     497             : 
     498           0 :         c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
     499           0 :                              slot, t->t_haveaux);
     500           0 :         if (c != -1 && q && CMD_IN_QUEUE(q)) {
     501             :                 /* we jumped into a running command - try to
     502             :                  deliver the response */
     503           0 :                 if (pckbc_cmdresponse(t, slot, c))
     504           0 :                         return (-1);
     505             :         }
     506           0 :         return (c);
     507           0 : }
     508             : 
     509             : /*
     510             :  * set scancode translation on
     511             :  */
     512             : int
     513           0 : pckbc_xt_translation(pckbc_tag_t self)
     514             : {
     515           0 :         struct pckbc_internal *t = self;
     516             : 
     517           0 :         if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE))
     518           0 :                 return (-1);
     519             : 
     520           0 :         if (t->t_cmdbyte & KC8_TRANS)
     521           0 :                 return (0);
     522             : 
     523           0 :         t->t_cmdbyte |= KC8_TRANS;
     524           0 :         if (!pckbc_put8042cmd(t))
     525           0 :                 return (-1);
     526             : 
     527             :         /* read back to be sure */
     528           0 :         if (!pckbc_get8042cmd(t))
     529           0 :                 return (-1);
     530             : 
     531           0 :         return (t->t_cmdbyte & KC8_TRANS) ? (0) : (-1);
     532           0 : }
     533             : 
     534             : static struct pckbc_portcmd {
     535             :         u_char cmd_en, cmd_dis;
     536             : } pckbc_portcmd[2] = {
     537             :         {
     538             :                 KBC_KBDENABLE, KBC_KBDDISABLE,
     539             :         }, {
     540             :                 KBC_AUXENABLE, KBC_AUXDISABLE,
     541             :         }
     542             : };
     543             : 
     544             : void
     545           0 : pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on)
     546             : {
     547           0 :         struct pckbc_internal *t = (struct pckbc_internal *)self;
     548             :         struct pckbc_portcmd *cmd;
     549             : 
     550           0 :         cmd = &pckbc_portcmd[slot];
     551             : 
     552           0 :         if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
     553           0 :                             on ? cmd->cmd_en : cmd->cmd_dis))
     554           0 :                 printf("pckbc_slot_enable(%d) failed\n", on);
     555             : 
     556           0 :         if (slot == PCKBC_KBD_SLOT) {
     557           0 :                 if (on)
     558           0 :                         timeout_add_sec(&t->t_poll, 1);
     559             :                 else
     560           0 :                         timeout_del(&t->t_poll);
     561             :         }
     562           0 : }
     563             : 
     564             : void
     565           0 : pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on)
     566             : {
     567           0 :         struct pckbc_internal *t = (struct pckbc_internal *)self;
     568             : 
     569           0 :         t->t_slotdata[slot]->polling = on;
     570             : 
     571           0 :         if (!on) {
     572             :                 int s;
     573             : 
     574             :                 /*
     575             :                  * If disabling polling on a device that's been configured,
     576             :                  * make sure there are no bytes left in the FIFO, holding up
     577             :                  * the interrupt line.  Otherwise we won't get any further
     578             :                  * interrupts.
     579             :                  */
     580           0 :                 if (t->t_sc) {
     581           0 :                         s = spltty();
     582           0 :                         pckbcintr_internal(t, t->t_sc);
     583           0 :                         splx(s);
     584           0 :                 }
     585           0 :         }
     586           0 : }
     587             : 
     588             : /*
     589             :  * Pass command to device, poll for ACK and data.
     590             :  * to be called at spltty()
     591             :  */
     592             : static void
     593           0 : pckbc_poll_cmd1(struct pckbc_internal *t, pckbc_slot_t slot,
     594             :     struct pckbc_devcmd *cmd)
     595             : {
     596           0 :         bus_space_tag_t iot = t->t_iot;
     597           0 :         bus_space_handle_t ioh_d = t->t_ioh_d;
     598           0 :         bus_space_handle_t ioh_c = t->t_ioh_c;
     599             :         int i, c = 0;
     600             : 
     601           0 :         while (cmd->cmdidx < cmd->cmdlen) {
     602           0 :                 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
     603           0 :                         printf("pckbc_cmd: send error\n");
     604           0 :                         cmd->status = EIO;
     605           0 :                         return;
     606             :                 }
     607           0 :                 for (i = 10; i; i--) { /* 1s ??? */
     608           0 :                         c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
     609           0 :                                              t->t_haveaux);
     610           0 :                         if (c != -1)
     611             :                                 break;
     612             :                 }
     613             : 
     614           0 :                 switch (c) {
     615             :                 case KBC_DEVCMD_ACK:
     616           0 :                         cmd->cmdidx++;
     617           0 :                         continue;
     618             :                 /*
     619             :                  * Some legacy free PCs keep returning Basic Assurance Test
     620             :                  * (BAT) instead of something usable, so fail gracefully.
     621             :                  */
     622             :                 case KBC_DEVCMD_RESEND:
     623             :                 case KBC_DEVCMD_BAT_DONE:
     624             :                 case KBC_DEVCMD_BAT_FAIL:
     625             :                         DPRINTF("pckbc_cmd: %s\n",
     626             :                             c == KBC_DEVCMD_RESEND ? "RESEND": "BAT");
     627           0 :                         if (cmd->retries++ < 5)
     628           0 :                                 continue;
     629             : 
     630             :                         DPRINTF("pckbc_cmd: cmd failed\n");
     631           0 :                         cmd->status = ENXIO;
     632           0 :                         return;
     633             :                 case -1:
     634             :                         DPRINTF("pckbc_cmd: timeout\n");
     635           0 :                         cmd->status = EIO;
     636           0 :                         return;
     637             :                 default:
     638             :                         DPRINTF("pckbc_cmd: lost 0x%x\n", c);
     639             :                 }
     640             :         }
     641             : 
     642           0 :         while (cmd->responseidx < cmd->responselen) {
     643           0 :                 if (cmd->flags & KBC_CMDFLAG_SLOW)
     644           0 :                         i = 100; /* 10s ??? */
     645             :                 else
     646             :                         i = 10; /* 1s ??? */
     647           0 :                 while (i--) {
     648           0 :                         c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
     649           0 :                                              t->t_haveaux);
     650           0 :                         if (c != -1)
     651             :                                 break;
     652             :                 }
     653           0 :                 if (c == -1) {
     654             :                         DPRINTF("pckbc_cmd: no data\n");
     655           0 :                         cmd->status = ETIMEDOUT;
     656           0 :                         return;
     657             :                 } else
     658           0 :                         cmd->response[cmd->responseidx++] = c;
     659             :         }
     660           0 : }
     661             : 
     662             : /* for use in autoconfiguration */
     663             : int
     664           0 : pckbc_poll_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
     665             :     int responselen, u_char *respbuf, int slow)
     666             : {
     667           0 :         struct pckbc_devcmd nc;
     668             : 
     669           0 :         if ((len > 4) || (responselen > 4))
     670           0 :                 return (EINVAL);
     671             : 
     672           0 :         bzero(&nc, sizeof(nc));
     673           0 :         memcpy(nc.cmd, cmd, len);
     674           0 :         nc.cmdlen = len;
     675           0 :         nc.responselen = responselen;
     676           0 :         nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
     677             : 
     678           0 :         pckbc_poll_cmd1(self, slot, &nc);
     679             : 
     680           0 :         if (nc.status == 0 && respbuf)
     681           0 :                 memcpy(respbuf, nc.response, responselen);
     682             : 
     683           0 :         return (nc.status);
     684           0 : }
     685             : 
     686             : /*
     687             :  * Clean up a command queue, throw away everything.
     688             :  */
     689             : void
     690           0 : pckbc_cleanqueue(struct pckbc_slotdata *q)
     691             : {
     692             :         struct pckbc_devcmd *cmd;
     693             : #ifdef PCKBCDEBUG
     694             :         int i;
     695             : #endif
     696             : 
     697           0 :         while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
     698           0 :                 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
     699             : #ifdef PCKBCDEBUG
     700             :                 printf("pckbc_cleanqueue: removing");
     701             :                 for (i = 0; i < cmd->cmdlen; i++)
     702             :                         printf(" %02x", cmd->cmd[i]);
     703             :                 printf("\n");
     704             : #endif
     705           0 :                 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
     706             :         }
     707           0 : }
     708             : 
     709             : void
     710           0 : pckbc_cleanqueues(struct pckbc_internal *t)
     711             : {
     712           0 :         if (t->t_slotdata[PCKBC_KBD_SLOT])
     713           0 :                 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
     714           0 :         if (t->t_slotdata[PCKBC_AUX_SLOT])
     715           0 :                 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
     716           0 : }
     717             : 
     718             : /*
     719             :  * Timeout error handler: clean queues and data port.
     720             :  * XXX could be less invasive.
     721             :  */
     722             : void
     723           0 : pckbc_cleanup(void *self)
     724             : {
     725           0 :         struct pckbc_internal *t = self;
     726             :         int s;
     727             : 
     728           0 :         printf("pckbc: command timeout\n");
     729             : 
     730           0 :         s = spltty();
     731             : 
     732           0 :         pckbc_cleanqueues(t);
     733             : 
     734           0 :         while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
     735           0 :                 KBD_DELAY;
     736           0 :                 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
     737             :         }
     738             : 
     739             :         /* reset KBC? */
     740             : 
     741           0 :         splx(s);
     742           0 : }
     743             : 
     744             : /*
     745             :  * Stop the keyboard controller when we are going to suspend
     746             :  */
     747             : void
     748           0 : pckbc_stop(struct pckbc_softc *sc)
     749             : {
     750           0 :         struct pckbc_internal *t = sc->id;
     751             : 
     752           0 :         timeout_del(&t->t_poll);
     753           0 :         pckbc_cleanqueues(t);
     754           0 :         timeout_del(&t->t_cleanup);
     755           0 : }
     756             : 
     757             : /*
     758             :  * Reset the keyboard controller in a violent fashion; normally done
     759             :  * after suspend/resume when we do not trust the machine.
     760             :  */
     761             : void
     762           0 : pckbc_reset(struct pckbc_softc *sc)
     763             : {
     764           0 :         struct pckbc_internal *t = sc->id;
     765           0 :         bus_space_tag_t iot = t->t_iot;
     766           0 :         bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c;
     767             : 
     768           0 :         pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
     769             :         /* KBC selftest */
     770           0 :         if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0)
     771           0 :                 return;
     772           0 :         pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
     773           0 :         (void)pckbc_put8042cmd(t);
     774           0 :         pckbcintr_internal(t->t_sc->id, t->t_sc);
     775           0 : }
     776             : 
     777             : /*
     778             :  * Pass command to device during normal operation.
     779             :  * to be called at spltty()
     780             :  */
     781             : void
     782           0 : pckbc_start(struct pckbc_internal *t, pckbc_slot_t slot)
     783             : {
     784           0 :         struct pckbc_slotdata *q = t->t_slotdata[slot];
     785           0 :         struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
     786             : 
     787           0 :         if (q->polling) {
     788           0 :                 do {
     789           0 :                         pckbc_poll_cmd1(t, slot, cmd);
     790           0 :                         if (cmd->status)
     791           0 :                                 printf("pckbc_start: command error\n");
     792             : 
     793           0 :                         if (cmd->flags & KBC_CMDFLAG_SYNC) {
     794           0 :                                 wakeup(cmd);
     795           0 :                                 cmd = TAILQ_NEXT(cmd, next);
     796           0 :                         } else {
     797           0 :                                 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
     798           0 :                                 timeout_del(&t->t_cleanup);
     799           0 :                                 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
     800           0 :                                 cmd = TAILQ_FIRST(&q->cmdqueue);
     801             :                         }
     802           0 :                 } while (cmd);
     803           0 :                 return;
     804             :         }
     805             : 
     806           0 :         if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
     807           0 :                 printf("pckbc_start: send error\n");
     808             :                 /* XXX what now? */
     809           0 :                 return;
     810             :         }
     811           0 : }
     812             : 
     813             : /*
     814             :  * Handle command responses coming in asynchronously,
     815             :  * return nonzero if valid response.
     816             :  * to be called at spltty()
     817             :  */
     818             : int
     819           0 : pckbc_cmdresponse(struct pckbc_internal *t, pckbc_slot_t slot, u_char data)
     820             : {
     821           0 :         struct pckbc_slotdata *q = t->t_slotdata[slot];
     822           0 :         struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
     823             : #ifdef DIAGNOSTIC
     824           0 :         if (!cmd)
     825           0 :                 panic("pckbc_cmdresponse: no active command");
     826             : #endif
     827           0 :         if (cmd->cmdidx < cmd->cmdlen) {
     828           0 :                 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
     829           0 :                         return (0);
     830             : 
     831           0 :                 if (data == KBC_DEVCMD_RESEND) {
     832           0 :                         if (cmd->retries++ < 5) {
     833             :                                 /* try again last command */
     834             :                                 goto restart;
     835             :                         } else {
     836             :                                 DPRINTF("pckbc: cmd failed\n");
     837           0 :                                 cmd->status = ENXIO;
     838             :                                 /* dequeue */
     839             :                         }
     840           0 :                 } else {
     841           0 :                         if (++cmd->cmdidx < cmd->cmdlen)
     842             :                                 goto restart;
     843           0 :                         if (cmd->responselen)
     844           0 :                                 return (1);
     845             :                         /* else dequeue */
     846             :                 }
     847           0 :         } else if (cmd->responseidx < cmd->responselen) {
     848           0 :                 cmd->response[cmd->responseidx++] = data;
     849           0 :                 if (cmd->responseidx < cmd->responselen)
     850           0 :                         return (1);
     851             :                 /* else dequeue */
     852             :         } else
     853           0 :                 return (0);
     854             : 
     855             :         /* dequeue: */
     856           0 :         if (cmd->flags & KBC_CMDFLAG_SYNC) {
     857           0 :                 wakeup(cmd);
     858           0 :                 cmd = TAILQ_NEXT(cmd, next);
     859           0 :         } else {
     860           0 :                 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
     861           0 :                 timeout_del(&t->t_cleanup);
     862           0 :                 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
     863           0 :                 cmd = TAILQ_FIRST(&q->cmdqueue);
     864             :         }
     865           0 :         if (cmd == NULL)
     866           0 :                 return (1);
     867             : restart:
     868           0 :         pckbc_start(t, slot);
     869           0 :         return (1);
     870           0 : }
     871             : 
     872             : /*
     873             :  * Put command into the device's command queue, return zero or errno.
     874             :  */
     875             : int
     876           0 : pckbc_enqueue_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
     877             :     int responselen, int sync, u_char *respbuf)
     878             : {
     879           0 :         struct pckbc_internal *t = self;
     880           0 :         struct pckbc_slotdata *q = t->t_slotdata[slot];
     881             :         struct pckbc_devcmd *nc;
     882             :         int s, isactive, res = 0;
     883             : 
     884           0 :         if ((len > 4) || (responselen > 4))
     885           0 :                 return (EINVAL);
     886           0 :         s = spltty();
     887           0 :         nc = TAILQ_FIRST(&q->freequeue);
     888           0 :         if (nc) {
     889           0 :                 TAILQ_REMOVE(&q->freequeue, nc, next);
     890           0 :         }
     891           0 :         splx(s);
     892           0 :         if (!nc)
     893           0 :                 return (ENOMEM);
     894             : 
     895           0 :         bzero(nc, sizeof(*nc));
     896           0 :         memcpy(nc->cmd, cmd, len);
     897           0 :         nc->cmdlen = len;
     898           0 :         nc->responselen = responselen;
     899           0 :         nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
     900             : 
     901           0 :         s = spltty();
     902             : 
     903           0 :         if (q->polling && sync) {
     904             :                 /*
     905             :                  * XXX We should poll until the queue is empty.
     906             :                  * But we don't come here normally, so make
     907             :                  * it simple and throw away everything.
     908             :                  */
     909           0 :                 pckbc_cleanqueue(q);
     910           0 :         }
     911             : 
     912           0 :         isactive = CMD_IN_QUEUE(q);
     913           0 :         TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
     914           0 :         if (!isactive)
     915           0 :                 pckbc_start(t, slot);
     916             : 
     917           0 :         if (q->polling)
     918           0 :                 res = (sync ? nc->status : 0);
     919           0 :         else if (sync) {
     920           0 :                 if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
     921           0 :                         TAILQ_REMOVE(&q->cmdqueue, nc, next);
     922           0 :                         pckbc_cleanup(t);
     923           0 :                 } else {
     924           0 :                         TAILQ_REMOVE(&q->cmdqueue, nc, next);
     925           0 :                         res = nc->status;
     926             :                 }
     927             :         } else
     928           0 :                 timeout_add_sec(&t->t_cleanup, 1);
     929             : 
     930           0 :         if (sync) {
     931           0 :                 if (respbuf)
     932           0 :                         memcpy(respbuf, nc->response, responselen);
     933           0 :                 TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
     934           0 :         }
     935             : 
     936           0 :         splx(s);
     937             : 
     938           0 :         return (res);
     939           0 : }
     940             : 
     941             : void
     942           0 : pckbc_set_inputhandler(pckbc_tag_t self, pckbc_slot_t slot, pckbc_inputfcn func,
     943             :     void *arg, char *name)
     944             : {
     945           0 :         struct pckbc_internal *t = (struct pckbc_internal *)self;
     946           0 :         struct pckbc_softc *sc = t->t_sc;
     947             : 
     948           0 :         if (slot >= PCKBC_NSLOTS)
     949           0 :                 panic("pckbc_set_inputhandler: bad slot %d", slot);
     950             : 
     951           0 :         sc->inputhandler[slot] = func;
     952           0 :         sc->inputarg[slot] = arg;
     953           0 :         sc->subname[slot] = name;
     954             : 
     955           0 :         if (pckbc_console && slot == PCKBC_KBD_SLOT)
     956           0 :                 timeout_add_sec(&t->t_poll, 1);
     957           0 : }
     958             : 
     959             : void
     960           0 : pckbc_poll(void *v)
     961             : {
     962           0 :         struct pckbc_internal *t = v;
     963             :         int s;
     964             : 
     965           0 :         s = spltty();
     966           0 :         (void)pckbcintr_internal(t, t->t_sc);
     967           0 :         timeout_add_sec(&t->t_poll, 1);
     968           0 :         splx(s);
     969           0 : }
     970             : 
     971             : int
     972           0 : pckbcintr(void *vsc)
     973             : {
     974           0 :         struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
     975             : 
     976           0 :         return (pckbcintr_internal(sc->id, sc));
     977             : }
     978             : 
     979             : int
     980           0 : pckbcintr_internal(struct pckbc_internal *t, struct pckbc_softc *sc)
     981             : {
     982             :         u_char stat;
     983             :         pckbc_slot_t slot;
     984             :         struct pckbc_slotdata *q;
     985             :         int served = 0, data;
     986             : 
     987             :         /* reschedule timeout further into the idle times */
     988           0 :         if (timeout_pending(&t->t_poll))
     989           0 :                 timeout_add_sec(&t->t_poll, 1);
     990             : 
     991           0 :         for(;;) {
     992           0 :                 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
     993           0 :                 if (!(stat & KBS_DIB))
     994             :                         break;
     995             : 
     996             :                 served = 1;
     997             : 
     998           0 :                 slot = (t->t_haveaux && (stat & KBS_AUXDATA)) ?
     999             :                     PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
    1000           0 :                 q = t->t_slotdata[slot];
    1001             : 
    1002           0 :                 if (!q) {
    1003             :                         /* XXX do something for live insertion? */
    1004             : #ifdef PCKBCDEBUG
    1005             :                         printf("pckbcintr: no dev for slot %d\n", slot);
    1006             : #endif
    1007           0 :                         KBD_DELAY;
    1008           0 :                         (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
    1009           0 :                         continue;
    1010             :                 }
    1011             : 
    1012           0 :                 if (q->polling)
    1013             :                         break; /* pckbc_poll_data() will get it */
    1014             : 
    1015           0 :                 KBD_DELAY;
    1016           0 :                 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
    1017             : 
    1018           0 :                 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
    1019           0 :                         continue;
    1020             : 
    1021           0 :                 if (sc != NULL) {
    1022           0 :                         if (sc->inputhandler[slot])
    1023           0 :                                 (*sc->inputhandler[slot])(sc->inputarg[slot],
    1024             :                                     data);
    1025             : #ifdef PCKBCDEBUG
    1026             :                         else
    1027             :                                 printf("pckbcintr: slot %d lost %d\n",
    1028             :                                     slot, data);
    1029             : #endif
    1030             :                 }
    1031             :         }
    1032             : 
    1033           0 :         return (served);
    1034             : }
    1035             : 
    1036             : int
    1037           0 : pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, bus_size_t cmd_offset,
    1038             :     int flags)
    1039             : {
    1040           0 :         bus_space_handle_t ioh_d, ioh_c;
    1041             :         int res = 0;
    1042             : 
    1043           0 :         if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
    1044           0 :                 return (ENXIO);
    1045           0 :         if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
    1046           0 :                 bus_space_unmap(iot, ioh_d, 1);
    1047           0 :                 return (ENXIO);
    1048             :         }
    1049             : 
    1050           0 :         pckbc_consdata.t_iot = iot;
    1051           0 :         pckbc_consdata.t_ioh_d = ioh_d;
    1052           0 :         pckbc_consdata.t_ioh_c = ioh_c;
    1053           0 :         pckbc_consdata.t_addr = addr;
    1054           0 :         pckbc_consdata.t_flags = flags;
    1055           0 :         timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata);
    1056           0 :         timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata);
    1057             : 
    1058             :         /* flush */
    1059           0 :         (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
    1060             : 
    1061             :         /* selftest? */
    1062             : 
    1063             :         /* init cmd byte, enable ports */
    1064           0 :         pckbc_consdata.t_cmdbyte = KC8_CPU;
    1065           0 :         if (!pckbc_put8042cmd(&pckbc_consdata)) {
    1066           0 :                 printf("kbc: cmd word write error\n");
    1067             :                 res = EIO;
    1068           0 :         }
    1069             : 
    1070           0 :         if (!res) {
    1071             : #if (NPCKBD > 0)
    1072           0 :                 res = pckbd_cnattach(&pckbc_consdata);
    1073             : #else
    1074             :                 res = ENXIO;
    1075             : #endif /* NPCKBD > 0 */
    1076           0 :         }
    1077             : 
    1078           0 :         if (res) {
    1079           0 :                 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
    1080           0 :                 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
    1081           0 :         } else {
    1082           0 :                 pckbc_consdata.t_slotdata[PCKBC_KBD_SLOT] = &pckbc_cons_slotdata;
    1083           0 :                 pckbc_init_slotdata(&pckbc_cons_slotdata);
    1084           0 :                 pckbc_console = 1;
    1085             :         }
    1086             : 
    1087           0 :         return (res);
    1088           0 : }
    1089             : 
    1090             : struct cfdriver pckbc_cd = {
    1091             :         NULL, "pckbc", DV_DULL
    1092             : };

Generated by: LCOV version 1.13