atkbdc_isa.c revision 188160
10Sstevel@tonic-gate/*- 20Sstevel@tonic-gate * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 30Sstevel@tonic-gate * All rights reserved. 40Sstevel@tonic-gate * 52660Sjacobs * Redistribution and use in source and binary forms, with or without 62660Sjacobs * modification, are permitted provided that the following conditions 70Sstevel@tonic-gate * are met: 80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 90Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer as 100Sstevel@tonic-gate * the first lines of this file unmodified. 110Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 120Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 130Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 140Sstevel@tonic-gate * 150Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 160Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 170Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 180Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 190Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 200Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 212660Sjacobs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 222660Sjacobs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 232660Sjacobs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 242660Sjacobs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 252660Sjacobs */ 262660Sjacobs 270Sstevel@tonic-gate#include <sys/cdefs.h> 280Sstevel@tonic-gate__FBSDID("$FreeBSD: head/sys/dev/atkbdc/atkbdc_isa.c 188160 2009-02-05 18:38:39Z imp $"); 290Sstevel@tonic-gate 300Sstevel@tonic-gate#include "opt_kbd.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate#include <sys/param.h> 330Sstevel@tonic-gate#include <sys/systm.h> 340Sstevel@tonic-gate#include <sys/kernel.h> 350Sstevel@tonic-gate#include <sys/module.h> 360Sstevel@tonic-gate#include <sys/bus.h> 370Sstevel@tonic-gate#include <sys/malloc.h> 380Sstevel@tonic-gate#include <machine/resource.h> 390Sstevel@tonic-gate#include <sys/rman.h> 400Sstevel@tonic-gate#include <machine/bus.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate#include <dev/atkbdc/atkbdc_subr.h> 430Sstevel@tonic-gate#include <dev/atkbdc/atkbdcreg.h> 440Sstevel@tonic-gate 450Sstevel@tonic-gate#include <isa/isareg.h> 460Sstevel@tonic-gate#include <isa/isavar.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gatestatic int atkbdc_isa_probe(device_t dev); 490Sstevel@tonic-gatestatic int atkbdc_isa_attach(device_t dev); 500Sstevel@tonic-gatestatic device_t atkbdc_isa_add_child(device_t bus, int order, const char *name, 510Sstevel@tonic-gate int unit); 520Sstevel@tonic-gate 530Sstevel@tonic-gatestatic device_method_t atkbdc_isa_methods[] = { 540Sstevel@tonic-gate DEVMETHOD(device_probe, atkbdc_isa_probe), 550Sstevel@tonic-gate DEVMETHOD(device_attach, atkbdc_isa_attach), 560Sstevel@tonic-gate DEVMETHOD(device_suspend, bus_generic_suspend), 570Sstevel@tonic-gate DEVMETHOD(device_resume, bus_generic_resume), 580Sstevel@tonic-gate 590Sstevel@tonic-gate DEVMETHOD(bus_add_child, atkbdc_isa_add_child), 600Sstevel@tonic-gate DEVMETHOD(bus_print_child, atkbdc_print_child), 610Sstevel@tonic-gate DEVMETHOD(bus_read_ivar, atkbdc_read_ivar), 620Sstevel@tonic-gate DEVMETHOD(bus_write_ivar, atkbdc_write_ivar), 630Sstevel@tonic-gate DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list), 640Sstevel@tonic-gate DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 650Sstevel@tonic-gate DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 660Sstevel@tonic-gate DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 670Sstevel@tonic-gate DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 680Sstevel@tonic-gate DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 690Sstevel@tonic-gate DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 700Sstevel@tonic-gate DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 710Sstevel@tonic-gate DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 720Sstevel@tonic-gate DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 730Sstevel@tonic-gate 740Sstevel@tonic-gate { 0, 0 } 752660Sjacobs}; 760Sstevel@tonic-gate 770Sstevel@tonic-gatestatic driver_t atkbdc_isa_driver = { 780Sstevel@tonic-gate ATKBDC_DRIVER_NAME, 790Sstevel@tonic-gate atkbdc_isa_methods, 800Sstevel@tonic-gate sizeof(atkbdc_softc_t *), 810Sstevel@tonic-gate}; 820Sstevel@tonic-gate 830Sstevel@tonic-gatestatic struct isa_pnp_id atkbdc_ids[] = { 840Sstevel@tonic-gate { 0x0303d041, "Keyboard controller (i8042)" }, /* PNP0303 */ 850Sstevel@tonic-gate { 0 } 860Sstevel@tonic-gate}; 870Sstevel@tonic-gate 880Sstevel@tonic-gatestatic int 890Sstevel@tonic-gateatkbdc_isa_probe(device_t dev) 900Sstevel@tonic-gate{ 910Sstevel@tonic-gate struct resource *port0; 920Sstevel@tonic-gate struct resource *port1; 930Sstevel@tonic-gate u_long start; 940Sstevel@tonic-gate u_long count; 950Sstevel@tonic-gate int error; 960Sstevel@tonic-gate int rid; 970Sstevel@tonic-gate#if defined(__i386__) 980Sstevel@tonic-gate bus_space_tag_t tag; 990Sstevel@tonic-gate bus_space_handle_t ioh1; 1000Sstevel@tonic-gate volatile int i; 1010Sstevel@tonic-gate register_t flags; 1020Sstevel@tonic-gate#endif 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* check PnP IDs */ 1050Sstevel@tonic-gate if (ISA_PNP_PROBE(device_get_parent(dev), dev, atkbdc_ids) == ENXIO) 1060Sstevel@tonic-gate return ENXIO; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate device_set_desc(dev, "Keyboard controller (i8042)"); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * Adjust I/O port resources. 1120Sstevel@tonic-gate * The AT keyboard controller uses two ports (a command/data port 1130Sstevel@tonic-gate * 0x60 and a status port 0x64), which may be given to us in 1140Sstevel@tonic-gate * one resource (0x60 through 0x64) or as two separate resources 1150Sstevel@tonic-gate * (0x60 and 0x64). Some brain-damaged ACPI BIOS has reversed 1160Sstevel@tonic-gate * command/data port and status port. Furthermore, /boot/device.hints 1170Sstevel@tonic-gate * may contain just one port, 0x60. We shall adjust resource settings 1180Sstevel@tonic-gate * so that these two ports are available as two separate resources 1190Sstevel@tonic-gate * in correct order. 1200Sstevel@tonic-gate */ 1210Sstevel@tonic-gate device_quiet(dev); 1220Sstevel@tonic-gate rid = 0; 1230Sstevel@tonic-gate if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0) 1240Sstevel@tonic-gate return ENXIO; 1250Sstevel@tonic-gate if (start == IO_KBD + KBD_STATUS_PORT) { 1260Sstevel@tonic-gate start = IO_KBD; 1270Sstevel@tonic-gate count++; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate if (count > 1) /* adjust the count and/or start port */ 1300Sstevel@tonic-gate bus_set_resource(dev, SYS_RES_IOPORT, rid, start, 1); 1310Sstevel@tonic-gate port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 1320Sstevel@tonic-gate if (port0 == NULL) 1330Sstevel@tonic-gate return ENXIO; 1340Sstevel@tonic-gate rid = 1; 1350Sstevel@tonic-gate if (bus_get_resource(dev, SYS_RES_IOPORT, rid, NULL, NULL) != 0) 1360Sstevel@tonic-gate bus_set_resource(dev, SYS_RES_IOPORT, 1, 1370Sstevel@tonic-gate start + KBD_STATUS_PORT, 1); 1380Sstevel@tonic-gate port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 1392660Sjacobs if (port1 == NULL) { 1400Sstevel@tonic-gate bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 1410Sstevel@tonic-gate return ENXIO; 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate#if defined(__i386__) 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * Check if we really have AT keyboard controller. Poll status 1470Sstevel@tonic-gate * register until we get "all clear" indication. If no such 1480Sstevel@tonic-gate * indication comes, it probably means that there is no AT 1490Sstevel@tonic-gate * keyboard controller present. Give up in such case. Check relies 1500Sstevel@tonic-gate * on the fact that reading from non-existing in/out port returns 1510Sstevel@tonic-gate * 0xff on i386. May or may not be true on other platforms. 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate tag = rman_get_bustag(port0); 1540Sstevel@tonic-gate ioh1 = rman_get_bushandle(port1); 1550Sstevel@tonic-gate flags = intr_disable(); 1560Sstevel@tonic-gate for (i = 0; i != 65535; i++) { 1570Sstevel@tonic-gate if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0) 1580Sstevel@tonic-gate break; 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate intr_restore(flags); 1610Sstevel@tonic-gate if (i == 65535) { 1620Sstevel@tonic-gate bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 1630Sstevel@tonic-gate bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); 1640Sstevel@tonic-gate return ENXIO; 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate#endif 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate device_verbose(dev); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate error = atkbdc_probe_unit(device_get_unit(dev), port0, port1); 1710Sstevel@tonic-gate if (error == 0) 1720Sstevel@tonic-gate bus_generic_probe(dev); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate bus_release_resource(dev, SYS_RES_IOPORT, 0, port0); 1750Sstevel@tonic-gate bus_release_resource(dev, SYS_RES_IOPORT, 1, port1); 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate return error; 1780Sstevel@tonic-gate} 1790Sstevel@tonic-gate 1800Sstevel@tonic-gatestatic int 1810Sstevel@tonic-gateatkbdc_isa_attach(device_t dev) 1820Sstevel@tonic-gate{ 1830Sstevel@tonic-gate atkbdc_softc_t *sc; 1840Sstevel@tonic-gate int unit; 1850Sstevel@tonic-gate int error; 1860Sstevel@tonic-gate int rid; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate unit = device_get_unit(dev); 1890Sstevel@tonic-gate sc = *(atkbdc_softc_t **)device_get_softc(dev); 1900Sstevel@tonic-gate if (sc == NULL) { 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * We have to maintain two copies of the kbdc_softc struct, 1930Sstevel@tonic-gate * as the low-level console needs to have access to the 1940Sstevel@tonic-gate * keyboard controller before kbdc is probed and attached. 1950Sstevel@tonic-gate * kbdc_soft[] contains the default entry for that purpose. 1960Sstevel@tonic-gate * See atkbdc.c. XXX 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate sc = atkbdc_get_softc(unit); 1990Sstevel@tonic-gate if (sc == NULL) 2000Sstevel@tonic-gate return ENOMEM; 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate rid = 0; 2040Sstevel@tonic-gate sc->port0 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 205 RF_ACTIVE); 206 if (sc->port0 == NULL) 207 return ENXIO; 208 rid = 1; 209 sc->port1 = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 210 RF_ACTIVE); 211 if (sc->port1 == NULL) { 212 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 213 return ENXIO; 214 } 215 216 error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1); 217 if (error) { 218 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0); 219 bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1); 220 return error; 221 } 222 *(atkbdc_softc_t **)device_get_softc(dev) = sc; 223 224 bus_generic_attach(dev); 225 226 return 0; 227} 228 229static device_t 230atkbdc_isa_add_child(device_t bus, int order, const char *name, int unit) 231{ 232 atkbdc_device_t *ivar; 233 device_t child; 234 int t; 235 236 ivar = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV, 237 M_NOWAIT | M_ZERO); 238 if (!ivar) 239 return NULL; 240 241 child = device_add_child_ordered(bus, order, name, unit); 242 if (child == NULL) { 243 free(ivar, M_ATKBDDEV); 244 return child; 245 } 246 247 resource_list_init(&ivar->resources); 248 ivar->rid = order; 249 250 /* 251 * If the device is not created by the PnP BIOS or ACPI, 252 * refer to device hints for IRQ. 253 */ 254 if (ISA_PNP_PROBE(device_get_parent(bus), bus, atkbdc_ids) != 0) { 255 if (resource_int_value(name, unit, "irq", &t) != 0) 256 t = -1; 257 } else { 258 t = bus_get_resource_start(bus, SYS_RES_IRQ, ivar->rid); 259 } 260 if (t > 0) 261 resource_list_add(&ivar->resources, SYS_RES_IRQ, ivar->rid, 262 t, t, 1); 263 264 if (resource_disabled(name, unit)) 265 device_disable(child); 266 267 device_set_ivars(child, ivar); 268 269 return child; 270} 271 272DRIVER_MODULE(atkbdc, isa, atkbdc_isa_driver, atkbdc_devclass, 0, 0); 273DRIVER_MODULE(atkbdc, acpi, atkbdc_isa_driver, atkbdc_devclass, 0, 0); 274