Home | History | Annotate | Line # | Download | only in acpi
pckbc_acpi.c revision 1.15
      1  1.15     kochi /*	$NetBSD: pckbc_acpi.c,v 1.15 2004/05/01 12:03:48 kochi Exp $	*/
      2   1.1      matt 
      3   1.1      matt /*-
      4   1.1      matt  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5   1.1      matt  * All rights reserved.
      6   1.1      matt  *
      7   1.1      matt  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1      matt  * by Jason R. Thorpe.
      9   1.1      matt  *
     10   1.1      matt  * Redistribution and use in source and binary forms, with or without
     11   1.1      matt  * modification, are permitted provided that the following conditions
     12   1.1      matt  * are met:
     13   1.1      matt  * 1. Redistributions of source code must retain the above copyright
     14   1.1      matt  *    notice, this list of conditions and the following disclaimer.
     15   1.1      matt  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1      matt  *    notice, this list of conditions and the following disclaimer in the
     17   1.1      matt  *    documentation and/or other materials provided with the distribution.
     18   1.1      matt  * 3. All advertising materials mentioning features or use of this software
     19   1.1      matt  *    must display the following acknowledgement:
     20   1.1      matt  *	This product includes software developed by the NetBSD
     21   1.1      matt  *	Foundation, Inc. and its contributors.
     22   1.1      matt  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.1      matt  *    contributors may be used to endorse or promote products derived
     24   1.1      matt  *    from this software without specific prior written permission.
     25   1.1      matt  *
     26   1.1      matt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.1      matt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.1      matt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.1      matt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.1      matt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.1      matt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.1      matt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.1      matt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.1      matt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.1      matt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.1      matt  * POSSIBILITY OF SUCH DAMAGE.
     37   1.1      matt  */
     38   1.1      matt 
     39   1.1      matt /*
     40   1.2      matt  * ACPI attachment for the PC Keyboard Controller driver.
     41   1.1      matt  *
     42   1.1      matt  * This is a little wonky.  The keyboard controller actually
     43   1.2      matt  * has 2 ACPI nodes: one for the controller and the keyboard
     44   1.1      matt  * interrupt, and one for the aux port (mouse) interrupt.
     45   1.1      matt  *
     46   1.1      matt  * For this reason, we actually attach *two* instances of this
     47   1.1      matt  * driver.  After both of them have been found, then we attach
     48   1.1      matt  * sub-devices.
     49   1.1      matt  */
     50   1.1      matt 
     51   1.1      matt #include <sys/cdefs.h>
     52  1.15     kochi __KERNEL_RCSID(0, "$NetBSD: pckbc_acpi.c,v 1.15 2004/05/01 12:03:48 kochi Exp $");
     53   1.1      matt 
     54   1.1      matt #include <sys/param.h>
     55   1.1      matt #include <sys/systm.h>
     56   1.1      matt #include <sys/kernel.h>
     57   1.1      matt #include <sys/proc.h>
     58   1.1      matt #include <sys/device.h>
     59   1.1      matt #include <sys/malloc.h>
     60   1.1      matt #include <sys/errno.h>
     61   1.1      matt #include <sys/queue.h>
     62   1.1      matt #include <sys/lock.h>
     63   1.1      matt 
     64   1.1      matt #include <machine/bus.h>
     65   1.1      matt 
     66   1.1      matt #include <dev/isa/isareg.h>
     67   1.1      matt #include <dev/isa/isavar.h>
     68   1.1      matt 
     69   1.1      matt #include <dev/ic/i8042reg.h>
     70   1.1      matt #include <dev/ic/pckbcvar.h>
     71   1.1      matt 
     72   1.1      matt #include <dev/acpi/acpivar.h>
     73   1.1      matt 
     74  1.15     kochi static int	pckbc_acpi_match(struct device *, struct cfdata *, void *);
     75  1.15     kochi static void	pckbc_acpi_attach(struct device *, struct device *, void *);
     76   1.1      matt 
     77   1.1      matt struct pckbc_acpi_softc {
     78   1.1      matt 	struct pckbc_softc sc_pckbc;
     79   1.1      matt 
     80   1.1      matt 	isa_chipset_tag_t sc_ic;
     81   1.1      matt 	int sc_irq;
     82   1.1      matt 	int sc_ist;
     83   1.1      matt 	pckbc_slot_t sc_slot;
     84   1.1      matt };
     85   1.1      matt 
     86   1.1      matt /* Save first port: */
     87   1.1      matt static struct pckbc_acpi_softc *first;
     88   1.1      matt 
     89   1.1      matt extern struct cfdriver pckbc_cd;
     90   1.1      matt 
     91   1.1      matt CFATTACH_DECL(pckbc_acpi, sizeof(struct pckbc_acpi_softc),
     92   1.1      matt     pckbc_acpi_match, pckbc_acpi_attach, NULL, NULL);
     93   1.1      matt 
     94  1.15     kochi static void	pckbc_acpi_intr_establish(struct pckbc_softc *, pckbc_slot_t);
     95   1.1      matt 
     96   1.1      matt /*
     97   1.1      matt  * Supported Device IDs
     98   1.1      matt  */
     99   1.1      matt 
    100  1.11   mycroft static const char * const pckbc_acpi_ids_kbd[] = {
    101  1.11   mycroft 	"PNP03??",	/* Standard PC KBD port */
    102  1.11   mycroft 	NULL
    103  1.11   mycroft };
    104  1.11   mycroft 
    105  1.11   mycroft static const char * const pckbc_acpi_ids_ms[] = {
    106  1.10   mycroft 	"PNP0F03",
    107  1.10   mycroft 	"PNP0F0E",
    108  1.10   mycroft 	"PNP0F12",
    109   1.1      matt 	"PNP0F13",
    110  1.10   mycroft 	"PNP0F19",
    111  1.10   mycroft 	"PNP0F1B",
    112  1.10   mycroft 	"PNP0F1C",
    113   1.1      matt 	NULL
    114   1.1      matt };
    115   1.1      matt 
    116   1.1      matt /*
    117   1.2      matt  * pckbc_acpi_match: autoconf(9) match routine
    118   1.1      matt  */
    119  1.15     kochi static int
    120   1.1      matt pckbc_acpi_match(struct device *parent, struct cfdata *match, void *aux)
    121   1.1      matt {
    122   1.1      matt 	struct acpi_attach_args *aa = aux;
    123  1.11   mycroft 	int rv;
    124   1.1      matt 
    125   1.1      matt 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    126  1.12     kochi 		return 0;
    127   1.1      matt 
    128  1.11   mycroft 	rv = acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_kbd);
    129  1.11   mycroft 	if (rv)
    130  1.12     kochi 		return rv;
    131  1.11   mycroft 	rv = acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_ms);
    132  1.11   mycroft 	if (rv)
    133  1.12     kochi 		return rv;
    134  1.12     kochi 	return 0;
    135   1.1      matt }
    136   1.1      matt 
    137  1.15     kochi static void
    138   1.1      matt pckbc_acpi_attach(struct device *parent,
    139   1.1      matt     struct device *self,
    140   1.1      matt     void *aux)
    141   1.1      matt {
    142   1.1      matt 	struct pckbc_acpi_softc *psc = (void *) self;
    143   1.1      matt 	struct pckbc_softc *sc = &psc->sc_pckbc;
    144   1.1      matt 	struct pckbc_internal *t;
    145   1.1      matt 	struct acpi_attach_args *aa = aux;
    146   1.1      matt 	bus_space_handle_t ioh_d, ioh_c;
    147   1.1      matt 	pckbc_slot_t peer;
    148   1.1      matt 	struct acpi_resources res;
    149   1.1      matt 	struct acpi_io *io0, *io1;
    150   1.1      matt 	struct acpi_irq *irq;
    151   1.1      matt 	ACPI_STATUS rv;
    152   1.1      matt 
    153   1.1      matt 	psc->sc_ic = aa->aa_ic;
    154   1.1      matt 
    155  1.11   mycroft 	if (acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_kbd)) {
    156   1.1      matt 		psc->sc_slot = PCKBC_KBD_SLOT;
    157   1.1      matt 		peer = PCKBC_AUX_SLOT;
    158  1.11   mycroft 	} else if (acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_ms)) {
    159   1.1      matt 		psc->sc_slot = PCKBC_AUX_SLOT;
    160   1.1      matt 		peer = PCKBC_KBD_SLOT;
    161   1.1      matt 	} else {
    162   1.1      matt 		printf(": unknown port!\n");
    163   1.1      matt 		panic("pckbc_acpi_attach: impossible");
    164   1.1      matt 	}
    165   1.1      matt 
    166   1.1      matt 	printf(": %s port\n", pckbc_slot_names[psc->sc_slot]);
    167   1.1      matt 
    168   1.1      matt 	/* parse resources */
    169  1.13     kochi 	rv = acpi_resource_parse(&sc->sc_dv, aa->aa_node->ad_handle, "_CRS",
    170  1.13     kochi 	    &res, &acpi_resource_parse_ops_default);
    171   1.9   mycroft 	if (ACPI_FAILURE(rv))
    172   1.1      matt 		return;
    173   1.1      matt 
    174   1.1      matt 	/* find our IRQ */
    175   1.1      matt 	irq = acpi_res_irq(&res, 0);
    176   1.1      matt 	if (irq == NULL) {
    177   1.1      matt 		printf("%s: unable to find irq resource\n", sc->sc_dv.dv_xname);
    178  1.14     kochi 		goto out;
    179   1.1      matt 	}
    180   1.1      matt 	psc->sc_irq = irq->ar_irq;
    181   1.1      matt 	psc->sc_ist = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
    182   1.1      matt 
    183   1.3      matt 	if (psc->sc_slot == PCKBC_KBD_SLOT)
    184   1.1      matt 		first = psc;
    185   1.1      matt 
    186   1.3      matt 	if ((!first || !first->sc_pckbc.id) &&
    187   1.3      matt 	    (psc->sc_slot == PCKBC_KBD_SLOT)) {
    188   1.1      matt 
    189   1.1      matt 		io0 = acpi_res_io(&res, 0);
    190   1.1      matt 		if (io0 == NULL) {
    191   1.1      matt 			printf("%s: unable to find i/o resources\n",
    192   1.1      matt 			    sc->sc_dv.dv_xname);
    193  1.14     kochi 			goto out;
    194   1.1      matt 		}
    195   1.1      matt 
    196   1.1      matt 		if (pckbc_is_console(aa->aa_iot, io0->ar_base)) {
    197   1.1      matt 			t = &pckbc_consdata;
    198   1.1      matt 			ioh_d = t->t_ioh_d;
    199   1.1      matt 			ioh_c = t->t_ioh_c;
    200   1.1      matt 			pckbc_console_attached = 1;
    201   1.1      matt 			/* t->t_cmdbyte was initialized by cnattach */
    202   1.1      matt 		} else {
    203   1.1      matt 			io1 = acpi_res_io(&res, 1);
    204   1.1      matt 			if (io1 == NULL) {
    205   1.1      matt 				printf("%s: unable to find i/o resources\n",
    206   1.1      matt 				    sc->sc_dv.dv_xname);
    207  1.14     kochi 				goto out;
    208   1.1      matt 			}
    209   1.1      matt 			if (bus_space_map(aa->aa_iot, io0->ar_base,
    210   1.1      matt 					  io0->ar_length, 0, &ioh_d) ||
    211   1.1      matt 			    bus_space_map(aa->aa_iot, io1->ar_base,
    212   1.1      matt 					  io1->ar_length, 0, &ioh_c))
    213   1.1      matt 				panic("pckbc_acpi_attach: couldn't map");
    214   1.1      matt 
    215   1.1      matt 			t = malloc(sizeof(struct pckbc_internal),
    216   1.1      matt 			    M_DEVBUF, M_WAITOK);
    217   1.1      matt 			memset(t, 0, sizeof(*t));
    218   1.1      matt 			t->t_iot = aa->aa_iot;
    219   1.1      matt 			t->t_ioh_d = ioh_d;
    220   1.1      matt 			t->t_ioh_c = ioh_c;
    221   1.1      matt 			t->t_addr = io0->ar_base;
    222   1.1      matt 			t->t_cmdbyte = KC8_CPU;	/* Enable ports */
    223   1.1      matt 			callout_init(&t->t_cleanup);
    224   1.1      matt 		}
    225   1.1      matt 
    226   1.1      matt 		t->t_sc = &first->sc_pckbc;
    227   1.1      matt 		first->sc_pckbc.id = t;
    228   1.1      matt 
    229   1.1      matt 		first->sc_pckbc.intr_establish = pckbc_acpi_intr_establish;
    230   1.1      matt 		config_defer(&first->sc_pckbc.sc_dv,
    231   1.1      matt 			     (void(*)(struct device *))pckbc_attach);
    232   1.1      matt 	}
    233  1.14     kochi  out:
    234  1.14     kochi 	acpi_resource_cleanup(&res);
    235   1.1      matt }
    236   1.1      matt 
    237  1.15     kochi static void
    238   1.1      matt pckbc_acpi_intr_establish(struct pckbc_softc *sc,
    239   1.1      matt     pckbc_slot_t slot)
    240   1.1      matt {
    241   1.1      matt 	struct pckbc_acpi_softc *psc;
    242   1.1      matt 	isa_chipset_tag_t ic = NULL;
    243   1.1      matt 	void *rv = NULL;
    244   1.5  christos 	int irq = 0, ist = 0; /* XXX: gcc */
    245   1.1      matt 	int i;
    246   1.1      matt 
    247   1.1      matt 	/*
    248   1.1      matt 	 * Note we're always called with sc == first.
    249   1.1      matt 	 */
    250   1.1      matt 	for (i = 0; i < pckbc_cd.cd_ndevs; i++) {
    251   1.1      matt 		psc = pckbc_cd.cd_devs[i];
    252   1.1      matt 		if (psc && psc->sc_slot == slot) {
    253   1.1      matt 			irq = psc->sc_irq;
    254   1.1      matt 			ist = psc->sc_ist;
    255   1.1      matt 			ic = psc->sc_ic;
    256   1.1      matt 			break;
    257   1.1      matt 		}
    258   1.1      matt 	}
    259   1.1      matt 	if (i < pckbc_cd.cd_ndevs)
    260   1.1      matt 		rv = isa_intr_establish(ic, irq, ist, IPL_TTY, pckbcintr, sc);
    261   1.1      matt 	if (rv == NULL) {
    262   1.1      matt 		printf("%s: unable to establish interrupt for %s slot\n",
    263   1.1      matt 		    sc->sc_dv.dv_xname, pckbc_slot_names[slot]);
    264   1.1      matt 	} else {
    265   1.1      matt 		printf("%s: using irq %d for %s slot\n", sc->sc_dv.dv_xname,
    266   1.1      matt 		    irq, pckbc_slot_names[slot]);
    267   1.1      matt 	}
    268   1.1      matt }
    269