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/atkbdc/atkbdc_isa.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer as
   12  *    the first lines of this file unmodified.
   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 AUTHORS ``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 AUTHORS 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 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_kbd.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/bus.h>
   39 #include <sys/malloc.h>
   40 #include <machine/resource.h>
   41 #include <sys/rman.h>
   42 #include <machine/bus.h>
   43 
   44 #include <dev/atkbdc/atkbdc_subr.h>
   45 #include <dev/atkbdc/atkbdcreg.h>
   46 
   47 #include <isa/isareg.h>
   48 #include <isa/isavar.h>
   49 
   50 static int      atkbdc_isa_probe(device_t dev);
   51 static int      atkbdc_isa_attach(device_t dev);
   52 static device_t atkbdc_isa_add_child(device_t bus, u_int order, const char *name,
   53                     int unit);
   54 static struct resource *atkbdc_isa_alloc_resource(device_t dev, device_t child,
   55                     int type, int *rid, rman_res_t start, rman_res_t end,
   56                     rman_res_t count, u_int flags);
   57 static int      atkbdc_isa_release_resource(device_t dev, device_t child,
   58                     int type, int rid, struct resource *r);
   59 
   60 static device_method_t atkbdc_isa_methods[] = {
   61         DEVMETHOD(device_probe,         atkbdc_isa_probe),
   62         DEVMETHOD(device_attach,        atkbdc_isa_attach),
   63         DEVMETHOD(device_suspend,       bus_generic_suspend),
   64         DEVMETHOD(device_resume,        bus_generic_resume),
   65 
   66         DEVMETHOD(bus_add_child,        atkbdc_isa_add_child),
   67         DEVMETHOD(bus_print_child,      atkbdc_print_child),
   68         DEVMETHOD(bus_read_ivar,        atkbdc_read_ivar),
   69         DEVMETHOD(bus_write_ivar,       atkbdc_write_ivar),
   70         DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list),
   71         DEVMETHOD(bus_alloc_resource,   atkbdc_isa_alloc_resource),
   72         DEVMETHOD(bus_release_resource, atkbdc_isa_release_resource),
   73         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
   74         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
   75         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
   76         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
   77         DEVMETHOD(bus_delete_resource,  bus_generic_rl_delete_resource),
   78         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
   79         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
   80         { 0, 0 }
   81 };
   82 
   83 static driver_t atkbdc_isa_driver = {
   84         ATKBDC_DRIVER_NAME,
   85         atkbdc_isa_methods,
   86         sizeof(atkbdc_softc_t *),
   87 };
   88 
   89 static struct isa_pnp_id atkbdc_ids[] = {
   90         { 0x0303d041, "Keyboard controller (i8042)" },  /* PNP0303 */
   91         { 0x0b03d041, "Keyboard controller (i8042)" },  /* PNP030B */
   92         { 0x2003d041, "Keyboard controller (i8042)" },  /* PNP0320 */
   93         { 0 }
   94 };
   95 
   96 static int
   97 atkbdc_isa_probe(device_t dev)
   98 {
   99         struct resource *port0;
  100         struct resource *port1;
  101         rman_res_t      start;
  102         rman_res_t      count;
  103         int             error;
  104         int             rid;
  105 #if defined(__i386__) || defined(__amd64__)
  106         bus_space_tag_t tag;
  107         bus_space_handle_t ioh1;
  108         volatile int    i;
  109         register_t      flags;
  110 #endif
  111 
  112         /* check PnP IDs */
  113         if (ISA_PNP_PROBE(device_get_parent(dev), dev, atkbdc_ids) == ENXIO)
  114                 return ENXIO;
  115 
  116         device_set_desc(dev, "Keyboard controller (i8042)");
  117 
  118         /*
  119          * Adjust I/O port resources.
  120          * The AT keyboard controller uses two ports (a command/data port
  121          * 0x60 and a status port 0x64), which may be given to us in 
  122          * one resource (0x60 through 0x64) or as two separate resources
  123          * (0x60 and 0x64). Some brain-damaged ACPI BIOS has reversed
  124          * command/data port and status port. Furthermore, /boot/device.hints
  125          * may contain just one port, 0x60. We shall adjust resource settings
  126          * so that these two ports are available as two separate resources
  127          * in correct order.
  128          */
  129         device_quiet(dev);
  130         rid = 0;
  131         if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
  132                 return ENXIO;
  133         if (start == IO_KBD + KBD_STATUS_PORT) {
  134                 start = IO_KBD;
  135                 count++;
  136         }
  137         if (count > 1)  /* adjust the count and/or start port */
  138                 bus_set_resource(dev, SYS_RES_IOPORT, rid, start, 1);
  139         port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
  140         if (port0 == NULL)
  141                 return ENXIO;
  142         rid = 1;
  143         if (bus_get_resource(dev, SYS_RES_IOPORT, rid, NULL, NULL) != 0)
  144                 bus_set_resource(dev, SYS_RES_IOPORT, 1,
  145                                  start + KBD_STATUS_PORT, 1);
  146         port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
  147         if (port1 == NULL) {
  148                 bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
  149                 return ENXIO;
  150         }
  151 
  152 #if defined(__i386__) || defined(__amd64__)
  153         /*
  154          * Check if we really have AT keyboard controller. Poll status
  155          * register until we get "all clear" indication. If no such
  156          * indication comes, it probably means that there is no AT
  157          * keyboard controller present. Give up in such case. Check relies
  158          * on the fact that reading from non-existing in/out port returns
  159          * 0xff on i386. May or may not be true on other platforms.
  160          */
  161         tag = rman_get_bustag(port0);
  162         ioh1 = rman_get_bushandle(port1);
  163         flags = intr_disable();
  164         for (i = 0; i != 65535; i++) {
  165                 if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0)
  166                         break;
  167         }
  168         intr_restore(flags);
  169         if (i == 65535) {
  170                 bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
  171                 bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
  172                 if (bootverbose)
  173                         device_printf(dev, "AT keyboard controller not found\n");
  174                 return ENXIO;
  175         }
  176 #endif
  177 
  178         device_verbose(dev);
  179 
  180         error = atkbdc_probe_unit(device_get_unit(dev), port0, port1);
  181 
  182         bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
  183         bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
  184 
  185         return error;
  186 }
  187 
  188 static int
  189 atkbdc_isa_attach(device_t dev)
  190 {
  191         atkbdc_softc_t  *sc;
  192         int             unit;
  193         int             error;
  194         int             rid;
  195 
  196         unit = device_get_unit(dev);
  197         sc = *(atkbdc_softc_t **)device_get_softc(dev);
  198         if (sc == NULL) {
  199                 /*
  200                  * We have to maintain two copies of the kbdc_softc struct,
  201                  * as the low-level console needs to have access to the
  202                  * keyboard controller before kbdc is probed and attached.
  203                  * kbdc_soft[] contains the default entry for that purpose.
  204                  * See atkbdc.c. XXX
  205                  */
  206                 sc = atkbdc_get_softc(unit);
  207                 if (sc == NULL)
  208                         return ENOMEM;
  209         }
  210 
  211         rid = 0;
  212         sc->retry = 5000;
  213         sc->port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  214                                            RF_ACTIVE);
  215         if (sc->port0 == NULL)
  216                 return ENXIO;
  217         rid = 1;
  218         sc->port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  219                                            RF_ACTIVE);
  220         if (sc->port1 == NULL) {
  221                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
  222                 return ENXIO;
  223         }
  224 
  225         /*
  226          * If the device is not created by the PnP BIOS or ACPI, then
  227          * the hint for the IRQ is on the child atkbd device, not the
  228          * keyboard controller, so this can fail.
  229          */
  230         rid = 0;
  231         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
  232 
  233         error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1);
  234         if (error) {
  235                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
  236                 bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1);
  237                 if (sc->irq != NULL)
  238                         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
  239                 return error;
  240         }
  241         *(atkbdc_softc_t **)device_get_softc(dev) = sc;
  242 
  243         bus_generic_probe(dev);
  244         bus_generic_attach(dev);
  245 
  246         return 0;
  247 }
  248 
  249 static device_t
  250 atkbdc_isa_add_child(device_t bus, u_int order, const char *name, int unit)
  251 {
  252         atkbdc_device_t *ivar;
  253         atkbdc_softc_t  *sc;
  254         device_t        child;
  255         int             t;
  256 
  257         sc = *(atkbdc_softc_t **)device_get_softc(bus);
  258         ivar = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV,
  259                 M_NOWAIT | M_ZERO);
  260         if (!ivar)
  261                 return NULL;
  262 
  263         child = device_add_child_ordered(bus, order, name, unit);
  264         if (child == NULL) {
  265                 free(ivar, M_ATKBDDEV);
  266                 return child;
  267         }
  268 
  269         resource_list_init(&ivar->resources);
  270         ivar->rid = order;
  271 
  272         /*
  273          * If the device is not created by the PnP BIOS or ACPI, refer
  274          * to device hints for IRQ.  We always populate the resource
  275          * list entry so we can use a standard bus_get_resource()
  276          * method.
  277          */
  278         if (order == KBDC_RID_KBD) {
  279                 if (sc->irq == NULL) {
  280                         if (resource_int_value(name, unit, "irq", &t) != 0)
  281                                 t = -1;
  282                 } else
  283                         t = rman_get_start(sc->irq);
  284                 if (t > 0)
  285                         resource_list_add(&ivar->resources, SYS_RES_IRQ,
  286                             ivar->rid, t, t, 1);
  287         }
  288 
  289         if (resource_disabled(name, unit))
  290                 device_disable(child);
  291 
  292         device_set_ivars(child, ivar);
  293 
  294         return child;
  295 }
  296 
  297 struct resource *
  298 atkbdc_isa_alloc_resource(device_t dev, device_t child, int type, int *rid,
  299     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  300 {
  301         atkbdc_softc_t  *sc;
  302 
  303         sc = *(atkbdc_softc_t **)device_get_softc(dev);
  304         if (type == SYS_RES_IRQ && *rid == KBDC_RID_KBD && sc->irq != NULL)
  305                 return (sc->irq);
  306         return (bus_generic_rl_alloc_resource(dev, child, type, rid, start,
  307             end, count, flags));
  308 }
  309 
  310 static int
  311 atkbdc_isa_release_resource(device_t dev, device_t child, int type, int rid,
  312     struct resource *r)
  313 {
  314         atkbdc_softc_t  *sc;
  315 
  316         sc = *(atkbdc_softc_t **)device_get_softc(dev);
  317         if (type == SYS_RES_IRQ && rid == KBDC_RID_KBD && r == sc->irq)
  318                 return (0);
  319         return (bus_generic_rl_release_resource(dev, child, type, rid, r));
  320 }
  321 
  322 DRIVER_MODULE(atkbdc, isa, atkbdc_isa_driver, 0, 0);
  323 DRIVER_MODULE(atkbdc, acpi, atkbdc_isa_driver, 0, 0);
  324 ISA_PNP_INFO(atkbdc_ids);

Cache object: b40fd79003c76fb6b4de189416cc19fc


[ 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.