atkbdc_isa.c revision 82555
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_isa.c 82555 2001-08-30 09:17:03Z msmith $ 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 4669774Sphkstatic MALLOC_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, 6559783Sbde uintptr_t *val); 6643105Sdfrstatic int atkbdc_write_ivar(device_t bus, device_t dev, int index, 6759783Sbde uintptr_t 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 14969781Sdwmalone kdev = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV, 15069781Sdwmalone M_NOWAIT | M_ZERO); 15143105Sdfr if (!kdev) 15243105Sdfr return; 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; 17278135Speter int unit, dunit; 17347296Syokota int error; 17448341Syokota int rid; 17543105Sdfr int i; 17678135Speter const char *name, *dname; 17743105Sdfr 17847296Syokota unit = device_get_unit(dev); 17943105Sdfr sc = *(atkbdc_softc_t **)device_get_softc(dev); 18047296Syokota if (sc == NULL) { 18147296Syokota /* 18247296Syokota * We have to maintain two copies of the kbdc_softc struct, 18347296Syokota * as the low-level console needs to have access to the 18447296Syokota * keyboard controller before kbdc is probed and attached. 18547296Syokota * kbdc_soft[] contains the default entry for that purpose. 18647296Syokota * See atkbdc.c. XXX 18747296Syokota */ 18847296Syokota sc = atkbdc_get_softc(unit); 18947296Syokota if (sc == NULL) 19047296Syokota return ENOMEM; 19147296Syokota } 19243105Sdfr 19348341Syokota rid = 0; 19458271Syokota sc->port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 19558271Syokota RF_ACTIVE); 19658271Syokota if (sc->port0 == NULL) 19748341Syokota return ENXIO; 19858271Syokota rid = 1; 19958271Syokota sc->port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 20058271Syokota RF_ACTIVE); 20158271Syokota if (sc->port1 == NULL) { 20258271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 20358271Syokota return ENXIO; 20458271Syokota } 20558271Syokota 20658271Syokota error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1); 20758271Syokota if (error) { 20858271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 20958271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1); 21047296Syokota return error; 21158271Syokota } 21247296Syokota *(atkbdc_softc_t **)device_get_softc(dev) = sc; 21347296Syokota 21443105Sdfr /* 21543105Sdfr * Add all devices configured to be attached to atkbdc0. 21643105Sdfr */ 21767153Speter name = device_get_nameunit(dev); 21878135Speter i = 0; 21978135Speter while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0) 22078135Speter atkbdc_add_device(dev, dname, dunit); 22143105Sdfr 22243105Sdfr /* 22343105Sdfr * and atkbdc? 22443105Sdfr */ 22567153Speter name = device_get_name(dev); 22678135Speter i = 0; 22778135Speter while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0) 22878135Speter atkbdc_add_device(dev, dname, dunit); 22943105Sdfr 23043105Sdfr bus_generic_attach(dev); 23143105Sdfr 23243105Sdfr return 0; 23343105Sdfr} 23443105Sdfr 23549195Smdoddstatic int 23643105Sdfratkbdc_print_child(device_t bus, device_t dev) 23743105Sdfr{ 23843105Sdfr atkbdc_device_t *kbdcdev; 23949195Smdodd int retval = 0; 24043105Sdfr 24143105Sdfr kbdcdev = (atkbdc_device_t *)device_get_ivars(dev); 24243105Sdfr 24349195Smdodd retval += bus_print_child_header(bus, dev); 24443105Sdfr if (kbdcdev->flags != 0) 24549195Smdodd retval += printf(" flags 0x%x", kbdcdev->flags); 24646729Speter if (kbdcdev->irq != -1) 24749195Smdodd retval += printf(" irq %d", kbdcdev->irq); 24849195Smdodd retval += bus_print_child_footer(bus, dev); 24943105Sdfr 25049195Smdodd return (retval); 25143105Sdfr} 25243105Sdfr 25343105Sdfrstatic int 25459783Sbdeatkbdc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val) 25543105Sdfr{ 25643105Sdfr atkbdc_device_t *ivar; 25743105Sdfr 25843105Sdfr ivar = (atkbdc_device_t *)device_get_ivars(dev); 25943105Sdfr switch (index) { 26043105Sdfr case KBDC_IVAR_IRQ: 26143105Sdfr *val = (u_long)ivar->irq; 26243105Sdfr break; 26343105Sdfr case KBDC_IVAR_FLAGS: 26443105Sdfr *val = (u_long)ivar->flags; 26543105Sdfr break; 26658272Syokota case KBDC_IVAR_VENDORID: 26758272Syokota *val = (u_long)ivar->vendorid; 26858272Syokota break; 26958272Syokota case KBDC_IVAR_SERIAL: 27058272Syokota *val = (u_long)ivar->serial; 27158272Syokota break; 27258272Syokota case KBDC_IVAR_LOGICALID: 27358272Syokota *val = (u_long)ivar->logicalid; 27458272Syokota break; 27558272Syokota case KBDC_IVAR_COMPATID: 27658272Syokota *val = (u_long)ivar->compatid; 27758272Syokota break; 27843105Sdfr default: 27943105Sdfr return ENOENT; 28043105Sdfr } 28143105Sdfr return 0; 28243105Sdfr} 28343105Sdfr 28443105Sdfrstatic int 28559783Sbdeatkbdc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val) 28643105Sdfr{ 28743105Sdfr atkbdc_device_t *ivar; 28843105Sdfr 28943105Sdfr ivar = (atkbdc_device_t *)device_get_ivars(dev); 29043105Sdfr switch (index) { 29143105Sdfr case KBDC_IVAR_IRQ: 29243105Sdfr ivar->irq = (int)val; 29343105Sdfr break; 29443105Sdfr case KBDC_IVAR_FLAGS: 29543105Sdfr ivar->flags = (int)val; 29643105Sdfr break; 29758272Syokota case KBDC_IVAR_VENDORID: 29858272Syokota ivar->vendorid = (u_int32_t)val; 29958272Syokota break; 30058272Syokota case KBDC_IVAR_SERIAL: 30158272Syokota ivar->serial = (u_int32_t)val; 30258272Syokota break; 30358272Syokota case KBDC_IVAR_LOGICALID: 30458272Syokota ivar->logicalid = (u_int32_t)val; 30558272Syokota break; 30658272Syokota case KBDC_IVAR_COMPATID: 30758272Syokota ivar->compatid = (u_int32_t)val; 30858272Syokota break; 30943105Sdfr default: 31043105Sdfr return ENOENT; 31143105Sdfr } 31243105Sdfr return 0; 31343105Sdfr} 31443105Sdfr 31543105SdfrDRIVER_MODULE(atkbdc, isa, atkbdc_driver, atkbdc_devclass, 0, 0); 31682555SmsmithDRIVER_MODULE(atkbdc, acpi, atkbdc_driver, atkbdc_devclass, 0, 0); 317