diff --git a/sys/dev/hid/hidmap.c b/sys/dev/hid/hidmap.c
index 163d63c20232..46e789fa7cec 100644
--- a/sys/dev/hid/hidmap.c
+++ b/sys/dev/hid/hidmap.c
@@ -1,832 +1,832 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 /*
  * Abstract 1 to 1 HID input usage to evdev event mapper driver.
  */
 
 #include "opt_hid.h"
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
 #include <dev/evdev/input.h>
 #include <dev/evdev/evdev.h>
 
 #include <dev/hid/hid.h>
 #include <dev/hid/hidbus.h>
 #include <dev/hid/hidmap.h>
 
 #ifdef HID_DEBUG
 #define DPRINTFN(hm, n, fmt, ...) do {					\
 	if ((hm)->debug_var != NULL && *(hm)->debug_var >= (n)) {	\
 		device_printf((hm)->dev, "%s: " fmt,			\
 		    __FUNCTION__ ,##__VA_ARGS__);			\
 	}								\
 } while (0)
 #define DPRINTF(hm, ...)	DPRINTFN(hm, 1, __VA_ARGS__)
 #else
 #define DPRINTF(...) do { } while (0)
 #define DPRINTFN(...) do { } while (0)
 #endif
 
 static evdev_open_t hidmap_ev_open;
 static evdev_close_t hidmap_ev_close;
 
 #define	HIDMAP_WANT_MERGE_KEYS(hm)	((hm)->key_rel != NULL)
 
 #define HIDMAP_FOREACH_ITEM(hm, mi, uoff)				\
 	for (u_int _map = 0, _item = 0, _uoff_priv = -1;		\
 	    ((mi) = hidmap_get_next_map_item(				\
 		(hm), &_map, &_item, &_uoff_priv, &(uoff))) != NULL;)
 
 static inline bool
 hidmap_get_next_map_index(const struct hidmap_item *map, int nmap_items,
     uint32_t *index, uint16_t *usage_offset)
 {
 
 	++*usage_offset;
 	if ((*index != 0 || *usage_offset != 0) &&
 	    *usage_offset >= map[*index].nusages) {
 		++*index;
 		*usage_offset = 0;
 	}
 
 	return (*index < nmap_items);
 }
 
 static inline const struct hidmap_item *
 hidmap_get_next_map_item(struct hidmap *hm, u_int *map, u_int *item,
     u_int *uoff_priv, uint16_t *uoff)
 {
 
 	*uoff = *uoff_priv;
 	while (!hidmap_get_next_map_index(
 	   hm->map[*map], hm->nmap_items[*map], item, uoff)) {
 		++*map;
 		*item = 0;
 		*uoff = -1;
 		if (*map >= hm->nmaps)
 			return (NULL);
 	}
 	*uoff_priv = *uoff;
 
 	return (hm->map[*map] + *item);
 }
 
 void
 _hidmap_set_debug_var(struct hidmap *hm, int *debug_var)
 {
 #ifdef HID_DEBUG
 	hm->debug_var = debug_var;
 #endif
 }
 
 static int
 hidmap_ev_close(struct evdev_dev *evdev)
 {
 	return (hidbus_intr_stop(evdev_get_softc(evdev)));
 }
 
 static int
 hidmap_ev_open(struct evdev_dev *evdev)
 {
 	return (hidbus_intr_start(evdev_get_softc(evdev)));
 }
 
 void
 hidmap_support_key(struct hidmap *hm, uint16_t key)
 {
 	if (hm->key_press == NULL) {
 		hm->key_press = malloc(howmany(KEY_CNT, 8), M_DEVBUF,
 		    M_ZERO | M_WAITOK);
 		evdev_support_event(hm->evdev, EV_KEY);
 		hm->key_min = key;
 		hm->key_max = key;
 	}
 	hm->key_min = MIN(hm->key_min, key);
 	hm->key_max = MAX(hm->key_max, key);
 	if (isset(hm->key_press, key)) {
 		if (hm->key_rel == NULL)
 			hm->key_rel = malloc(howmany(KEY_CNT, 8), M_DEVBUF,
 			    M_ZERO | M_WAITOK);
 	} else {
 		setbit(hm->key_press, key);
 		evdev_support_key(hm->evdev, key);
 	}
 }
 
 void
 hidmap_push_key(struct hidmap *hm, uint16_t key, int32_t value)
 {
 	if (HIDMAP_WANT_MERGE_KEYS(hm))
 		setbit(value != 0 ? hm->key_press : hm->key_rel, key);
 	else
 		evdev_push_key(hm->evdev, key, value);
 }
 
 static void
 hidmap_sync_keys(struct hidmap *hm)
 {
 	int i, j;
 	bool press, rel;
 
 	for (j = hm->key_min / 8; j <= hm->key_max / 8; j++) {
 		if (hm->key_press[j] != hm->key_rel[j]) {
 			for (i = j * 8; i < j * 8 + 8; i++) {
 				press = isset(hm->key_press, i);
 				rel = isset(hm->key_rel, i);
 				if (press != rel)
 					evdev_push_key(hm->evdev, i, press);
 			}
 		}
 	}
 	bzero(hm->key_press, howmany(KEY_CNT, 8));
 	bzero(hm->key_rel, howmany(KEY_CNT, 8));
 }
 
 void
 hidmap_intr(void *context, void *buf, hid_size_t len)
 {
 	struct hidmap *hm = context;
 	struct hidmap_hid_item *hi;
 	const struct hidmap_item *mi;
 	int32_t usage;
 	int32_t data;
 	uint16_t key, uoff;
 	uint8_t id = 0;
 	bool found, do_sync = false;
 
 	DPRINTFN(hm, 6, "hm=%p len=%d\n", hm, len);
 	DPRINTFN(hm, 6, "data = %*D\n", len, buf, " ");
 
 	/* Strip leading "report ID" byte */
 	if (hm->hid_items[0].id) {
 		id = *(uint8_t *)buf;
 		len--;
 		buf = (uint8_t *)buf + 1;
 	}
 
 	hm->intr_buf = buf;
 	hm->intr_len = len;
 
 	for (hi = hm->hid_items; hi < hm->hid_items + hm->nhid_items; hi++) {
 		/* At first run callbacks that not tied to HID items */
 		if (hi->type == HIDMAP_TYPE_FINALCB) {
 			DPRINTFN(hm, 6, "type=%d item=%*D\n", hi->type,
 			    (int)sizeof(hi->cb), &hi->cb, " ");
 			if (hi->cb(hm, hi, (union hidmap_cb_ctx){.rid = id})
 			    == 0)
 				do_sync = true;
 			continue;
 		}
 
 		/* Ignore irrelevant reports */
 		if (id != hi->id)
 			continue;
 
 		/*
 		 * 5.8. If Logical Minimum and Logical Maximum are both
 		 * positive values then the contents of a field can be assumed
 		 * to be an unsigned value. Otherwise, all integer values are
 		 * signed values represented in 2’s complement format.
 		 */
 		data = hi->lmin < 0 || hi->lmax < 0
 		    ? hid_get_data(buf, len, &hi->loc)
 		    : hid_get_udata(buf, len, &hi->loc);
 
 		DPRINTFN(hm, 6, "type=%d data=%d item=%*D\n", hi->type, data,
 		    (int)sizeof(hi->cb), &hi->cb, " ");
 
 		if (hi->invert_value && hi->type < HIDMAP_TYPE_ARR_LIST)
 			data = hi->evtype == EV_REL
 			    ? -data
 			    : hi->lmin + hi->lmax - data;
 
 		switch (hi->type) {
 		case HIDMAP_TYPE_CALLBACK:
 			if (hi->cb(hm, hi, (union hidmap_cb_ctx){.data = data})
 			    != 0)
 				continue;
 			break;
 
 		case HIDMAP_TYPE_VAR_NULLST:
 			/*
 			 * 5.10. If the host or the device receives an
 			 * out-of-range value then the current value for the
 			 * respective control will not be modified.
 			 */
 			if (data < hi->lmin || data > hi->lmax)
 				continue;
 			/* FALLTHROUGH */
 		case HIDMAP_TYPE_VARIABLE:
 			/*
 			 * Ignore reports for absolute data if the data did not
 			 * change and for relative data if data is 0.
 			 * Evdev layer filters out them anyway.
 			 */
 			if (data == (hi->evtype == EV_REL ? 0 : hi->last_val))
 				continue;
 			if (hi->evtype == EV_KEY)
 				hidmap_push_key(hm, hi->code, data);
 			else
 				evdev_push_event(hm->evdev, hi->evtype,
 				    hi->code, data);
 			hi->last_val = data;
 			break;
 
 		case HIDMAP_TYPE_ARR_LIST:
 			key = KEY_RESERVED;
 			/*
 			 * 6.2.2.5. An out-of range value in an array field
 			 * is considered no controls asserted.
 			 */
 			if (data < hi->lmin || data > hi->lmax)
 				goto report_key;
 			/*
 			 * 6.2.2.5. Rather than returning a single bit for each
 			 * button in the group, an array returns an index in
 			 * each field that corresponds to the pressed button.
 			 */
 			key = hi->codes[data - hi->lmin];
 			if (key == KEY_RESERVED)
 				DPRINTF(hm, "Can not map unknown HID "
 				    "array index: %08x\n", data);
 			goto report_key;
 
 		case HIDMAP_TYPE_ARR_RANGE:
 			key = KEY_RESERVED;
 			/*
 			 * 6.2.2.5. An out-of range value in an array field
 			 * is considered no controls asserted.
 			 */
 			if (data < hi->lmin || data > hi->lmax)
 				goto report_key;
 			/*
 			 * When the input field is an array and the usage is
 			 * specified with a range instead of an ID, we have to
 			 * derive the actual usage by using the item value as
 			 * an index in the usage range list.
 			 */
 			usage = data - hi->lmin + hi->umin;
 			found = false;
 			HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
 				if (usage == mi->usage + uoff &&
 				    mi->type == EV_KEY && !mi->has_cb) {
 					key = mi->code;
 					found = true;
 					break;
 				}
 			}
 			if (!found)
 				DPRINTF(hm, "Can not map unknown HID "
 				    "usage: %08x\n", usage);
 report_key:
 			if (key == HIDMAP_KEY_NULL || key == hi->last_key)
 				continue;
 			if (hi->last_key != KEY_RESERVED)
 				hidmap_push_key(hm, hi->last_key, 0);
 			if (key != KEY_RESERVED)
 				hidmap_push_key(hm, key, 1);
 			hi->last_key = key;
 			break;
 
 		default:
 			KASSERT(0, ("Unknown map type (%d)", hi->type));
 		}
 		do_sync = true;
 	}
 
 	if (do_sync) {
 		if (HIDMAP_WANT_MERGE_KEYS(hm))
 			hidmap_sync_keys(hm);
 		evdev_sync(hm->evdev);
 	}
 }
 
 static inline bool
 can_map_callback(struct hid_item *hi, const struct hidmap_item *mi,
     uint16_t usage_offset)
 {
 
 	return (mi->has_cb && !mi->final_cb &&
 	    hi->usage == mi->usage + usage_offset &&
 	    (mi->relabs == HIDMAP_RELABS_ANY ||
 	    !(hi->flags & HIO_RELATIVE) == !(mi->relabs == HIDMAP_RELATIVE)));
 }
 
 static inline bool
 can_map_variable(struct hid_item *hi, const struct hidmap_item *mi,
     uint16_t usage_offset)
 {
 
 	return ((hi->flags & HIO_VARIABLE) != 0 && !mi->has_cb &&
 	    hi->usage == mi->usage + usage_offset &&
 	    (mi->relabs == HIDMAP_RELABS_ANY ||
 	    !(hi->flags & HIO_RELATIVE) == !(mi->relabs == HIDMAP_RELATIVE)));
 }
 
 static inline bool
 can_map_arr_range(struct hid_item *hi, const struct hidmap_item *mi,
     uint16_t usage_offset)
 {
 
 	return ((hi->flags & HIO_VARIABLE) == 0 && !mi->has_cb &&
 	    hi->usage_minimum <= mi->usage + usage_offset &&
 	    hi->usage_maximum >= mi->usage + usage_offset &&
 	    mi->type == EV_KEY &&
 	    (mi->code != KEY_RESERVED && mi->code != HIDMAP_KEY_NULL));
 }
 
 static inline bool
 can_map_arr_list(struct hid_item *hi, const struct hidmap_item *mi,
     uint32_t usage, uint16_t usage_offset)
 {
 
 	return ((hi->flags & HIO_VARIABLE) == 0 && !mi->has_cb &&
 	    usage == mi->usage + usage_offset &&
 	    mi->type == EV_KEY &&
 	    (mi->code != KEY_RESERVED && mi->code != HIDMAP_KEY_NULL));
 }
 
 static bool
 hidmap_probe_hid_item(struct hid_item *hi, const struct hidmap_item *map,
     int nitems_map, hidmap_caps_t caps)
 {
 	u_int i, j;
 	uint16_t uoff;
 	bool found = false;
 
 #define	HIDMAP_FOREACH_INDEX(map, nitems, idx, uoff)	\
 	for ((idx) = 0, (uoff) = -1;			\
 	     hidmap_get_next_map_index((map), (nitems), &(idx), &(uoff));)
 
 	HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
 		if (can_map_callback(hi, map + i, uoff)) {
 			if (map[i].cb(NULL, NULL,
 			    (union hidmap_cb_ctx){.hi = hi}) != 0)
 				break;
 			setbit(caps, i);
 			return (true);
 		}
 	}
 
 	if (hi->flags & HIO_VARIABLE) {
 		HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
 			if (can_map_variable(hi, map + i, uoff)) {
 				KASSERT(map[i].type == EV_KEY ||
 					map[i].type == EV_REL ||
 					map[i].type == EV_ABS ||
 					map[i].type == EV_SW,
 				    ("Unsupported event type"));
 				setbit(caps, i);
 				return (true);
 			}
 		}
 		return (false);
 	}
 
 	if (hi->usage_minimum != 0 || hi->usage_maximum != 0) {
 		HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
 			if (can_map_arr_range(hi, map + i, uoff)) {
 				setbit(caps, i);
 				found = true;
 			}
 		}
 		return (found);
 	}
 
 	for (j = 0; j < hi->nusages; j++) {
 		HIDMAP_FOREACH_INDEX(map, nitems_map, i, uoff) {
 			if (can_map_arr_list(hi, map+i, hi->usages[j], uoff)) {
 				setbit(caps, i);
 				found = true;
 			}
 		}
 	}
 
 	return (found);
 }
 
 static uint32_t
 hidmap_probe_hid_descr(void *d_ptr, hid_size_t d_len, uint8_t tlc_index,
     const struct hidmap_item *map, int nitems_map, hidmap_caps_t caps)
 {
 	struct hid_data *hd;
 	struct hid_item hi;
 	uint32_t i, items = 0;
 	bool do_free = false;
 
 	if (caps == NULL) {
 		caps = malloc(HIDMAP_CAPS_SZ(nitems_map), M_DEVBUF, M_WAITOK);
 		do_free = true;
 	} else
 		bzero (caps, HIDMAP_CAPS_SZ(nitems_map));
 
 	/* Parse inputs */
 	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
 	HIDBUS_FOREACH_ITEM(hd, &hi, tlc_index) {
 		if (hi.kind != hid_input)
 			continue;
 		if (hi.flags & HIO_CONST)
 			continue;
 		for (i = 0; i < hi.loc.count; i++, hi.loc.pos += hi.loc.size)
 			if (hidmap_probe_hid_item(&hi, map, nitems_map, caps))
 				items++;
 	}
 	hid_end_parse(hd);
 
 	/* Take finalizing callbacks in to account */
 	for (i = 0; i < nitems_map; i++) {
 		if (map[i].has_cb && map[i].final_cb &&
 		    map[i].cb(NULL, NULL, (union hidmap_cb_ctx){}) == 0) {
 			setbit(caps, i);
 			items++;
 		}
 	}
 
 	/* Check that all mandatory usages are present in report descriptor */
 	if (items != 0) {
 		for (i = 0; i < nitems_map; i++) {
 			if (map[i].required && isclr(caps, i)) {
 				items = 0;
 				break;
 			}
 		}
 	}
 
 	if (do_free)
 		free(caps, M_DEVBUF);
 
 	return (items);
 }
 
 uint32_t
 hidmap_add_map(struct hidmap *hm, const struct hidmap_item *map,
     int nitems_map, hidmap_caps_t caps)
 {
 	void *d_ptr;
 	uint32_t items;
 	int i, error;
 	hid_size_t d_len;
 	uint8_t tlc_index = hidbus_get_index(hm->dev);
 
 	/* Avoid double-adding of map in probe() handler */
 	for (i = 0; i < hm->nmaps; i++)
 		if (hm->map[i] == map)
 			return (0);
 
 	error = hid_get_report_descr(hm->dev, &d_ptr, &d_len);
 	if (error != 0) {
 		device_printf(hm->dev, "could not retrieve report descriptor "
 		     "from device: %d\n", error);
 		return (error);
 	}
 
 	hm->cb_state = HIDMAP_CB_IS_PROBING;
 	items = hidmap_probe_hid_descr(d_ptr, d_len, tlc_index, map,
 	    nitems_map, caps);
 	if (items == 0)
 		return (ENXIO);
 
 	KASSERT(hm->nmaps < HIDMAP_MAX_MAPS,
 	    ("Not more than %d maps is supported", HIDMAP_MAX_MAPS));
 	hm->nhid_items += items;
 	hm->map[hm->nmaps] = map;
 	hm->nmap_items[hm->nmaps] = nitems_map;
 	hm->nmaps++;
 
 	return (0);
 }
 
 static bool
 hidmap_parse_hid_item(struct hidmap *hm, struct hid_item *hi,
     struct hidmap_hid_item *item)
 {
 	const struct hidmap_item *mi;
 	struct hidmap_hid_item hi_temp;
 	uint32_t i;
 	uint16_t uoff;
 	bool found = false;
 
 	HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
 		if (can_map_callback(hi, mi, uoff)) {
 			bzero(&hi_temp, sizeof(hi_temp));
 			hi_temp.cb = mi->cb;
 			hi_temp.type = HIDMAP_TYPE_CALLBACK;
 			/*
 			 * Values returned by probe- and attach-stage
 			 * callbacks MUST be identical.
 			 */
 			if (mi->cb(hm, &hi_temp,
 			    (union hidmap_cb_ctx){.hi = hi}) != 0)
 				break;
 			bcopy(&hi_temp, item, sizeof(hi_temp));
 			goto mapped;
 		}
 	}
 
 	if (hi->flags & HIO_VARIABLE) {
 		HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
 			if (can_map_variable(hi, mi, uoff)) {
 				item->evtype = mi->type;
 				item->code = mi->code + uoff;
 				item->type = hi->flags & HIO_NULLSTATE
 				    ? HIDMAP_TYPE_VAR_NULLST
 				    : HIDMAP_TYPE_VARIABLE;
 				item->last_val = 0;
 				item->invert_value = mi->invert_value;
 				switch (mi->type) {
 				case EV_KEY:
 					hidmap_support_key(hm, item->code);
 					break;
 				case EV_REL:
 					evdev_support_event(hm->evdev, EV_REL);
 					evdev_support_rel(hm->evdev,
 					    item->code);
 					break;
 				case EV_ABS:
 					evdev_support_event(hm->evdev, EV_ABS);
 					evdev_support_abs(hm->evdev,
 					    item->code,
 					    hi->logical_minimum,
 					    hi->logical_maximum,
 					    mi->fuzz,
 					    mi->flat,
 					    hid_item_resolution(hi));
 					break;
 				case EV_SW:
 					evdev_support_event(hm->evdev, EV_SW);
 					evdev_support_sw(hm->evdev,
 					    item->code);
 					break;
 				default:
 					KASSERT(0, ("Unsupported event type"));
 				}
 				goto mapped;
 			}
 		}
 		return (false);
 	}
 
 	if (hi->usage_minimum != 0 || hi->usage_maximum != 0) {
 		HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
 			if (can_map_arr_range(hi, mi, uoff)) {
 				hidmap_support_key(hm, mi->code + uoff);
 				found = true;
 			}
 		}
 		if (!found)
 			return (false);
 		item->umin = hi->usage_minimum;
 		item->type = HIDMAP_TYPE_ARR_RANGE;
 		item->last_key = KEY_RESERVED;
 		goto mapped;
 	}
 
 	for (i = 0; i < hi->nusages; i++) {
 		HIDMAP_FOREACH_ITEM(hm, mi, uoff) {
 			if (can_map_arr_list(hi, mi, hi->usages[i], uoff)) {
 				hidmap_support_key(hm, mi->code + uoff);
 				if (item->codes == NULL)
 					item->codes = malloc(
 					    hi->nusages * sizeof(uint16_t),
 					    M_DEVBUF, M_WAITOK | M_ZERO);
 				item->codes[i] = mi->code + uoff;
 				found = true;
 				break;
 			}
 		}
 	}
 	if (!found)
 		return (false);
 	item->type = HIDMAP_TYPE_ARR_LIST;
 	item->last_key = KEY_RESERVED;
 
 mapped:
 	item->id = hi->report_ID;
 	item->loc = hi->loc;
 	item->loc.count = 1;
 	item->lmin = hi->logical_minimum;
 	item->lmax = hi->logical_maximum;
 
 	DPRINTFN(hm, 6, "usage=%04x id=%d loc=%u/%u type=%d item=%*D\n",
 	    hi->usage, hi->report_ID, hi->loc.pos, hi->loc.size, item->type,
 	    (int)sizeof(item->cb), &item->cb, " ");
 
 	return (true);
 }
 
 static int
 hidmap_parse_hid_descr(struct hidmap *hm, uint8_t tlc_index)
 {
 	const struct hidmap_item *map;
 	struct hidmap_hid_item *item = hm->hid_items;
 	void *d_ptr;
 	struct hid_data *hd;
 	struct hid_item hi;
 	int i, error;
 	hid_size_t d_len;
 
 	error = hid_get_report_descr(hm->dev, &d_ptr, &d_len);
 	if (error != 0) {
 		DPRINTF(hm, "could not retrieve report descriptor from "
 		     "device: %d\n", error);
 		return (error);
 	}
 
 	/* Parse inputs */
 	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
 	HIDBUS_FOREACH_ITEM(hd, &hi, tlc_index) {
 		if (hi.kind != hid_input)
 			continue;
 		if (hi.flags & HIO_CONST)
 			continue;
 		for (i = 0; i < hi.loc.count; i++, hi.loc.pos += hi.loc.size)
 			if (hidmap_parse_hid_item(hm, &hi, item))
 				item++;
 		KASSERT(item <= hm->hid_items + hm->nhid_items,
 		    ("Parsed HID item array overflow"));
 	}
 	hid_end_parse(hd);
 
 	/* Add finalizing callbacks to the end of list */
 	for (i = 0; i < hm->nmaps; i++) {
 		for (map = hm->map[i];
 		     map < hm->map[i] + hm->nmap_items[i];
 		     map++) {
 			if (map->has_cb && map->final_cb &&
 			    map->cb(hm, item, (union hidmap_cb_ctx){}) == 0) {
 				item->cb = map->cb;
 				item->type = HIDMAP_TYPE_FINALCB;
 				item++;
 			}
 		}
 	}
 
 	/*
 	 * Resulting number of parsed HID items can be less than expected as
 	 * map items might be duplicated in different maps. Save real number.
 	 */
 	if (hm->nhid_items != item - hm->hid_items)
 		DPRINTF(hm, "Parsed HID item number mismatch: expected=%u "
 		    "result=%td\n", hm->nhid_items, item - hm->hid_items);
 	hm->nhid_items = item - hm->hid_items;
 
 	if (HIDMAP_WANT_MERGE_KEYS(hm))
 		bzero(hm->key_press, howmany(KEY_CNT, 8));
 
 	return (0);
 }
 
 int
 hidmap_probe(struct hidmap* hm, device_t dev,
     const struct hid_device_id *id, int nitems_id,
     const struct hidmap_item *map, int nitems_map,
     const char *suffix, hidmap_caps_t caps)
 {
 	int error;
 
 	error = hidbus_lookup_driver_info(dev, id, nitems_id);
 	if (error != 0)
 		return (error);
 
 	hidmap_set_dev(hm, dev);
 
 	error = hidmap_add_map(hm, map, nitems_map, caps);
 	if (error != 0)
 		return (error);
 
 	hidbus_set_desc(dev, suffix);
 
 	return (BUS_PROBE_DEFAULT);
 }
 
 int
 hidmap_attach(struct hidmap* hm)
 {
 	const struct hid_device_info *hw = hid_get_device_info(hm->dev);
 #ifdef HID_DEBUG
 	char tunable[40];
 #endif
 	int error;
 
 #ifdef HID_DEBUG
 	if (hm->debug_var == NULL) {
 		hm->debug_var = &hm->debug_level;
 		snprintf(tunable, sizeof(tunable), "hw.hid.%s.debug",
 		    device_get_name(hm->dev));
 		TUNABLE_INT_FETCH(tunable, &hm->debug_level);
 		SYSCTL_ADD_INT(device_get_sysctl_ctx(hm->dev),
 			SYSCTL_CHILDREN(device_get_sysctl_tree(hm->dev)),
-			OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RWTUN,
+			OID_AUTO, "debug", CTLFLAG_RWTUN,
 			&hm->debug_level, 0, "Verbosity level");
 	}
 #endif
 
 	DPRINTFN(hm, 11, "hm=%p\n", hm);
 
 	hm->cb_state = HIDMAP_CB_IS_ATTACHING;
 
 	hm->hid_items = malloc(hm->nhid_items * sizeof(struct hid_item),
 	    M_DEVBUF, M_WAITOK | M_ZERO);
 
 	hidbus_set_intr(hm->dev, hidmap_intr, hm);
 	hm->evdev_methods = (struct evdev_methods) {
 		.ev_open = &hidmap_ev_open,
 		.ev_close = &hidmap_ev_close,
 	};
 
 	hm->evdev = evdev_alloc();
 	evdev_set_name(hm->evdev, device_get_desc(hm->dev));
 	evdev_set_phys(hm->evdev, device_get_nameunit(hm->dev));
 	evdev_set_id(hm->evdev, hw->idBus, hw->idVendor, hw->idProduct,
 	    hw->idVersion);
 	evdev_set_serial(hm->evdev, hw->serial);
 	evdev_set_flag(hm->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
 	evdev_support_event(hm->evdev, EV_SYN);
 	error = hidmap_parse_hid_descr(hm, hidbus_get_index(hm->dev));
 	if (error) {
 		DPRINTF(hm, "error=%d\n", error);
 		hidmap_detach(hm);
 		return (ENXIO);
 	}
 
 	evdev_set_methods(hm->evdev, hm->dev, &hm->evdev_methods);
 	hm->cb_state = HIDMAP_CB_IS_RUNNING;
 
 	error = evdev_register(hm->evdev);
 	if (error) {
 		DPRINTF(hm, "error=%d\n", error);
 		hidmap_detach(hm);
 		return (ENXIO);
 	}
 
 	return (0);
 }
 
 int
 hidmap_detach(struct hidmap* hm)
 {
 	struct hidmap_hid_item *hi;
 
 	DPRINTFN(hm, 11, "\n");
 
 	hm->cb_state = HIDMAP_CB_IS_DETACHING;
 
 	evdev_free(hm->evdev);
 	if (hm->hid_items != NULL) {
 		for (hi = hm->hid_items;
 		     hi < hm->hid_items + hm->nhid_items;
 		     hi++)
 			if (hi->type == HIDMAP_TYPE_FINALCB ||
 			    hi->type == HIDMAP_TYPE_CALLBACK)
 				hi->cb(hm, hi, (union hidmap_cb_ctx){});
 			else if (hi->type == HIDMAP_TYPE_ARR_LIST)
 				free(hi->codes, M_DEVBUF);
 		free(hm->hid_items, M_DEVBUF);
 	}
 
 	free(hm->key_press, M_DEVBUF);
 	free(hm->key_rel, M_DEVBUF);
 
 	return (0);
 }
 
 MODULE_DEPEND(hidmap, hid, 1, 1, 1);
 MODULE_DEPEND(hidmap, hidbus, 1, 1, 1);
 MODULE_DEPEND(hidmap, evdev, 1, 1, 1);
 MODULE_VERSION(hidmap, 1);
diff --git a/sys/dev/iicbus/iichid.c b/sys/dev/iicbus/iichid.c
index c4bc2d3cee1f..fe949f113984 100644
--- a/sys/dev/iicbus/iichid.c
+++ b/sys/dev/iicbus/iichid.c
@@ -1,1252 +1,1252 @@
 /*-
  * Copyright (c) 2018-2019 Marc Priggemeyer <marc.priggemeyer@gmail.com>
  * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 /*
  * I2C HID transport backend.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include "opt_hid.h"
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/callout.h>
 #include <sys/endian.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/rman.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/taskqueue.h>
 
 #include <machine/resource.h>
 
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
 #include <dev/acpica/acpivar.h>
 
 #include <dev/evdev/input.h>
 
 #include <dev/hid/hid.h>
 #include <dev/hid/hidquirk.h>
 
 #include <dev/iicbus/iic.h>
 #include <dev/iicbus/iicbus.h>
 #include <dev/iicbus/iiconf.h>
 
 #include "hid_if.h"
 
 #ifdef IICHID_DEBUG
 static int iichid_debug = 0;
 
 static SYSCTL_NODE(_hw, OID_AUTO, iichid, CTLFLAG_RW, 0, "I2C HID");
 SYSCTL_INT(_hw_iichid, OID_AUTO, debug, CTLFLAG_RWTUN,
     &iichid_debug, 1, "Debug level");
 
 #define	DPRINTFN(sc, n, ...) do {			\
 	if (iichid_debug >= (n))			\
 		device_printf((sc)->dev, __VA_ARGS__);	\
 } while (0)
 #define	DPRINTF(sc, ...)	DPRINTFN(sc, 1, __VA_ARGS__)
 #else
 #define	DPRINTFN(...)		do {} while (0)
 #define	DPRINTF(...)		do {} while (0)
 #endif
 
 typedef	hid_size_t	iichid_size_t;
 #define	IICHID_SIZE_MAX	(UINT16_MAX - 2)
 
 /* 7.2 */
 enum {
 	I2C_HID_CMD_DESCR	= 0x0,
 	I2C_HID_CMD_RESET	= 0x1,
 	I2C_HID_CMD_GET_REPORT	= 0x2,
 	I2C_HID_CMD_SET_REPORT	= 0x3,
 	I2C_HID_CMD_GET_IDLE	= 0x4,
 	I2C_HID_CMD_SET_IDLE	= 0x5,
 	I2C_HID_CMD_GET_PROTO	= 0x6,
 	I2C_HID_CMD_SET_PROTO	= 0x7,
 	I2C_HID_CMD_SET_POWER	= 0x8,
 };
 
 #define	I2C_HID_POWER_ON		0x0
 #define	I2C_HID_POWER_OFF		0x1
 
 /*
  * Since interrupt resource acquisition is not always possible (in case of GPIO
  * interrupts) iichid now supports a sampling_mode.
  * Set dev.iichid.<unit>.sampling_rate_slow to a value greater then 0
  * to activate sampling. A value of 0 is possible but will not reset the
  * callout and, thereby, disable further report requests. Do not set the
  * sampling_rate_fast value too high as it may result in periodical lags of
  * cursor motion.
  */
 #define	IICHID_SAMPLING_RATE_FAST	60
 #define	IICHID_SAMPLING_RATE_SLOW	10
 #define	IICHID_SAMPLING_HYSTERESIS	1
 
 /* 5.1.1 - HID Descriptor Format */
 struct i2c_hid_desc {
 	uint16_t wHIDDescLength;
 	uint16_t bcdVersion;
 	uint16_t wReportDescLength;
 	uint16_t wReportDescRegister;
 	uint16_t wInputRegister;
 	uint16_t wMaxInputLength;
 	uint16_t wOutputRegister;
 	uint16_t wMaxOutputLength;
 	uint16_t wCommandRegister;
 	uint16_t wDataRegister;
 	uint16_t wVendorID;
 	uint16_t wProductID;
 	uint16_t wVersionID;
 	uint32_t reserved;
 } __packed;
 
 static char *iichid_ids[] = {
 	"PNP0C50",
 	"ACPI0C50",
 	NULL
 };
 
 enum iichid_powerstate_how {
 	IICHID_PS_NULL,
 	IICHID_PS_ON,
 	IICHID_PS_OFF,
 };
 
 /*
  * Locking: no internal locks are used. To serialize access to shared members,
  * external iicbus lock should be taken.  That allows to make locking greatly
  * simple at the cost of running front interrupt handlers with locked bus.
  */
 struct iichid_softc {
 	device_t		dev;
 
 	bool			probe_done;
 	int			probe_result;
 
 	struct hid_device_info	hw;
 	uint16_t		addr;	/* Shifted left by 1 */
 	struct i2c_hid_desc	desc;
 
 	hid_intr_t		*intr_handler;
 	void			*intr_ctx;
 	uint8_t			*intr_buf;
 	iichid_size_t		intr_bufsize;
 
 	int			irq_rid;
 	struct resource		*irq_res;
 	void			*irq_cookie;
 
 #ifdef IICHID_SAMPLING
 	int			sampling_rate_slow;	/* iicbus lock */
 	int			sampling_rate_fast;
 	int			sampling_hysteresis;
 	int			missing_samples;	/* iicbus lock */
 	struct timeout_task	periodic_task;		/* iicbus lock */
 	bool			callout_setup;		/* iicbus lock */
 	struct taskqueue	*taskqueue;
 	struct task		event_task;
 #endif
 
 	bool			open;			/* iicbus lock */
 	bool			suspend;		/* iicbus lock */
 	bool			power_on;		/* iicbus lock */
 };
 
 static device_probe_t	iichid_probe;
 static device_attach_t	iichid_attach;
 static device_detach_t	iichid_detach;
 static device_resume_t	iichid_resume;
 static device_suspend_t	iichid_suspend;
 
 #ifdef IICHID_SAMPLING
 static int	iichid_setup_callout(struct iichid_softc *);
 static int	iichid_reset_callout(struct iichid_softc *);
 static void	iichid_teardown_callout(struct iichid_softc *);
 #endif
 
 static __inline bool
 acpi_is_iichid(ACPI_HANDLE handle)
 {
 	char	**ids;
 	UINT32	sta;
 
 	for (ids = iichid_ids; *ids != NULL; ids++) {
 		if (acpi_MatchHid(handle, *ids))
 			break;
 	}
 	if (*ids == NULL)
 		return (false);
 
 	/*
 	 * If no _STA method or if it failed, then assume that
 	 * the device is present.
 	 */
 	if (ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) ||
 	    ACPI_DEVICE_PRESENT(sta))
 		return (true);
 
 	return (false);
 }
 
 static ACPI_STATUS
 iichid_get_config_reg(ACPI_HANDLE handle, uint16_t *config_reg)
 {
 	ACPI_OBJECT *result;
 	ACPI_BUFFER acpi_buf;
 	ACPI_STATUS status;
 
 	/*
 	 * function (_DSM) to be evaluated to retrieve the address of
 	 * the configuration register of the HID device.
 	 */
 	/* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
 	static uint8_t dsm_guid[ACPI_UUID_LENGTH] = {
 		0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
 		0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
 	};
 
 	status = acpi_EvaluateDSMTyped(handle, dsm_guid, 1, 1, NULL, &acpi_buf,
 	    ACPI_TYPE_INTEGER);
 	if (ACPI_FAILURE(status)) {
 		printf("%s: error evaluating _DSM\n", __func__);
 		return (status);
 	}
 	result = (ACPI_OBJECT *) acpi_buf.Pointer;
 	*config_reg = result->Integer.Value & 0xFFFF;
 
 	AcpiOsFree(result);
 	return (status);
 }
 
 static int
 iichid_cmd_read(struct iichid_softc* sc, void *buf, iichid_size_t maxlen,
     iichid_size_t *actual_len)
 {
 	/*
 	 * 6.1.3 - Retrieval of Input Reports
 	 * DEVICE returns the length (2 Bytes) and the entire Input Report.
 	 */
 	uint8_t actbuf[2] = { 0, 0 };
 	/* Read actual input report length. */
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_RD | IIC_M_NOSTOP, sizeof(actbuf), actbuf },
 	};
 	uint16_t actlen;
 	int error;
 
 	error = iicbus_transfer(sc->dev, msgs, nitems(msgs));
 	if (error != 0)
 		return (error);
 
 	actlen = actbuf[0] | actbuf[1] << 8;
 	if (actlen <= 2 || actlen == 0xFFFF || maxlen == 0) {
 		/* Read and discard 1 byte to send I2C STOP condition. */
 		msgs[0] = (struct iic_msg)
 		    { sc->addr, IIC_M_RD | IIC_M_NOSTART, 1, actbuf };
 		actlen = 0;
 	} else {
 		actlen -= 2;
 		if (actlen > maxlen) {
 			DPRINTF(sc, "input report too big. requested=%d "
 			    "received=%d\n", maxlen, actlen);
 			actlen = maxlen;
 		}
 		/* Read input report itself. */
 		msgs[0] = (struct iic_msg)
 		    { sc->addr, IIC_M_RD | IIC_M_NOSTART, actlen, buf };
 	}
 
 	error = iicbus_transfer(sc->dev, msgs, 1);
 	if (error == 0 && actual_len != NULL)
 		*actual_len = actlen;
 
 	DPRINTFN(sc, 5,
 	    "%*D - %*D\n", 2, actbuf, " ", msgs[0].len, msgs[0].buf, " ");
 
 	return (error);
 }
 
 static int
 iichid_cmd_write(struct iichid_softc *sc, const void *buf, iichid_size_t len)
 {
 	/* 6.2.3 - Sending Output Reports. */
 	uint8_t *cmdreg = (uint8_t *)&sc->desc.wOutputRegister;
 	uint16_t replen = 2 + len;
 	uint8_t cmd[4] = { cmdreg[0], cmdreg[1], replen & 0xFF, replen >> 8 };
 	struct iic_msg msgs[] = {
 	    {sc->addr, IIC_M_WR | IIC_M_NOSTOP, sizeof(cmd), cmd},
 	    {sc->addr, IIC_M_WR | IIC_M_NOSTART, len, __DECONST(void *, buf)},
 	};
 
 	if (le16toh(sc->desc.wMaxOutputLength) == 0)
 		return (IIC_ENOTSUPP);
 	if (len < 2)
 		return (IIC_ENOTSUPP);
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_WRITE (len %d): "
 	    "%*D\n", len, len, buf, " ");
 
 	return (iicbus_transfer(sc->dev, msgs, nitems(msgs)));
 }
 
 static int
 iichid_cmd_get_hid_desc(struct iichid_softc *sc, uint16_t config_reg,
     struct i2c_hid_desc *hid_desc)
 {
 	/*
 	 * 5.2.2 - HID Descriptor Retrieval
 	 * register is passed from the controller.
 	 */
 	uint16_t cmd = htole16(config_reg);
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_WR | IIC_M_NOSTOP, 2, (uint8_t *)&cmd },
 	    { sc->addr, IIC_M_RD, sizeof(*hid_desc), (uint8_t *)hid_desc },
 	};
 	int error;
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_DESCR at 0x%x\n", config_reg);
 
 	error = iicbus_transfer(sc->dev, msgs, nitems(msgs));
 	if (error != 0)
 		return (error);
 
 	DPRINTF(sc, "HID descriptor: %*D\n",
 	    (int)sizeof(struct i2c_hid_desc), hid_desc, " ");
 
 	return (0);
 }
 
 static int
 iichid_set_power(struct iichid_softc *sc, uint8_t param)
 {
 	uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister;
 	uint8_t cmd[] = { cmdreg[0], cmdreg[1], param, I2C_HID_CMD_SET_POWER };
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_WR, sizeof(cmd), cmd },
 	};
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_SET_POWER(%d)\n", param);
 
 	return (iicbus_transfer(sc->dev, msgs, nitems(msgs)));
 }
 
 static int
 iichid_reset(struct iichid_softc *sc)
 {
 	uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister;
 	uint8_t cmd[] = { cmdreg[0], cmdreg[1], 0, I2C_HID_CMD_RESET };
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_WR, sizeof(cmd), cmd },
 	};
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_RESET\n");
 
 	return (iicbus_transfer(sc->dev, msgs, nitems(msgs)));
 }
 
 static int
 iichid_cmd_get_report_desc(struct iichid_softc* sc, void *buf,
     iichid_size_t len)
 {
 	uint16_t cmd = sc->desc.wReportDescRegister;
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_WR | IIC_M_NOSTOP, 2, (uint8_t *)&cmd },
 	    { sc->addr, IIC_M_RD, len, buf },
 	};
 	int error;
 
 	DPRINTF(sc, "HID command I2C_HID_REPORT_DESCR at 0x%x with size %d\n",
 	    le16toh(cmd), len);
 
 	error = iicbus_transfer(sc->dev, msgs, nitems(msgs));
 	if (error != 0)
 		return (error);
 
 	DPRINTF(sc, "HID report descriptor: %*D\n", len, buf, " ");
 
 	return (0);
 }
 
 static int
 iichid_cmd_get_report(struct iichid_softc* sc, void *buf, iichid_size_t maxlen,
     iichid_size_t *actual_len, uint8_t type, uint8_t id)
 {
 	/*
 	 * 7.2.2.4 - "The protocol is optimized for Report < 15.  If a
 	 * report ID >= 15 is necessary, then the Report ID in the Low Byte
 	 * must be set to 1111 and a Third Byte is appended to the protocol.
 	 * This Third Byte contains the entire/actual report ID."
 	 */
 	uint8_t *dtareg = (uint8_t *)&sc->desc.wDataRegister;
 	uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister;
 	uint8_t cmd[] =	{   /*________|______id>=15_____|______id<15______*/
 						    cmdreg[0]		   ,
 						    cmdreg[1]		   ,
 			    (id >= 15 ? 15 | (type << 4): id | (type << 4)),
 					      I2C_HID_CMD_GET_REPORT	   ,
 			    (id >= 15 ?		id	:    dtareg[0]	  ),
 			    (id >= 15 ?	   dtareg[0]	:    dtareg[1]	  ),
 			    (id >= 15 ?    dtareg[1]	:	0	  ),
 			};
 	int cmdlen    =	    (id >= 15 ?		7	:	6	  );
 	uint8_t actbuf[2] = { 0, 0 };
 	uint16_t actlen;
 	int d, error;
 	struct iic_msg msgs[] = {
 	    { sc->addr, IIC_M_WR | IIC_M_NOSTOP, cmdlen, cmd },
 	    { sc->addr, IIC_M_RD | IIC_M_NOSTOP, 2, actbuf },
 	    { sc->addr, IIC_M_RD | IIC_M_NOSTART, maxlen, buf },
 	};
 
 	if (maxlen == 0)
 		return (EINVAL);
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_GET_REPORT %d "
 	    "(type %d, len %d)\n", id, type, maxlen);
 
 	/*
 	 * 7.2.2.2 - Response will be a 2-byte length value, the report
 	 * id (1 byte, if defined in Report Descriptor), and then the report.
 	 */
 	error = iicbus_transfer(sc->dev, msgs, nitems(msgs));
 	if (error != 0)
 		return (error);
 
 	actlen = actbuf[0] | actbuf[1] << 8;
 	if (actlen != maxlen + 2)
 		DPRINTF(sc, "response size %d != expected length %d\n",
 		    actlen, maxlen + 2);
 
 	if (actlen <= 2 || actlen == 0xFFFF)
 		return (ENOMSG);
 
 	d = id != 0 ? *(uint8_t *)buf : 0;
 	if (d != id) {
 		DPRINTF(sc, "response report id %d != %d\n", d, id);
 		return (EBADMSG);
 	}
 
 	actlen -= 2;
 	if (actlen > maxlen)
 		actlen = maxlen;
 	if (actual_len != NULL)
 		*actual_len = actlen;
 
 	DPRINTF(sc, "response: %*D %*D\n", 2, actbuf, " ", actlen, buf, " ");
 
 	return (0);
 }
 
 static int
 iichid_cmd_set_report(struct iichid_softc* sc, const void *buf,
     iichid_size_t len, uint8_t type, uint8_t id)
 {
 	/*
 	 * 7.2.2.4 - "The protocol is optimized for Report < 15.  If a
 	 * report ID >= 15 is necessary, then the Report ID in the Low Byte
 	 * must be set to 1111 and a Third Byte is appended to the protocol.
 	 * This Third Byte contains the entire/actual report ID."
 	 */
 	uint8_t *dtareg = (uint8_t *)&sc->desc.wDataRegister;
 	uint8_t *cmdreg = (uint8_t *)&sc->desc.wCommandRegister;
 	uint16_t replen = 2 + len;
 	uint8_t cmd[] =	{   /*________|______id>=15_____|______id<15______*/
 						    cmdreg[0]		   ,
 						    cmdreg[1]		   ,
 			    (id >= 15 ? 15 | (type << 4): id | (type << 4)),
 					      I2C_HID_CMD_SET_REPORT	   ,
 			    (id >= 15 ?		id	:    dtareg[0]    ),
 			    (id >= 15 ?    dtareg[0]	:    dtareg[1]    ),
 			    (id >= 15 ?    dtareg[1]	:   replen & 0xff ),
 			    (id >= 15 ?   replen & 0xff	:   replen >> 8   ),
 			    (id >= 15 ?   replen >> 8	:	0	  ),
 			};
 	int cmdlen    =	    (id >= 15 ?		9	:	8	  );
 	struct iic_msg msgs[] = {
 	    {sc->addr, IIC_M_WR | IIC_M_NOSTOP, cmdlen, cmd},
 	    {sc->addr, IIC_M_WR | IIC_M_NOSTART, len, __DECONST(void *, buf)},
 	};
 
 	DPRINTF(sc, "HID command I2C_HID_CMD_SET_REPORT %d (type %d, len %d): "
 	    "%*D\n", id, type, len, len, buf, " ");
 
 	return (iicbus_transfer(sc->dev, msgs, nitems(msgs)));
 }
 
 #ifdef IICHID_SAMPLING
 static void
 iichid_event_task(void *context, int pending)
 {
 	struct iichid_softc *sc;
 	device_t parent;
 	iichid_size_t actual;
 	bool bus_requested;
 	int error;
 
 	sc = context;
 	parent = device_get_parent(sc->dev);
 
 	bus_requested = false;
 	if (iicbus_request_bus(parent, sc->dev, IIC_WAIT) != 0)
 		goto rearm;
 	bus_requested = true;
 
 	if (!sc->power_on)
 		goto out;
 
 	error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual);
 	if (error == 0) {
 		if (actual > 0) {
 			sc->intr_handler(sc->intr_ctx, sc->intr_buf, actual);
 			sc->missing_samples = 0;
 		} else
 			++sc->missing_samples;
 	} else
 		DPRINTF(sc, "read error occured: %d\n", error);
 
 rearm:
 	if (sc->callout_setup && sc->sampling_rate_slow > 0) {
 		if (sc->missing_samples == sc->sampling_hysteresis)
 			sc->intr_handler(sc->intr_ctx, sc->intr_buf, 0);
 		taskqueue_enqueue_timeout(sc->taskqueue, &sc->periodic_task,
 		    hz / MAX(sc->missing_samples >= sc->sampling_hysteresis ?
 		      sc->sampling_rate_slow : sc->sampling_rate_fast, 1));
 	}
 out:
 	if (bus_requested)
 		iicbus_release_bus(parent, sc->dev);
 }
 #endif	/* IICHID_SAMPLING */
 
 static void
 iichid_intr(void *context)
 {
 	struct iichid_softc *sc;
 	device_t parent;
 	iichid_size_t maxlen, actual;
 	int error;
 
 	sc = context;
 	parent = device_get_parent(sc->dev);
 
 	/*
 	 * Designware(IG4) driver-specific hack.
 	 * Requesting of an I2C bus with IIC_DONTWAIT parameter enables polled
 	 * mode in the driver, making possible iicbus_transfer execution from
 	 * interrupt handlers and callouts.
 	 */
 	if (iicbus_request_bus(parent, sc->dev, IIC_DONTWAIT) != 0)
 		return;
 
 	/*
 	 * Reading of input reports of I2C devices residing in SLEEP state is
 	 * not allowed and often returns a garbage.  If a HOST needs to
 	 * communicate with the DEVICE it MUST issue a SET POWER command
 	 * (to ON) before any other command. As some hardware requires reads to
 	 * acknoledge interrupts we fetch only length header and discard it.
 	 */
 	maxlen = sc->power_on ? sc->intr_bufsize : 0;
 	error = iichid_cmd_read(sc, sc->intr_buf, maxlen, &actual);
 	if (error == 0) {
 		if (sc->power_on) {
 			if (actual != 0)
 				sc->intr_handler(sc->intr_ctx, sc->intr_buf,
 				    actual);
 			else
 				DPRINTF(sc, "no data received\n");
 		}
 	} else
 		DPRINTF(sc, "read error occured: %d\n", error);
 
 	iicbus_release_bus(parent, sc->dev);
 }
 
 static int
 iichid_set_power_state(struct iichid_softc *sc,
      enum iichid_powerstate_how how_open,
      enum iichid_powerstate_how how_suspend)
 {
 	device_t parent;
 	int error;
 	int how_request;
 	bool power_on;
 
 	/*
 	 * Request iicbus early as sc->suspend and sc->power_on
 	 * are protected by iicbus internal lock.
 	 */
 	parent = device_get_parent(sc->dev);
 	/* Allow to interrupt open()/close() handlers by SIGINT */
 	how_request = how_open == IICHID_PS_NULL ? IIC_WAIT : IIC_INTRWAIT;
 	error = iicbus_request_bus(parent, sc->dev, how_request);
 	if (error != 0)
 		return (error);
 
 	switch (how_open) {
 	case IICHID_PS_ON:
 		sc->open = true;
 		break;
 	case IICHID_PS_OFF:
 		sc->open = false;
 		break;
 	case IICHID_PS_NULL:
 	default:
 		break;
 	}
 
 	switch (how_suspend) {
 	case IICHID_PS_ON:
 		sc->suspend = false;
 		break;
 	case IICHID_PS_OFF:
 		sc->suspend = true;
 		break;
 	case IICHID_PS_NULL:
 	default:
 		break;
 	}
 
 	power_on = sc->open & !sc->suspend;
 
 	if (power_on != sc->power_on) {
 		error = iichid_set_power(sc,
 		    power_on ? I2C_HID_POWER_ON : I2C_HID_POWER_OFF);
 
 		sc->power_on = power_on;
 #ifdef IICHID_SAMPLING
 		if (sc->sampling_rate_slow >= 0 && sc->intr_handler != NULL) {
 			if (power_on) {
 				iichid_setup_callout(sc);
 				iichid_reset_callout(sc);
 			} else
 				iichid_teardown_callout(sc);
 		}
 #endif
 	}
 
 	iicbus_release_bus(parent, sc->dev);
 
 	return (error);
 }
 
 static int
 iichid_setup_interrupt(struct iichid_softc *sc)
 {
 	sc->irq_cookie = 0;
 
 	int error = bus_setup_intr(sc->dev, sc->irq_res,
 	    INTR_TYPE_TTY|INTR_MPSAFE, NULL, iichid_intr, sc, &sc->irq_cookie);
 	if (error != 0)
 		DPRINTF(sc, "Could not setup interrupt handler\n");
 	else
 		DPRINTF(sc, "successfully setup interrupt\n");
 
 	return (error);
 }
 
 static void
 iichid_teardown_interrupt(struct iichid_softc *sc)
 {
 	if (sc->irq_cookie)
 		bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_cookie);
 
 	sc->irq_cookie = 0;
 }
 
 #ifdef IICHID_SAMPLING
 static int
 iichid_setup_callout(struct iichid_softc *sc)
 {
 
 	if (sc->sampling_rate_slow < 0) {
 		DPRINTF(sc, "sampling_rate is below 0, can't setup callout\n");
 		return (EINVAL);
 	}
 
 	sc->callout_setup = true;
 	DPRINTF(sc, "successfully setup callout\n");
 	return (0);
 }
 
 static int
 iichid_reset_callout(struct iichid_softc *sc)
 {
 
 	if (sc->sampling_rate_slow <= 0) {
 		DPRINTF(sc, "sampling_rate is below or equal to 0, "
 		    "can't reset callout\n");
 		return (EINVAL);
 	}
 
 	if (!sc->callout_setup)
 		return (EINVAL);
 
 	/* Start with slow sampling. */
 	sc->missing_samples = sc->sampling_hysteresis;
 	taskqueue_enqueue(sc->taskqueue, &sc->event_task);
 
 	return (0);
 }
 
 static void
 iichid_teardown_callout(struct iichid_softc *sc)
 {
 
 	sc->callout_setup = false;
 	taskqueue_cancel_timeout(sc->taskqueue, &sc->periodic_task, NULL);
 	DPRINTF(sc, "tore callout down\n");
 }
 
 static int
 iichid_sysctl_sampling_rate_handler(SYSCTL_HANDLER_ARGS)
 {
 	struct iichid_softc *sc;
 	device_t parent;
 	int error, oldval, value;
 
 	sc = arg1;
 
 	value = sc->sampling_rate_slow;
 	error = sysctl_handle_int(oidp, &value, 0, req);
 
 	if (error != 0 || req->newptr == NULL ||
 	    value == sc->sampling_rate_slow)
 		return (error);
 
 	/* Can't switch to interrupt mode if it is not supported. */
 	if (sc->irq_res == NULL && value < 0)
 		return (EINVAL);
 
 	parent = device_get_parent(sc->dev);
 	error = iicbus_request_bus(parent, sc->dev, IIC_WAIT);
 	if (error != 0)
 		return (iic2errno(error));
 
 	oldval = sc->sampling_rate_slow;
 	sc->sampling_rate_slow = value;
 
 	if (oldval < 0 && value >= 0) {
 		iichid_teardown_interrupt(sc);
 		if (sc->power_on)
 			iichid_setup_callout(sc);
 	} else if (oldval >= 0 && value < 0) {
 		if (sc->power_on)
 			iichid_teardown_callout(sc);
 		iichid_setup_interrupt(sc);
 	}
 
 	if (sc->power_on && value > 0)
 		iichid_reset_callout(sc);
 
 	iicbus_release_bus(parent, sc->dev);
 
 	DPRINTF(sc, "new sampling_rate value: %d\n", value);
 
 	return (0);
 }
 #endif /* IICHID_SAMPLING */
 
 static void
 iichid_intr_setup(device_t dev, hid_intr_t intr, void *context,
     struct hid_rdesc_info *rdesc)
 {
 	struct iichid_softc *sc;
 
 	sc = device_get_softc(dev);
 	/*
 	 * Do not rely on wMaxInputLength, as some devices may set it to
 	 * a wrong length. Find the longest input report in report descriptor.
 	 */
 	rdesc->rdsize = rdesc->isize;
 	/* Write and get/set_report sizes are limited by I2C-HID protocol. */
 	rdesc->grsize = rdesc->srsize = IICHID_SIZE_MAX;
 	rdesc->wrsize = IICHID_SIZE_MAX;
 
 	sc->intr_handler = intr;
 	sc->intr_ctx = context;
 	sc->intr_buf = malloc(rdesc->rdsize, M_DEVBUF, M_WAITOK | M_ZERO);
 	sc->intr_bufsize = rdesc->rdsize;
 #ifdef IICHID_SAMPLING
 	taskqueue_start_threads(&sc->taskqueue, 1, PI_TTY,
 	    "%s taskq", device_get_nameunit(sc->dev));
 #endif
 }
 
 static void
 iichid_intr_unsetup(device_t dev)
 {
 	struct iichid_softc *sc;
 
 	sc = device_get_softc(dev);
 #ifdef IICHID_SAMPLING
 	taskqueue_drain_all(sc->taskqueue);
 #endif
 	free(sc->intr_buf, M_DEVBUF);
 }
 
 static int
 iichid_intr_start(device_t dev)
 {
 	struct iichid_softc *sc;
 
 	sc = device_get_softc(dev);
 	DPRINTF(sc, "iichid device open\n");
 	iichid_set_power_state(sc, IICHID_PS_ON, IICHID_PS_NULL);
 
 	return (0);
 }
 
 static int
 iichid_intr_stop(device_t dev)
 {
 	struct iichid_softc *sc;
 
 	sc = device_get_softc(dev);
 	DPRINTF(sc, "iichid device close\n");
 	/*
 	 * 8.2 - The HOST determines that there are no active applications
 	 * that are currently using the specific HID DEVICE.  The HOST
 	 * is recommended to issue a HIPO command to the DEVICE to force
 	 * the DEVICE in to a lower power state.
 	 */
 	iichid_set_power_state(sc, IICHID_PS_OFF, IICHID_PS_NULL);
 
 	return (0);
 }
 
 static void
 iichid_intr_poll(device_t dev)
 {
 	struct iichid_softc *sc;
 	iichid_size_t actual;
 	int error;
 
 	sc = device_get_softc(dev);
 	error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual);
 	if (error == 0 && actual != 0)
 		sc->intr_handler(sc->intr_ctx, sc->intr_buf, actual);
 }
 
 /*
  * HID interface
  */
 static int
 iichid_get_rdesc(device_t dev, void *buf, hid_size_t len)
 {
 	struct iichid_softc *sc;
 	int error;
 
 	sc = device_get_softc(dev);
 	error = iichid_cmd_get_report_desc(sc, buf, len);
 	if (error)
 		DPRINTF(sc, "failed to fetch report descriptor: %d\n", error);
 
 	return (iic2errno(error));
 }
 
 static int
 iichid_read(device_t dev, void *buf, hid_size_t maxlen, hid_size_t *actlen)
 {
 	struct iichid_softc *sc;
 	device_t parent;
 	int error;
 
 	if (maxlen > IICHID_SIZE_MAX)
 		return (EMSGSIZE);
 	sc = device_get_softc(dev);
 	parent = device_get_parent(sc->dev);
 	error = iicbus_request_bus(parent, sc->dev, IIC_WAIT);
 	if (error == 0) {
 		error = iichid_cmd_read(sc, buf, maxlen, actlen);
 		iicbus_release_bus(parent, sc->dev);
 	}
 	return (iic2errno(error));
 }
 
 static int
 iichid_write(device_t dev, const void *buf, hid_size_t len)
 {
 	struct iichid_softc *sc;
 
 	if (len > IICHID_SIZE_MAX)
 		return (EMSGSIZE);
 	sc = device_get_softc(dev);
 	return (iic2errno(iichid_cmd_write(sc, buf, len)));
 }
 
 static int
 iichid_get_report(device_t dev, void *buf, hid_size_t maxlen,
     hid_size_t *actlen, uint8_t type, uint8_t id)
 {
 	struct iichid_softc *sc;
 
 	if (maxlen > IICHID_SIZE_MAX)
 		return (EMSGSIZE);
 	sc = device_get_softc(dev);
 	return (iic2errno(
 	    iichid_cmd_get_report(sc, buf, maxlen, actlen, type, id)));
 }
 
 static int
 iichid_set_report(device_t dev, const void *buf, hid_size_t len, uint8_t type,
     uint8_t id)
 {
 	struct iichid_softc *sc;
 
 	if (len > IICHID_SIZE_MAX)
 		return (EMSGSIZE);
 	sc = device_get_softc(dev);
 	return (iic2errno(iichid_cmd_set_report(sc, buf, len, type, id)));
 }
 
 static int
 iichid_set_idle(device_t dev, uint16_t duration, uint8_t id)
 {
 	return (ENOTSUP);
 }
 
 static int
 iichid_set_protocol(device_t dev, uint16_t protocol)
 {
 	return (ENOTSUP);
 }
 
 static int
 iichid_fill_device_info(struct i2c_hid_desc *desc, ACPI_HANDLE handle,
     struct hid_device_info *hw)
 {
 	ACPI_DEVICE_INFO *device_info;
 
 	hw->idBus = BUS_I2C;
 	hw->idVendor = le16toh(desc->wVendorID);
 	hw->idProduct = le16toh(desc->wProductID);
 	hw->idVersion = le16toh(desc->wVersionID);
 
 	/* get ACPI HID. It is a base part of the device name. */
 	if (ACPI_FAILURE(AcpiGetObjectInfo(handle, &device_info)))
 		return (ENXIO);
 
 	if (device_info->Valid & ACPI_VALID_HID)
 		strlcpy(hw->idPnP, device_info->HardwareId.String,
 		    HID_PNP_ID_SIZE);
 	snprintf(hw->name, sizeof(hw->name), "%s:%02lX %04X:%04X",
 	    (device_info->Valid & ACPI_VALID_HID) ?
 	    device_info->HardwareId.String : "Unknown",
 	    (device_info->Valid & ACPI_VALID_UID) ?
 	    strtoul(device_info->UniqueId.String, NULL, 10) : 0UL,
 	    le16toh(desc->wVendorID), le16toh(desc->wProductID));
 
 	AcpiOsFree(device_info);
 
 	strlcpy(hw->serial, "", sizeof(hw->serial));
 	hw->rdescsize = le16toh(desc->wReportDescLength);
 	if (desc->wOutputRegister == 0 || desc->wMaxOutputLength == 0)
 		hid_add_dynamic_quirk(hw, HQ_NOWRITE);
 
 	return (0);
 }
 
 static int
 iichid_probe(device_t dev)
 {
 	struct iichid_softc *sc;
 	ACPI_HANDLE handle;
 	char buf[80];
 	uint16_t config_reg;
 	int error;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
 	if (sc->probe_done)
 		goto done;
 
 	sc->probe_done = true;
 	sc->probe_result = ENXIO;
 
 	if (acpi_disabled("iichid"))
 		return (ENXIO);
 
 	sc->addr = iicbus_get_addr(dev) << 1;
 	if (sc->addr == 0)
 		return (ENXIO);
 
 	handle = acpi_get_handle(dev);
 	if (handle == NULL)
 		return (ENXIO);
 
 	if (!acpi_is_iichid(handle))
 		return (ENXIO);
 
 	if (ACPI_FAILURE(iichid_get_config_reg(handle, &config_reg)))
 		return (ENXIO);
 
 	DPRINTF(sc, "  IICbus addr       : 0x%02X\n", sc->addr >> 1);
 	DPRINTF(sc, "  HID descriptor reg: 0x%02X\n", config_reg);
 
 	error = iichid_cmd_get_hid_desc(sc, config_reg, &sc->desc);
 	if (error) {
 		DPRINTF(sc, "could not retrieve HID descriptor from the "
 		    "device: %d\n", error);
 		return (ENXIO);
 	}
 
 	if (le16toh(sc->desc.wHIDDescLength) != 30 ||
 	    le16toh(sc->desc.bcdVersion) != 0x100) {
 		DPRINTF(sc, "HID descriptor is broken\n");
 		return (ENXIO);
 	}
 
 	/* Setup hid_device_info so we can figure out quirks for the device. */
 	if (iichid_fill_device_info(&sc->desc, handle, &sc->hw) != 0) {
 		DPRINTF(sc, "error evaluating AcpiGetObjectInfo\n");
 		return (ENXIO);
 	}
 
 	if (hid_test_quirk(&sc->hw, HQ_HID_IGNORE))
 		return (ENXIO);
 
 	sc->probe_result = BUS_PROBE_DEFAULT;
 done:
 	if (sc->probe_result <= BUS_PROBE_SPECIFIC) {
 		snprintf(buf, sizeof(buf), "%s I2C HID device", sc->hw.name);
 		device_set_desc_copy(dev, buf);
 	}
 	return (sc->probe_result);
 }
 
 static int
 iichid_attach(device_t dev)
 {
 	struct iichid_softc *sc;
 	device_t child;
 	int error;
 
 	sc = device_get_softc(dev);
 	error = iichid_set_power(sc, I2C_HID_POWER_ON);
 	if (error) {
 		device_printf(dev, "failed to power on: %d\n", error);
 		return (ENXIO);
 	}
 	/*
 	 * Windows driver sleeps for 1ms between the SET_POWER and RESET
 	 * commands. So we too as some devices may depend on this.
 	 */
 	pause("iichid", (hz + 999) / 1000);
 
 	error = iichid_reset(sc);
 	if (error) {
 		device_printf(dev, "failed to reset hardware: %d\n", error);
 		return (ENXIO);
 	}
 
 	sc->power_on = false;
 #ifdef IICHID_SAMPLING
 	TASK_INIT(&sc->event_task, 0, iichid_event_task, sc);
 	/* taskqueue_create can't fail with M_WAITOK mflag passed. */
 	sc->taskqueue = taskqueue_create("hmt_tq", M_WAITOK | M_ZERO,
 	    taskqueue_thread_enqueue, &sc->taskqueue);
 	TIMEOUT_TASK_INIT(sc->taskqueue, &sc->periodic_task, 0,
 	    iichid_event_task, sc);
 
 	sc->sampling_rate_slow = -1;
 	sc->sampling_rate_fast = IICHID_SAMPLING_RATE_FAST;
 	sc->sampling_hysteresis = IICHID_SAMPLING_HYSTERESIS;
 #endif
 
 	sc->irq_rid = 0;
 	sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
 	    &sc->irq_rid, RF_ACTIVE);
 
 	if (sc->irq_res != NULL) {
 		DPRINTF(sc, "allocated irq at %p and rid %d\n",
 		    sc->irq_res, sc->irq_rid);
 		error = iichid_setup_interrupt(sc);
 	}
 
 	if (sc->irq_res == NULL || error != 0) {
 #ifdef IICHID_SAMPLING
 		device_printf(sc->dev,
 		    "Interrupt setup failed. Fallback to sampling\n");
 		sc->sampling_rate_slow = IICHID_SAMPLING_RATE_SLOW;
 #else
 		device_printf(sc->dev, "Interrupt setup failed\n");
 		if (sc->irq_res != NULL)
 			bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
 			    sc->irq_res);
 		error = ENXIO;
 		goto done;
 #endif
 	}
 
 #ifdef IICHID_SAMPLING
 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
 		SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
 		OID_AUTO, "sampling_rate_slow", CTLTYPE_INT | CTLFLAG_RWTUN,
 		sc, 0, iichid_sysctl_sampling_rate_handler, "I",
 		"idle sampling rate in num/second");
 	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev),
 		SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
