• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $	*/
2 
3 /* Also already merged from NetBSD:
4  *	$NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $
5  */
6 
7 #include <sys/cdefs.h>
8 __FBSDID("$FreeBSD$");
9 
10 /*-
11  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
12  *
13  * Copyright (c) 1998 The NetBSD Foundation, Inc.
14  * All rights reserved.
15  *
16  * This code is derived from software contributed to The NetBSD Foundation
17  * by Lennart Augustsson (lennart@augustsson.net) at
18  * Carlstedt Research & Technology.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  */
41 
42 /*
43  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
44  */
45 
46 #include "implementation/global_implementation.h"
47 #include "input/usb_rdesc.h"
48 #include "implementation/usbdevs.h"
49 #include "event_hub.h"
50 #include <dev/usb/usb_generic.h>
51 
52 #undef USB_DEBUG_VAR
53 #define	USB_DEBUG_VAR uhid_debug
54 
55 #ifdef LOSCFG_USB_DEBUG
56 static int uhid_debug = 0;
57 #endif
58 
59 #define	UHID_BSIZE	1024		/* bytes, buffer size */
60 #define	UHID_FRAME_NUM 	  50		/* bytes, frame number */
61 
62 #define MOUSE_DATA_LEN 4
63 #define BTN_LEFT_VALUE(v) ((v) & 0x01)
64 #define BTN_RIGHT_VALUE(v) (((v) & 0x02)>>1)
65 #define BTN_MIDDLE_VALUE(v) (((v) & 0x04)>>2)
66 
67 enum {
68 	UHID_INTR_DT_WR,
69 	UHID_INTR_DT_RD,
70 	UHID_CTRL_DT_WR,
71 	UHID_CTRL_DT_RD,
72 	UHID_N_TRANSFER,
73 };
74 
75 struct uhid_softc {
76 	struct usb_fifo_sc sc_fifo;
77 	struct mtx sc_mtx;
78 
79 	struct usb_xfer *sc_xfer[UHID_N_TRANSFER];
80 	struct usb_device *sc_udev;
81 	void   *sc_repdesc_ptr;
82 
83 	uint32_t sc_isize;
84 	uint32_t sc_osize;
85 	uint32_t sc_fsize;
86 
87 	InputDevice *input_dev;
88 
89 	uint16_t sc_repdesc_size;
90 
91 	uint8_t	sc_iface_no;
92 	uint8_t	sc_iface_index;
93 	uint8_t	sc_iid;
94 	uint8_t	sc_oid;
95 	uint8_t	sc_fid;
96 	uint8_t	sc_flags;
97 #define	UHID_FLAG_IMMED        0x01	/* set if read should be immediate */
98 #define	UHID_FLAG_STATIC_DESC  0x04	/* set if report descriptors are
99 					 * static */
100 };
101 
102 static const uint8_t uhid_xb360gp_report_descr[] = {UHID_XB360GP_REPORT_DESCR()};
103 static const uint8_t uhid_graphire_report_descr[] = {UHID_GRAPHIRE_REPORT_DESCR()};
104 static const uint8_t uhid_graphire3_4x5_report_descr[] = {UHID_GRAPHIRE3_4X5_REPORT_DESCR()};
105 
106 /* prototypes */
107 
108 static device_probe_t uhid_probe;
109 static device_attach_t uhid_attach;
110 static device_detach_t uhid_detach;
111 
112 static usb_callback_t uhid_intr_write_callback;
113 static usb_callback_t uhid_intr_read_callback;
114 static usb_callback_t uhid_write_callback;
115 static usb_callback_t uhid_read_callback;
116 
117 static usb_fifo_cmd_t uhid_start_read;
118 static usb_fifo_cmd_t uhid_stop_read;
119 static usb_fifo_cmd_t uhid_start_write;
120 static usb_fifo_cmd_t uhid_stop_write;
121 static usb_fifo_open_t uhid_open;
122 static usb_fifo_close_t uhid_close;
123 static usb_fifo_ioctl_t uhid_ioctl;
124 static usb_fifo_ioctl_t uhid_ioctl_post;
125 
126 static struct usb_fifo_methods uhid_fifo_methods = {
127 	.f_open = &uhid_open,
128 	.f_close = &uhid_close,
129 	.f_ioctl = &uhid_ioctl,
130 	.f_ioctl_post = &uhid_ioctl_post,
131 	.f_start_read = &uhid_start_read,
132 	.f_stop_read = &uhid_stop_read,
133 	.f_start_write = &uhid_start_write,
134 	.f_stop_write = &uhid_stop_write,
135 	.basename[0] = "uhid",
136 };
137 
138 static void
uhid_intr_write_callback(struct usb_xfer * xfer,usb_error_t error)139 uhid_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
140 {
141 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
142 	struct usb_page_cache *pc;
143 	usb_frlength_t actlen;
144 
145 	switch (USB_GET_STATE(xfer)) {
146 	case USB_ST_TRANSFERRED:
147 	case USB_ST_SETUP:
148 tr_setup:
149 		pc = usbd_xfer_get_frame(xfer, 0);
150 		if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
151 		    0, usbd_xfer_max_len(xfer), &actlen, 0)) {
152 			usbd_xfer_set_frame_len(xfer, 0, actlen);
153 			usbd_transfer_submit(xfer);
154 		}
155 		return;
156 
157 	default:			/* Error */
158 		if (error != USB_ERR_CANCELLED) {
159 			/* try to clear stall first */
160 			usbd_xfer_set_stall(xfer);
161 			goto tr_setup;
162 		}
163 		return;
164 	}
165 }
166 
report_event(InputDevice * input_dev,uint32_t type,uint32_t code,int32_t value)167 void report_event(InputDevice *input_dev, uint32_t type, uint32_t code, int32_t value)
168 {
169 	DPRINTF("%s type = %u, code = %u, value = %d\n", input_dev->devName, type, code, value);
170 	if (type == EV_SYN || type == EV_KEY) {
171 		PushOnePackage(input_dev, type, code, value);
172 	} else if (value) {
173 		PushOnePackage(input_dev, type, code, value);
174 	}
175 }
176 
mouse_report_events(InputDevice * input_dev,void * buffer,int len)177 void mouse_report_events(InputDevice *input_dev, void *buffer, int len)
178 {
179 	if (len != MOUSE_DATA_LEN) {
180 		DPRINTF("%s: invalid data len = %d\n", __func__, len);
181 		return;
182 	}
183 
184 	const char *buf = buffer;
185 	report_event(input_dev, EV_KEY, BTN_LEFT, BTN_LEFT_VALUE((unsigned char)buf[0]));
186 	report_event(input_dev, EV_KEY, BTN_RIGHT, BTN_RIGHT_VALUE((unsigned char)buf[0]));
187 	report_event(input_dev, EV_KEY, BTN_MIDDLE, BTN_MIDDLE_VALUE((unsigned char)buf[0]));
188 	report_event(input_dev, EV_REL, REL_X, buf[1]);
189 	report_event(input_dev, EV_REL, REL_Y, buf[2]);
190 	report_event(input_dev, EV_REL, REL_WHEEL, buf[3]);
191 	report_event(input_dev, EV_SYN, SYN_REPORT, 0);
192 }
193 
194 static void
uhid_intr_read_callback(struct usb_xfer * xfer,usb_error_t error)195 uhid_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
196 {
197 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
198 	struct usb_page_cache *pc;
199 	int actlen;
200 
201 	DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer));
202 
203 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
204 
205 	switch (USB_GET_STATE(xfer)) {
206 	case USB_ST_TRANSFERRED:
207 		pc = usbd_xfer_get_frame(xfer, 0);
208 		if (sc->input_dev && sc->input_dev->devType == INDEV_TYPE_MOUSE) {
209 			mouse_report_events(sc->input_dev, pc->buffer, actlen);
210 		}
211 
212 	case USB_ST_SETUP:
213 		usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
214 		usbd_transfer_submit(xfer);
215 		return;
216 
217 	default:
218 		if (error != USB_ERR_CANCELLED) {
219 			usbd_xfer_set_stall(xfer);
220 			usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
221 			usbd_transfer_submit(xfer);
222 		}
223 		return;
224 	}
225 }
226 
227 static void
uhid_fill_set_report(struct usb_device_request * req,uint8_t iface_no,uint8_t type,uint8_t id,uint16_t size)228 uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no,
229     uint8_t type, uint8_t id, uint16_t size)
230 {
231 	req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
232 	req->bRequest = UR_SET_REPORT;
233 	USETW2(req->wValue, type, id);
234 	req->wIndex[0] = iface_no;
235 	req->wIndex[1] = 0;
236 	USETW(req->wLength, size);
237 }
238 
239 static void
uhid_fill_get_report(struct usb_device_request * req,uint8_t iface_no,uint8_t type,uint8_t id,uint16_t size)240 uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no,
241     uint8_t type, uint8_t id, uint16_t size)
242 {
243 	req->bmRequestType = UT_READ_CLASS_INTERFACE;
244 	req->bRequest = UR_GET_REPORT;
245 	USETW2(req->wValue, type, id);
246 	req->wIndex[0] = iface_no;
247 	req->wIndex[1] = 0;
248 	USETW(req->wLength, size);
249 }
250 
251 static void
uhid_write_callback(struct usb_xfer * xfer,usb_error_t error)252 uhid_write_callback(struct usb_xfer *xfer, usb_error_t error)
253 {
254 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
255 	struct usb_device_request req;
256 	struct usb_page_cache *pc;
257 	uint32_t size = sc->sc_osize;
258 	uint32_t actlen;
259 	uint8_t id;
260 
261 	switch (USB_GET_STATE(xfer)) {
262 	case USB_ST_TRANSFERRED:
263 	case USB_ST_SETUP:
264 		/* try to extract the ID byte */
265 		if (sc->sc_oid) {
266 			pc = usbd_xfer_get_frame(xfer, 0);
267 			if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
268 			    0, 1, &actlen, 0)) {
269 				if (actlen != 1) {
270 					goto tr_error;
271 				}
272 				usbd_copy_out(pc, 0, &id, 1);
273 
274 			} else {
275 				return;
276 			}
277 			if (size) {
278 				size--;
279 			}
280 		} else {
281 			id = 0;
282 		}
283 
284 		pc = usbd_xfer_get_frame(xfer, 1);
285 		if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
286 		    0, UHID_BSIZE, &actlen, 1)) {
287 			if (actlen != size) {
288 				goto tr_error;
289 			}
290 			uhid_fill_set_report
291 			    (&req, sc->sc_iface_no,
292 			    UHID_OUTPUT_REPORT, id, size);
293 
294 			pc = usbd_xfer_get_frame(xfer, 0);
295 			usbd_copy_in(pc, 0, &req, sizeof(req));
296 
297 			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
298 			usbd_xfer_set_frame_len(xfer, 1, size);
299 			usbd_xfer_set_frames(xfer, size ? 2 : 1);
300 			usbd_transfer_submit(xfer);
301 		}
302 		return;
303 
304 	default:
305 tr_error:
306 		/* bomb out */
307 		usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]);
308 		return;
309 	}
310 }
311 
312 static void
uhid_read_callback(struct usb_xfer * xfer,usb_error_t error)313 uhid_read_callback(struct usb_xfer *xfer, usb_error_t error)
314 {
315 	struct uhid_softc *sc = usbd_xfer_softc(xfer);
316 	struct usb_device_request req;
317 	struct usb_page_cache *pc;
318 
319 	DPRINTF("enter state of xfer is %u!\n", USB_GET_STATE(xfer));
320 
321 	pc = usbd_xfer_get_frame(xfer, 0);
322 
323 	switch (USB_GET_STATE(xfer)) {
324 	case USB_ST_TRANSFERRED:
325 		usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req),
326 		    sc->sc_isize, 1);
327 		return;
328 
329 	case USB_ST_SETUP:
330 
331 		if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) {
332 			uhid_fill_get_report
333 			    (&req, sc->sc_iface_no, UHID_INPUT_REPORT,
334 			    sc->sc_iid, sc->sc_isize);
335 
336 			usbd_copy_in(pc, 0, &req, sizeof(req));
337 
338 			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
339 			usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize);
340 			usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1);
341 			usbd_transfer_submit(xfer);
342 		}
343 		return;
344 
345 	default:			/* Error */
346 		/* bomb out */
347 		usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]);
348 		return;
349 	}
350 }
351 
352 static const struct usb_config uhid_config[UHID_N_TRANSFER] = {
353 	[UHID_INTR_DT_WR] = {
354 		.type = UE_INTERRUPT,
355 		.endpoint = UE_ADDR_ANY,
356 		.direction = UE_DIR_OUT,
357 		.flags = {.pipe_bof = 1,.no_pipe_ok = 1, },
358 		.bufsize = UHID_BSIZE,
359 		.callback = &uhid_intr_write_callback,
360 	},
361 
362 	[UHID_INTR_DT_RD] = {
363 		.type = UE_INTERRUPT,
364 		.endpoint = UE_ADDR_ANY,
365 		.direction = UE_DIR_IN,
366 		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
367 		.bufsize = UHID_BSIZE,
368 		.callback = &uhid_intr_read_callback,
369 	},
370 
371 	[UHID_CTRL_DT_WR] = {
372 		.type = UE_CONTROL,
373 		.endpoint = 0x00,	/* Control pipe */
374 		.direction = UE_DIR_ANY,
375 		.bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
376 		.callback = &uhid_write_callback,
377 		.timeout = 1000,	/* 1 second */
378 	},
379 
380 	[UHID_CTRL_DT_RD] = {
381 		.type = UE_CONTROL,
382 		.endpoint = 0x00,	/* Control pipe */
383 		.direction = UE_DIR_ANY,
384 		.bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
385 		.callback = &uhid_read_callback,
386 		.timeout = 1000,	/* 1 second */
387 	},
388 };
389 
390 static void
uhid_start_read(struct usb_fifo * fifo)391 uhid_start_read(struct usb_fifo *fifo)
392 {
393 	struct uhid_softc *sc = usb_fifo_softc(fifo);
394 
395 	if (sc->sc_flags & UHID_FLAG_IMMED) {
396 		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_RD]);
397 	} else {
398 		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
399 	}
400 }
401 
402 static void
uhid_stop_read(struct usb_fifo * fifo)403 uhid_stop_read(struct usb_fifo *fifo)
404 {
405 	struct uhid_softc *sc = usb_fifo_softc(fifo);
406 
407 	usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_RD]);
408 	usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]);
409 }
410 
411 static void
uhid_start_write(struct usb_fifo * fifo)412 uhid_start_write(struct usb_fifo *fifo)
413 {
414 	struct uhid_softc *sc = usb_fifo_softc(fifo);
415 
416 	if ((sc->sc_flags & UHID_FLAG_IMMED) ||
417 	    sc->sc_xfer[UHID_INTR_DT_WR] == NULL) {
418 		usbd_transfer_start(sc->sc_xfer[UHID_CTRL_DT_WR]);
419 	} else {
420 		usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_WR]);
421 	}
422 }
423 
424 static void
uhid_stop_write(struct usb_fifo * fifo)425 uhid_stop_write(struct usb_fifo *fifo)
426 {
427 	struct uhid_softc *sc = usb_fifo_softc(fifo);
428 
429 	usbd_transfer_stop(sc->sc_xfer[UHID_CTRL_DT_WR]);
430 	usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_WR]);
431 }
432 
433 static int
uhid_get_report(struct uhid_softc * sc,uint8_t type,uint8_t id,void * kern_data,void * user_data,uint16_t len)434 uhid_get_report(struct uhid_softc *sc, uint8_t type,
435     uint8_t id, void *kern_data, void *user_data,
436     uint16_t len)
437 {
438 	int err;
439 	uint8_t free_data = 0;
440 
441 	if (kern_data == NULL) {
442 		if (len == 0) {
443 			err = EPERM;
444 			goto done;
445 		}
446 
447 		kern_data = malloc(len);
448 		if (kern_data == NULL) {
449 			err = ENOMEM;
450 			goto done;
451 		}
452 		free_data = 1;
453 	}
454 	err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
455 	    len, sc->sc_iface_index, type, id);
456 	if (err) {
457 		err = ENXIO;
458 		goto done;
459 	}
460 	if (user_data) {
461 		/* dummy buffer */
462 		err = copyout(kern_data, user_data, len);
463 		if (err) {
464 			goto done;
465 		}
466 	}
467 done:
468 	if (free_data) {
469 		free(kern_data);
470 	}
471 	return (err);
472 }
473 
474 static int
uhid_set_report(struct uhid_softc * sc,uint8_t type,uint8_t id,void * kern_data,const void * user_data,uint16_t len)475 uhid_set_report(struct uhid_softc *sc, uint8_t type,
476     uint8_t id, void *kern_data, const void *user_data,
477     uint16_t len)
478 {
479 	int err;
480 	uint8_t free_data = 0;
481 
482 	if (kern_data == NULL) {
483 		if (len == 0) {
484 			err = EPERM;
485 			goto done;
486 		}
487 
488 		kern_data = malloc(len);
489 		if (kern_data == NULL) {
490 			err = ENOMEM;
491 			goto done;
492 		}
493 		free_data = 1;
494 		err = copyin(user_data, kern_data, len);
495 		if (err) {
496 			goto done;
497 		}
498 	}
499 	err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
500 	    len, sc->sc_iface_index, type, id);
501 	if (err) {
502 		err = ENXIO;
503 		goto done;
504 	}
505 done:
506 	if (free_data) {
507 		free(kern_data);
508 	}
509 	return (err);
510 }
511 
512 static int
uhid_open(struct usb_fifo * fifo,int fflags)513 uhid_open(struct usb_fifo *fifo, int fflags)
514 {
515 	struct uhid_softc *sc = usb_fifo_softc(fifo);
516 
517 	/*
518 	 * The buffers are one byte larger than maximum so that one
519 	 * can detect too large read/writes and short transfers:
520 	 */
521 	if ((unsigned int)fflags & FREAD) {
522 		/* reset flags */
523 		mtx_lock(&sc->sc_mtx);
524 		sc->sc_flags &= ~UHID_FLAG_IMMED;
525 		mtx_unlock(&sc->sc_mtx);
526 
527 		if (usb_fifo_alloc_buffer(fifo,
528 		    sc->sc_isize + 1, UHID_FRAME_NUM)) {
529 			return (ENOMEM);
530 		}
531 	}
532 	if ((unsigned int)fflags & FWRITE) {
533 		if (usb_fifo_alloc_buffer(fifo,
534 		    sc->sc_osize + 1, UHID_FRAME_NUM)) {
535 			return (ENOMEM);
536 		}
537 	}
538 
539 	return (0);
540 }
541 
542 static void
uhid_close(struct usb_fifo * fifo,int fflags)543 uhid_close(struct usb_fifo *fifo, int fflags)
544 {
545 	if ((unsigned int)fflags & (FREAD | FWRITE)) {
546 		usb_fifo_free_buffer(fifo);
547 	}
548 }
549 
550 static int
uhid_ioctl(struct usb_fifo * fifo,u_long cmd,void * addr,int fflags)551 uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
552     int fflags)
553 {
554 	struct uhid_softc *sc = usb_fifo_softc(fifo);
555 	struct usb_gen_descriptor ugd;
556 	uint32_t size;
557 	int error = 0;
558 	uint8_t id;
559 
560 	switch (cmd) {
561 	case USB_GET_REPORT_DESC:
562 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
563 		if (error != ENOERR) {
564 			break;
565 		}
566 		if (sc->sc_repdesc_size > ugd.ugd_maxlen) {
567 			size = ugd.ugd_maxlen;
568 		} else {
569 			size = sc->sc_repdesc_size;
570 		}
571 		ugd.ugd_actlen = size;
572 		if (ugd.ugd_data == NULL)
573 			break;		/* descriptor length only */
574 		error = copyout(sc->sc_repdesc_ptr, ugd.ugd_data, size);
575 		if (error == ENOERR) {
576 			error = copyout((const void *)&ugd, addr, sizeof(struct usb_gen_descriptor));
577 		}
578 		break;
579 
580 	case USB_SET_IMMED: {
581 		int data;
582 		if (!((unsigned int)fflags & FREAD)) {
583 			error = EPERM;
584 			break;
585 		}
586 		error = copyin((const void *)addr, &data, sizeof(data));
587 		if (error != ENOERR) {
588 			break;
589 		}
590 		if (data) {
591 			/* do a test read */
592 
593 			error = uhid_get_report(sc, UHID_INPUT_REPORT,
594 			    sc->sc_iid, NULL, NULL, sc->sc_isize);
595 			if (error) {
596 				break;
597 			}
598 			mtx_lock(&sc->sc_mtx);
599 			sc->sc_flags |= UHID_FLAG_IMMED;
600 			mtx_unlock(&sc->sc_mtx);
601 		} else {
602 			mtx_lock(&sc->sc_mtx);
603 			sc->sc_flags &= ~UHID_FLAG_IMMED;
604 			mtx_unlock(&sc->sc_mtx);
605 		}
606 		break;
607 	}
608 
609 	case USB_GET_REPORT:
610 		if (!((unsigned int)fflags & FREAD)) {
611 			error = EPERM;
612 			break;
613 		}
614 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
615 		if (error != ENOERR) {
616 			break;
617 		}
618 		switch (ugd.ugd_report_type) {
619 		case UHID_INPUT_REPORT:
620 			size = sc->sc_isize;
621 			id = sc->sc_iid;
622 			break;
623 		case UHID_OUTPUT_REPORT:
624 			size = sc->sc_osize;
625 			id = sc->sc_oid;
626 			break;
627 		case UHID_FEATURE_REPORT:
628 			size = sc->sc_fsize;
629 			id = sc->sc_fid;
630 			break;
631 		default:
632 			return (EINVAL);
633 		}
634 		if (id != 0)
635 			copyin(ugd.ugd_data, &id, 1);
636 		error = uhid_get_report(sc, ugd.ugd_report_type, id,
637 		    NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size));
638 		break;
639 
640 	case USB_SET_REPORT:
641 		if (!((unsigned int)fflags & FWRITE)) {
642 			error = EPERM;
643 			break;
644 		}
645 		error = copyin((const void *)addr, &ugd, sizeof(struct usb_gen_descriptor));
646 		if (error != ENOERR) {
647 			break;
648 		}
649 		switch (ugd.ugd_report_type) {
650 		case UHID_INPUT_REPORT:
651 			size = sc->sc_isize;
652 			id = sc->sc_iid;
653 			break;
654 		case UHID_OUTPUT_REPORT:
655 			size = sc->sc_osize;
656 			id = sc->sc_oid;
657 			break;
658 		case UHID_FEATURE_REPORT:
659 			size = sc->sc_fsize;
660 			id = sc->sc_fid;
661 			break;
662 		default:
663 			return (EINVAL);
664 		}
665 		if (id != 0)
666 			copyin(ugd.ugd_data, &id, 1);
667 		error = uhid_set_report(sc, ugd.ugd_report_type, id,
668 		    NULL, ugd.ugd_data, MIN(ugd.ugd_maxlen, size));
669 		break;
670 
671 	case USB_GET_REPORT_ID: {
672 		int data = 0;
673 		error = copyout((const void *)&data, addr, sizeof(data)); /* XXX: we only support reportid 0? */
674 		break;
675 	}
676 
677 	default:
678 		error = ENOIOCTL;
679 		break;
680 	}
681 
682 	return (error);
683 }
684 
685 static int
uhid_ioctl_post(struct usb_fifo * fifo,u_long cmd,void * addr,int fflags)686 uhid_ioctl_post(struct usb_fifo *fifo, u_long cmd, void *addr,
687     int fflags)
688 {
689 	int error;
690 
691 	switch (cmd) {
692 	case USB_GET_DEVICEINFO:
693 		error = ugen_fill_deviceinfo(fifo, addr);
694 		break;
695 
696 	default:
697 		error = EINVAL;
698 		break;
699 	}
700 
701 	return (error);
702 }
703 
704 static const STRUCT_USB_HOST_ID uhid_devs[] = {
705 	/* generic HID class */
706 	{USB_IFACE_CLASS(UICLASS_HID),},
707 	/* the Xbox 360 gamepad doesn't use the HID class */
708 	{USB_IFACE_CLASS(UICLASS_VENDOR),
709 	 USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER),
710 	 USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),},
711 };
712 
713 static int
uhid_probe(device_t dev)714 uhid_probe(device_t dev)
715 {
716 	struct usb_attach_arg *uaa = device_get_ivars(dev);
717 	int error;
718 
719 	DPRINTFN(11, "\n");
720 
721 	if (uaa->usb_mode != USB_MODE_HOST)
722 		return (ENXIO);
723 
724 	error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa);
725 	if (error)
726 		return (error);
727 
728 	if (usb_test_quirk(uaa, UQ_HID_IGNORE))
729 		return (ENXIO);
730 
731 	return (0);
732 }
733 
734 static int
uhid_attach(device_t dev)735 uhid_attach(device_t dev)
736 {
737 	struct usb_attach_arg *uaa = device_get_ivars(dev);
738 	struct uhid_softc *sc = device_get_softc(dev);
739 	int unit = device_get_unit(dev);
740 	int error = 0;
741 	int32_t ret;
742 
743 	DPRINTFN(10, "sc=%p\n", sc);
744 
745 	device_set_usb_desc(dev);
746 
747 	mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE);
748 
749 	sc->sc_udev = uaa->device;
750 
751 	sc->sc_iface_no = uaa->info.bIfaceNum;
752 	sc->sc_iface_index = uaa->info.bIfaceIndex;
753 
754 	error = usbd_transfer_setup(uaa->device,
755 	    &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config,
756 	    UHID_N_TRANSFER, sc, &sc->sc_mtx);
757 
758 	if (error) {
759 		DPRINTF("error=%s\n", usbd_errstr(error));
760 		goto detach;
761 	}
762 	if (uaa->info.idVendor == USB_VENDOR_WACOM) {
763 		/* the report descriptor for the Wacom Graphire is broken */
764 
765 		if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) {
766 			sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr);
767 			sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire_report_descr);
768 			sc->sc_flags |= UHID_FLAG_STATIC_DESC;
769 
770 		} else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
771 			static uint8_t reportbuf[] = {2, 2, 2};
772 
773 			/*
774 			 * The Graphire3 needs 0x0202 to be written to
775 			 * feature report ID 2 before it'll start
776 			 * returning digitizer data.
777 			 */
778 			error = usbd_req_set_report(uaa->device, NULL,
779 			    reportbuf, sizeof(reportbuf),
780 			    uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2);
781 
782 			if (error) {
783 				DPRINTF("set report failed, error=%s (ignored)\n",
784 				    usbd_errstr(error));
785 			}
786 			sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr);
787 			sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire3_4x5_report_descr);
788 			sc->sc_flags |= UHID_FLAG_STATIC_DESC;
789 		}
790 	} else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) &&
791 	    (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) &&
792 	    (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) {
793 		static const uint8_t reportbuf[3] = {1, 3, 0};
794 		/*
795 		 * Turn off the four LEDs on the gamepad which
796 		 * are blinking by default:
797 		 */
798 		error = usbd_req_set_report(uaa->device, NULL,
799 		    __DECONST(void *, reportbuf), sizeof(reportbuf),
800 		    uaa->info.bIfaceIndex, UHID_OUTPUT_REPORT, 0);
801 		if (error) {
802 			DPRINTF("set output report failed, error=%s (ignored)\n",
803 			    usbd_errstr(error));
804 		}
805 		/* the Xbox 360 gamepad has no report descriptor */
806 		sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr);
807 		sc->sc_repdesc_ptr = __DECONST(void *, &uhid_xb360gp_report_descr);
808 		sc->sc_flags |= UHID_FLAG_STATIC_DESC;
809 	}
810 
811 	if (sc->sc_repdesc_ptr == NULL) {
812 		error = usbd_req_get_hid_desc(uaa->device, NULL,
813 		    &sc->sc_repdesc_ptr, &sc->sc_repdesc_size,
814 		    M_USBDEV, uaa->info.bIfaceIndex);
815 
816 		if (error) {
817 			device_printf(dev, "no report descriptor\n");
818 			goto detach;
819 		}
820 	}
821 
822 	error = usbd_req_set_idle(uaa->device, NULL,
823 	    uaa->info.bIfaceIndex, 0, 0);
824 
825 	if (error) {
826 		DPRINTF("set idle failed, error=%s (ignored)\n",
827 		    usbd_errstr(error));
828 	}
829 
830 	sc->sc_isize = hid_report_size
831 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid);
832 
833 	sc->sc_osize = hid_report_size
834 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid);
835 
836 	sc->sc_fsize = hid_report_size
837 	    (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid);
838 
839 	if (sc->sc_isize > UHID_BSIZE) {
840 		DPRINTF("input size is too large, "
841 		    "%d bytes (truncating)\n",
842 		    sc->sc_isize);
843 		sc->sc_isize = UHID_BSIZE;
844 	}
845 	if (sc->sc_osize > UHID_BSIZE) {
846 		DPRINTF("output size is too large, "
847 		    "%d bytes (truncating)\n",
848 		    sc->sc_osize);
849 		sc->sc_osize = UHID_BSIZE;
850 	}
851 	if (sc->sc_fsize > UHID_BSIZE) {
852 		DPRINTF("feature size is too large, "
853 		    "%d bytes (truncating)\n",
854 		    sc->sc_fsize);
855 		sc->sc_fsize = UHID_BSIZE;
856 	}
857 
858 	error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
859 	    &uhid_fifo_methods, &sc->sc_fifo,
860 	    unit, -1, uaa->info.bIfaceIndex,
861 	    UID_ROOT, GID_OPERATOR, 0644);
862 	if (error) {
863 		goto detach;
864 	}
865 
866 	sc->input_dev = (InputDevice*)zalloc(sizeof(InputDevice));
867 	if (sc->input_dev) {
868 		if (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) {
869 			sc->input_dev->devType = INDEV_TYPE_MOUSE;
870 			sc->input_dev->devName = "mouse";
871 		} else {
872 			sc->input_dev->devType = INDEV_TYPE_UNKNOWN;
873 			sc->input_dev->devName = "other";
874 		}
875 
876 		ret = RegisterInputDevice(sc->input_dev);
877 		if (ret != HDF_SUCCESS) {
878 			DPRINTF("%s register failed, ret = %d!\n", sc->input_dev->devName, ret);
879 			free(sc->input_dev);
880 			sc->input_dev = NULL;
881 		} else if (sc->input_dev->devType == INDEV_TYPE_MOUSE) {
882 			DPRINTF("mouse register success!\n");
883 			mtx_lock(&sc->sc_mtx);
884 			sc->sc_flags &= ~UHID_FLAG_IMMED;
885 			usbd_transfer_start(sc->sc_xfer[UHID_INTR_DT_RD]);
886 			mtx_unlock(&sc->sc_mtx);
887 		}
888 	}
889 
890 	return (0);			/* success */
891 
892 detach:
893 	uhid_detach(dev);
894 	return (ENOMEM);
895 }
896 
897 static int
uhid_detach(device_t dev)898 uhid_detach(device_t dev)
899 {
900 	struct uhid_softc *sc = device_get_softc(dev);
901 
902 	DPRINTF("enter\n");
903 
904 	if (sc->input_dev) {
905 		if (sc->input_dev->devType == INDEV_TYPE_MOUSE) {
906 			usbd_transfer_stop(sc->sc_xfer[UHID_INTR_DT_RD]);
907 		}
908 
909 		UnregisterInputDevice(sc->input_dev);
910 		free(sc->input_dev);
911 		sc->input_dev = NULL;
912 	}
913 
914 	usb_fifo_detach(&sc->sc_fifo);
915 
916 	usbd_transfer_unsetup(sc->sc_xfer, UHID_N_TRANSFER);
917 
918 	if (sc->sc_repdesc_ptr) {
919 		if (!(sc->sc_flags & UHID_FLAG_STATIC_DESC)) {
920 			free(sc->sc_repdesc_ptr);
921 		}
922 	}
923 	mtx_destroy(&sc->sc_mtx);
924 
925 	return (0);
926 }
927 
928 static devclass_t uhid_devclass;
929 
930 static device_method_t uhid_methods[] = {
931 	DEVMETHOD(device_probe, uhid_probe),
932 	DEVMETHOD(device_attach, uhid_attach),
933 	DEVMETHOD(device_detach, uhid_detach),
934 
935 	DEVMETHOD_END
936 };
937 
938 static driver_t uhid_driver = {
939 	.name = "uhid",
940 	.methods = uhid_methods,
941 	.size = sizeof(struct uhid_softc),
942 };
943 
944 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0);
945