xref: /dflybsd-src/lib/libu4bhid/descr.c (revision adf9e9ed6c92cbcbe269f6a766aabbccdf827672)
112bd3c8bSSascha Wildner /*	$NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $	*/
212bd3c8bSSascha Wildner 
312bd3c8bSSascha Wildner /*
412bd3c8bSSascha Wildner  * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
512bd3c8bSSascha Wildner  * All rights reserved.
612bd3c8bSSascha Wildner  *
712bd3c8bSSascha Wildner  * Redistribution and use in source and binary forms, with or without
812bd3c8bSSascha Wildner  * modification, are permitted provided that the following conditions
912bd3c8bSSascha Wildner  * are met:
1012bd3c8bSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
1112bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1212bd3c8bSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1312bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
1412bd3c8bSSascha Wildner  *    documentation and/or other materials provided with the distribution.
1512bd3c8bSSascha Wildner  *
1612bd3c8bSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1712bd3c8bSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1812bd3c8bSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1912bd3c8bSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2012bd3c8bSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2112bd3c8bSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2212bd3c8bSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2312bd3c8bSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2412bd3c8bSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2512bd3c8bSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2612bd3c8bSSascha Wildner  * SUCH DAMAGE.
27ee284e10SSascha Wildner  *
28ee284e10SSascha Wildner  * $FreeBSD: head/lib/libusbhid/descr.c 240762 2012-09-20 18:56:27Z mav $
2912bd3c8bSSascha Wildner  */
3012bd3c8bSSascha Wildner 
3112bd3c8bSSascha Wildner #include <sys/types.h>
3212bd3c8bSSascha Wildner 
3312bd3c8bSSascha Wildner #include <assert.h>
3412bd3c8bSSascha Wildner #include <errno.h>
3512bd3c8bSSascha Wildner #include <stdlib.h>
3612bd3c8bSSascha Wildner #include <string.h>
3712bd3c8bSSascha Wildner #include <unistd.h>
3812bd3c8bSSascha Wildner #include <sys/time.h>
3912bd3c8bSSascha Wildner #include <sys/ioctl.h>
403186c89eSSascha Wildner #include <bus/u4b/usb_ioctl.h>
4112bd3c8bSSascha Wildner 
4212bd3c8bSSascha Wildner #include "usbhid.h"
4312bd3c8bSSascha Wildner #include "usbvar.h"
4412bd3c8bSSascha Wildner 
4512bd3c8bSSascha Wildner int
hid_set_immed(int fd,int enable)4612bd3c8bSSascha Wildner hid_set_immed(int fd, int enable)
4712bd3c8bSSascha Wildner {
4812bd3c8bSSascha Wildner 	int ret;
4912bd3c8bSSascha Wildner 	ret = ioctl(fd, USB_SET_IMMED, &enable);
5012bd3c8bSSascha Wildner 	return (ret);
5112bd3c8bSSascha Wildner }
5212bd3c8bSSascha Wildner 
5312bd3c8bSSascha Wildner int
hid_get_report_id(int fd)5412bd3c8bSSascha Wildner hid_get_report_id(int fd)
5512bd3c8bSSascha Wildner {
5612bd3c8bSSascha Wildner 	report_desc_t rep;
5712bd3c8bSSascha Wildner 	hid_data_t d;
5812bd3c8bSSascha Wildner 	hid_item_t h;
5912bd3c8bSSascha Wildner 	int kindset;
6012bd3c8bSSascha Wildner 	int temp = -1;
6112bd3c8bSSascha Wildner 	int ret;
6212bd3c8bSSascha Wildner 
6312bd3c8bSSascha Wildner 	if ((rep = hid_get_report_desc(fd)) == NULL)
6412bd3c8bSSascha Wildner 		goto use_ioctl;
6512bd3c8bSSascha Wildner 	kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature;
66ee284e10SSascha Wildner 	for (d = hid_start_parse(rep, kindset, -1); hid_get_item(d, &h); ) {
6712bd3c8bSSascha Wildner 		/* Return the first report ID we met. */
6812bd3c8bSSascha Wildner 		if (h.report_ID != 0) {
6912bd3c8bSSascha Wildner 			temp = h.report_ID;
7012bd3c8bSSascha Wildner 			break;
7112bd3c8bSSascha Wildner 		}
7212bd3c8bSSascha Wildner 	}
7312bd3c8bSSascha Wildner 	hid_end_parse(d);
7412bd3c8bSSascha Wildner 	hid_dispose_report_desc(rep);
7512bd3c8bSSascha Wildner 
7612bd3c8bSSascha Wildner 	if (temp > 0)
7712bd3c8bSSascha Wildner 		return (temp);
7812bd3c8bSSascha Wildner 
7912bd3c8bSSascha Wildner use_ioctl:
8012bd3c8bSSascha Wildner 	ret = ioctl(fd, USB_GET_REPORT_ID, &temp);
8112bd3c8bSSascha Wildner 	ret = temp;
8212bd3c8bSSascha Wildner 
8312bd3c8bSSascha Wildner 	return (ret);
8412bd3c8bSSascha Wildner }
8512bd3c8bSSascha Wildner 
8612bd3c8bSSascha Wildner report_desc_t
hid_get_report_desc(int fd)8712bd3c8bSSascha Wildner hid_get_report_desc(int fd)
8812bd3c8bSSascha Wildner {
8912bd3c8bSSascha Wildner 	struct usb_gen_descriptor ugd;
9012bd3c8bSSascha Wildner 	report_desc_t rep;
9112bd3c8bSSascha Wildner 	void *data;
9212bd3c8bSSascha Wildner 
9312bd3c8bSSascha Wildner 	memset(&ugd, 0, sizeof(ugd));
9412bd3c8bSSascha Wildner 
9512bd3c8bSSascha Wildner 	/* get actual length first */
9612bd3c8bSSascha Wildner 	ugd.ugd_data = hid_pass_ptr(NULL);
9712bd3c8bSSascha Wildner 	ugd.ugd_maxlen = 65535;
98*adf9e9edSSascha Wildner 	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0)
9912bd3c8bSSascha Wildner 		return (NULL);
10012bd3c8bSSascha Wildner 
10112bd3c8bSSascha Wildner 	/*
10212bd3c8bSSascha Wildner 	 * NOTE: The kernel will return a failure if
10312bd3c8bSSascha Wildner 	 * "ugd_actlen" is zero.
10412bd3c8bSSascha Wildner 	 */
10512bd3c8bSSascha Wildner 	data = malloc(ugd.ugd_actlen);
10612bd3c8bSSascha Wildner 	if (data == NULL)
10712bd3c8bSSascha Wildner 		return (NULL);
10812bd3c8bSSascha Wildner 
10912bd3c8bSSascha Wildner 	/* fetch actual descriptor */
11012bd3c8bSSascha Wildner 	ugd.ugd_data = hid_pass_ptr(data);
11112bd3c8bSSascha Wildner 	ugd.ugd_maxlen = ugd.ugd_actlen;
11212bd3c8bSSascha Wildner 	if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
11312bd3c8bSSascha Wildner 		/* could not read descriptor */
11412bd3c8bSSascha Wildner 		free(data);
11512bd3c8bSSascha Wildner 		return (NULL);
11612bd3c8bSSascha Wildner 	}
11712bd3c8bSSascha Wildner 
11812bd3c8bSSascha Wildner 	/* sanity check */
11912bd3c8bSSascha Wildner 	if (ugd.ugd_actlen < 1) {
12012bd3c8bSSascha Wildner 		/* invalid report descriptor */
12112bd3c8bSSascha Wildner 		free(data);
12212bd3c8bSSascha Wildner 		return (NULL);
12312bd3c8bSSascha Wildner 	}
12412bd3c8bSSascha Wildner 
12512bd3c8bSSascha Wildner 	/* check END_COLLECTION */
12612bd3c8bSSascha Wildner 	if (((unsigned char *)data)[ugd.ugd_actlen -1] != 0xC0) {
12712bd3c8bSSascha Wildner 		/* invalid end byte */
12812bd3c8bSSascha Wildner 		free(data);
12912bd3c8bSSascha Wildner 		return (NULL);
13012bd3c8bSSascha Wildner 	}
13112bd3c8bSSascha Wildner 
13212bd3c8bSSascha Wildner 	rep = hid_use_report_desc(data, ugd.ugd_actlen);
13312bd3c8bSSascha Wildner 
13412bd3c8bSSascha Wildner 	free(data);
13512bd3c8bSSascha Wildner 
13612bd3c8bSSascha Wildner 	return (rep);
13712bd3c8bSSascha Wildner }
13812bd3c8bSSascha Wildner 
13912bd3c8bSSascha Wildner report_desc_t
hid_use_report_desc(unsigned char * data,unsigned int size)14012bd3c8bSSascha Wildner hid_use_report_desc(unsigned char *data, unsigned int size)
14112bd3c8bSSascha Wildner {
14212bd3c8bSSascha Wildner 	report_desc_t r;
14312bd3c8bSSascha Wildner 
14412bd3c8bSSascha Wildner 	r = malloc(sizeof(*r) + size);
14512bd3c8bSSascha Wildner 	if (r == 0) {
14612bd3c8bSSascha Wildner 		errno = ENOMEM;
14712bd3c8bSSascha Wildner 		return (NULL);
14812bd3c8bSSascha Wildner 	}
14912bd3c8bSSascha Wildner 	r->size = size;
15012bd3c8bSSascha Wildner 	memcpy(r->data, data, size);
15112bd3c8bSSascha Wildner 	return (r);
15212bd3c8bSSascha Wildner }
15312bd3c8bSSascha Wildner 
15412bd3c8bSSascha Wildner void
hid_dispose_report_desc(report_desc_t r)15512bd3c8bSSascha Wildner hid_dispose_report_desc(report_desc_t r)
15612bd3c8bSSascha Wildner {
15712bd3c8bSSascha Wildner 
15812bd3c8bSSascha Wildner 	free(r);
15912bd3c8bSSascha Wildner }
160