-		OID_AUTO, "sampling_rate_fast", CTLTYPE_INT | CTLFLAG_RWTUN,
+		OID_AUTO, "sampling_rate_fast", CTLFLAG_RWTUN,
 		&sc->sampling_rate_fast, 0,
 		"active sampling rate in num/second");
 	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev),
 		SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
-		OID_AUTO, "sampling_hysteresis", CTLTYPE_INT | CTLFLAG_RWTUN,
+		OID_AUTO, "sampling_hysteresis", CTLFLAG_RWTUN,
 		&sc->sampling_hysteresis, 0,
 		"number of missing samples before enabling of slow mode");
 	hid_add_dynamic_quirk(&sc->hw, HQ_IICHID_SAMPLING);
 #endif /* IICHID_SAMPLING */
 
 	child = device_add_child(dev, "hidbus", -1);
 	if (child == NULL) {
 		device_printf(sc->dev, "Could not add I2C device\n");
 		iichid_detach(dev);
 		error = ENOMEM;
 		goto done;
 	}
 
 	device_set_ivars(child, &sc->hw);
 	error = bus_generic_attach(dev);
 	if (error) {
 		device_printf(dev, "failed to attach child: error %d\n", error);
 		iichid_detach(dev);
 	}
 done:
 	(void)iichid_set_power(sc, I2C_HID_POWER_OFF);
 	return (error);
 }
 
 static int
 iichid_detach(device_t dev)
 {
 	struct iichid_softc *sc;
 	int error;
 
 	sc = device_get_softc(dev);
 	error = device_delete_children(dev);
 	if (error)
 		return (error);
 	iichid_teardown_interrupt(sc);
 	if (sc->irq_res != NULL)
 		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
 		    sc->irq_res);
 #ifdef IICHID_SAMPLING
 	if (sc->taskqueue != NULL)
 		taskqueue_free(sc->taskqueue);
 	sc->taskqueue = NULL;
 #endif
 	return (0);
 }
 
 static int
 iichid_suspend(device_t dev)
 {
 	struct iichid_softc *sc;
 	int error;
 
 	sc = device_get_softc(dev);
 	DPRINTF(sc, "Suspend called, setting device to power_state 1\n");
 	(void)bus_generic_suspend(dev);
 	/*
 	 * 8.2 - The HOST is going into a deep power optimized state and wishes
 	 * to put all the devices into a low power state also.  The HOST
 	 * is recommended to issue a HIPO command to the DEVICE to force
 	 * the DEVICE in to a lower power state.
 	 */
 	error = iichid_set_power_state(sc, IICHID_PS_NULL, IICHID_PS_OFF);
 	if (error != 0)
 		DPRINTF(sc, "Could not set power_state, error: %d\n", error);
 	else
 		DPRINTF(sc, "Successfully set power_state\n");
 
         return (0);
 }
 
 static int
 iichid_resume(device_t dev)
 {
 	struct iichid_softc *sc;
 	int error;
 
 	sc = device_get_softc(dev);
 	DPRINTF(sc, "Resume called, setting device to power_state 0\n");
 	error = iichid_set_power_state(sc, IICHID_PS_NULL, IICHID_PS_ON);
 	if (error != 0)
 		DPRINTF(sc, "Could not set power_state, error: %d\n", error);
 	else
 		DPRINTF(sc, "Successfully set power_state\n");
 	(void)bus_generic_resume(dev);
 
 	return (0);
 }
 
 static devclass_t iichid_devclass;
 
 static device_method_t iichid_methods[] = {
 	DEVMETHOD(device_probe,		iichid_probe),
 	DEVMETHOD(device_attach,	iichid_attach),
 	DEVMETHOD(device_detach,	iichid_detach),
 	DEVMETHOD(device_suspend,	iichid_suspend),
 	DEVMETHOD(device_resume,	iichid_resume),
 
 	DEVMETHOD(hid_intr_setup,	iichid_intr_setup),
 	DEVMETHOD(hid_intr_unsetup,	iichid_intr_unsetup),
 	DEVMETHOD(hid_intr_start,	iichid_intr_start),
 	DEVMETHOD(hid_intr_stop,	iichid_intr_stop),
 	DEVMETHOD(hid_intr_poll,	iichid_intr_poll),
 
 	/* HID interface */
 	DEVMETHOD(hid_get_rdesc,	iichid_get_rdesc),
 	DEVMETHOD(hid_read,		iichid_read),
 	DEVMETHOD(hid_write,		iichid_write),
 	DEVMETHOD(hid_get_report,	iichid_get_report),
 	DEVMETHOD(hid_set_report,	iichid_set_report),
 	DEVMETHOD(hid_set_idle,		iichid_set_idle),
 	DEVMETHOD(hid_set_protocol,	iichid_set_protocol),
 
 	DEVMETHOD_END
 };
 
 static driver_t iichid_driver = {
 	.name = "iichid",
 	.methods = iichid_methods,
 	.size = sizeof(struct iichid_softc),
 };
 
 DRIVER_MODULE(iichid, iicbus, iichid_driver, iichid_devclass, NULL, 0);
 MODULE_DEPEND(iichid, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
 MODULE_DEPEND(iichid, acpi, 1, 1, 1);
 MODULE_DEPEND(iichid, hid, 1, 1, 1);
 MODULE_DEPEND(iichid, hidbus, 1, 1, 1);
 MODULE_VERSION(iichid, 1);
 IICBUS_ACPI_PNP_INFO(iichid_ids);