Home | History | Annotate | Line # | Download | only in i2c
ihidev.c revision 1.33
      1  1.33  jmcneill /* $NetBSD: ihidev.c,v 1.33 2024/12/09 22:06:31 jmcneill Exp $ */
      2   1.1    bouyer /* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */
      3   1.1    bouyer 
      4   1.1    bouyer /*-
      5   1.1    bouyer  * Copyright (c) 2017 The NetBSD Foundation, Inc.
      6   1.1    bouyer  * All rights reserved.
      7   1.1    bouyer  *
      8   1.1    bouyer  * This code is derived from software contributed to The NetBSD Foundation
      9   1.1    bouyer  * by Manuel Bouyer.
     10   1.1    bouyer  *
     11   1.1    bouyer  * Redistribution and use in source and binary forms, with or without
     12   1.1    bouyer  * modification, are permitted provided that the following conditions
     13   1.1    bouyer  * are met:
     14   1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     15   1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     16   1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     18   1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     19   1.1    bouyer  *
     20   1.1    bouyer  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21   1.1    bouyer  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22   1.1    bouyer  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23   1.1    bouyer  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24   1.1    bouyer  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25   1.1    bouyer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26   1.1    bouyer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27   1.1    bouyer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28   1.1    bouyer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29   1.1    bouyer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30   1.1    bouyer  * POSSIBILITY OF SUCH DAMAGE.
     31   1.1    bouyer  */
     32   1.1    bouyer 
     33   1.1    bouyer /*
     34   1.1    bouyer  * Copyright (c) 2015, 2016 joshua stein <jcs (at) openbsd.org>
     35   1.1    bouyer  *
     36   1.1    bouyer  * Permission to use, copy, modify, and distribute this software for any
     37   1.1    bouyer  * purpose with or without fee is hereby granted, provided that the above
     38   1.1    bouyer  * copyright notice and this permission notice appear in all copies.
     39   1.1    bouyer  *
     40   1.1    bouyer  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     41   1.1    bouyer  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     42   1.1    bouyer  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     43   1.1    bouyer  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     44   1.1    bouyer  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     45   1.1    bouyer  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     46   1.1    bouyer  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     47   1.1    bouyer  */
     48   1.1    bouyer 
     49   1.1    bouyer /*
     50   1.1    bouyer  * HID-over-i2c driver
     51   1.1    bouyer  *
     52   1.1    bouyer  * https://msdn.microsoft.com/en-us/library/windows/hardware/dn642101%28v=vs.85%29.aspx
     53   1.1    bouyer  *
     54   1.1    bouyer  */
     55   1.1    bouyer 
     56  1.31  jmcneill #include "gpio.h"
     57  1.31  jmcneill #include "acpica.h"
     58  1.31  jmcneill 
     59   1.1    bouyer #include <sys/cdefs.h>
     60  1.33  jmcneill __KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.33 2024/12/09 22:06:31 jmcneill Exp $");
     61   1.1    bouyer 
     62   1.1    bouyer #include <sys/param.h>
     63   1.1    bouyer #include <sys/systm.h>
     64   1.1    bouyer #include <sys/device.h>
     65   1.1    bouyer #include <sys/kmem.h>
     66  1.21  riastrad #include <sys/workqueue.h>
     67   1.1    bouyer 
     68   1.1    bouyer #include <dev/i2c/i2cvar.h>
     69   1.1    bouyer #include <dev/i2c/ihidev.h>
     70   1.1    bouyer 
     71   1.1    bouyer #include <dev/hid/hid.h>
     72   1.1    bouyer 
     73   1.1    bouyer #if NACPICA > 0
     74  1.12   thorpej #include <dev/acpi/acpivar.h>
     75   1.1    bouyer #include <dev/acpi/acpi_intr.h>
     76  1.31  jmcneill #include <dev/acpi/acpi_gpio.h>
     77  1.31  jmcneill #endif
     78  1.31  jmcneill #if NGPIO > 0
     79  1.31  jmcneill #include <dev/gpio/gpiovar.h>
     80   1.1    bouyer #endif
     81   1.1    bouyer 
     82   1.1    bouyer #include "locators.h"
     83   1.1    bouyer 
     84   1.1    bouyer /* #define IHIDEV_DEBUG */
     85   1.1    bouyer 
     86   1.1    bouyer #ifdef IHIDEV_DEBUG
     87   1.1    bouyer #define DPRINTF(x) printf x
     88   1.1    bouyer #else
     89   1.1    bouyer #define DPRINTF(x)
     90   1.1    bouyer #endif
     91   1.1    bouyer 
     92   1.1    bouyer /* 7.2 */
     93   1.1    bouyer enum {
     94   1.1    bouyer 	I2C_HID_CMD_DESCR	= 0x0,
     95   1.1    bouyer 	I2C_HID_CMD_RESET	= 0x1,
     96   1.1    bouyer 	I2C_HID_CMD_GET_REPORT	= 0x2,
     97   1.1    bouyer 	I2C_HID_CMD_SET_REPORT	= 0x3,
     98   1.1    bouyer 	I2C_HID_CMD_GET_IDLE	= 0x4,
     99   1.1    bouyer 	I2C_HID_CMD_SET_IDLE	= 0x5,
    100   1.1    bouyer 	I2C_HID_CMD_GET_PROTO	= 0x6,
    101   1.1    bouyer 	I2C_HID_CMD_SET_PROTO	= 0x7,
    102   1.1    bouyer 	I2C_HID_CMD_SET_POWER	= 0x8,
    103   1.1    bouyer 
    104   1.1    bouyer 	/* pseudo commands */
    105   1.1    bouyer 	I2C_HID_REPORT_DESCR	= 0x100,
    106   1.1    bouyer };
    107   1.1    bouyer 
    108   1.1    bouyer static int I2C_HID_POWER_ON	= 0x0;
    109   1.1    bouyer static int I2C_HID_POWER_OFF	= 0x1;
    110   1.1    bouyer 
    111   1.1    bouyer static int	ihidev_match(device_t, cfdata_t, void *);
    112   1.1    bouyer static void	ihidev_attach(device_t, device_t, void *);
    113   1.1    bouyer static int	ihidev_detach(device_t, int);
    114   1.1    bouyer CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc),
    115   1.1    bouyer     ihidev_match, ihidev_attach, ihidev_detach, NULL);
    116   1.1    bouyer 
    117  1.21  riastrad static bool	ihidev_intr_init(struct ihidev_softc *);
    118  1.21  riastrad static void	ihidev_intr_fini(struct ihidev_softc *);
    119  1.12   thorpej 
    120   1.1    bouyer static bool	ihidev_suspend(device_t, const pmf_qual_t *);
    121   1.1    bouyer static bool	ihidev_resume(device_t, const pmf_qual_t *);
    122   1.1    bouyer static int	ihidev_hid_command(struct ihidev_softc *, int, void *, bool);
    123  1.30    andvar #if NACPICA > 0
    124   1.7  jmcneill static int	ihidev_intr(void *);
    125  1.21  riastrad static void	ihidev_work(struct work *, void *);
    126  1.30    andvar #endif
    127  1.33  jmcneill static int	ihidev_poweron(struct ihidev_softc *, bool);
    128   1.1    bouyer static int	ihidev_reset(struct ihidev_softc *, bool);
    129   1.1    bouyer static int	ihidev_hid_desc_parse(struct ihidev_softc *);
    130   1.1    bouyer 
    131   1.1    bouyer static int	ihidev_maxrepid(void *, int);
    132   1.1    bouyer static int	ihidev_print(void *, const char *);
    133   1.1    bouyer static int	ihidev_submatch(device_t, cfdata_t, const int *, void *);
    134   1.1    bouyer 
    135  1.17   thorpej static bool	ihidev_acpi_get_info(struct ihidev_softc *);
    136  1.17   thorpej 
    137   1.5   thorpej static const struct device_compatible_entry compat_data[] = {
    138  1.16   thorpej 	{ .compat = "PNP0C50" },
    139  1.16   thorpej 	{ .compat = "ACPI0C50" },
    140  1.13   thorpej 	{ .compat = "hid-over-i2c" },
    141  1.18   thorpej 	DEVICE_COMPAT_EOL
    142   1.4   thorpej };
    143   1.4   thorpej 
    144   1.1    bouyer static int
    145   1.1    bouyer ihidev_match(device_t parent, cfdata_t match, void *aux)
    146   1.1    bouyer {
    147   1.1    bouyer 	struct i2c_attach_args * const ia = aux;
    148   1.3   thorpej 	int match_result;
    149   1.3   thorpej 
    150   1.5   thorpej 	if (iic_use_direct_match(ia, match, compat_data, &match_result))
    151  1.29  riastrad 		return match_result;
    152   1.1    bouyer 
    153   1.1    bouyer 	return 0;
    154   1.1    bouyer }
    155   1.1    bouyer 
    156   1.1    bouyer static void
    157   1.1    bouyer ihidev_attach(device_t parent, device_t self, void *aux)
    158   1.1    bouyer {
    159   1.1    bouyer 	struct ihidev_softc *sc = device_private(self);
    160   1.1    bouyer 	struct i2c_attach_args *ia = aux;
    161   1.1    bouyer 	struct ihidev_attach_arg iha;
    162   1.1    bouyer 	device_t dev;
    163   1.1    bouyer 	int repid, repsz;
    164   1.1    bouyer 	int isize;
    165   1.1    bouyer 	int locs[IHIDBUSCF_NLOCS];
    166   1.1    bouyer 
    167   1.1    bouyer 	sc->sc_dev = self;
    168   1.1    bouyer 	sc->sc_tag = ia->ia_tag;
    169   1.1    bouyer 	sc->sc_addr = ia->ia_addr;
    170  1.21  riastrad 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    171   1.1    bouyer 
    172  1.17   thorpej 	sc->sc_phandle = ia->ia_cookie;
    173  1.17   thorpej 	if (ia->ia_cookietype != I2C_COOKIE_ACPI) {
    174  1.17   thorpej 		aprint_error(": unsupported device tree type\n");
    175  1.17   thorpej 		return;
    176  1.17   thorpej 	}
    177  1.21  riastrad 	if (!ihidev_acpi_get_info(sc)) {
    178   1.1    bouyer 		return;
    179   1.1    bouyer 	}
    180   1.1    bouyer 
    181   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_DESCR, NULL, false) ||
    182   1.1    bouyer 	    ihidev_hid_desc_parse(sc)) {
    183   1.1    bouyer 		aprint_error(": failed fetching initial HID descriptor\n");
    184   1.1    bouyer 		return;
    185   1.1    bouyer 	}
    186   1.1    bouyer 
    187   1.1    bouyer 	aprint_naive("\n");
    188   1.1    bouyer 	aprint_normal(": vendor 0x%x product 0x%x, %s\n",
    189   1.1    bouyer 	    le16toh(sc->hid_desc.wVendorID), le16toh(sc->hid_desc.wProductID),
    190   1.1    bouyer 	    ia->ia_name);
    191   1.1    bouyer 
    192   1.1    bouyer 	sc->sc_nrepid = ihidev_maxrepid(sc->sc_report, sc->sc_reportlen);
    193   1.1    bouyer 	if (sc->sc_nrepid < 0)
    194   1.1    bouyer 		return;
    195   1.1    bouyer 
    196   1.1    bouyer 	aprint_normal_dev(self, "%d report id%s\n", sc->sc_nrepid,
    197   1.1    bouyer 	    sc->sc_nrepid > 1 ? "s" : "");
    198   1.1    bouyer 
    199   1.1    bouyer 	sc->sc_nrepid++;
    200   1.1    bouyer 	sc->sc_subdevs = kmem_zalloc(sc->sc_nrepid * sizeof(struct ihidev *),
    201   1.9       chs 	    KM_SLEEP);
    202   1.1    bouyer 
    203   1.1    bouyer 	/* find largest report size and allocate memory for input buffer */
    204   1.1    bouyer 	sc->sc_isize = le16toh(sc->hid_desc.wMaxInputLength);
    205   1.1    bouyer 	for (repid = 0; repid < sc->sc_nrepid; repid++) {
    206   1.1    bouyer 		repsz = hid_report_size(sc->sc_report, sc->sc_reportlen,
    207   1.1    bouyer 		    hid_input, repid);
    208   1.1    bouyer 
    209   1.1    bouyer 		isize = repsz + 2; /* two bytes for the length */
    210   1.1    bouyer 		isize += (sc->sc_nrepid != 1); /* one byte for the report ID */
    211   1.1    bouyer 		if (isize > sc->sc_isize)
    212   1.1    bouyer 			sc->sc_isize = isize;
    213   1.1    bouyer 
    214  1.28  riastrad 		DPRINTF(("%s: repid %d size %d\n",
    215  1.28  riastrad 		    device_xname(sc->sc_dev), repid, repsz));
    216   1.1    bouyer 	}
    217   1.9       chs 	sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP);
    218  1.21  riastrad 	if (!ihidev_intr_init(sc)) {
    219  1.12   thorpej 		return;
    220   1.1    bouyer 	}
    221   1.1    bouyer 
    222   1.1    bouyer 	iha.iaa = ia;
    223   1.1    bouyer 	iha.parent = sc;
    224   1.1    bouyer 
    225   1.1    bouyer 	/* Look for a driver claiming all report IDs first. */
    226   1.1    bouyer 	iha.reportid = IHIDEV_CLAIM_ALLREPORTID;
    227   1.1    bouyer 	locs[IHIDBUSCF_REPORTID] = IHIDEV_CLAIM_ALLREPORTID;
    228  1.19   thorpej 	dev = config_found(self, &iha, ihidev_print,
    229  1.20   thorpej 	    CFARGS(.submatch = ihidev_submatch,
    230  1.31  jmcneill 		   .locators = locs,
    231  1.31  jmcneill 		   .iattr = "ihidbus"));
    232   1.1    bouyer 	if (dev != NULL) {
    233   1.1    bouyer 		for (repid = 0; repid < sc->sc_nrepid; repid++)
    234   1.1    bouyer 			sc->sc_subdevs[repid] = device_private(dev);
    235   1.1    bouyer 		return;
    236   1.1    bouyer 	}
    237   1.1    bouyer 
    238   1.1    bouyer 	for (repid = 0; repid < sc->sc_nrepid; repid++) {
    239   1.1    bouyer 		if (hid_report_size(sc->sc_report, sc->sc_reportlen, hid_input,
    240   1.1    bouyer 		    repid) == 0 &&
    241   1.1    bouyer 		    hid_report_size(sc->sc_report, sc->sc_reportlen,
    242   1.1    bouyer 		    hid_output, repid) == 0 &&
    243   1.1    bouyer 		    hid_report_size(sc->sc_report, sc->sc_reportlen,
    244   1.1    bouyer 		    hid_feature, repid) == 0)
    245   1.1    bouyer 			continue;
    246   1.1    bouyer 
    247   1.1    bouyer 		iha.reportid = repid;
    248   1.1    bouyer 		locs[IHIDBUSCF_REPORTID] = repid;
    249  1.19   thorpej 		dev = config_found(self, &iha, ihidev_print,
    250  1.20   thorpej 		    CFARGS(.submatch = ihidev_submatch,
    251  1.31  jmcneill 			   .locators = locs,
    252  1.31  jmcneill 			   .iattr = "ihidbus"));
    253   1.1    bouyer 		sc->sc_subdevs[repid] = device_private(dev);
    254   1.1    bouyer 	}
    255   1.1    bouyer 
    256   1.1    bouyer 	/* power down until we're opened */
    257  1.21  riastrad 	if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF,
    258  1.21  riastrad 		false)) {
    259   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed to power down\n");
    260   1.1    bouyer 		return;
    261   1.1    bouyer 	}
    262   1.1    bouyer 	if (!pmf_device_register(self, ihidev_suspend, ihidev_resume))
    263   1.1    bouyer 		aprint_error_dev(self, "couldn't establish power handler\n");
    264   1.1    bouyer }
    265   1.1    bouyer 
    266   1.1    bouyer static int
    267   1.1    bouyer ihidev_detach(device_t self, int flags)
    268   1.1    bouyer {
    269   1.1    bouyer 	struct ihidev_softc *sc = device_private(self);
    270  1.21  riastrad 	int error;
    271  1.21  riastrad 
    272  1.21  riastrad 	error = config_detach_children(self, flags);
    273  1.21  riastrad 	if (error)
    274  1.21  riastrad 		return error;
    275  1.21  riastrad 
    276  1.21  riastrad 	pmf_device_deregister(self);
    277  1.21  riastrad 	ihidev_intr_fini(sc);
    278  1.21  riastrad 
    279  1.21  riastrad 	if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER, &I2C_HID_POWER_OFF,
    280  1.21  riastrad 		true))
    281  1.21  riastrad 		aprint_error_dev(sc->sc_dev, "failed to power down\n");
    282   1.1    bouyer 
    283   1.1    bouyer 	if (sc->sc_ibuf != NULL) {
    284   1.1    bouyer 		kmem_free(sc->sc_ibuf, sc->sc_isize);
    285   1.1    bouyer 		sc->sc_ibuf = NULL;
    286   1.1    bouyer 	}
    287   1.1    bouyer 
    288   1.1    bouyer 	if (sc->sc_report != NULL)
    289   1.1    bouyer 		kmem_free(sc->sc_report, sc->sc_reportlen);
    290   1.1    bouyer 
    291  1.21  riastrad 	mutex_destroy(&sc->sc_lock);
    292  1.21  riastrad 
    293  1.21  riastrad 	return 0;
    294   1.1    bouyer }
    295   1.1    bouyer 
    296   1.1    bouyer static bool
    297   1.1    bouyer ihidev_suspend(device_t self, const pmf_qual_t *q)
    298   1.1    bouyer {
    299   1.1    bouyer 	struct ihidev_softc *sc = device_private(self);
    300   1.1    bouyer 
    301  1.21  riastrad 	mutex_enter(&sc->sc_lock);
    302   1.1    bouyer 	if (sc->sc_refcnt > 0) {
    303   1.1    bouyer 		printf("ihidev power off\n");
    304   1.1    bouyer 		if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
    305   1.1    bouyer 		    &I2C_HID_POWER_OFF, true))
    306   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed to power down\n");
    307   1.1    bouyer 	}
    308  1.21  riastrad 	mutex_exit(&sc->sc_lock);
    309   1.1    bouyer 	return true;
    310   1.1    bouyer }
    311   1.1    bouyer 
    312   1.1    bouyer static bool
    313   1.1    bouyer ihidev_resume(device_t self, const pmf_qual_t *q)
    314   1.1    bouyer {
    315   1.1    bouyer 	struct ihidev_softc *sc = device_private(self);
    316   1.1    bouyer 
    317  1.21  riastrad 	mutex_enter(&sc->sc_lock);
    318   1.1    bouyer 	if (sc->sc_refcnt > 0) {
    319   1.1    bouyer 		printf("ihidev power reset\n");
    320   1.1    bouyer 		ihidev_reset(sc, true);
    321   1.1    bouyer 	}
    322  1.21  riastrad 	mutex_exit(&sc->sc_lock);
    323   1.1    bouyer 	return true;
    324   1.1    bouyer }
    325   1.1    bouyer 
    326   1.1    bouyer static int
    327   1.1    bouyer ihidev_hid_command(struct ihidev_softc *sc, int hidcmd, void *arg, bool poll)
    328   1.1    bouyer {
    329   1.1    bouyer 	int i, res = 1;
    330   1.1    bouyer 	int flags = poll ? I2C_F_POLL : 0;
    331   1.1    bouyer 
    332   1.1    bouyer 	iic_acquire_bus(sc->sc_tag, flags);
    333   1.1    bouyer 
    334   1.1    bouyer 	switch (hidcmd) {
    335   1.1    bouyer 	case I2C_HID_CMD_DESCR: {
    336   1.1    bouyer 		/*
    337   1.1    bouyer 		 * 5.2.2 - HID Descriptor Retrieval
    338   1.1    bouyer 		 * register is passed from the controller
    339   1.1    bouyer 		 */
    340   1.1    bouyer 		uint8_t cmd[] = {
    341   1.1    bouyer 			htole16(sc->sc_hid_desc_addr) & 0xff,
    342   1.1    bouyer 			htole16(sc->sc_hid_desc_addr) >> 8,
    343   1.1    bouyer 		};
    344   1.1    bouyer 
    345   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_CMD_DESCR at 0x%x\n",
    346  1.28  riastrad 		    device_xname(sc->sc_dev), htole16(sc->sc_hid_desc_addr)));
    347   1.1    bouyer 
    348   1.1    bouyer 		/* 20 00 */
    349   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
    350   1.1    bouyer 		    &cmd, sizeof(cmd), &sc->hid_desc_buf,
    351   1.1    bouyer 		    sizeof(struct i2c_hid_desc), flags);
    352   1.1    bouyer 
    353  1.28  riastrad 		DPRINTF(("%s: HID descriptor:", device_xname(sc->sc_dev)));
    354   1.1    bouyer 		for (i = 0; i < sizeof(struct i2c_hid_desc); i++)
    355   1.1    bouyer 			DPRINTF((" %.2x", sc->hid_desc_buf[i]));
    356   1.1    bouyer 		DPRINTF(("\n"));
    357   1.1    bouyer 
    358   1.1    bouyer 		break;
    359   1.1    bouyer 	}
    360   1.1    bouyer 	case I2C_HID_CMD_RESET: {
    361   1.1    bouyer 		uint8_t cmd[] = {
    362   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) & 0xff,
    363   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) >> 8,
    364   1.1    bouyer 			0,
    365   1.1    bouyer 			I2C_HID_CMD_RESET,
    366   1.1    bouyer 		};
    367   1.1    bouyer 
    368   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_CMD_RESET\n",
    369  1.28  riastrad 		    device_xname(sc->sc_dev)));
    370   1.1    bouyer 
    371   1.1    bouyer 		/* 22 00 00 01 */
    372   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
    373   1.1    bouyer 		    &cmd, sizeof(cmd), NULL, 0, flags);
    374   1.1    bouyer 
    375   1.1    bouyer 		break;
    376   1.1    bouyer 	}
    377   1.1    bouyer 	case I2C_HID_CMD_GET_REPORT: {
    378   1.1    bouyer 		struct i2c_hid_report_request *rreq =
    379   1.1    bouyer 		    (struct i2c_hid_report_request *)arg;
    380   1.1    bouyer 
    381   1.1    bouyer 		uint8_t cmd[] = {
    382   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) & 0xff,
    383   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) >> 8,
    384   1.1    bouyer 			0,
    385   1.1    bouyer 			I2C_HID_CMD_GET_REPORT,
    386   1.1    bouyer 			0, 0, 0,
    387   1.1    bouyer 		};
    388   1.1    bouyer 		int cmdlen = 7;
    389   1.1    bouyer 		int dataoff = 4;
    390   1.1    bouyer 		int report_id = rreq->id;
    391   1.1    bouyer 		int report_id_len = 1;
    392   1.1    bouyer 		int report_len = rreq->len + 2;
    393   1.1    bouyer 		int d;
    394   1.1    bouyer 		uint8_t *tmprep;
    395   1.1    bouyer 
    396   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_CMD_GET_REPORT %d "
    397  1.28  riastrad 		    "(type %d, len %d)\n", device_xname(sc->sc_dev), report_id,
    398   1.1    bouyer 		    rreq->type, rreq->len));
    399   1.1    bouyer 
    400   1.1    bouyer 		/*
    401   1.1    bouyer 		 * 7.2.2.4 - "The protocol is optimized for Report < 15.  If a
    402   1.1    bouyer 		 * report ID >= 15 is necessary, then the Report ID in the Low
    403   1.1    bouyer 		 * Byte must be set to 1111 and a Third Byte is appended to the
    404   1.1    bouyer 		 * protocol.  This Third Byte contains the entire/actual report
    405   1.1    bouyer 		 * ID."
    406   1.1    bouyer 		 */
    407   1.1    bouyer 		if (report_id >= 15) {
    408   1.1    bouyer 			cmd[dataoff++] = report_id;
    409   1.1    bouyer 			report_id = 15;
    410   1.1    bouyer 			report_id_len = 2;
    411   1.1    bouyer 		} else
    412   1.1    bouyer 			cmdlen--;
    413   1.1    bouyer 
    414   1.1    bouyer 		cmd[2] = report_id | rreq->type << 4;
    415   1.1    bouyer 
    416   1.1    bouyer 		cmd[dataoff++] = sc->hid_desc.wDataRegister & 0xff;
    417   1.1    bouyer 		cmd[dataoff] = sc->hid_desc.wDataRegister >> 8;
    418   1.1    bouyer 
    419   1.1    bouyer 		/*
    420   1.1    bouyer 		 * 7.2.2.2 - Response will be a 2-byte length value, the report
    421   1.1    bouyer 		 * id with length determined above, and then the report.
    422   1.1    bouyer 		 * Allocate rreq->len + 2 + 2 bytes, read into that temporary
    423   1.1    bouyer 		 * buffer, and then copy only the report back out to
    424   1.1    bouyer 		 * rreq->data.
    425   1.1    bouyer 		 */
    426   1.1    bouyer 		report_len += report_id_len;
    427   1.1    bouyer 		tmprep = kmem_zalloc(report_len, KM_NOSLEEP);
    428  1.23  riastrad 		if (tmprep == NULL) {
    429  1.23  riastrad 			/* XXX pool or preallocate? */
    430  1.23  riastrad 			DPRINTF(("%s: out of memory\n",
    431  1.23  riastrad 				device_xname(sc->sc_dev)));
    432  1.23  riastrad 			res = ENOMEM;
    433  1.23  riastrad 			break;
    434  1.23  riastrad 		}
    435   1.1    bouyer 
    436   1.1    bouyer 		/* type 3 id 8: 22 00 38 02 23 00 */
    437   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
    438   1.1    bouyer 		    &cmd, cmdlen, tmprep, report_len, flags);
    439   1.1    bouyer 
    440   1.1    bouyer 		d = tmprep[0] | tmprep[1] << 8;
    441   1.1    bouyer 		if (d != report_len) {
    442   1.1    bouyer 			DPRINTF(("%s: response size %d != expected length %d\n",
    443  1.28  riastrad 			    device_xname(sc->sc_dev), d, report_len));
    444   1.1    bouyer 		}
    445   1.1    bouyer 
    446   1.1    bouyer 		if (report_id_len == 2)
    447   1.1    bouyer 			d = tmprep[2] | tmprep[3] << 8;
    448   1.1    bouyer 		else
    449   1.1    bouyer 			d = tmprep[2];
    450   1.1    bouyer 
    451   1.1    bouyer 		if (d != rreq->id) {
    452   1.1    bouyer 			DPRINTF(("%s: response report id %d != %d\n",
    453  1.28  riastrad 			    device_xname(sc->sc_dev), d, rreq->id));
    454   1.1    bouyer 			iic_release_bus(sc->sc_tag, 0);
    455   1.1    bouyer 			kmem_free(tmprep, report_len);
    456   1.1    bouyer 			return (1);
    457   1.1    bouyer 		}
    458   1.1    bouyer 
    459  1.28  riastrad 		DPRINTF(("%s: response:", device_xname(sc->sc_dev)));
    460   1.1    bouyer 		for (i = 0; i < report_len; i++)
    461   1.1    bouyer 			DPRINTF((" %.2x", tmprep[i]));
    462   1.1    bouyer 		DPRINTF(("\n"));
    463   1.1    bouyer 
    464   1.1    bouyer 		memcpy(rreq->data, tmprep + 2 + report_id_len, rreq->len);
    465   1.1    bouyer 		kmem_free(tmprep, report_len);
    466   1.1    bouyer 
    467   1.1    bouyer 		break;
    468   1.1    bouyer 	}
    469   1.1    bouyer 	case I2C_HID_CMD_SET_REPORT: {
    470   1.1    bouyer 		struct i2c_hid_report_request *rreq =
    471   1.1    bouyer 		    (struct i2c_hid_report_request *)arg;
    472   1.1    bouyer 
    473   1.1    bouyer 		uint8_t cmd[] = {
    474   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) & 0xff,
    475   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) >> 8,
    476   1.1    bouyer 			0,
    477   1.1    bouyer 			I2C_HID_CMD_SET_REPORT,
    478   1.1    bouyer 			0, 0, 0, 0, 0, 0,
    479   1.1    bouyer 		};
    480   1.1    bouyer 		int cmdlen = 10;
    481   1.1    bouyer 		int report_id = rreq->id;
    482   1.1    bouyer 		int report_len = 2 + (report_id ? 1 : 0) + rreq->len;
    483   1.1    bouyer 		int dataoff;
    484   1.1    bouyer 		uint8_t *finalcmd;
    485   1.1    bouyer 
    486   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_CMD_SET_REPORT %d "
    487  1.28  riastrad 		    "(type %d, len %d):", device_xname(sc->sc_dev), report_id,
    488   1.1    bouyer 		    rreq->type, rreq->len));
    489   1.1    bouyer 		for (i = 0; i < rreq->len; i++)
    490   1.1    bouyer 			DPRINTF((" %.2x", ((uint8_t *)rreq->data)[i]));
    491   1.1    bouyer 		DPRINTF(("\n"));
    492   1.1    bouyer 
    493   1.1    bouyer 		/*
    494   1.1    bouyer 		 * 7.2.2.4 - "The protocol is optimized for Report < 15.  If a
    495   1.1    bouyer 		 * report ID >= 15 is necessary, then the Report ID in the Low
    496   1.1    bouyer 		 * Byte must be set to 1111 and a Third Byte is appended to the
    497   1.1    bouyer 		 * protocol.  This Third Byte contains the entire/actual report
    498   1.1    bouyer 		 * ID."
    499   1.1    bouyer 		 */
    500   1.1    bouyer 		dataoff = 4;
    501   1.1    bouyer 		if (report_id >= 15) {
    502   1.1    bouyer 			cmd[dataoff++] = report_id;
    503   1.1    bouyer 			report_id = 15;
    504   1.1    bouyer 		} else
    505   1.1    bouyer 			cmdlen--;
    506   1.1    bouyer 
    507   1.1    bouyer 		cmd[2] = report_id | rreq->type << 4;
    508   1.1    bouyer 
    509   1.1    bouyer 		if (rreq->type == I2C_HID_REPORT_TYPE_FEATURE) {
    510   1.1    bouyer 			cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
    511   1.1    bouyer 			    & 0xff;
    512   1.1    bouyer 			cmd[dataoff++] = htole16(sc->hid_desc.wDataRegister)
    513   1.1    bouyer 			    >> 8;
    514   1.1    bouyer 		} else {
    515   1.1    bouyer 			cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
    516   1.1    bouyer 			    & 0xff;
    517   1.1    bouyer 			cmd[dataoff++] = htole16(sc->hid_desc.wOutputRegister)
    518   1.1    bouyer 			    >> 8;
    519   1.1    bouyer 		}
    520   1.1    bouyer 
    521   1.1    bouyer 		cmd[dataoff++] = report_len & 0xff;
    522   1.1    bouyer 		cmd[dataoff++] = report_len >> 8;
    523   1.1    bouyer 		cmd[dataoff] = rreq->id;
    524   1.1    bouyer 
    525   1.1    bouyer 		finalcmd = kmem_zalloc(cmdlen + rreq->len, KM_NOSLEEP);
    526  1.23  riastrad 		if (finalcmd == NULL) {
    527  1.23  riastrad 			res = ENOMEM;
    528  1.23  riastrad 			break;
    529  1.23  riastrad 		}
    530   1.1    bouyer 
    531   1.1    bouyer 		memcpy(finalcmd, cmd, cmdlen);
    532   1.1    bouyer 		memcpy(finalcmd + cmdlen, rreq->data, rreq->len);
    533   1.1    bouyer 
    534   1.1    bouyer 		/* type 3 id 4: 22 00 34 03 23 00 04 00 04 03 */
    535   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
    536   1.1    bouyer 		    finalcmd, cmdlen + rreq->len, NULL, 0, flags);
    537   1.1    bouyer 		kmem_free(finalcmd, cmdlen + rreq->len);
    538   1.1    bouyer 
    539   1.1    bouyer  		break;
    540   1.1    bouyer  	}
    541   1.1    bouyer 
    542   1.1    bouyer 	case I2C_HID_CMD_SET_POWER: {
    543   1.1    bouyer 		int power = *(int *)arg;
    544   1.1    bouyer 		uint8_t cmd[] = {
    545   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) & 0xff,
    546   1.1    bouyer 			htole16(sc->hid_desc.wCommandRegister) >> 8,
    547   1.1    bouyer 			power,
    548   1.1    bouyer 			I2C_HID_CMD_SET_POWER,
    549   1.1    bouyer 		};
    550   1.1    bouyer 
    551   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_CMD_SET_POWER(%d)\n",
    552  1.28  riastrad 		    device_xname(sc->sc_dev), power));
    553   1.1    bouyer 
    554   1.1    bouyer 		/* 22 00 00 08 */
    555   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
    556   1.1    bouyer 		    &cmd, sizeof(cmd), NULL, 0, flags);
    557   1.1    bouyer 
    558   1.1    bouyer 		break;
    559   1.1    bouyer 	}
    560   1.1    bouyer 	case I2C_HID_REPORT_DESCR: {
    561   1.1    bouyer 		uint8_t cmd[] = {
    562   1.1    bouyer 			htole16(sc->hid_desc.wReportDescRegister) & 0xff,
    563   1.1    bouyer 			htole16(sc->hid_desc.wReportDescRegister) >> 8,
    564   1.1    bouyer 		};
    565   1.1    bouyer 
    566   1.1    bouyer 		DPRINTF(("%s: HID command I2C_HID_REPORT_DESCR at 0x%x with "
    567  1.28  riastrad 		    "size %d\n", device_xname(sc->sc_dev), cmd[0],
    568   1.1    bouyer 		    sc->sc_reportlen));
    569   1.1    bouyer 
    570   1.1    bouyer 		/* 20 00 */
    571   1.1    bouyer 		res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
    572   1.1    bouyer 		    &cmd, sizeof(cmd), sc->sc_report, sc->sc_reportlen, flags);
    573   1.1    bouyer 
    574  1.28  riastrad 		DPRINTF(("%s: HID report descriptor:",
    575  1.28  riastrad 		    device_xname(sc->sc_dev)));
    576   1.1    bouyer 		for (i = 0; i < sc->sc_reportlen; i++)
    577   1.1    bouyer 			DPRINTF((" %.2x", sc->sc_report[i]));
    578   1.1    bouyer 		DPRINTF(("\n"));
    579   1.1    bouyer 
    580   1.1    bouyer 		break;
    581   1.1    bouyer 	}
    582   1.1    bouyer 	default:
    583   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "unknown command %d\n",
    584   1.1    bouyer 		    hidcmd);
    585   1.1    bouyer 	}
    586   1.1    bouyer 
    587   1.1    bouyer 	iic_release_bus(sc->sc_tag, flags);
    588   1.1    bouyer 
    589   1.1    bouyer 	return (res);
    590   1.1    bouyer }
    591   1.1    bouyer 
    592   1.1    bouyer static int
    593  1.33  jmcneill ihidev_poweron(struct ihidev_softc *sc, bool poll)
    594   1.1    bouyer {
    595  1.33  jmcneill 	DPRINTF(("%s: poweron\n", device_xname(sc->sc_dev)));
    596   1.1    bouyer 
    597   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
    598   1.1    bouyer 	    &I2C_HID_POWER_ON, poll)) {
    599   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed to power on\n");
    600   1.1    bouyer 		return (1);
    601   1.1    bouyer 	}
    602   1.1    bouyer 
    603   1.1    bouyer 	DELAY(1000);
    604   1.1    bouyer 
    605  1.33  jmcneill 	return (0);
    606  1.33  jmcneill }
    607  1.33  jmcneill 
    608  1.33  jmcneill static int
    609  1.33  jmcneill ihidev_reset(struct ihidev_softc *sc, bool poll)
    610  1.33  jmcneill {
    611  1.33  jmcneill 	DPRINTF(("%s: resetting\n", device_xname(sc->sc_dev)));
    612  1.33  jmcneill 
    613   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_RESET, 0, poll)) {
    614   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed to reset hardware\n");
    615   1.1    bouyer 
    616   1.1    bouyer 		ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
    617   1.1    bouyer 		    &I2C_HID_POWER_OFF, poll);
    618   1.1    bouyer 
    619   1.1    bouyer 		return (1);
    620   1.1    bouyer 	}
    621   1.1    bouyer 
    622   1.1    bouyer 	DELAY(1000);
    623   1.1    bouyer 
    624   1.1    bouyer 	return (0);
    625   1.1    bouyer }
    626   1.1    bouyer 
    627   1.1    bouyer /*
    628   1.1    bouyer  * 5.2.2 - HID Descriptor Retrieval
    629   1.1    bouyer  *
    630   1.1    bouyer  * parse HID Descriptor that has already been read into hid_desc with
    631   1.1    bouyer  * I2C_HID_CMD_DESCR
    632   1.1    bouyer  */
    633   1.1    bouyer static int
    634   1.1    bouyer ihidev_hid_desc_parse(struct ihidev_softc *sc)
    635   1.1    bouyer {
    636   1.1    bouyer 	int retries = 3;
    637   1.1    bouyer 
    638   1.1    bouyer 	/* must be v01.00 */
    639   1.1    bouyer 	if (le16toh(sc->hid_desc.bcdVersion) != 0x0100) {
    640   1.1    bouyer 		aprint_error_dev(sc->sc_dev,
    641   1.1    bouyer 		    "bad HID descriptor bcdVersion (0x%x)\n",
    642   1.1    bouyer 		    le16toh(sc->hid_desc.bcdVersion));
    643   1.1    bouyer 		return (1);
    644   1.1    bouyer 	}
    645   1.1    bouyer 
    646   1.1    bouyer 	/* must be 30 bytes for v1.00 */
    647   1.1    bouyer 	if (le16toh(sc->hid_desc.wHIDDescLength !=
    648   1.1    bouyer 	    sizeof(struct i2c_hid_desc))) {
    649   1.1    bouyer 		aprint_error_dev(sc->sc_dev,
    650   1.1    bouyer 		    "bad HID descriptor size (%d != %zu)\n",
    651   1.1    bouyer 		    le16toh(sc->hid_desc.wHIDDescLength),
    652   1.1    bouyer 		    sizeof(struct i2c_hid_desc));
    653   1.1    bouyer 		return (1);
    654   1.1    bouyer 	}
    655   1.1    bouyer 
    656   1.1    bouyer 	if (le16toh(sc->hid_desc.wReportDescLength) <= 0) {
    657   1.1    bouyer 		aprint_error_dev(sc->sc_dev,
    658   1.1    bouyer 		    "bad HID report descriptor size (%d)\n",
    659   1.1    bouyer 		    le16toh(sc->hid_desc.wReportDescLength));
    660   1.1    bouyer 		return (1);
    661   1.1    bouyer 	}
    662   1.1    bouyer 
    663   1.1    bouyer 	while (retries-- > 0) {
    664   1.1    bouyer 		if (ihidev_reset(sc, false)) {
    665   1.1    bouyer 			if (retries == 0)
    666   1.1    bouyer 				return(1);
    667   1.1    bouyer 
    668   1.1    bouyer 			DELAY(1000);
    669   1.1    bouyer 		}
    670   1.1    bouyer 		else
    671   1.1    bouyer 			break;
    672   1.1    bouyer 	}
    673   1.1    bouyer 
    674   1.1    bouyer 	sc->sc_reportlen = le16toh(sc->hid_desc.wReportDescLength);
    675  1.22  riastrad 	sc->sc_report = kmem_zalloc(sc->sc_reportlen, KM_SLEEP);
    676   1.1    bouyer 
    677   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_REPORT_DESCR, 0, false)) {
    678   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed fetching HID report\n");
    679   1.1    bouyer 		return (1);
    680   1.1    bouyer 	}
    681   1.1    bouyer 
    682   1.1    bouyer 	return (0);
    683   1.1    bouyer }
    684   1.1    bouyer 
    685  1.12   thorpej static bool
    686  1.21  riastrad ihidev_intr_init(struct ihidev_softc *sc)
    687  1.12   thorpej {
    688  1.12   thorpej #if NACPICA > 0
    689  1.12   thorpej 	ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
    690  1.12   thorpej 	struct acpi_resources res;
    691  1.12   thorpej 	ACPI_STATUS rv;
    692  1.12   thorpej 	char buf[100];
    693  1.12   thorpej 
    694  1.12   thorpej 	rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res,
    695  1.12   thorpej 	    &acpi_resource_parse_ops_quiet);
    696  1.12   thorpej 	if (ACPI_FAILURE(rv)) {
    697  1.12   thorpej 		aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n");
    698  1.12   thorpej 		return false;
    699  1.12   thorpej 	}
    700  1.12   thorpej 
    701  1.12   thorpej 	const struct acpi_irq * const irq = acpi_res_irq(&res, 0);
    702  1.12   thorpej 	if (irq == NULL) {
    703  1.31  jmcneill 		aprint_debug_dev(sc->sc_dev, "no IRQ resource\n");
    704  1.12   thorpej 		acpi_resource_cleanup(&res);
    705  1.31  jmcneill #if NGPIO > 0
    706  1.31  jmcneill 		goto try_gpioint;
    707  1.31  jmcneill #else
    708  1.12   thorpej 		return false;
    709  1.31  jmcneill #endif
    710  1.12   thorpej 	}
    711  1.12   thorpej 
    712  1.12   thorpej 	sc->sc_intr_type =
    713  1.12   thorpej 	    irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL;
    714  1.12   thorpej 
    715  1.12   thorpej 	acpi_resource_cleanup(&res);
    716  1.12   thorpej 
    717  1.12   thorpej 	sc->sc_ih = acpi_intr_establish(sc->sc_dev, sc->sc_phandle, IPL_TTY,
    718  1.12   thorpej 	    false, ihidev_intr, sc, device_xname(sc->sc_dev));
    719  1.12   thorpej 	if (sc->sc_ih == NULL) {
    720  1.12   thorpej 		aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
    721  1.12   thorpej 		return false;
    722  1.12   thorpej 	}
    723  1.12   thorpej 	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n",
    724  1.12   thorpej 	    acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
    725  1.12   thorpej 
    726  1.31  jmcneill #if NGPIO > 0
    727  1.31  jmcneill try_gpioint:
    728  1.31  jmcneill 	if (sc->sc_ih == NULL) {
    729  1.31  jmcneill 		int pin, irqmode, error;
    730  1.31  jmcneill 
    731  1.31  jmcneill 		rv = acpi_gpio_get_int(hdl, 0, &sc->sc_ih_gpio, &pin, &irqmode);
    732  1.31  jmcneill 		if (ACPI_FAILURE(rv)) {
    733  1.31  jmcneill 			aprint_error_dev(sc->sc_dev,
    734  1.31  jmcneill 			    "can't find gpioint resource\n");
    735  1.31  jmcneill 			return false;
    736  1.31  jmcneill 		}
    737  1.31  jmcneill 
    738  1.31  jmcneill 		sc->sc_ih_gpiomap.pm_map = sc->sc_ih_gpiopins;
    739  1.31  jmcneill 		error = gpio_pin_map(sc->sc_ih_gpio, pin, 1,
    740  1.31  jmcneill 		    &sc->sc_ih_gpiomap);
    741  1.31  jmcneill 		if (error) {
    742  1.31  jmcneill 			aprint_error_dev(sc->sc_dev, "can't map pin %d\n", pin);
    743  1.31  jmcneill 			return false;
    744  1.31  jmcneill 		}
    745  1.31  jmcneill 
    746  1.31  jmcneill 		sc->sc_ih = gpio_intr_establish(sc->sc_ih_gpio,
    747  1.31  jmcneill 		    &sc->sc_ih_gpiomap, 0, IPL_VM, irqmode, ihidev_intr, sc);
    748  1.31  jmcneill 		if (sc->sc_ih == NULL) {
    749  1.31  jmcneill 			aprint_error_dev(sc->sc_dev,
    750  1.31  jmcneill 			    "can't establish gpio interrupt\n");
    751  1.31  jmcneill 			return false;
    752  1.31  jmcneill 		}
    753  1.31  jmcneill 
    754  1.31  jmcneill 		sc->sc_intr_type = (irqmode & GPIO_INTR_LEVEL_MASK) ?
    755  1.31  jmcneill 		    IST_LEVEL : IST_EDGE;
    756  1.31  jmcneill 
    757  1.31  jmcneill 		gpio_intr_str(sc->sc_ih_gpio, &sc->sc_ih_gpiomap, 0,
    758  1.31  jmcneill 		    irqmode, buf, sizeof(buf));
    759  1.31  jmcneill 		aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", buf);
    760  1.31  jmcneill 	}
    761  1.31  jmcneill #endif
    762  1.31  jmcneill 
    763  1.21  riastrad 	if (workqueue_create(&sc->sc_wq, device_xname(sc->sc_dev), ihidev_work,
    764  1.21  riastrad 		sc, PRI_NONE, IPL_TTY, WQ_MPSAFE)) {
    765  1.12   thorpej 		aprint_error_dev(sc->sc_dev,
    766  1.21  riastrad 		    "can't establish workqueue\n");
    767  1.12   thorpej 		return false;
    768  1.12   thorpej 	}
    769  1.21  riastrad 	sc->sc_work_pending = 0;
    770  1.12   thorpej 
    771  1.12   thorpej 	return true;
    772  1.12   thorpej #else
    773  1.12   thorpej 	aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
    774  1.12   thorpej 	return false;
    775  1.12   thorpej #endif
    776  1.12   thorpej }
    777  1.12   thorpej 
    778  1.12   thorpej static void
    779  1.21  riastrad ihidev_intr_fini(struct ihidev_softc *sc)
    780  1.12   thorpej {
    781  1.12   thorpej #if NACPICA > 0
    782  1.12   thorpej 	if (sc->sc_ih != NULL) {
    783  1.31  jmcneill 		if (sc->sc_ih_gpio != NULL) {
    784  1.31  jmcneill #if NGPIO > 0
    785  1.31  jmcneill 			gpio_intr_disestablish(sc->sc_ih_gpio, sc->sc_ih);
    786  1.31  jmcneill #endif
    787  1.31  jmcneill 		} else {
    788  1.31  jmcneill 			acpi_intr_disestablish(sc->sc_ih);
    789  1.31  jmcneill 		}
    790  1.12   thorpej 	}
    791  1.21  riastrad 	if (sc->sc_wq != NULL) {
    792  1.21  riastrad 		workqueue_destroy(sc->sc_wq);
    793  1.12   thorpej 	}
    794  1.12   thorpej #endif
    795  1.12   thorpej }
    796  1.12   thorpej 
    797  1.30    andvar #if NACPICA > 0
    798  1.12   thorpej static void
    799  1.12   thorpej ihidev_intr_mask(struct ihidev_softc * const sc)
    800  1.12   thorpej {
    801  1.12   thorpej 
    802  1.12   thorpej 	if (sc->sc_intr_type == IST_LEVEL) {
    803  1.31  jmcneill 		if (sc->sc_ih_gpio != NULL) {
    804  1.31  jmcneill #if NGPIO > 0
    805  1.31  jmcneill 			gpio_intr_mask(sc->sc_ih_gpio, sc->sc_ih);
    806  1.31  jmcneill #endif
    807  1.31  jmcneill 		} else {
    808  1.31  jmcneill 			acpi_intr_mask(sc->sc_ih);
    809  1.31  jmcneill 		}
    810  1.12   thorpej 	}
    811  1.12   thorpej }
    812  1.12   thorpej 
    813  1.12   thorpej static void
    814  1.12   thorpej ihidev_intr_unmask(struct ihidev_softc * const sc)
    815  1.12   thorpej {
    816  1.12   thorpej 
    817  1.12   thorpej 	if (sc->sc_intr_type == IST_LEVEL) {
    818  1.31  jmcneill 		if (sc->sc_ih_gpio != NULL) {
    819  1.31  jmcneill #if NGPIO > 0
    820  1.31  jmcneill 			gpio_intr_unmask(sc->sc_ih_gpio, sc->sc_ih);
    821  1.31  jmcneill #endif
    822  1.31  jmcneill 		} else {
    823  1.31  jmcneill 			acpi_intr_unmask(sc->sc_ih);
    824  1.31  jmcneill 		}
    825  1.12   thorpej 	}
    826  1.12   thorpej }
    827  1.12   thorpej 
    828   1.7  jmcneill static int
    829   1.1    bouyer ihidev_intr(void *arg)
    830   1.1    bouyer {
    831  1.12   thorpej 	struct ihidev_softc * const sc = arg;
    832  1.12   thorpej 
    833  1.12   thorpej 	/*
    834  1.21  riastrad 	 * Schedule our work.  If we're using a level-triggered
    835  1.21  riastrad 	 * interrupt, we have to mask it off while we wait for service.
    836  1.12   thorpej 	 */
    837  1.21  riastrad 	if (atomic_swap_uint(&sc->sc_work_pending, 1) == 0)
    838  1.21  riastrad 		workqueue_enqueue(sc->sc_wq, &sc->sc_work, NULL);
    839  1.12   thorpej 	ihidev_intr_mask(sc);
    840  1.12   thorpej 
    841  1.12   thorpej 	return 1;
    842  1.12   thorpej }
    843  1.12   thorpej 
    844  1.12   thorpej static void
    845  1.21  riastrad ihidev_work(struct work *wk, void *arg)
    846  1.12   thorpej {
    847  1.12   thorpej 	struct ihidev_softc * const sc = arg;
    848   1.1    bouyer 	struct ihidev *scd;
    849   1.1    bouyer 	u_int psize;
    850   1.1    bouyer 	int res, i;
    851   1.1    bouyer 	u_char *p;
    852   1.1    bouyer 	u_int rep = 0;
    853   1.1    bouyer 
    854  1.21  riastrad 	atomic_store_relaxed(&sc->sc_work_pending, 0);
    855  1.21  riastrad 
    856  1.21  riastrad 	mutex_enter(&sc->sc_lock);
    857  1.21  riastrad 
    858  1.12   thorpej 	iic_acquire_bus(sc->sc_tag, 0);
    859   1.1    bouyer 	res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
    860  1.12   thorpej 	    sc->sc_ibuf, sc->sc_isize, 0);
    861  1.12   thorpej 	iic_release_bus(sc->sc_tag, 0);
    862   1.1    bouyer 	if (res != 0)
    863  1.12   thorpej 		goto out;
    864   1.1    bouyer 
    865   1.1    bouyer 	/*
    866   1.1    bouyer 	 * 6.1.1 - First two bytes are the packet length, which must be less
    867   1.1    bouyer 	 * than or equal to wMaxInputLength
    868   1.1    bouyer 	 */
    869   1.1    bouyer 	psize = sc->sc_ibuf[0] | sc->sc_ibuf[1] << 8;
    870   1.1    bouyer 	if (!psize || psize > sc->sc_isize) {
    871   1.1    bouyer 		DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n",
    872  1.28  riastrad 		    device_xname(sc->sc_dev), __func__, psize, sc->sc_isize));
    873  1.12   thorpej 		goto out;
    874   1.1    bouyer 	}
    875   1.1    bouyer 
    876   1.1    bouyer 	/* 3rd byte is the report id */
    877   1.1    bouyer 	p = sc->sc_ibuf + 2;
    878   1.1    bouyer 	psize -= 2;
    879   1.1    bouyer 	if (sc->sc_nrepid != 1)
    880   1.1    bouyer 		rep = *p++, psize--;
    881   1.1    bouyer 
    882   1.1    bouyer 	if (rep >= sc->sc_nrepid) {
    883   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n",
    884   1.1    bouyer 		    __func__, rep);
    885  1.12   thorpej 		goto out;
    886   1.1    bouyer 	}
    887   1.1    bouyer 
    888  1.28  riastrad 	DPRINTF(("%s: %s: hid input (rep %d):", device_xname(sc->sc_dev),
    889  1.12   thorpej 	    __func__, rep));
    890   1.1    bouyer 	for (i = 0; i < sc->sc_isize; i++)
    891   1.1    bouyer 		DPRINTF((" %.2x", sc->sc_ibuf[i]));
    892   1.1    bouyer 	DPRINTF(("\n"));
    893   1.1    bouyer 
    894   1.1    bouyer 	scd = sc->sc_subdevs[rep];
    895   1.1    bouyer 	if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN))
    896  1.12   thorpej 		goto out;
    897   1.1    bouyer 
    898   1.1    bouyer 	scd->sc_intr(scd, p, psize);
    899   1.1    bouyer 
    900  1.12   thorpej  out:
    901  1.21  riastrad 	mutex_exit(&sc->sc_lock);
    902  1.21  riastrad 
    903  1.12   thorpej 	/*
    904  1.12   thorpej 	 * If our interrupt is level-triggered, re-enable it now.
    905  1.12   thorpej 	 */
    906  1.12   thorpej 	ihidev_intr_unmask(sc);
    907   1.1    bouyer }
    908  1.30    andvar #endif
    909   1.1    bouyer 
    910   1.1    bouyer static int
    911   1.1    bouyer ihidev_maxrepid(void *buf, int len)
    912   1.1    bouyer {
    913   1.1    bouyer 	struct hid_data *d;
    914   1.1    bouyer 	struct hid_item h;
    915   1.1    bouyer 	int maxid;
    916   1.1    bouyer 
    917   1.1    bouyer 	maxid = -1;
    918   1.1    bouyer 	h.report_ID = 0;
    919   1.1    bouyer 	for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
    920   1.6  jakllsch 		if ((int)h.report_ID > maxid)
    921   1.1    bouyer 			maxid = h.report_ID;
    922   1.1    bouyer 	hid_end_parse(d);
    923   1.1    bouyer 
    924   1.1    bouyer 	return (maxid);
    925   1.1    bouyer }
    926   1.1    bouyer 
    927   1.1    bouyer static int
    928   1.1    bouyer ihidev_print(void *aux, const char *pnp)
    929   1.1    bouyer {
    930   1.1    bouyer 	struct ihidev_attach_arg *iha = aux;
    931   1.1    bouyer 
    932   1.1    bouyer 	if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID)
    933   1.1    bouyer 		return (QUIET);
    934  1.21  riastrad 
    935   1.1    bouyer 	if (pnp)
    936   1.1    bouyer 		aprint_normal("hid at %s", pnp);
    937   1.1    bouyer 
    938   1.1    bouyer 	if (iha->reportid != 0)
    939   1.1    bouyer 		aprint_normal(" reportid %d", iha->reportid);
    940   1.1    bouyer 
    941   1.1    bouyer 	return (UNCONF);
    942   1.1    bouyer }
    943   1.1    bouyer 
    944   1.1    bouyer static int
    945   1.1    bouyer ihidev_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
    946   1.1    bouyer {
    947   1.1    bouyer 	struct ihidev_attach_arg *iha = aux;
    948   1.1    bouyer 
    949   1.1    bouyer 	if (cf->ihidevcf_reportid != IHIDEV_UNK_REPORTID &&
    950   1.1    bouyer 	    cf->ihidevcf_reportid != iha->reportid)
    951   1.1    bouyer 		return (0);
    952   1.1    bouyer 
    953   1.1    bouyer 	return config_match(parent, cf, aux);
    954   1.1    bouyer }
    955   1.1    bouyer 
    956   1.1    bouyer int
    957   1.1    bouyer ihidev_open(struct ihidev *scd)
    958   1.1    bouyer {
    959   1.1    bouyer 	struct ihidev_softc *sc = scd->sc_parent;
    960  1.24  riastrad 	int error;
    961   1.1    bouyer 
    962  1.28  riastrad 	DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev),
    963   1.1    bouyer 	    __func__, scd->sc_state, sc->sc_refcnt));
    964   1.1    bouyer 
    965  1.24  riastrad 	mutex_enter(&sc->sc_lock);
    966  1.24  riastrad 
    967  1.25  riastrad 	if (scd->sc_state & IHIDEV_OPEN || sc->sc_refcnt == INT_MAX) {
    968  1.24  riastrad 		error = EBUSY;
    969  1.24  riastrad 		goto out;
    970  1.24  riastrad 	}
    971   1.1    bouyer 
    972   1.1    bouyer 	scd->sc_state |= IHIDEV_OPEN;
    973   1.1    bouyer 
    974  1.24  riastrad 	if (sc->sc_refcnt++ || sc->sc_isize == 0) {
    975  1.24  riastrad 		error = 0;
    976  1.24  riastrad 		goto out;
    977  1.24  riastrad 	}
    978   1.1    bouyer 
    979   1.1    bouyer 	/* power on */
    980  1.33  jmcneill 	ihidev_poweron(sc, false);
    981  1.24  riastrad 	error = 0;
    982   1.1    bouyer 
    983  1.24  riastrad out:	mutex_exit(&sc->sc_lock);
    984  1.24  riastrad 	return error;
    985   1.1    bouyer }
    986   1.1    bouyer 
    987   1.1    bouyer void
    988   1.1    bouyer ihidev_close(struct ihidev *scd)
    989   1.1    bouyer {
    990   1.1    bouyer 	struct ihidev_softc *sc = scd->sc_parent;
    991   1.1    bouyer 
    992  1.28  riastrad 	DPRINTF(("%s: %s: state=%d refcnt=%d\n", device_xname(sc->sc_dev),
    993   1.1    bouyer 	    __func__, scd->sc_state, sc->sc_refcnt));
    994   1.1    bouyer 
    995  1.24  riastrad 	mutex_enter(&sc->sc_lock);
    996  1.24  riastrad 
    997  1.26  riastrad 	KASSERTMSG(scd->sc_state & IHIDEV_OPEN,
    998  1.26  riastrad 	    "%s: closing %s when not open",
    999  1.26  riastrad 	    device_xname(scd->sc_idev),
   1000  1.26  riastrad 	    device_xname(sc->sc_dev));
   1001   1.1    bouyer 	scd->sc_state &= ~IHIDEV_OPEN;
   1002   1.1    bouyer 
   1003   1.1    bouyer 	if (--sc->sc_refcnt)
   1004  1.24  riastrad 		goto out;
   1005   1.1    bouyer 
   1006   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
   1007   1.1    bouyer 	    &I2C_HID_POWER_OFF, false))
   1008   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed to power down\n");
   1009  1.24  riastrad 
   1010  1.24  riastrad out:	mutex_exit(&sc->sc_lock);
   1011   1.1    bouyer }
   1012   1.1    bouyer 
   1013   1.1    bouyer void
   1014   1.1    bouyer ihidev_get_report_desc(struct ihidev_softc *sc, void **desc, int *size)
   1015   1.1    bouyer {
   1016   1.1    bouyer 	*desc = sc->sc_report;
   1017   1.1    bouyer 	*size = sc->sc_reportlen;
   1018   1.1    bouyer }
   1019   1.1    bouyer 
   1020   1.1    bouyer /* convert hid_* constants used throughout HID code to i2c HID equivalents */
   1021   1.1    bouyer int
   1022   1.1    bouyer ihidev_report_type_conv(int hid_type_id)
   1023   1.1    bouyer {
   1024   1.1    bouyer 	switch (hid_type_id) {
   1025   1.1    bouyer 	case hid_input:
   1026   1.1    bouyer 		return I2C_HID_REPORT_TYPE_INPUT;
   1027   1.1    bouyer 	case hid_output:
   1028   1.1    bouyer 		return I2C_HID_REPORT_TYPE_OUTPUT;
   1029   1.1    bouyer 	case hid_feature:
   1030   1.1    bouyer 		return I2C_HID_REPORT_TYPE_FEATURE;
   1031   1.1    bouyer 	default:
   1032   1.1    bouyer 		return -1;
   1033   1.1    bouyer 	}
   1034   1.1    bouyer }
   1035   1.1    bouyer 
   1036   1.1    bouyer int
   1037   1.1    bouyer ihidev_get_report(struct device *dev, int type, int id, void *data, int len)
   1038   1.1    bouyer {
   1039   1.1    bouyer 	struct ihidev_softc *sc = (struct ihidev_softc *)dev;
   1040   1.1    bouyer 	struct i2c_hid_report_request rreq;
   1041   1.1    bouyer 	int ctype;
   1042   1.1    bouyer 
   1043   1.1    bouyer 	if ((ctype = ihidev_report_type_conv(type)) < 0)
   1044   1.1    bouyer 		return (1);
   1045   1.1    bouyer 
   1046   1.1    bouyer 	rreq.type = ctype;
   1047   1.1    bouyer 	rreq.id = id;
   1048   1.1    bouyer 	rreq.data = data;
   1049   1.1    bouyer 	rreq.len = len;
   1050   1.1    bouyer 
   1051   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_GET_REPORT, &rreq, false)) {
   1052   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed fetching report\n");
   1053   1.1    bouyer 		return (1);
   1054   1.1    bouyer 	}
   1055   1.1    bouyer 
   1056   1.1    bouyer 	return 0;
   1057   1.1    bouyer }
   1058   1.1    bouyer 
   1059   1.1    bouyer int
   1060   1.1    bouyer ihidev_set_report(struct device *dev, int type, int id, void *data,
   1061   1.1    bouyer     int len)
   1062   1.1    bouyer {
   1063   1.1    bouyer 	struct ihidev_softc *sc = (struct ihidev_softc *)dev;
   1064   1.1    bouyer 	struct i2c_hid_report_request rreq;
   1065   1.1    bouyer 	int ctype;
   1066   1.1    bouyer 
   1067   1.1    bouyer 	if ((ctype = ihidev_report_type_conv(type)) < 0)
   1068   1.1    bouyer 		return (1);
   1069   1.1    bouyer 
   1070   1.1    bouyer 	rreq.type = ctype;
   1071   1.1    bouyer 	rreq.id = id;
   1072   1.1    bouyer 	rreq.data = data;
   1073   1.1    bouyer 	rreq.len = len;
   1074   1.1    bouyer 
   1075   1.1    bouyer 	if (ihidev_hid_command(sc, I2C_HID_CMD_SET_REPORT, &rreq, false)) {
   1076   1.1    bouyer 		aprint_error_dev(sc->sc_dev, "failed setting report\n");
   1077   1.1    bouyer 		return (1);
   1078   1.1    bouyer 	}
   1079   1.1    bouyer 
   1080   1.1    bouyer 	return 0;
   1081   1.1    bouyer }
   1082  1.17   thorpej 
   1083  1.17   thorpej static bool
   1084  1.17   thorpej ihidev_acpi_get_info(struct ihidev_softc *sc)
   1085  1.21  riastrad {
   1086  1.30    andvar #if NACPICA > 0
   1087  1.17   thorpej 	ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
   1088  1.17   thorpej 	ACPI_STATUS status;
   1089  1.17   thorpej 	ACPI_INTEGER val;
   1090  1.17   thorpej 
   1091  1.17   thorpej 	/* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
   1092  1.17   thorpej 	uint8_t i2c_hid_guid[] = {
   1093  1.17   thorpej 		0xF7, 0xF6, 0xDF, 0x3C,
   1094  1.17   thorpej 		0x67, 0x42,
   1095  1.17   thorpej 		0x55, 0x45,
   1096  1.17   thorpej 		0xAD, 0x05,
   1097  1.17   thorpej 		0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
   1098  1.17   thorpej 	};
   1099  1.17   thorpej 
   1100  1.17   thorpej 	status = acpi_dsm_integer(hdl, i2c_hid_guid, 1, 1, NULL, &val);
   1101  1.17   thorpej 	if (ACPI_FAILURE(status)) {
   1102  1.17   thorpej 		aprint_error_dev(sc->sc_dev,
   1103  1.17   thorpej 		    "failed to get HidDescriptorAddress: %s\n",
   1104  1.27     skrll 		    AcpiFormatException(status));
   1105  1.17   thorpej 		return false;
   1106  1.17   thorpej 	}
   1107  1.17   thorpej 
   1108  1.17   thorpej 	sc->sc_hid_desc_addr = (u_int)val;
   1109  1.17   thorpej 
   1110  1.17   thorpej 	return true;
   1111  1.30    andvar #else
   1112  1.30    andvar 	return false;
   1113  1.30    andvar #endif
   1114  1.17   thorpej }
   1115