atkbdc_subr.c revision 58272
143105Sdfr/*- 243105Sdfr * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 343105Sdfr * All rights reserved. 443105Sdfr * 543105Sdfr * Redistribution and use in source and binary forms, with or without 643105Sdfr * modification, are permitted provided that the following conditions 743105Sdfr * are met: 843105Sdfr * 1. Redistributions of source code must retain the above copyright 943105Sdfr * notice, this list of conditions and the following disclaimer as 1043105Sdfr * the first lines of this file unmodified. 1143105Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1243105Sdfr * notice, this list of conditions and the following disclaimer in the 1343105Sdfr * documentation and/or other materials provided with the distribution. 1443105Sdfr * 1543105Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1643105Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1743105Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1843105Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1943105Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2043105Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2143105Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2243105Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2343105Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2443105Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2543105Sdfr * 2650477Speter * $FreeBSD: head/sys/dev/atkbdc/atkbdc_subr.c 58272 2000-03-19 04:37:18Z yokota $ 2743105Sdfr */ 2843105Sdfr 2943105Sdfr#include "opt_kbd.h" 3043105Sdfr 3143105Sdfr#include <sys/param.h> 3243105Sdfr#include <sys/systm.h> 3343105Sdfr#include <sys/kernel.h> 3443105Sdfr#include <sys/bus.h> 3543105Sdfr#include <sys/malloc.h> 3658271Syokota#include <machine/bus_pio.h> 3747400Sdfr#include <machine/bus.h> 3847400Sdfr#include <machine/resource.h> 3947400Sdfr#include <sys/rman.h> 4043105Sdfr 4143105Sdfr#include <dev/kbd/atkbdcreg.h> 4243105Sdfr 4343105Sdfr#include <isa/isareg.h> 4443105Sdfr#include <isa/isavar.h> 4543105Sdfr 4643105SdfrMALLOC_DEFINE(M_ATKBDDEV, "atkbddev", "AT Keyboard device"); 4743105Sdfr 4843105Sdfr/* children */ 4943105Sdfrtypedef struct atkbdc_device { 5043105Sdfr int flags; /* configuration flags */ 5143105Sdfr int irq; /* ISA IRQ mask */ 5258272Syokota u_int32_t vendorid; 5358272Syokota u_int32_t serial; 5458272Syokota u_int32_t logicalid; 5558272Syokota u_int32_t compatid; 5643105Sdfr} atkbdc_device_t; 5743105Sdfr 5843105Sdfr/* kbdc */ 5943105Sdfrdevclass_t atkbdc_devclass; 6043105Sdfr 6143105Sdfrstatic int atkbdc_probe(device_t dev); 6243105Sdfrstatic int atkbdc_attach(device_t dev); 6349195Smdoddstatic int atkbdc_print_child(device_t bus, device_t dev); 6443105Sdfrstatic int atkbdc_read_ivar(device_t bus, device_t dev, int index, 6543105Sdfr u_long *val); 6643105Sdfrstatic int atkbdc_write_ivar(device_t bus, device_t dev, int index, 6743105Sdfr u_long val); 6843105Sdfr 6943105Sdfrstatic device_method_t atkbdc_methods[] = { 7043105Sdfr DEVMETHOD(device_probe, atkbdc_probe), 7143105Sdfr DEVMETHOD(device_attach, atkbdc_attach), 7247296Syokota DEVMETHOD(device_suspend, bus_generic_suspend), 7347296Syokota DEVMETHOD(device_resume, bus_generic_resume), 7443105Sdfr 7543105Sdfr DEVMETHOD(bus_print_child, atkbdc_print_child), 7643105Sdfr DEVMETHOD(bus_read_ivar, atkbdc_read_ivar), 7743105Sdfr DEVMETHOD(bus_write_ivar, atkbdc_write_ivar), 7843105Sdfr DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 7943105Sdfr DEVMETHOD(bus_release_resource, bus_generic_release_resource), 8043105Sdfr DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 8143105Sdfr DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 8243105Sdfr DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 8343105Sdfr DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 8443105Sdfr 8543105Sdfr { 0, 0 } 8643105Sdfr}; 8743105Sdfr 8843105Sdfrstatic driver_t atkbdc_driver = { 8943105Sdfr ATKBDC_DRIVER_NAME, 9043105Sdfr atkbdc_methods, 9143105Sdfr sizeof(atkbdc_softc_t *), 9243105Sdfr}; 9343105Sdfr 9458271Syokotastatic struct isa_pnp_id atkbdc_ids[] = { 9558271Syokota { 0x0303d041, "Keyboard controller (i8042)" }, /* PNP0303 */ 9658271Syokota { 0 } 9758271Syokota}; 9858271Syokota 9943105Sdfrstatic int 10043105Sdfratkbdc_probe(device_t dev) 10143105Sdfr{ 10258271Syokota struct resource *port0; 10358271Syokota struct resource *port1; 10458271Syokota int error; 10558271Syokota int rid; 10643105Sdfr 10758271Syokota /* check PnP IDs */ 10858271Syokota if (ISA_PNP_PROBE(device_get_parent(dev), dev, atkbdc_ids) == ENXIO) 10958271Syokota return ENXIO; 11047618Sdfr 11158271Syokota device_set_desc(dev, "Keyboard controller (i8042)"); 11258271Syokota 11347400Sdfr rid = 0; 11458271Syokota port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 11558271Syokota RF_ACTIVE); 11658271Syokota if (port0 == NULL) 11747400Sdfr return ENXIO; 11858271Syokota /* XXX */ 11958271Syokota if (bus_get_resource_start(dev, SYS_RES_IOPORT, 1) <= 0) { 12058271Syokota bus_set_resource(dev, SYS_RES_IOPORT, 1, 12158271Syokota rman_get_start(port0) + KBD_STATUS_PORT, 1); 12258271Syokota } 12358271Syokota rid = 1; 12458271Syokota port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 12558271Syokota RF_ACTIVE); 12658271Syokota if (port1 == NULL) { 12758271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 12858271Syokota return ENXIO; 12958271Syokota } 13058271Syokota 13158271Syokota error = atkbdc_probe_unit(device_get_unit(dev), port0, port1); 13258271Syokota 13358271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 13458271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); 13558271Syokota 13643105Sdfr return error; 13743105Sdfr} 13843105Sdfr 13943105Sdfrstatic void 14043105Sdfratkbdc_add_device(device_t dev, const char *name, int unit) 14143105Sdfr{ 14243105Sdfr atkbdc_device_t *kdev; 14343105Sdfr device_t child; 14443105Sdfr int t; 14543105Sdfr 14657481Syokota if (resource_int_value(name, unit, "disabled", &t) == 0 && t != 0) 14757481Syokota return; 14857481Syokota 14943105Sdfr kdev = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV, M_NOWAIT); 15043105Sdfr if (!kdev) 15143105Sdfr return; 15243105Sdfr bzero(kdev, sizeof *kdev); 15343105Sdfr 15443105Sdfr if (resource_int_value(name, unit, "irq", &t) == 0) 15543105Sdfr kdev->irq = t; 15643105Sdfr else 15743105Sdfr kdev->irq = -1; 15843105Sdfr 15943105Sdfr if (resource_int_value(name, unit, "flags", &t) == 0) 16043105Sdfr kdev->flags = t; 16143105Sdfr else 16243105Sdfr kdev->flags = 0; 16343105Sdfr 16454073Smdodd child = device_add_child(dev, name, unit); 16554073Smdodd device_set_ivars(child, kdev); 16643105Sdfr} 16743105Sdfr 16843105Sdfrstatic int 16943105Sdfratkbdc_attach(device_t dev) 17043105Sdfr{ 17143105Sdfr atkbdc_softc_t *sc; 17247296Syokota int unit; 17347296Syokota int error; 17448341Syokota int rid; 17543105Sdfr int i; 17643105Sdfr 17747296Syokota unit = device_get_unit(dev); 17843105Sdfr sc = *(atkbdc_softc_t **)device_get_softc(dev); 17947296Syokota if (sc == NULL) { 18047296Syokota /* 18147296Syokota * We have to maintain two copies of the kbdc_softc struct, 18247296Syokota * as the low-level console needs to have access to the 18347296Syokota * keyboard controller before kbdc is probed and attached. 18447296Syokota * kbdc_soft[] contains the default entry for that purpose. 18547296Syokota * See atkbdc.c. XXX 18647296Syokota */ 18747296Syokota sc = atkbdc_get_softc(unit); 18847296Syokota if (sc == NULL) 18947296Syokota return ENOMEM; 19047296Syokota } 19143105Sdfr 19248341Syokota rid = 0; 19358271Syokota sc->port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 19458271Syokota RF_ACTIVE); 19558271Syokota if (sc->port0 == NULL) 19648341Syokota return ENXIO; 19758271Syokota rid = 1; 19858271Syokota sc->port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 19958271Syokota RF_ACTIVE); 20058271Syokota if (sc->port1 == NULL) { 20158271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 20258271Syokota return ENXIO; 20358271Syokota } 20458271Syokota 20558271Syokota error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1); 20658271Syokota if (error) { 20758271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 20858271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1); 20947296Syokota return error; 21058271Syokota } 21147296Syokota *(atkbdc_softc_t **)device_get_softc(dev) = sc; 21247296Syokota 21343105Sdfr /* 21443105Sdfr * Add all devices configured to be attached to atkbdc0. 21543105Sdfr */ 21658272Syokota for (i = resource_query_string(-1, "at", device_get_nameunit(dev)); 21743105Sdfr i != -1; 21858272Syokota i = resource_query_string(i, "at", device_get_nameunit(dev))) { 21943105Sdfr atkbdc_add_device(dev, resource_query_name(i), 22043105Sdfr resource_query_unit(i)); 22143105Sdfr } 22243105Sdfr 22343105Sdfr /* 22443105Sdfr * and atkbdc? 22543105Sdfr */ 22658272Syokota for (i = resource_query_string(-1, "at", device_get_name(dev)); 22743105Sdfr i != -1; 22858272Syokota i = resource_query_string(i, "at", device_get_name(dev))) { 22943105Sdfr atkbdc_add_device(dev, resource_query_name(i), 23043105Sdfr resource_query_unit(i)); 23143105Sdfr } 23243105Sdfr 23343105Sdfr bus_generic_attach(dev); 23443105Sdfr 23543105Sdfr return 0; 23643105Sdfr} 23743105Sdfr 23849195Smdoddstatic int 23943105Sdfratkbdc_print_child(device_t bus, device_t dev) 24043105Sdfr{ 24143105Sdfr atkbdc_device_t *kbdcdev; 24249195Smdodd int retval = 0; 24343105Sdfr 24443105Sdfr kbdcdev = (atkbdc_device_t *)device_get_ivars(dev); 24543105Sdfr 24649195Smdodd retval += bus_print_child_header(bus, dev); 24743105Sdfr if (kbdcdev->flags != 0) 24849195Smdodd retval += printf(" flags 0x%x", kbdcdev->flags); 24946729Speter if (kbdcdev->irq != -1) 25049195Smdodd retval += printf(" irq %d", kbdcdev->irq); 25149195Smdodd retval += bus_print_child_footer(bus, dev); 25243105Sdfr 25349195Smdodd return (retval); 25443105Sdfr} 25543105Sdfr 25643105Sdfrstatic int 25743105Sdfratkbdc_read_ivar(device_t bus, device_t dev, int index, u_long *val) 25843105Sdfr{ 25943105Sdfr atkbdc_device_t *ivar; 26043105Sdfr 26143105Sdfr ivar = (atkbdc_device_t *)device_get_ivars(dev); 26243105Sdfr switch (index) { 26343105Sdfr case KBDC_IVAR_IRQ: 26443105Sdfr *val = (u_long)ivar->irq; 26543105Sdfr break; 26643105Sdfr case KBDC_IVAR_FLAGS: 26743105Sdfr *val = (u_long)ivar->flags; 26843105Sdfr break; 26958272Syokota case KBDC_IVAR_VENDORID: 27058272Syokota *val = (u_long)ivar->vendorid; 27158272Syokota break; 27258272Syokota case KBDC_IVAR_SERIAL: 27358272Syokota *val = (u_long)ivar->serial; 27458272Syokota break; 27558272Syokota case KBDC_IVAR_LOGICALID: 27658272Syokota *val = (u_long)ivar->logicalid; 27758272Syokota break; 27858272Syokota case KBDC_IVAR_COMPATID: 27958272Syokota *val = (u_long)ivar->compatid; 28058272Syokota break; 28143105Sdfr default: 28243105Sdfr return ENOENT; 28343105Sdfr } 28443105Sdfr return 0; 28543105Sdfr} 28643105Sdfr 28743105Sdfrstatic int 28843105Sdfratkbdc_write_ivar(device_t bus, device_t dev, int index, u_long val) 28943105Sdfr{ 29043105Sdfr atkbdc_device_t *ivar; 29143105Sdfr 29243105Sdfr ivar = (atkbdc_device_t *)device_get_ivars(dev); 29343105Sdfr switch (index) { 29443105Sdfr case KBDC_IVAR_IRQ: 29543105Sdfr ivar->irq = (int)val; 29643105Sdfr break; 29743105Sdfr case KBDC_IVAR_FLAGS: 29843105Sdfr ivar->flags = (int)val; 29943105Sdfr break; 30058272Syokota case KBDC_IVAR_VENDORID: 30158272Syokota ivar->vendorid = (u_int32_t)val; 30258272Syokota break; 30358272Syokota case KBDC_IVAR_SERIAL: 30458272Syokota ivar->serial = (u_int32_t)val; 30558272Syokota break; 30658272Syokota case KBDC_IVAR_LOGICALID: 30758272Syokota ivar->logicalid = (u_int32_t)val; 30858272Syokota break; 30958272Syokota case KBDC_IVAR_COMPATID: 31058272Syokota ivar->compatid = (u_int32_t)val; 31158272Syokota break; 31243105Sdfr default: 31343105Sdfr return ENOENT; 31443105Sdfr } 31543105Sdfr return 0; 31643105Sdfr} 31743105Sdfr 31843105SdfrDRIVER_MODULE(atkbdc, isa, atkbdc_driver, atkbdc_devclass, 0, 0); 319