atkbdc_isa.c revision 216614
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 */ 2643105Sdfr 27116181Sobrien#include <sys/cdefs.h> 28116181Sobrien__FBSDID("$FreeBSD: head/sys/dev/atkbdc/atkbdc_isa.c 216614 2010-12-21 12:49:37Z jhb $"); 29116181Sobrien 3043105Sdfr#include "opt_kbd.h" 3143105Sdfr 3243105Sdfr#include <sys/param.h> 3343105Sdfr#include <sys/systm.h> 3443105Sdfr#include <sys/kernel.h> 35129880Sphk#include <sys/module.h> 3643105Sdfr#include <sys/bus.h> 3743105Sdfr#include <sys/malloc.h> 3847400Sdfr#include <machine/resource.h> 3947400Sdfr#include <sys/rman.h> 40159541Simp#include <machine/bus.h> 4143105Sdfr 42147271Smarius#include <dev/atkbdc/atkbdc_subr.h> 43147271Smarius#include <dev/atkbdc/atkbdcreg.h> 4443105Sdfr 4543105Sdfr#include <isa/isareg.h> 4643105Sdfr#include <isa/isavar.h> 4743105Sdfr 48147271Smariusstatic int atkbdc_isa_probe(device_t dev); 49147271Smariusstatic int atkbdc_isa_attach(device_t dev); 50212413Savgstatic device_t atkbdc_isa_add_child(device_t bus, u_int order, const char *name, 51188160Simp int unit); 52216492Sjhbstatic struct resource *atkbdc_isa_alloc_resource(device_t dev, device_t child, 53216492Sjhb int type, int *rid, u_long start, u_long end, 54216492Sjhb u_long count, u_int flags); 55216492Sjhbstatic int atkbdc_isa_release_resource(device_t dev, device_t child, 56216492Sjhb int type, int rid, struct resource *r); 5743105Sdfr 58147271Smariusstatic device_method_t atkbdc_isa_methods[] = { 59147271Smarius DEVMETHOD(device_probe, atkbdc_isa_probe), 60147271Smarius DEVMETHOD(device_attach, atkbdc_isa_attach), 6147296Syokota DEVMETHOD(device_suspend, bus_generic_suspend), 6247296Syokota DEVMETHOD(device_resume, bus_generic_resume), 6343105Sdfr 64147271Smarius DEVMETHOD(bus_add_child, atkbdc_isa_add_child), 6543105Sdfr DEVMETHOD(bus_print_child, atkbdc_print_child), 6643105Sdfr DEVMETHOD(bus_read_ivar, atkbdc_read_ivar), 6743105Sdfr DEVMETHOD(bus_write_ivar, atkbdc_write_ivar), 6883147Syokota DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list), 69216492Sjhb DEVMETHOD(bus_alloc_resource, atkbdc_isa_alloc_resource), 70216492Sjhb DEVMETHOD(bus_release_resource, atkbdc_isa_release_resource), 7143105Sdfr DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 7243105Sdfr DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 7383147Syokota DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 7483147Syokota DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 7583147Syokota DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 7643105Sdfr DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 7743105Sdfr DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 7843105Sdfr 7943105Sdfr { 0, 0 } 8043105Sdfr}; 8143105Sdfr 82147271Smariusstatic driver_t atkbdc_isa_driver = { 8343105Sdfr ATKBDC_DRIVER_NAME, 84147271Smarius atkbdc_isa_methods, 8543105Sdfr sizeof(atkbdc_softc_t *), 8643105Sdfr}; 8743105Sdfr 8858271Syokotastatic struct isa_pnp_id atkbdc_ids[] = { 8958271Syokota { 0x0303d041, "Keyboard controller (i8042)" }, /* PNP0303 */ 9058271Syokota { 0 } 9158271Syokota}; 9258271Syokota 9343105Sdfrstatic int 94147271Smariusatkbdc_isa_probe(device_t dev) 9543105Sdfr{ 9658271Syokota struct resource *port0; 9758271Syokota struct resource *port1; 9883147Syokota u_long start; 9983147Syokota u_long count; 10058271Syokota int error; 10158271Syokota int rid; 102207354Ssobomax#if defined(__i386__) || defined(__amd64__) 103158041Ssobomax bus_space_tag_t tag; 104158041Ssobomax bus_space_handle_t ioh1; 105158041Ssobomax volatile int i; 106158041Ssobomax register_t flags; 107158041Ssobomax#endif 10843105Sdfr 10958271Syokota /* check PnP IDs */ 11058271Syokota if (ISA_PNP_PROBE(device_get_parent(dev), dev, atkbdc_ids) == ENXIO) 11158271Syokota return ENXIO; 11247618Sdfr 11358271Syokota device_set_desc(dev, "Keyboard controller (i8042)"); 11458271Syokota 11583147Syokota /* 11683147Syokota * Adjust I/O port resources. 11783147Syokota * The AT keyboard controller uses two ports (a command/data port 11883147Syokota * 0x60 and a status port 0x64), which may be given to us in 11983147Syokota * one resource (0x60 through 0x64) or as two separate resources 120160091Sjkim * (0x60 and 0x64). Some brain-damaged ACPI BIOS has reversed 121160091Sjkim * command/data port and status port. Furthermore, /boot/device.hints 122160091Sjkim * may contain just one port, 0x60. We shall adjust resource settings 123160091Sjkim * so that these two ports are available as two separate resources 124160091Sjkim * in correct order. 12583147Syokota */ 12683147Syokota device_quiet(dev); 12747400Sdfr rid = 0; 12883147Syokota if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) 12983147Syokota return ENXIO; 130160091Sjkim if (start == IO_KBD + KBD_STATUS_PORT) { 131160091Sjkim start = IO_KBD; 132160091Sjkim count++; 133160091Sjkim } 134160091Sjkim if (count > 1) /* adjust the count and/or start port */ 13583147Syokota bus_set_resource(dev, SYS_RES_IOPORT, rid, start, 1); 136127135Snjl port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 13758271Syokota if (port0 == NULL) 13847400Sdfr return ENXIO; 13983147Syokota rid = 1; 14083147Syokota if (bus_get_resource(dev, SYS_RES_IOPORT, rid, NULL, NULL) != 0) 14158271Syokota bus_set_resource(dev, SYS_RES_IOPORT, 1, 14283147Syokota start + KBD_STATUS_PORT, 1); 143127135Snjl port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 14458271Syokota if (port1 == NULL) { 14558271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 14658271Syokota return ENXIO; 14758271Syokota } 148158041Ssobomax 149207354Ssobomax#if defined(__i386__) || defined(__amd64__) 150158041Ssobomax /* 151158041Ssobomax * Check if we really have AT keyboard controller. Poll status 152158041Ssobomax * register until we get "all clear" indication. If no such 153158041Ssobomax * indication comes, it probably means that there is no AT 154158041Ssobomax * keyboard controller present. Give up in such case. Check relies 155158041Ssobomax * on the fact that reading from non-existing in/out port returns 156158041Ssobomax * 0xff on i386. May or may not be true on other platforms. 157158041Ssobomax */ 158158041Ssobomax tag = rman_get_bustag(port0); 159158041Ssobomax ioh1 = rman_get_bushandle(port1); 160158041Ssobomax flags = intr_disable(); 161158041Ssobomax for (i = 0; i != 65535; i++) { 162158041Ssobomax if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0) 163158041Ssobomax break; 164158041Ssobomax } 165158041Ssobomax intr_restore(flags); 166158041Ssobomax if (i == 65535) { 167158041Ssobomax bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 168158041Ssobomax bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); 169207354Ssobomax if (bootverbose) 170207354Ssobomax device_printf(dev, "AT keyboard controller not found\n"); 171158041Ssobomax return ENXIO; 172158041Ssobomax } 173158041Ssobomax#endif 174158041Ssobomax 17583147Syokota device_verbose(dev); 17658271Syokota 17758271Syokota error = atkbdc_probe_unit(device_get_unit(dev), port0, port1); 17858271Syokota 17958271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 18058271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); 18158271Syokota 18243105Sdfr return error; 18343105Sdfr} 18443105Sdfr 18543105Sdfrstatic int 186147271Smariusatkbdc_isa_attach(device_t dev) 18743105Sdfr{ 18843105Sdfr atkbdc_softc_t *sc; 18983147Syokota int unit; 19047296Syokota int error; 19148341Syokota int rid; 19243105Sdfr 19347296Syokota unit = device_get_unit(dev); 19443105Sdfr sc = *(atkbdc_softc_t **)device_get_softc(dev); 19547296Syokota if (sc == NULL) { 19647296Syokota /* 19747296Syokota * We have to maintain two copies of the kbdc_softc struct, 19847296Syokota * as the low-level console needs to have access to the 199147271Smarius * keyboard controller before kbdc is probed and attached. 20047296Syokota * kbdc_soft[] contains the default entry for that purpose. 20147296Syokota * See atkbdc.c. XXX 20247296Syokota */ 20347296Syokota sc = atkbdc_get_softc(unit); 20447296Syokota if (sc == NULL) 20547296Syokota return ENOMEM; 20647296Syokota } 20743105Sdfr 20848341Syokota rid = 0; 209207354Ssobomax sc->retry = 5000; 210127135Snjl sc->port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 211127135Snjl RF_ACTIVE); 21258271Syokota if (sc->port0 == NULL) 21348341Syokota return ENXIO; 21458271Syokota rid = 1; 215127135Snjl sc->port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 216127135Snjl RF_ACTIVE); 21758271Syokota if (sc->port1 == NULL) { 21858271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 21958271Syokota return ENXIO; 22058271Syokota } 22158271Syokota 222216492Sjhb /* 223216492Sjhb * If the device is not created by the PnP BIOS or ACPI, then 224216492Sjhb * the hint for the IRQ is on the child atkbd device, not the 225216492Sjhb * keyboard controller, so this can fail. 226216492Sjhb */ 227216492Sjhb rid = 0; 228216492Sjhb sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 229216492Sjhb 23058271Syokota error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1); 23158271Syokota if (error) { 23258271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 23358271Syokota bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1); 234216492Sjhb if (sc->irq != NULL) 235216492Sjhb bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 23647296Syokota return error; 23758271Syokota } 23847296Syokota *(atkbdc_softc_t **)device_get_softc(dev) = sc; 23947296Syokota 240216492Sjhb bus_generic_probe(dev); 24183147Syokota bus_generic_attach(dev); 24243105Sdfr 24383147Syokota return 0; 24483147Syokota} 24583147Syokota 24683147Syokotastatic device_t 247212413Savgatkbdc_isa_add_child(device_t bus, u_int order, const char *name, int unit) 24883147Syokota{ 24983147Syokota atkbdc_device_t *ivar; 250216492Sjhb atkbdc_softc_t *sc; 25183147Syokota device_t child; 25283147Syokota int t; 25383147Syokota 254216492Sjhb sc = *(atkbdc_softc_t **)device_get_softc(bus); 25583147Syokota ivar = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV, 25683147Syokota M_NOWAIT | M_ZERO); 25783147Syokota if (!ivar) 25883147Syokota return NULL; 25983147Syokota 26083931Syokota child = device_add_child_ordered(bus, order, name, unit); 26183147Syokota if (child == NULL) { 26283147Syokota free(ivar, M_ATKBDDEV); 26383147Syokota return child; 26483147Syokota } 26583147Syokota 26683147Syokota resource_list_init(&ivar->resources); 26783147Syokota ivar->rid = order; 26883147Syokota 26943105Sdfr /* 270216492Sjhb * If the device is not created by the PnP BIOS or ACPI, refer 271216492Sjhb * to device hints for IRQ. We always populate the resource 272216492Sjhb * list entry so we can use a standard bus_get_resource() 273216492Sjhb * method. 27443105Sdfr */ 275216614Sjhb if (order == KBDC_RID_KBD) { 276216614Sjhb if (sc->irq == NULL) { 277216614Sjhb if (resource_int_value(name, unit, "irq", &t) != 0) 278216614Sjhb t = -1; 279216614Sjhb } else 280216614Sjhb t = rman_get_start(sc->irq); 281216614Sjhb if (t > 0) 282216614Sjhb resource_list_add(&ivar->resources, SYS_RES_IRQ, 283216614Sjhb ivar->rid, t, t, 1); 284216614Sjhb } 28543105Sdfr 286117167Sjhb if (resource_disabled(name, unit)) 28783147Syokota device_disable(child); 28843105Sdfr 28983147Syokota device_set_ivars(child, ivar); 29083147Syokota 29183147Syokota return child; 29243105Sdfr} 29343105Sdfr 294216492Sjhbstruct resource * 295216492Sjhbatkbdc_isa_alloc_resource(device_t dev, device_t child, int type, int *rid, 296216492Sjhb u_long start, u_long end, u_long count, u_int flags) 297216492Sjhb{ 298216492Sjhb atkbdc_softc_t *sc; 299216492Sjhb 300216492Sjhb sc = *(atkbdc_softc_t **)device_get_softc(dev); 301216492Sjhb if (type == SYS_RES_IRQ && *rid == KBDC_RID_KBD && sc->irq != NULL) 302216492Sjhb return (sc->irq); 303216492Sjhb return (bus_generic_rl_alloc_resource(dev, child, type, rid, start, 304216492Sjhb end, count, flags)); 305216492Sjhb} 306216492Sjhb 307216492Sjhbstatic int 308216492Sjhbatkbdc_isa_release_resource(device_t dev, device_t child, int type, int rid, 309216492Sjhb struct resource *r) 310216492Sjhb{ 311216492Sjhb atkbdc_softc_t *sc; 312216492Sjhb 313216492Sjhb sc = *(atkbdc_softc_t **)device_get_softc(dev); 314216492Sjhb if (type == SYS_RES_IRQ && rid == KBDC_RID_KBD && r == sc->irq) 315216492Sjhb return (0); 316216492Sjhb return (bus_generic_rl_release_resource(dev, child, type, rid, r)); 317216492Sjhb} 318216492Sjhb 319147271SmariusDRIVER_MODULE(atkbdc, isa, atkbdc_isa_driver, atkbdc_devclass, 0, 0); 320147271SmariusDRIVER_MODULE(atkbdc, acpi, atkbdc_isa_driver, atkbdc_devclass, 0, 0); 321