1/*	$NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/types.h>
32
33#include <assert.h>
34#include <errno.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <sys/time.h>
39#include <sys/ioctl.h>
40#include <dev/usb/usb_ioctl.h>
41
42#include "usbhid.h"
43#include "usbvar.h"
44
45int
46hid_set_immed(int fd, int enable)
47{
48	int ret;
49	ret = ioctl(fd, USB_SET_IMMED, &enable);
50#ifdef HID_COMPAT7
51	if (ret < 0)
52		ret = hid_set_immed_compat7(fd, enable);
53#endif
54	return (ret);
55}
56
57int
58hid_get_report_id(int fd)
59{
60	report_desc_t rep;
61	hid_data_t d;
62	hid_item_t h;
63	int kindset;
64	int temp = -1;
65	int ret;
66
67	if ((rep = hid_get_report_desc(fd)) == NULL)
68		goto use_ioctl;
69	kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature;
70	for (d = hid_start_parse(rep, kindset, -1); hid_get_item(d, &h); ) {
71		/* Return the first report ID we met. */
72		if (h.report_ID != 0) {
73			temp = h.report_ID;
74			break;
75		}
76	}
77	hid_end_parse(d);
78	hid_dispose_report_desc(rep);
79
80	if (temp > 0)
81		return (temp);
82
83use_ioctl:
84	ret = ioctl(fd, USB_GET_REPORT_ID, &temp);
85#ifdef HID_COMPAT7
86	if (ret < 0)
87		ret = hid_get_report_id_compat7(fd);
88	else
89#endif
90		ret = temp;
91
92	return (ret);
93}
94
95report_desc_t
96hid_get_report_desc(int fd)
97{
98	struct usb_gen_descriptor ugd;
99	report_desc_t rep;
100	void *data;
101
102	memset(&ugd, 0, sizeof(ugd));
103
104	/* get actual length first */
105	ugd.ugd_data = NULL;
106	ugd.ugd_maxlen = 65535;
107	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
108#ifdef HID_COMPAT7
109		/* could not read descriptor */
110		/* try FreeBSD 7 compat code */
111		return (hid_get_report_desc_compat7(fd));
112#else
113		return (NULL);
114#endif
115	}
116
117	/*
118	 * NOTE: The kernel will return a failure if
119	 * "ugd_actlen" is zero.
120	 */
121	data = malloc(ugd.ugd_actlen);
122	if (data == NULL)
123		return (NULL);
124
125	/* fetch actual descriptor */
126	ugd.ugd_data = data;
127	ugd.ugd_maxlen = ugd.ugd_actlen;
128	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
129		/* could not read descriptor */
130		free(data);
131		return (NULL);
132	}
133
134	/* sanity check */
135	if (ugd.ugd_actlen < 1) {
136		/* invalid report descriptor */
137		free(data);
138		return (NULL);
139	}
140
141	/* check END_COLLECTION */
142	if (((unsigned char *)data)[ugd.ugd_actlen -1] != 0xC0) {
143		/* invalid end byte */
144		free(data);
145		return (NULL);
146	}
147
148	rep = hid_use_report_desc(data, ugd.ugd_actlen);
149
150	free(data);
151
152	return (rep);
153}
154
155report_desc_t
156hid_use_report_desc(unsigned char *data, unsigned int size)
157{
158	report_desc_t r;
159
160	r = malloc(sizeof(*r) + size);
161	if (r == NULL) {
162		errno = ENOMEM;
163		return (NULL);
164	}
165	r->size = size;
166	memcpy(r->data, data, size);
167	return (r);
168}
169
170void
171hid_dispose_report_desc(report_desc_t r)
172{
173
174	free(r);
175}
176