167217Sn_hibma/*	$NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $	*/
261560Sn_hibma
361560Sn_hibma/*
461560Sn_hibma * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
561560Sn_hibma * All rights reserved.
661560Sn_hibma *
761560Sn_hibma * Redistribution and use in source and binary forms, with or without
861560Sn_hibma * modification, are permitted provided that the following conditions
961560Sn_hibma * are met:
1061560Sn_hibma * 1. Redistributions of source code must retain the above copyright
1161560Sn_hibma *    notice, this list of conditions and the following disclaimer.
1261560Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright
1361560Sn_hibma *    notice, this list of conditions and the following disclaimer in the
1461560Sn_hibma *    documentation and/or other materials provided with the distribution.
1561560Sn_hibma *
1661560Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1761560Sn_hibma * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1861560Sn_hibma * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1961560Sn_hibma * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2061560Sn_hibma * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2161560Sn_hibma * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2261560Sn_hibma * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2361560Sn_hibma * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2461560Sn_hibma * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2561560Sn_hibma * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2661560Sn_hibma * SUCH DAMAGE.
2761560Sn_hibma */
2861560Sn_hibma
2984224Sdillon#include <sys/cdefs.h>
3084224Sdillon__FBSDID("$FreeBSD$");
3184224Sdillon
3261560Sn_hibma#include <sys/types.h>
3361560Sn_hibma
3461560Sn_hibma#include <assert.h>
3561560Sn_hibma#include <errno.h>
3661560Sn_hibma#include <stdlib.h>
3761560Sn_hibma#include <string.h>
3861560Sn_hibma#include <unistd.h>
3961560Sn_hibma#include <sys/time.h>
4061560Sn_hibma#include <sys/ioctl.h>
41188945Sthompsa#include <dev/usb/usb_ioctl.h>
4261560Sn_hibma
43113273Smdodd#include "usbhid.h"
4461560Sn_hibma#include "usbvar.h"
4561560Sn_hibma
46187994Salfredint
47187994Salfredhid_set_immed(int fd, int enable)
48187994Salfred{
49187994Salfred	int ret;
50187994Salfred	ret = ioctl(fd, USB_SET_IMMED, &enable);
51188945Sthompsa#ifdef HID_COMPAT7
52187994Salfred	if (ret < 0)
53187994Salfred		ret = hid_set_immed_compat7(fd, enable);
54188945Sthompsa#endif
55187994Salfred	return (ret);
56187994Salfred}
57187994Salfred
58187994Salfredint
59187994Salfredhid_get_report_id(int fd)
60187994Salfred{
61205728Skaiw	report_desc_t rep;
62205728Skaiw	hid_data_t d;
63205728Skaiw	hid_item_t h;
64205728Skaiw	int kindset;
65187994Salfred	int temp = -1;
66187994Salfred	int ret;
67187994Salfred
68205728Skaiw	if ((rep = hid_get_report_desc(fd)) == NULL)
69205728Skaiw		goto use_ioctl;
70205728Skaiw	kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature;
71240762Smav	for (d = hid_start_parse(rep, kindset, -1); hid_get_item(d, &h); ) {
72205728Skaiw		/* Return the first report ID we met. */
73205728Skaiw		if (h.report_ID != 0) {
74205728Skaiw			temp = h.report_ID;
75205728Skaiw			break;
76205728Skaiw		}
77205728Skaiw	}
78205728Skaiw	hid_end_parse(d);
79205728Skaiw	hid_dispose_report_desc(rep);
80205728Skaiw
81205728Skaiw	if (temp > 0)
82205728Skaiw		return (temp);
83205728Skaiw
84205728Skaiwuse_ioctl:
85187994Salfred	ret = ioctl(fd, USB_GET_REPORT_ID, &temp);
86188945Sthompsa#ifdef HID_COMPAT7
87187994Salfred	if (ret < 0)
88187994Salfred		ret = hid_get_report_id_compat7(fd);
89187994Salfred	else
90188945Sthompsa#endif
91187994Salfred		ret = temp;
92187994Salfred
93187994Salfred	return (ret);
94187994Salfred}
95187994Salfred
9661560Sn_hibmareport_desc_t
9767217Sn_hibmahid_get_report_desc(int fd)
9861560Sn_hibma{
99192992Sthompsa	struct usb_gen_descriptor ugd;
100187994Salfred	report_desc_t rep;
101187994Salfred	void *data;
10261560Sn_hibma
103187994Salfred	memset(&ugd, 0, sizeof(ugd));
104187994Salfred
105187994Salfred	/* get actual length first */
106213920Shselasky	ugd.ugd_data = hid_pass_ptr(NULL);
107187994Salfred	ugd.ugd_maxlen = 65535;
108189108Sthompsa	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
109188945Sthompsa#ifdef HID_COMPAT7
110187994Salfred		/* could not read descriptor */
111187994Salfred		/* try FreeBSD 7 compat code */
112187994Salfred		return (hid_get_report_desc_compat7(fd));
113189108Sthompsa#else
114189108Sthompsa		return (NULL);
115189108Sthompsa#endif
116187994Salfred	}
117187994Salfred
118187994Salfred	/*
119187994Salfred	 * NOTE: The kernel will return a failure if
120187994Salfred	 * "ugd_actlen" is zero.
121187994Salfred	 */
122187994Salfred	data = malloc(ugd.ugd_actlen);
123187994Salfred	if (data == NULL)
12467217Sn_hibma		return (NULL);
12567217Sn_hibma
126187994Salfred	/* fetch actual descriptor */
127213920Shselasky	ugd.ugd_data = hid_pass_ptr(data);
128187994Salfred	ugd.ugd_maxlen = ugd.ugd_actlen;
129187994Salfred	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
130187994Salfred		/* could not read descriptor */
131187994Salfred		free(data);
132187994Salfred		return (NULL);
133187994Salfred	}
134187994Salfred
135213920Shselasky	/* sanity check */
136213920Shselasky	if (ugd.ugd_actlen < 1) {
137213920Shselasky		/* invalid report descriptor */
138213920Shselasky		free(data);
139213920Shselasky		return (NULL);
140213920Shselasky	}
141213920Shselasky
142187994Salfred	/* check END_COLLECTION */
143213920Shselasky	if (((unsigned char *)data)[ugd.ugd_actlen -1] != 0xC0) {
144187994Salfred		/* invalid end byte */
145187994Salfred		free(data);
146187994Salfred		return (NULL);
147187994Salfred	}
148187994Salfred
149187994Salfred	rep = hid_use_report_desc(data, ugd.ugd_actlen);
150187994Salfred
151187994Salfred	free(data);
152187994Salfred
153187994Salfred	return (rep);
15467217Sn_hibma}
15567217Sn_hibma
15667217Sn_hibmareport_desc_t
15767217Sn_hibmahid_use_report_desc(unsigned char *data, unsigned int size)
15867217Sn_hibma{
15967217Sn_hibma	report_desc_t r;
16067217Sn_hibma
16167217Sn_hibma	r = malloc(sizeof(*r) + size);
16261560Sn_hibma	if (r == 0) {
16361560Sn_hibma		errno = ENOMEM;
16467217Sn_hibma		return (NULL);
16561560Sn_hibma	}
16667217Sn_hibma	r->size = size;
16767217Sn_hibma	memcpy(r->data, data, size);
16861560Sn_hibma	return (r);
16961560Sn_hibma}
17061560Sn_hibma
17161560Sn_hibmavoid
17267217Sn_hibmahid_dispose_report_desc(report_desc_t r)
17361560Sn_hibma{
17461560Sn_hibma
17561560Sn_hibma	free(r);
17661560Sn_hibma}
177