The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/pckbc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: pckbc.c,v 1.32 2004/03/24 17:26:53 drochner Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2004 Ben Harris.
    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/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.32 2004/03/24 17:26:53 drochner Exp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/callout.h>
   35 #include <sys/kernel.h>
   36 #include <sys/proc.h>
   37 #include <sys/device.h>
   38 #include <sys/malloc.h>
   39 #include <sys/errno.h>
   40 #include <sys/queue.h>
   41 #include <sys/lock.h>
   42 
   43 #include <machine/bus.h>
   44 
   45 #include <dev/ic/i8042reg.h>
   46 #include <dev/ic/pckbcvar.h>
   47 
   48 #include <dev/pckbport/pckbportvar.h>
   49 
   50 #include "rnd.h"
   51 #include "locators.h"
   52 
   53 #if NRND > 0
   54 #include <sys/rnd.h>
   55 #endif
   56 
   57 /* data per slave device */
   58 struct pckbc_slotdata {
   59         int polling;    /* don't process data in interrupt handler */
   60         int poll_data;  /* data read from inr handler if polling */
   61         int poll_stat;  /* status read from inr handler if polling */
   62 #if NRND > 0
   63         rndsource_element_t     rnd_source;
   64 #endif
   65 };
   66 
   67 static void pckbc_init_slotdata __P((struct pckbc_slotdata *));
   68 static int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
   69 
   70 struct pckbc_internal pckbc_consdata;
   71 int pckbc_console_attached;
   72 
   73 static int pckbc_console;
   74 static struct pckbc_slotdata pckbc_cons_slotdata;
   75 
   76 static int pckbc_xt_translation __P((void *, pckbport_slot_t, int));
   77 static int pckbc_send_devcmd __P((void *, pckbport_slot_t, u_char));
   78 static void pckbc_slot_enable __P((void *, pckbport_slot_t, int));
   79 static void pckbc_intr_establish __P((void *, pckbport_slot_t));
   80 static void pckbc_set_poll __P((void *, pckbc_slot_t, int on));
   81 
   82 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
   83 
   84 static int pckbc_get8042cmd __P((struct pckbc_internal *));
   85 static int pckbc_put8042cmd __P((struct pckbc_internal *));
   86 
   87 void pckbc_cleanqueue __P((struct pckbc_slotdata *));
   88 void pckbc_cleanup __P((void *));
   89 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
   90 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
   91 
   92 const char * const pckbc_slot_names[] = { "kbd", "aux" };
   93 
   94 static struct pckbport_accessops const pckbc_ops = {
   95         pckbc_xt_translation,
   96         pckbc_send_devcmd,
   97         pckbc_poll_data1,
   98         pckbc_slot_enable,
   99         pckbc_intr_establish,
  100         pckbc_set_poll
  101 };
  102 
  103 #define KBD_DELAY       DELAY(8)
  104 
  105 static inline int
  106 pckbc_wait_output(iot, ioh_c)
  107         bus_space_tag_t iot;
  108         bus_space_handle_t ioh_c;
  109 {
  110         u_int i;
  111 
  112         for (i = 100000; i; i--)
  113                 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
  114                         KBD_DELAY;
  115                         return (1);
  116                 }
  117         return (0);
  118 }
  119 
  120 int
  121 pckbc_send_cmd(iot, ioh_c, val)
  122         bus_space_tag_t iot;
  123         bus_space_handle_t ioh_c;
  124         u_char val;
  125 {
  126         if (!pckbc_wait_output(iot, ioh_c))
  127                 return (0);
  128         bus_space_write_1(iot, ioh_c, 0, val);
  129         return (1);
  130 }
  131 
  132 /*
  133  * Note: the spl games here are to deal with some strange PC kbd controllers
  134  * in some system configurations.
  135  * This is not canonical way to handle polling input.
  136  */
  137 int
  138 pckbc_poll_data1(pt, slot)
  139         void *pt;
  140         pckbc_slot_t slot;
  141 {
  142         struct pckbc_internal *t = pt;
  143         struct pckbc_slotdata *q = t->t_slotdata[slot];
  144         int s;
  145         u_char stat, c;
  146         int i = 100000; /* if 1 port read takes 1us (?), this polls for 100ms */
  147         int checkaux = t->t_haveaux;
  148 
  149         s = splhigh();
  150 
  151         if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
  152                 stat    = q->poll_stat;
  153                 c       = q->poll_data;
  154                 q->poll_data = -1;
  155                 q->poll_stat = -1;
  156                 goto process;
  157         }
  158 
  159         for (; i; i--) {
  160                 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
  161                 if (stat & KBS_DIB) {
  162                         KBD_DELAY;
  163                         c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
  164                     
  165                     process:
  166                         if (checkaux && (stat & 0x20)) { /* aux data */
  167                                 if (slot != PCKBC_AUX_SLOT) {
  168 #ifdef PCKBCDEBUG
  169                                         printf("lost aux 0x%x\n", c);
  170 #endif
  171                                         continue;
  172                                 }
  173                         } else {
  174                                 if (slot == PCKBC_AUX_SLOT) {
  175 #ifdef PCKBCDEBUG
  176                                         printf("lost kbd 0x%x\n", c);
  177 #endif
  178                                         continue;
  179                                 }
  180                         }
  181                         splx(s);
  182                         return (c);
  183                 }
  184         }
  185 
  186         splx(s);
  187         return (-1);
  188 }
  189 
  190 /*
  191  * Get the current command byte.
  192  */
  193 static int
  194 pckbc_get8042cmd(t)
  195         struct pckbc_internal *t;
  196 {
  197         bus_space_tag_t iot = t->t_iot;
  198         bus_space_handle_t ioh_c = t->t_ioh_c;
  199         int data;
  200 
  201         if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
  202                 return (0);
  203         data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
  204         if (data == -1)
  205                 return (0);
  206         t->t_cmdbyte = data;
  207         return (1);
  208 }
  209 
  210 /*
  211  * Pass command byte to keyboard controller (8042).
  212  */
  213 static int
  214 pckbc_put8042cmd(t)
  215         struct pckbc_internal *t;
  216 {
  217         bus_space_tag_t iot = t->t_iot;
  218         bus_space_handle_t ioh_d = t->t_ioh_d;
  219         bus_space_handle_t ioh_c = t->t_ioh_c;
  220 
  221         if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
  222                 return (0);
  223         if (!pckbc_wait_output(iot, ioh_c))
  224                 return (0);
  225         bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
  226         return (1);
  227 }
  228 
  229 static int
  230 pckbc_send_devcmd(pt, slot, val)
  231         void *pt;
  232         pckbc_slot_t slot;
  233         u_char val;
  234 {
  235         struct pckbc_internal *t = pt;
  236         bus_space_tag_t iot = t->t_iot;
  237         bus_space_handle_t ioh_d = t->t_ioh_d;
  238         bus_space_handle_t ioh_c = t->t_ioh_c;
  239 
  240         if (slot == PCKBC_AUX_SLOT) {
  241                 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
  242                         return (0);
  243         }
  244         if (!pckbc_wait_output(iot, ioh_c))
  245                 return (0);
  246         bus_space_write_1(iot, ioh_d, 0, val);
  247         return (1);
  248 }
  249 
  250 int
  251 pckbc_is_console(iot, addr)
  252         bus_space_tag_t iot;
  253         bus_addr_t addr;
  254 {
  255         if (pckbc_console && !pckbc_console_attached &&
  256             pckbc_consdata.t_iot == iot &&
  257             pckbc_consdata.t_addr == addr)
  258                 return (1);
  259         return (0);
  260 }
  261 
  262 static 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         void *sdata;
  270         struct device *child;
  271         int alloced = 0;
  272 
  273         pa.pa_tag = t;
  274         pa.pa_slot = slot;
  275 
  276         if (t->t_slotdata[slot] == NULL) {
  277                 sdata = malloc(sizeof(struct pckbc_slotdata),
  278                     M_DEVBUF, M_NOWAIT);
  279                 if (sdata == NULL) {
  280                         printf("%s: no memory\n", sc->sc_dv.dv_xname);
  281                         return (0);
  282                 }
  283                 t->t_slotdata[slot] = sdata;
  284                 pckbc_init_slotdata(t->t_slotdata[slot]);
  285                 alloced++;
  286         }
  287 
  288         child = pckbport_attach_slot(&sc->sc_dv, t->t_pt, slot);
  289 
  290         if (child == NULL && alloced) {
  291                 free(t->t_slotdata[slot], M_DEVBUF);
  292                 t->t_slotdata[slot] = NULL;
  293         }
  294 
  295 #if NRND > 0
  296         if (child != NULL && t->t_slotdata[slot] != NULL)
  297                 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
  298                     child->dv_xname, RND_TYPE_TTY, 0);
  299 #endif
  300         return child != NULL;
  301 }
  302 
  303 void
  304 pckbc_attach(sc)
  305         struct pckbc_softc *sc;
  306 {
  307         struct pckbc_internal *t;
  308         bus_space_tag_t iot;
  309         bus_space_handle_t ioh_d, ioh_c;
  310         int res;
  311         u_char cmdbits = 0;
  312 
  313         t = sc->id;
  314         iot = t->t_iot;
  315         ioh_d = t->t_ioh_d;
  316         ioh_c = t->t_ioh_c;
  317 
  318         t->t_pt = pckbport_attach(t, &pckbc_ops);
  319         if (t->t_pt == NULL) {
  320                 aprint_error(": attach failed\n");
  321                 return;
  322         }
  323 
  324         /* flush */
  325         (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
  326 
  327         /* set initial cmd byte */
  328         if (!pckbc_put8042cmd(t)) {
  329                 printf("kbc: cmd word write error\n");
  330                 return;
  331         }
  332 
  333 /*
  334  * XXX Don't check the keyboard port. There are broken keyboard controllers
  335  * which don't pass the test but work normally otherwise.
  336  */
  337 #if 0
  338         /*
  339          * check kbd port ok
  340          */
  341         if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
  342                 return;
  343         res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
  344 
  345         /*
  346          * Normally, we should get a "" here.
  347          * But there are keyboard controllers behaving differently.
  348          */
  349         if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
  350 #ifdef PCKBCDEBUG
  351                 if (res != 0)
  352                         printf("kbc: returned %x on kbd slot test\n", res);
  353 #endif
  354                 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
  355                         cmdbits |= KC8_KENABLE;
  356         } else {
  357                 printf("kbc: kbd port test: %x\n", res);
  358                 return;
  359         }
  360 #else
  361         if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
  362                 cmdbits |= KC8_KENABLE;
  363 #endif /* 0 */
  364 
  365         /*
  366          * Check aux port ok.
  367          * Avoid KBC_AUXTEST because it hangs some older controllers
  368          *  (eg UMC880?).
  369          */
  370         if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
  371                 printf("kbc: aux echo error 1\n");
  372                 goto nomouse;
  373         }
  374         if (!pckbc_wait_output(iot, ioh_c)) {
  375                 printf("kbc: aux echo error 2\n");
  376                 goto nomouse;
  377         }
  378         t->t_haveaux = 1;
  379         bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
  380         res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
  381         if (res != -1) {
  382                 /*
  383                  * In most cases, the 0x5a gets echoed.
  384                  * Some older controllers (Gateway 2000 circa 1993)
  385                  * return 0xfe here.
  386                  * We are satisfied if there is anything in the
  387                  * aux output buffer.
  388                  */
  389                 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
  390                         cmdbits |= KC8_MENABLE;
  391         } else {
  392 #ifdef PCKBCDEBUG
  393                 printf("kbc: aux echo test failed\n");
  394 #endif
  395                 t->t_haveaux = 0;
  396         }
  397 
  398 nomouse:
  399         /* enable needed interrupts */
  400         t->t_cmdbyte |= cmdbits;
  401         if (!pckbc_put8042cmd(t))
  402                 printf("kbc: cmd word write error\n");
  403 }
  404 
  405 static void
  406 pckbc_init_slotdata(q)
  407         struct pckbc_slotdata *q;
  408 {
  409 
  410         q->polling = 0;
  411 }
  412 
  413 /*
  414  * switch scancode translation on / off
  415  * return nonzero on success
  416  */
  417 static int
  418 pckbc_xt_translation(self, slot, on)
  419         void *self;
  420         pckbc_slot_t slot;
  421         int on;
  422 {
  423         struct pckbc_internal *t = self;
  424         int ison;
  425 
  426         if (slot != PCKBC_KBD_SLOT) {
  427                 /* translation only for kbd slot */
  428                 if (on)
  429                         return (0);
  430                 else
  431                         return (1);
  432         }
  433 
  434         ison = t->t_cmdbyte & KC8_TRANS;
  435         if ((on && ison) || (!on && !ison))
  436                 return (1);
  437 
  438         t->t_cmdbyte ^= KC8_TRANS;
  439         if (!pckbc_put8042cmd(t))
  440                 return (0);
  441 
  442         /* read back to be sure */
  443         if (!pckbc_get8042cmd(t))
  444                 return (0);
  445 
  446         ison = t->t_cmdbyte & KC8_TRANS;
  447         if ((on && ison) || (!on && !ison))
  448                 return (1);
  449         return (0);
  450 }
  451 
  452 static const struct pckbc_portcmd {
  453         u_char cmd_en, cmd_dis;
  454 } pckbc_portcmd[2] = {
  455         {
  456                 KBC_KBDENABLE, KBC_KBDDISABLE,
  457         }, {
  458                 KBC_AUXENABLE, KBC_AUXDISABLE,
  459         }
  460 };
  461 
  462 void
  463 pckbc_slot_enable(self, slot, on)
  464         void *self;
  465         pckbc_slot_t slot;
  466         int on;
  467 {
  468         struct pckbc_internal *t = (struct pckbc_internal *)self;
  469         const struct pckbc_portcmd *cmd;
  470 
  471         cmd = &pckbc_portcmd[slot];
  472 
  473         if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
  474                             on ? cmd->cmd_en : cmd->cmd_dis))
  475                 printf("pckbc_slot_enable(%d) failed\n", on);
  476 }
  477 
  478 static void
  479 pckbc_set_poll(self, slot, on)
  480         void *self;
  481         pckbc_slot_t slot;
  482         int on;
  483 {
  484         struct pckbc_internal *t = (struct pckbc_internal *)self;
  485 
  486         t->t_slotdata[slot]->polling = on;
  487 
  488         if (on) {
  489                 t->t_slotdata[slot]->poll_data = -1;
  490                 t->t_slotdata[slot]->poll_stat = -1;
  491         } else {
  492                 int s;
  493 
  494                 /*
  495                  * If disabling polling on a device that's been configured,
  496                  * make sure there are no bytes left in the FIFO, holding up
  497                  * the interrupt line.  Otherwise we won't get any further
  498                  * interrupts.
  499                  */
  500                 if (t->t_sc) {
  501                         s = spltty();
  502                         pckbcintr(t->t_sc);
  503                         splx(s);
  504                 }
  505         }
  506 }
  507 
  508 static void
  509 pckbc_intr_establish(pt, slot)
  510         void *pt;
  511         pckbport_slot_t slot;
  512 {
  513         struct pckbc_internal *t = pt;
  514 
  515         (*t->t_sc->intr_establish)(t->t_sc, slot);
  516 }
  517 
  518 int
  519 pckbcintr_hard(vsc)
  520         void *vsc;
  521 {
  522         struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
  523         struct pckbc_internal *t = sc->id;
  524         u_char stat;
  525         pckbc_slot_t slot;
  526         struct pckbc_slotdata *q;
  527         int served = 0, data, next, s;
  528 
  529         for(;;) {
  530                 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
  531                 if (!(stat & KBS_DIB))
  532                         break;
  533 
  534                 served = 1;
  535 
  536                 slot = (t->t_haveaux && (stat & 0x20)) ?
  537                     PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
  538                 q = t->t_slotdata[slot];
  539 
  540                 if (!q) {
  541                         /* XXX do something for live insertion? */
  542                         printf("pckbcintr: no dev for slot %d\n", slot);
  543                         KBD_DELAY;
  544                         (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
  545                         continue;
  546                 }
  547 
  548                 KBD_DELAY;
  549                 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
  550 
  551 #if NRND > 0
  552                 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
  553 #endif
  554 
  555                 if (q->polling) {
  556                         q->poll_data = data;
  557                         q->poll_stat = stat;
  558                         break; /* pckbc_poll_data() will get it */
  559                 }
  560 
  561 #if 0 /* XXXBJH */
  562                 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
  563                         continue;
  564 #endif
  565 
  566                 s = splhigh();
  567                 next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
  568                 if (next == t->rbuf_read) {
  569                         splx(s);
  570                         break;
  571                 }
  572                 t->rbuf[t->rbuf_write].data = data;
  573                 t->rbuf[t->rbuf_write].slot = slot;
  574                 t->rbuf_write = next;
  575                 splx(s);
  576         }
  577 
  578         return (served);
  579 }
  580 
  581 void
  582 pckbcintr_soft(vsc)
  583         void *vsc;
  584 {
  585         struct pckbc_softc *sc = vsc;
  586         struct pckbc_internal *t = sc->id;
  587         int data, slot, s;
  588 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
  589         int st;
  590 
  591         st = spltty();
  592 #endif
  593 
  594         s = splhigh();
  595         while (t->rbuf_read != t->rbuf_write) {
  596                 slot = t->rbuf[t->rbuf_read].slot;
  597                 data = t->rbuf[t->rbuf_read].data;
  598                 t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
  599                 splx(s);
  600                 pckbportintr(t->t_pt, slot, data);
  601                 s = splhigh();
  602         }
  603         splx(s);
  604 
  605 
  606 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
  607         splx(st);
  608 #endif
  609 }
  610 
  611 int
  612 pckbcintr(vsc)
  613         void *vsc;
  614 {
  615         struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
  616         struct pckbc_internal *t = sc->id;
  617         u_char stat;
  618         pckbc_slot_t slot;
  619         struct pckbc_slotdata *q;
  620         int served = 0, data;
  621 
  622         for(;;) {
  623                 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
  624                 if (!(stat & KBS_DIB))
  625                         break;
  626 
  627                 served = 1;
  628 
  629                 slot = (t->t_haveaux && (stat & 0x20)) ?
  630                     PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
  631                 q = t->t_slotdata[slot];
  632 
  633                 KBD_DELAY;
  634                 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
  635 
  636 #if NRND > 0
  637                 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
  638 #endif
  639 
  640                 pckbportintr(t->t_pt, slot, data);
  641         }
  642 
  643         return (served);
  644 }
  645 
  646 int
  647 pckbc_cnattach(iot, addr, cmd_offset, slot)
  648         bus_space_tag_t iot;
  649         bus_addr_t addr;
  650         bus_size_t cmd_offset;
  651         pckbc_slot_t slot;
  652 {
  653         bus_space_handle_t ioh_d, ioh_c;
  654 #ifdef PCKBC_CNATTACH_SELFTEST
  655         int reply;
  656 #endif
  657         int res = 0;
  658 
  659         if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
  660                 return (ENXIO);
  661         if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
  662                 bus_space_unmap(iot, ioh_d, 1);
  663                 return (ENXIO);
  664         }
  665 
  666         memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
  667         pckbc_consdata.t_iot = iot;
  668         pckbc_consdata.t_ioh_d = ioh_d;
  669         pckbc_consdata.t_ioh_c = ioh_c;
  670         pckbc_consdata.t_addr = addr;
  671         callout_init(&pckbc_consdata.t_cleanup);
  672 
  673         /* flush */
  674         (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
  675 
  676 #ifdef PCKBC_CNATTACH_SELFTEST
  677         /*
  678          * In some machines (e.g. netwinder) pckbc refuses to talk at
  679          * all until we request a self-test.
  680          */
  681         if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
  682                 printf("kbc: unable to request selftest\n");
  683                 res = EIO;
  684                 goto out;
  685         }
  686 
  687         reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
  688         if (reply != 0x55) {
  689                 printf("kbc: selftest returned 0x%02x\n", reply);
  690                 res = EIO;
  691                 goto out;
  692         }
  693 #endif /* PCKBC_CNATTACH_SELFTEST */
  694 
  695         /* init cmd byte, enable ports */
  696         pckbc_consdata.t_cmdbyte = KC8_CPU;
  697         if (!pckbc_put8042cmd(&pckbc_consdata)) {
  698                 printf("kbc: cmd word write error\n");
  699                 res = EIO;
  700                 goto out;
  701         }
  702 
  703         res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
  704 
  705   out:
  706         if (res) {
  707                 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
  708                 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
  709         } else {
  710                 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
  711                 pckbc_init_slotdata(&pckbc_cons_slotdata);
  712                 pckbc_console = 1;
  713         }
  714 
  715         return (res);
  716 }

Cache object: 987152275537a091b1052f6fc2b99141


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.