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_ebus.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  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
    3  * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer as
   11  *    the first lines of this file unmodified.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  *      from: FreeBSD: src/sys/isa/atkbdc_isa.c,v 1.31 2005/05/29 04:42:28 nyan
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/8.1/sys/dev/atkbdc/atkbdc_ebus.c 147271 2005-06-10 20:56:38Z marius $");
   32 
   33 #include "opt_kbd.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/bus.h>
   40 #include <sys/kbio.h>
   41 #include <sys/malloc.h>
   42 
   43 #include <dev/ofw/ofw_bus.h>
   44 
   45 #include <machine/resource.h>
   46 #include <machine/ver.h>
   47 
   48 #include <sys/rman.h>
   49 
   50 #include <dev/kbd/kbdreg.h>
   51 #include <dev/atkbdc/atkbdreg.h>
   52 #include <dev/atkbdc/atkbdc_subr.h>
   53 #include <dev/atkbdc/atkbdcreg.h>
   54 #include <dev/atkbdc/psm.h>
   55 
   56 static device_probe_t atkbdc_ebus_probe;
   57 static device_attach_t atkbdc_ebus_attach;
   58 
   59 static device_method_t atkbdc_ebus_methods[] = {
   60         DEVMETHOD(device_probe,         atkbdc_ebus_probe),
   61         DEVMETHOD(device_attach,        atkbdc_ebus_attach),
   62         DEVMETHOD(device_suspend,       bus_generic_suspend),
   63         DEVMETHOD(device_resume,        bus_generic_resume),
   64 
   65         DEVMETHOD(bus_print_child,      atkbdc_print_child),
   66         DEVMETHOD(bus_read_ivar,        atkbdc_read_ivar),
   67         DEVMETHOD(bus_write_ivar,       atkbdc_write_ivar),
   68         DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list),
   69         DEVMETHOD(bus_alloc_resource,   bus_generic_rl_alloc_resource),
   70         DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
   71         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
   72         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
   73         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
   74         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
   75         DEVMETHOD(bus_delete_resource,  bus_generic_rl_delete_resource),
   76         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
   77         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
   78 
   79         { 0, 0 }
   80 };
   81 
   82 static driver_t atkbdc_ebus_driver = {
   83         ATKBDC_DRIVER_NAME,
   84         atkbdc_ebus_methods,
   85         sizeof(atkbdc_softc_t *),
   86 };
   87 
   88 DRIVER_MODULE(atkbdc, ebus, atkbdc_ebus_driver, atkbdc_devclass, 0, 0);
   89 
   90 static int
   91 atkbdc_ebus_probe(device_t dev)
   92 {
   93         struct resource *port0, *port1;
   94         u_long count, start;
   95         int error, rid;
   96 
   97         if (strcmp(ofw_bus_get_name(dev), "8042") != 0)
   98                 return (ENXIO);
   99 
  100         /*
  101          * On AXi and AXmp boards the NS16550 (used to connect keyboard/
  102          * mouse) share their IRQ lines with the i8042. Any IRQ activity
  103          * (typically during attach) of the NS16550 used to connect the
  104          * keyboard when actually the PS/2 keyboard is selected in OFW
  105          * causes interaction with the OBP i8042 driver resulting in a
  106          * hang and vice versa. As RS232 keyboards and mice obviously
  107          * aren't meant to be used in parallel with PS/2 ones on these
  108          * boards don't attach to the i8042 in case the PS/2 keyboard
  109          * isn't selected in order to prevent such hangs.
  110          * Note that it's not sufficient here to rely on the '8042' node
  111          * only showing up when a PS/2 keyboard is actually connected as
  112          * the user still might have adjusted the 'keyboard' alias to
  113          * point to the RS232 keyboard.
  114          */
  115         if ((!strcmp(sparc64_model, "SUNW,UltraAX-MP") ||
  116             !strcmp(sparc64_model, "SUNW,UltraSPARC-IIi-Engine")) &&
  117             OF_finddevice("keyboard") != ofw_bus_get_node(dev)) {
  118                 device_disable(dev);
  119                 return (ENXIO);
  120         }
  121 
  122         device_set_desc(dev, "Keyboard controller (i8042)");
  123 
  124         /*
  125          * The '8042' node has two identical 8 addresses wide resources
  126          * which are apparently meant to be used one for the keyboard
  127          * half and the other one for the mouse half. To simplify matters
  128          * we use one for the command/data port resource and the other
  129          * one for the status port resource as the atkbdc(4) back-end
  130          * expects two struct resource rather than two bus space handles.
  131          */
  132         rid = 0;
  133         if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) {
  134                 device_printf(dev,
  135                     "cannot determine command/data port resource\n");
  136                 return (ENXIO);
  137         }
  138         port0 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1,
  139             RF_ACTIVE);
  140         if (port0 == NULL) {
  141                 device_printf(dev,
  142                     "cannot allocate command/data port resource\n");
  143                 return (ENXIO);
  144         }
  145 
  146         rid = 1;
  147         if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) {
  148                 device_printf(dev, "cannot determine status port resource\n");
  149                 error = ENXIO;
  150                 goto fail_port0;
  151         }
  152         start += KBD_STATUS_PORT;
  153         port1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1,
  154             RF_ACTIVE);
  155         if (port1 == NULL) {
  156                 device_printf(dev, "cannot allocate status port resource\n");
  157                 error = ENXIO;
  158                 goto fail_port0;
  159         }
  160 
  161         error = atkbdc_probe_unit(device_get_unit(dev), port0, port1);
  162         if (error != 0)
  163                 device_printf(dev, "atkbdc_porbe_unit failed\n");
  164 
  165         bus_release_resource(dev, SYS_RES_MEMORY, 1, port1);
  166  fail_port0:
  167         bus_release_resource(dev, SYS_RES_MEMORY, 0, port0);
  168 
  169         return (error);
  170 }
  171 
  172 static int
  173 atkbdc_ebus_attach(device_t dev)
  174 {
  175         atkbdc_softc_t *sc;
  176         atkbdc_device_t *adi;
  177         device_t cdev;
  178         phandle_t child;
  179         u_long count, intr, start;
  180         int children, error, rid, unit;
  181         char *cname, *dname;
  182 
  183         unit = device_get_unit(dev);
  184         sc = *(atkbdc_softc_t **)device_get_softc(dev);
  185         if (sc == NULL) {
  186                 /*
  187                  * We have to maintain two copies of the kbdc_softc struct,
  188                  * as the low-level console needs to have access to the
  189                  * keyboard controller before kbdc is probed and attached.
  190                  * kbdc_soft[] contains the default entry for that purpose.
  191                  * See atkbdc.c. XXX
  192                  */
  193                 sc = atkbdc_get_softc(unit);
  194                 if (sc == NULL)
  195                         return (ENOMEM);
  196                 device_set_softc(dev, sc);
  197         }
  198 
  199         rid = 0;
  200         if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) {
  201                 device_printf(dev,
  202                     "cannot determine command/data port resource\n");
  203                 return (ENXIO);
  204         }
  205         sc->port0 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start,
  206             1, RF_ACTIVE);
  207         if (sc->port0 == NULL) {
  208                 device_printf(dev,
  209                     "cannot allocate command/data port resource\n");
  210                 return (ENXIO);
  211         }
  212 
  213         rid = 1;
  214         if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) {
  215                 device_printf(dev, "cannot determine status port resource\n");
  216                 error = ENXIO;
  217                 goto fail_port0;
  218         }
  219         start += KBD_STATUS_PORT;
  220         sc->port1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start,
  221             1, RF_ACTIVE);
  222         if (sc->port1 == NULL) {
  223                 device_printf(dev, "cannot allocate status port resource\n");
  224                 error = ENXIO;
  225                 goto fail_port0;
  226         }
  227 
  228         error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1);
  229         if (error != 0) {
  230                 device_printf(dev, "atkbdc_attach_unit failed\n");
  231                 goto fail_port1;
  232         }
  233 
  234         /* Attach children. */
  235         children = 0;
  236         for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
  237             child = OF_peer(child)) {
  238                 if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1)
  239                         continue;
  240                 if (children >= 2) {
  241                         device_printf(dev,
  242                             "<%s>: only two children per 8042 supported\n",
  243                             cname);
  244                         free(cname, M_OFWPROP);
  245                         continue;
  246                 }
  247                 adi = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV,
  248                     M_NOWAIT | M_ZERO);
  249                 if (adi == NULL) {
  250                         device_printf(dev, "<%s>: malloc failed\n", cname);
  251                         free(cname, M_OFWPROP);
  252                         continue;
  253                 }
  254                 if (strcmp(cname, "kb_ps2") == 0) {
  255                         adi->rid = KBDC_RID_KBD;
  256                         dname = ATKBD_DRIVER_NAME;
  257                 } else if (strcmp(cname, "kdmouse") == 0) {
  258                         adi->rid = KBDC_RID_AUX;
  259                         dname = PSM_DRIVER_NAME;
  260                 } else {
  261                         device_printf(dev, "<%s>: unknown device\n", cname);
  262                         free(adi, M_ATKBDDEV);
  263                         free(cname, M_OFWPROP);
  264                         continue;
  265                 }
  266                 intr = bus_get_resource_start(dev, SYS_RES_IRQ, adi->rid);
  267                 if (intr == 0) {
  268                         device_printf(dev,
  269                             "<%s>: cannot determine interrupt resource\n",
  270                             cname);
  271                         free(adi, M_ATKBDDEV);
  272                         free(cname, M_OFWPROP);
  273                         continue;
  274                 }
  275                 resource_list_init(&adi->resources);
  276                 resource_list_add(&adi->resources, SYS_RES_IRQ, adi->rid,
  277                     intr, intr, 1);
  278                 if ((cdev = device_add_child(dev, dname, -1)) == NULL) {
  279                         device_printf(dev, "<%s>: device_add_child failed\n",
  280                             cname);
  281                         resource_list_free(&adi->resources);
  282                         free(adi, M_ATKBDDEV);
  283                         free(cname, M_OFWPROP);
  284                         continue;
  285                 }
  286                 device_set_ivars(cdev, adi);
  287                 children++;
  288         }
  289 
  290         error = bus_generic_attach(dev);
  291         if (error != 0) {
  292                 device_printf(dev, "bus_generic_attach failed\n");
  293                 goto fail_port1;
  294         }
  295 
  296         return (0);
  297 
  298  fail_port1:
  299         bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->port1);
  300  fail_port0:
  301         bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->port0);
  302 
  303         return (error);
  304 }

Cache object: 11ac71729b3e0cb7600ac27f339ed5c6


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