Home | History | Annotate | Line # | Download | only in acpi
pckbc_acpi.c revision 1.37
      1  1.37       rin /*	$NetBSD: pckbc_acpi.c,v 1.37 2019/08/11 06:46:35 rin 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  *
     19   1.1      matt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1      matt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1      matt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1      matt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1      matt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1      matt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1      matt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1      matt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1      matt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1      matt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1      matt  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1      matt  */
     31   1.1      matt 
     32   1.1      matt /*
     33   1.2      matt  * ACPI attachment for the PC Keyboard Controller driver.
     34   1.1      matt  *
     35   1.1      matt  * This is a little wonky.  The keyboard controller actually
     36   1.2      matt  * has 2 ACPI nodes: one for the controller and the keyboard
     37   1.1      matt  * interrupt, and one for the aux port (mouse) interrupt.
     38   1.1      matt  *
     39   1.1      matt  * For this reason, we actually attach *two* instances of this
     40   1.1      matt  * driver.  After both of them have been found, then we attach
     41   1.1      matt  * sub-devices.
     42   1.1      matt  */
     43   1.1      matt 
     44   1.1      matt #include <sys/cdefs.h>
     45  1.37       rin __KERNEL_RCSID(0, "$NetBSD: pckbc_acpi.c,v 1.37 2019/08/11 06:46:35 rin Exp $");
     46   1.1      matt 
     47   1.1      matt #include <sys/param.h>
     48  1.33    jruoho #include <sys/callout.h>
     49   1.1      matt #include <sys/device.h>
     50   1.1      matt #include <sys/malloc.h>
     51  1.33    jruoho #include <sys/systm.h>
     52  1.33    jruoho 
     53  1.33    jruoho #include <dev/acpi/acpivar.h>
     54   1.1      matt 
     55   1.1      matt #include <dev/isa/isareg.h>
     56   1.1      matt 
     57   1.1      matt #include <dev/ic/i8042reg.h>
     58   1.1      matt #include <dev/ic/pckbcvar.h>
     59   1.1      matt 
     60  1.36  riastrad #include "ioconf.h"
     61  1.36  riastrad 
     62  1.25      cube static int	pckbc_acpi_match(device_t, cfdata_t, void *);
     63  1.25      cube static void	pckbc_acpi_attach(device_t, device_t, void *);
     64   1.1      matt 
     65   1.1      matt struct pckbc_acpi_softc {
     66   1.1      matt 	struct pckbc_softc sc_pckbc;
     67   1.1      matt 
     68   1.1      matt 	isa_chipset_tag_t sc_ic;
     69   1.1      matt 	int sc_irq;
     70   1.1      matt 	int sc_ist;
     71   1.1      matt 	pckbc_slot_t sc_slot;
     72   1.1      matt };
     73   1.1      matt 
     74   1.1      matt /* Save first port: */
     75   1.1      matt static struct pckbc_acpi_softc *first;
     76   1.1      matt 
     77  1.25      cube CFATTACH_DECL_NEW(pckbc_acpi, sizeof(struct pckbc_acpi_softc),
     78   1.1      matt     pckbc_acpi_match, pckbc_acpi_attach, NULL, NULL);
     79   1.1      matt 
     80  1.15     kochi static void	pckbc_acpi_intr_establish(struct pckbc_softc *, pckbc_slot_t);
     81  1.25      cube static void	pckbc_acpi_finish_attach(device_t);
     82   1.1      matt 
     83   1.1      matt /*
     84   1.1      matt  * Supported Device IDs
     85   1.1      matt  */
     86   1.1      matt 
     87  1.11   mycroft static const char * const pckbc_acpi_ids_kbd[] = {
     88  1.11   mycroft 	"PNP03??",	/* Standard PC KBD port */
     89  1.11   mycroft 	NULL
     90  1.11   mycroft };
     91  1.11   mycroft 
     92  1.11   mycroft static const char * const pckbc_acpi_ids_ms[] = {
     93  1.10   mycroft 	"PNP0F03",
     94  1.10   mycroft 	"PNP0F0E",
     95  1.10   mycroft 	"PNP0F12",
     96   1.1      matt 	"PNP0F13",
     97  1.10   mycroft 	"PNP0F19",
     98  1.10   mycroft 	"PNP0F1B",
     99  1.10   mycroft 	"PNP0F1C",
    100  1.30  pgoyette 	"SYN0302",
    101   1.1      matt 	NULL
    102   1.1      matt };
    103   1.1      matt 
    104   1.1      matt /*
    105   1.2      matt  * pckbc_acpi_match: autoconf(9) match routine
    106   1.1      matt  */
    107  1.15     kochi static int
    108  1.25      cube pckbc_acpi_match(device_t parent, cfdata_t match, void *aux)
    109   1.1      matt {
    110   1.1      matt 	struct acpi_attach_args *aa = aux;
    111  1.11   mycroft 	int rv;
    112   1.1      matt 
    113   1.1      matt 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
    114  1.12     kochi 		return 0;
    115   1.1      matt 
    116  1.11   mycroft 	rv = acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_kbd);
    117  1.11   mycroft 	if (rv)
    118  1.12     kochi 		return rv;
    119  1.11   mycroft 	rv = acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_ms);
    120  1.11   mycroft 	if (rv)
    121  1.12     kochi 		return rv;
    122  1.12     kochi 	return 0;
    123   1.1      matt }
    124   1.1      matt 
    125  1.15     kochi static void
    126  1.25      cube pckbc_acpi_attach(device_t parent, device_t self, void *aux)
    127   1.1      matt {
    128  1.25      cube 	struct pckbc_acpi_softc *psc = device_private(self);
    129   1.1      matt 	struct pckbc_softc *sc = &psc->sc_pckbc;
    130   1.1      matt 	struct pckbc_internal *t;
    131   1.1      matt 	struct acpi_attach_args *aa = aux;
    132   1.1      matt 	bus_space_handle_t ioh_d, ioh_c;
    133   1.1      matt 	struct acpi_resources res;
    134  1.21  jmcneill 	struct acpi_io *io0, *io1, *ioswap;
    135   1.1      matt 	struct acpi_irq *irq;
    136   1.1      matt 	ACPI_STATUS rv;
    137   1.1      matt 
    138  1.25      cube 	sc->sc_dv = self;
    139   1.1      matt 	psc->sc_ic = aa->aa_ic;
    140   1.1      matt 
    141  1.11   mycroft 	if (acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_kbd)) {
    142   1.1      matt 		psc->sc_slot = PCKBC_KBD_SLOT;
    143  1.11   mycroft 	} else if (acpi_match_hid(aa->aa_node->ad_devinfo, pckbc_acpi_ids_ms)) {
    144   1.1      matt 		psc->sc_slot = PCKBC_AUX_SLOT;
    145   1.1      matt 	} else {
    146  1.25      cube 		aprint_error(": unknown port!\n");
    147   1.1      matt 		panic("pckbc_acpi_attach: impossible");
    148   1.1      matt 	}
    149   1.1      matt 
    150  1.31  jmcneill 	aprint_normal(" (%s port)", pckbc_slot_names[psc->sc_slot]);
    151   1.1      matt 
    152   1.1      matt 	/* parse resources */
    153  1.25      cube 	rv = acpi_resource_parse(sc->sc_dv, aa->aa_node->ad_handle, "_CRS",
    154  1.13     kochi 	    &res, &acpi_resource_parse_ops_default);
    155   1.9   mycroft 	if (ACPI_FAILURE(rv))
    156   1.1      matt 		return;
    157   1.1      matt 
    158   1.1      matt 	/* find our IRQ */
    159   1.1      matt 	irq = acpi_res_irq(&res, 0);
    160   1.1      matt 	if (irq == NULL) {
    161  1.25      cube 		aprint_error_dev(self, "unable to find irq resource\n");
    162  1.14     kochi 		goto out;
    163   1.1      matt 	}
    164   1.1      matt 	psc->sc_irq = irq->ar_irq;
    165   1.1      matt 	psc->sc_ist = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
    166   1.1      matt 
    167   1.3      matt 	if (psc->sc_slot == PCKBC_KBD_SLOT)
    168   1.1      matt 		first = psc;
    169   1.1      matt 
    170   1.3      matt 	if ((!first || !first->sc_pckbc.id) &&
    171   1.3      matt 	    (psc->sc_slot == PCKBC_KBD_SLOT)) {
    172   1.1      matt 
    173   1.1      matt 		io0 = acpi_res_io(&res, 0);
    174  1.21  jmcneill 		io1 = acpi_res_io(&res, 1);
    175  1.21  jmcneill 		if (io0 == NULL || io1 == NULL) {
    176  1.25      cube 			aprint_error_dev(self,
    177  1.25      cube 			    "unable to find i/o resources\n");
    178  1.14     kochi 			goto out;
    179   1.1      matt 		}
    180   1.1      matt 
    181  1.21  jmcneill 		/*
    182  1.21  jmcneill 		 * JDM: Some firmware doesn't report resources in the order we
    183  1.21  jmcneill 		 * expect; sort IO resources here (lowest first)
    184  1.21  jmcneill 		 */
    185  1.21  jmcneill 		if (io0->ar_base > io1->ar_base) {
    186  1.21  jmcneill 			ioswap = io0;
    187  1.21  jmcneill 			io0 = io1;
    188  1.21  jmcneill 			io1 = ioswap;
    189  1.21  jmcneill 		}
    190  1.21  jmcneill 
    191   1.1      matt 		if (pckbc_is_console(aa->aa_iot, io0->ar_base)) {
    192   1.1      matt 			t = &pckbc_consdata;
    193   1.1      matt 			ioh_d = t->t_ioh_d;
    194   1.1      matt 			ioh_c = t->t_ioh_c;
    195   1.1      matt 			pckbc_console_attached = 1;
    196   1.1      matt 			/* t->t_cmdbyte was initialized by cnattach */
    197   1.1      matt 		} else {
    198   1.1      matt 			if (bus_space_map(aa->aa_iot, io0->ar_base,
    199   1.1      matt 					  io0->ar_length, 0, &ioh_d) ||
    200   1.1      matt 			    bus_space_map(aa->aa_iot, io1->ar_base,
    201  1.32  jmcneill 					  io1->ar_length, 0, &ioh_c)) {
    202  1.32  jmcneill 				aprint_error_dev(self,
    203  1.32  jmcneill 				    "unable to map registers\n");
    204  1.32  jmcneill 				goto out;
    205  1.32  jmcneill 			}
    206   1.1      matt 
    207   1.1      matt 			t = malloc(sizeof(struct pckbc_internal),
    208  1.28  jmcneill 			    M_DEVBUF, M_WAITOK|M_ZERO);
    209   1.1      matt 			t->t_iot = aa->aa_iot;
    210   1.1      matt 			t->t_ioh_d = ioh_d;
    211   1.1      matt 			t->t_ioh_c = ioh_c;
    212   1.1      matt 			t->t_addr = io0->ar_base;
    213   1.1      matt 			t->t_cmdbyte = KC8_CPU;	/* Enable ports */
    214  1.20        ad 			callout_init(&t->t_cleanup, 0);
    215   1.1      matt 		}
    216   1.1      matt 
    217   1.1      matt 		t->t_sc = &first->sc_pckbc;
    218   1.1      matt 		first->sc_pckbc.id = t;
    219   1.1      matt 
    220  1.23  jmcneill 		if (!pmf_device_register(self, NULL, pckbc_resume))
    221  1.25      cube 			aprint_error_dev(self,
    222  1.25      cube 			    "couldn't establish power handler\n");
    223  1.23  jmcneill 
    224   1.1      matt 		first->sc_pckbc.intr_establish = pckbc_acpi_intr_establish;
    225  1.25      cube 		config_defer(first->sc_pckbc.sc_dv, pckbc_acpi_finish_attach);
    226  1.32  jmcneill 	}
    227  1.32  jmcneill 
    228  1.32  jmcneill out:
    229  1.32  jmcneill 	if (!pmf_device_register(self, NULL, NULL))
    230  1.23  jmcneill 		aprint_error_dev(self, "couldn't establish power handler\n");
    231  1.14     kochi 	acpi_resource_cleanup(&res);
    232   1.1      matt }
    233   1.1      matt 
    234  1.15     kochi static void
    235  1.25      cube pckbc_acpi_intr_establish(struct pckbc_softc *sc, pckbc_slot_t slot)
    236   1.1      matt {
    237  1.37       rin 	struct pckbc_acpi_softc *psc = NULL; /* XXX: gcc */
    238   1.1      matt 	isa_chipset_tag_t ic = NULL;
    239   1.1      matt 	void *rv = NULL;
    240   1.5  christos 	int irq = 0, ist = 0; /* XXX: gcc */
    241   1.1      matt 	int i;
    242   1.1      matt 
    243   1.1      matt 	/*
    244   1.1      matt 	 * Note we're always called with sc == first.
    245   1.1      matt 	 */
    246   1.1      matt 	for (i = 0; i < pckbc_cd.cd_ndevs; i++) {
    247  1.29    cegger 		psc = device_lookup_private(&pckbc_cd, i);
    248   1.1      matt 		if (psc && psc->sc_slot == slot) {
    249   1.1      matt 			irq = psc->sc_irq;
    250   1.1      matt 			ist = psc->sc_ist;
    251   1.1      matt 			ic = psc->sc_ic;
    252   1.1      matt 			break;
    253   1.1      matt 		}
    254   1.1      matt 	}
    255  1.35  jdolecek 	if (i < pckbc_cd.cd_ndevs) {
    256  1.35  jdolecek 		char intr_xname[64];
    257  1.35  jdolecek 		snprintf(intr_xname, sizeof(intr_xname), "%s %s",
    258  1.35  jdolecek 		    device_xname(psc->sc_pckbc.sc_dv), pckbc_slot_names[slot]);
    259  1.35  jdolecek 
    260  1.35  jdolecek 		rv = isa_intr_establish_xname(ic, irq, ist, IPL_TTY, pckbcintr,
    261  1.35  jdolecek 		    sc, intr_xname);
    262  1.35  jdolecek 	}
    263   1.1      matt 	if (rv == NULL) {
    264  1.25      cube 		aprint_error_dev(sc->sc_dv,
    265  1.25      cube 		    "unable to establish interrupt for %s slot\n",
    266  1.25      cube 		    pckbc_slot_names[slot]);
    267   1.1      matt 	} else {
    268  1.25      cube 		aprint_normal_dev(sc->sc_dv, "using irq %d for %s slot\n",
    269   1.1      matt 		    irq, pckbc_slot_names[slot]);
    270   1.1      matt 	}
    271   1.1      matt }
    272  1.25      cube 
    273  1.25      cube static void
    274  1.25      cube pckbc_acpi_finish_attach(device_t dv)
    275  1.25      cube {
    276  1.25      cube 
    277  1.25      cube 	pckbc_attach(device_private(dv));
    278  1.25      cube }
    279