root/dev/ic/pckbc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pckbc_wait_output
  2. pckbc_send_cmd
  3. pckbc_poll_data1
  4. pckbc_get8042cmd
  5. pckbc_put8042cmd
  6. pckbc_send_devcmd
  7. pckbc_is_console
  8. pckbc_submatch
  9. pckbc_attach_slot
  10. pckbc_attach
  11. pckbcprint
  12. pckbc_init_slotdata
  13. pckbc_flush
  14. pckbc_poll_data
  15. pckbc_xt_translation
  16. pckbc_slot_enable
  17. pckbc_set_poll
  18. pckbc_poll_cmd1
  19. pckbc_poll_cmd
  20. pckbc_cleanqueue
  21. pckbc_cleanup
  22. pckbc_start
  23. pckbc_cmdresponse
  24. pckbc_enqueue_cmd
  25. pckbc_set_inputhandler
  26. pckbc_poll
  27. pckbcintr
  28. pckbcintr_internal
  29. pckbc_cnattach

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

/* [<][>][^][v][top][bottom][index][help] */