102ac6454SAndrew Thompson /* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */
202ac6454SAndrew Thompson /*-
3*b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
4718cf2ccSPedro F. Giffuni *
502ac6454SAndrew Thompson * Copyright (c) 1998 The NetBSD Foundation, Inc.
602ac6454SAndrew Thompson * All rights reserved.
702ac6454SAndrew Thompson *
802ac6454SAndrew Thompson * This code is derived from software contributed to The NetBSD Foundation
902ac6454SAndrew Thompson * by Lennart Augustsson (lennart@augustsson.net) at
1002ac6454SAndrew Thompson * Carlstedt Research & Technology.
1102ac6454SAndrew Thompson *
1202ac6454SAndrew Thompson * Redistribution and use in source and binary forms, with or without
1302ac6454SAndrew Thompson * modification, are permitted provided that the following conditions
1402ac6454SAndrew Thompson * are met:
1502ac6454SAndrew Thompson * 1. Redistributions of source code must retain the above copyright
1602ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer.
1702ac6454SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright
1802ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer in the
1902ac6454SAndrew Thompson * documentation and/or other materials provided with the distribution.
2002ac6454SAndrew Thompson *
2102ac6454SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2202ac6454SAndrew Thompson * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2302ac6454SAndrew Thompson * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2402ac6454SAndrew Thompson * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2502ac6454SAndrew Thompson * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2602ac6454SAndrew Thompson * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2702ac6454SAndrew Thompson * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2802ac6454SAndrew Thompson * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2902ac6454SAndrew Thompson * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3002ac6454SAndrew Thompson * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3102ac6454SAndrew Thompson * POSSIBILITY OF SUCH DAMAGE.
3202ac6454SAndrew Thompson */
3302ac6454SAndrew Thompson
34d2b99310SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE
35d2b99310SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE
36d2b99310SHans Petter Selasky #else
37ed6d949aSAndrew Thompson #include <sys/stdint.h>
38ed6d949aSAndrew Thompson #include <sys/stddef.h>
39ed6d949aSAndrew Thompson #include <sys/param.h>
40ed6d949aSAndrew Thompson #include <sys/queue.h>
41ed6d949aSAndrew Thompson #include <sys/types.h>
42ed6d949aSAndrew Thompson #include <sys/systm.h>
43ed6d949aSAndrew Thompson #include <sys/kernel.h>
44ed6d949aSAndrew Thompson #include <sys/bus.h>
45ed6d949aSAndrew Thompson #include <sys/module.h>
46ed6d949aSAndrew Thompson #include <sys/lock.h>
47ed6d949aSAndrew Thompson #include <sys/mutex.h>
48ed6d949aSAndrew Thompson #include <sys/condvar.h>
49ed6d949aSAndrew Thompson #include <sys/sysctl.h>
50ed6d949aSAndrew Thompson #include <sys/sx.h>
51ed6d949aSAndrew Thompson #include <sys/unistd.h>
52ed6d949aSAndrew Thompson #include <sys/callout.h>
53ed6d949aSAndrew Thompson #include <sys/malloc.h>
54ed6d949aSAndrew Thompson #include <sys/priv.h>
55ed6d949aSAndrew Thompson
5602ac6454SAndrew Thompson #include <dev/usb/usb.h>
57ed6d949aSAndrew Thompson #include <dev/usb/usbdi.h>
58ed6d949aSAndrew Thompson #include <dev/usb/usbdi_util.h>
5902ac6454SAndrew Thompson #include <dev/usb/usbhid.h>
6002ac6454SAndrew Thompson
61a593f6b8SAndrew Thompson #define USB_DEBUG_VAR usb_debug
6202ac6454SAndrew Thompson
6302ac6454SAndrew Thompson #include <dev/usb/usb_core.h>
6402ac6454SAndrew Thompson #include <dev/usb/usb_debug.h>
6502ac6454SAndrew Thompson #include <dev/usb/usb_process.h>
6602ac6454SAndrew Thompson #include <dev/usb/usb_device.h>
6702ac6454SAndrew Thompson #include <dev/usb/usb_request.h>
68d2b99310SHans Petter Selasky #endif /* USB_GLOBAL_INCLUDE_FILE */
6902ac6454SAndrew Thompson
7002ac6454SAndrew Thompson /*------------------------------------------------------------------------*
7102ac6454SAndrew Thompson * hid_get_descriptor_from_usb
7202ac6454SAndrew Thompson *
7302ac6454SAndrew Thompson * This function will search for a HID descriptor between two USB
7402ac6454SAndrew Thompson * interface descriptors.
7502ac6454SAndrew Thompson *
7602ac6454SAndrew Thompson * Return values:
7702ac6454SAndrew Thompson * NULL: No more HID descriptors.
7802ac6454SAndrew Thompson * Else: Pointer to HID descriptor.
7902ac6454SAndrew Thompson *------------------------------------------------------------------------*/
80760bc48eSAndrew Thompson struct usb_hid_descriptor *
hid_get_descriptor_from_usb(struct usb_config_descriptor * cd,struct usb_interface_descriptor * id)81760bc48eSAndrew Thompson hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
82760bc48eSAndrew Thompson struct usb_interface_descriptor *id)
8302ac6454SAndrew Thompson {
84760bc48eSAndrew Thompson struct usb_descriptor *desc = (void *)id;
8502ac6454SAndrew Thompson
8602ac6454SAndrew Thompson if (desc == NULL) {
8702ac6454SAndrew Thompson return (NULL);
8802ac6454SAndrew Thompson }
89a593f6b8SAndrew Thompson while ((desc = usb_desc_foreach(cd, desc))) {
9002ac6454SAndrew Thompson if ((desc->bDescriptorType == UDESC_HID) &&
9102ac6454SAndrew Thompson (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
9202ac6454SAndrew Thompson return (void *)desc;
9302ac6454SAndrew Thompson }
9402ac6454SAndrew Thompson if (desc->bDescriptorType == UDESC_INTERFACE) {
9502ac6454SAndrew Thompson break;
9602ac6454SAndrew Thompson }
9702ac6454SAndrew Thompson }
9802ac6454SAndrew Thompson return (NULL);
9902ac6454SAndrew Thompson }
10002ac6454SAndrew Thompson
10102ac6454SAndrew Thompson /*------------------------------------------------------------------------*
102a593f6b8SAndrew Thompson * usbd_req_get_hid_desc
10302ac6454SAndrew Thompson *
10402ac6454SAndrew Thompson * This function will read out an USB report descriptor from the USB
10502ac6454SAndrew Thompson * device.
10602ac6454SAndrew Thompson *
10702ac6454SAndrew Thompson * Return values:
10802ac6454SAndrew Thompson * NULL: Failure.
10902ac6454SAndrew Thompson * Else: Success. The pointer should eventually be passed to free().
11002ac6454SAndrew Thompson *------------------------------------------------------------------------*/
111e0a69b51SAndrew Thompson usb_error_t
usbd_req_get_hid_desc(struct usb_device * udev,struct mtx * mtx,void ** descp,uint16_t * sizep,struct malloc_type * mem,uint8_t iface_index)112a593f6b8SAndrew Thompson usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
11302ac6454SAndrew Thompson void **descp, uint16_t *sizep,
114e0a69b51SAndrew Thompson struct malloc_type *mem, uint8_t iface_index)
11502ac6454SAndrew Thompson {
116a593f6b8SAndrew Thompson struct usb_interface *iface = usbd_get_iface(udev, iface_index);
117760bc48eSAndrew Thompson struct usb_hid_descriptor *hid;
118e0a69b51SAndrew Thompson usb_error_t err;
11902ac6454SAndrew Thompson
12002ac6454SAndrew Thompson if ((iface == NULL) || (iface->idesc == NULL)) {
12102ac6454SAndrew Thompson return (USB_ERR_INVAL);
12202ac6454SAndrew Thompson }
12302ac6454SAndrew Thompson hid = hid_get_descriptor_from_usb
124a593f6b8SAndrew Thompson (usbd_get_config_descriptor(udev), iface->idesc);
12502ac6454SAndrew Thompson
12602ac6454SAndrew Thompson if (hid == NULL) {
12702ac6454SAndrew Thompson return (USB_ERR_IOERROR);
12802ac6454SAndrew Thompson }
12902ac6454SAndrew Thompson *sizep = UGETW(hid->descrs[0].wDescriptorLength);
13002ac6454SAndrew Thompson if (*sizep == 0) {
13102ac6454SAndrew Thompson return (USB_ERR_IOERROR);
13202ac6454SAndrew Thompson }
13302ac6454SAndrew Thompson if (mtx)
13402ac6454SAndrew Thompson mtx_unlock(mtx);
13502ac6454SAndrew Thompson
13602ac6454SAndrew Thompson *descp = malloc(*sizep, mem, M_ZERO | M_WAITOK);
13702ac6454SAndrew Thompson
13802ac6454SAndrew Thompson if (mtx)
13902ac6454SAndrew Thompson mtx_lock(mtx);
14002ac6454SAndrew Thompson
14102ac6454SAndrew Thompson if (*descp == NULL) {
14202ac6454SAndrew Thompson return (USB_ERR_NOMEM);
14302ac6454SAndrew Thompson }
144a593f6b8SAndrew Thompson err = usbd_req_get_report_descriptor
14502ac6454SAndrew Thompson (udev, mtx, *descp, *sizep, iface_index);
14602ac6454SAndrew Thompson
14702ac6454SAndrew Thompson if (err) {
14802ac6454SAndrew Thompson free(*descp, mem);
14902ac6454SAndrew Thompson *descp = NULL;
15002ac6454SAndrew Thompson return (err);
15102ac6454SAndrew Thompson }
15202ac6454SAndrew Thompson return (USB_ERR_NORMAL_COMPLETION);
15302ac6454SAndrew Thompson }
154