1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright 2010, Gleb Smirnoff <glebius@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 *  http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf
31 */
32
33#include "opt_evdev.h"
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/callout.h>
38#include <sys/conf.h>
39#include <sys/kernel.h>
40#include <sys/lock.h>
41#include <sys/module.h>
42#include <sys/mutex.h>
43#include <sys/sysctl.h>
44#include <sys/systm.h>
45
46#include <dev/usb/usb.h>
47#include <dev/usb/usbdi.h>
48#include <dev/usb/usbdi_util.h>
49#include <dev/usb/usbhid.h>
50#include "usbdevs.h"
51
52#ifdef EVDEV_SUPPORT
53#include <dev/evdev/input.h>
54#include <dev/evdev/evdev.h>
55#else
56#include <sys/ioccom.h>
57#include <sys/fcntl.h>
58#endif
59
60#define USB_DEBUG_VAR uep_debug
61#include <dev/usb/usb_debug.h>
62
63#ifdef USB_DEBUG
64static int uep_debug = 0;
65
66static SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
67    "USB uep");
68SYSCTL_INT(_hw_usb_uep, OID_AUTO, debug, CTLFLAG_RWTUN,
69    &uep_debug, 0, "Debug level");
70#endif
71
72#define UEP_MAX_X		2047
73#define UEP_MAX_Y		2047
74
75#define UEP_DOWN		0x01
76#define UEP_PACKET_LEN_MAX	16
77#define UEP_PACKET_LEN_REPORT	5
78#define UEP_PACKET_LEN_REPORT2	6
79#define UEP_PACKET_DIAG		0x0a
80#define UEP_PACKET_REPORT_MASK		0xe0
81#define UEP_PACKET_REPORT		0x80
82#define UEP_PACKET_REPORT_PRESSURE	0xc0
83#define UEP_PACKET_REPORT_PLAYER	0xa0
84#define	UEP_PACKET_LEN_MASK
85
86#define UEP_FIFO_BUF_SIZE	8	/* bytes */
87#define UEP_FIFO_QUEUE_MAXLEN	50	/* units */
88
89enum {
90	UEP_INTR_DT,
91	UEP_N_TRANSFER,
92};
93
94struct uep_softc {
95	struct mtx mtx;
96
97	struct usb_xfer *xfer[UEP_N_TRANSFER];
98#ifdef EVDEV_SUPPORT
99	struct evdev_dev *evdev;
100#else
101	struct usb_fifo_sc fifo;
102
103	u_int		pollrate;
104	u_int		state;
105#define UEP_ENABLED	0x01
106#endif
107
108	/* Reassembling buffer. */
109	u_char		buf[UEP_PACKET_LEN_MAX];
110	uint8_t		buf_len;
111};
112
113static usb_callback_t uep_intr_callback;
114
115static device_probe_t	uep_probe;
116static device_attach_t	uep_attach;
117static device_detach_t	uep_detach;
118
119#ifdef EVDEV_SUPPORT
120
121static evdev_open_t	uep_ev_open;
122static evdev_close_t	uep_ev_close;
123
124static const struct evdev_methods uep_evdev_methods = {
125	.ev_open = &uep_ev_open,
126	.ev_close = &uep_ev_close,
127};
128
129#else /* !EVDEV_SUPPORT */
130
131static usb_fifo_cmd_t	uep_start_read;
132static usb_fifo_cmd_t	uep_stop_read;
133static usb_fifo_open_t	uep_open;
134static usb_fifo_close_t	uep_close;
135
136static void uep_put_queue(struct uep_softc *, u_char *);
137
138static struct usb_fifo_methods uep_fifo_methods = {
139	.f_open = &uep_open,
140	.f_close = &uep_close,
141	.f_start_read = &uep_start_read,
142	.f_stop_read = &uep_stop_read,
143	.basename[0] = "uep",
144};
145#endif /* !EVDEV_SUPPORT */
146
147static int
148get_pkt_len(u_char *buf)
149{
150	if (buf[0] == UEP_PACKET_DIAG) {
151		int len;
152
153		len = buf[1] + 2;
154		if (len > UEP_PACKET_LEN_MAX) {
155			DPRINTF("bad packet len %u\n", len);
156			return (UEP_PACKET_LEN_MAX);
157		}
158
159		return (len);
160	}
161
162	switch (buf[0] & UEP_PACKET_REPORT_MASK) {
163	case UEP_PACKET_REPORT:
164		return (UEP_PACKET_LEN_REPORT);
165	case UEP_PACKET_REPORT_PRESSURE:
166	case UEP_PACKET_REPORT_PLAYER:
167	case UEP_PACKET_REPORT_PRESSURE | UEP_PACKET_REPORT_PLAYER:
168		return (UEP_PACKET_LEN_REPORT2);
169	default:
170		DPRINTF("bad packet len 0\n");
171		return (0);
172	}
173}
174
175static void
176uep_process_pkt(struct uep_softc *sc, u_char *buf)
177{
178	int32_t x __usbdebug_used, y __usbdebug_used;
179#ifdef EVDEV_SUPPORT
180	int touch;
181#endif
182
183	if ((buf[0] & 0xFE) != 0x80) {
184		DPRINTF("bad input packet format 0x%.2x\n", buf[0]);
185		return;
186	}
187
188	/*
189	 * Packet format is 5 bytes:
190	 *
191	 * 1000000T
192	 * 0000AAAA
193	 * 0AAAAAAA
194	 * 0000BBBB
195	 * 0BBBBBBB
196	 *
197	 * T: 1=touched 0=not touched
198	 * A: bits of axis A position, MSB to LSB
199	 * B: bits of axis B position, MSB to LSB
200	 *
201	 * For the unit I have, which is CTF1020-S from CarTFT.com,
202	 * A = X and B = Y. But in NetBSD uep(4) it is other way round :)
203	 *
204	 * The controller sends a stream of T=1 events while the
205	 * panel is touched, followed by a single T=0 event.
206	 *
207	 */
208
209	x = (buf[1] << 7) | buf[2];
210	y = (buf[3] << 7) | buf[4];
211
212	DPRINTFN(2, "x %u y %u\n", x, y);
213
214#ifdef EVDEV_SUPPORT
215	touch = buf[0] & (1 << 0);
216	if (touch) {
217		evdev_push_abs(sc->evdev, ABS_X, x);
218		evdev_push_abs(sc->evdev, ABS_Y, y);
219	}
220	evdev_push_key(sc->evdev, BTN_TOUCH, touch);
221	evdev_sync(sc->evdev);
222#else
223	uep_put_queue(sc, buf);
224#endif
225}
226
227static void
228uep_intr_callback(struct usb_xfer *xfer, usb_error_t error)
229{
230	struct uep_softc *sc = usbd_xfer_softc(xfer);
231	int len;
232
233	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
234
235	switch (USB_GET_STATE(xfer)) {
236	case USB_ST_TRANSFERRED:
237	    {
238		struct usb_page_cache *pc;
239		u_char buf[17], *p;
240		int pkt_len;
241
242		if (len > (int)sizeof(buf)) {
243			DPRINTF("bad input length %d\n", len);
244			goto tr_setup;
245		}
246
247		pc = usbd_xfer_get_frame(xfer, 0);
248		usbd_copy_out(pc, 0, buf, len);
249
250		/*
251		 * The below code mimics Linux a lot. I don't know
252		 * why NetBSD reads complete packets, but we need
253		 * to reassamble 'em like Linux does (tries?).
254		 */
255		if (sc->buf_len > 0) {
256			int res;
257
258			if (sc->buf_len == 1)
259				sc->buf[1] = buf[0];
260
261			if ((pkt_len = get_pkt_len(sc->buf)) == 0)
262				goto tr_setup;
263
264			res = pkt_len - sc->buf_len;
265			memcpy(sc->buf + sc->buf_len, buf, res);
266			uep_process_pkt(sc, sc->buf);
267			sc->buf_len = 0;
268
269			p = buf + res;
270			len -= res;
271		} else
272			p = buf;
273
274		if (len == 1) {
275			sc->buf[0] = buf[0];
276			sc->buf_len = 1;
277
278			goto tr_setup;
279		}
280
281		while (len > 0) {
282			if ((pkt_len = get_pkt_len(p)) == 0)
283				goto tr_setup;
284
285			/* full packet: process */
286			if (pkt_len <= len) {
287				uep_process_pkt(sc, p);
288			} else {
289				/* incomplete packet: save in buffer */
290				memcpy(sc->buf, p, len);
291				sc->buf_len = len;
292			}
293			p += pkt_len;
294			len -= pkt_len;
295		}
296	    }
297	case USB_ST_SETUP:
298	tr_setup:
299#ifndef EVDEV_SUPPORT
300		/* check if we can put more data into the FIFO */
301		if (usb_fifo_put_bytes_max(sc->fifo.fp[USB_FIFO_RX]) == 0)
302			break;
303#endif
304		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
305		usbd_transfer_submit(xfer);
306		break;
307
308	default:
309		if (error != USB_ERR_CANCELLED) {
310			/* try clear stall first */
311			usbd_xfer_set_stall(xfer);
312			goto tr_setup;
313		}
314		break;
315	}
316}
317
318static const struct usb_config uep_config[UEP_N_TRANSFER] = {
319	[UEP_INTR_DT] = {
320		.type = UE_INTERRUPT,
321		.endpoint = UE_ADDR_ANY,
322		.direction = UE_DIR_IN,
323		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
324		.bufsize = 0,   /* use wMaxPacketSize */
325		.callback = &uep_intr_callback,
326	},
327};
328
329static const STRUCT_USB_HOST_ID uep_devs[] = {
330	{USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL, 0)},
331	{USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2, 0)},
332	{USB_VPI(USB_VENDOR_EGALAX2, USB_PRODUCT_EGALAX2_TPANEL, 0)},
333};
334
335static int
336uep_probe(device_t dev)
337{
338	struct usb_attach_arg *uaa = device_get_ivars(dev);
339
340	if (uaa->usb_mode != USB_MODE_HOST)
341		return (ENXIO);
342	if (uaa->info.bConfigIndex != 0)
343		return (ENXIO);
344	if (uaa->info.bIfaceIndex != 0)
345		return (ENXIO);
346
347	return (usbd_lookup_id_by_uaa(uep_devs, sizeof(uep_devs), uaa));
348}
349
350static int
351uep_attach(device_t dev)
352{
353	struct usb_attach_arg *uaa = device_get_ivars(dev);
354	struct uep_softc *sc = device_get_softc(dev);
355	int error;
356
357	device_set_usb_desc(dev);
358
359	mtx_init(&sc->mtx, "uep lock", NULL, MTX_DEF);
360
361	error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
362	    sc->xfer, uep_config, UEP_N_TRANSFER, sc, &sc->mtx);
363
364	if (error) {
365		DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error));
366		goto detach;
367	}
368
369#ifdef EVDEV_SUPPORT
370	sc->evdev = evdev_alloc();
371	evdev_set_name(sc->evdev, device_get_desc(dev));
372	evdev_set_phys(sc->evdev, device_get_nameunit(dev));
373	evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor,
374	    uaa->info.idProduct, 0);
375	evdev_set_serial(sc->evdev, usb_get_serial(uaa->device));
376	evdev_set_methods(sc->evdev, sc, &uep_evdev_methods);
377	evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
378	evdev_support_event(sc->evdev, EV_SYN);
379	evdev_support_event(sc->evdev, EV_ABS);
380	evdev_support_event(sc->evdev, EV_KEY);
381	evdev_support_key(sc->evdev, BTN_TOUCH);
382	evdev_support_abs(sc->evdev, ABS_X, 0, UEP_MAX_X, 0, 0, 0);
383	evdev_support_abs(sc->evdev, ABS_Y, 0, UEP_MAX_Y, 0, 0, 0);
384
385	error = evdev_register_mtx(sc->evdev, &sc->mtx);
386	if (error) {
387		DPRINTF("evdev_register_mtx error=%s\n", usbd_errstr(error));
388		goto detach;
389	}
390#else /* !EVDEV_SUPPORT */
391	error = usb_fifo_attach(uaa->device, sc, &sc->mtx, &uep_fifo_methods,
392	    &sc->fifo, device_get_unit(dev), -1, uaa->info.bIfaceIndex,
393	    UID_ROOT, GID_OPERATOR, 0644);
394
395        if (error) {
396		DPRINTF("usb_fifo_attach error=%s\n", usbd_errstr(error));
397                goto detach;
398        }
399#endif /* !EVDEV_SUPPORT */
400
401	sc->buf_len = 0;
402
403	return (0);
404
405detach:
406	uep_detach(dev);
407
408	return (ENOMEM); /* XXX */
409}
410
411static int
412uep_detach(device_t dev)
413{
414	struct uep_softc *sc = device_get_softc(dev);
415
416#ifdef EVDEV_SUPPORT
417	evdev_free(sc->evdev);
418#else
419	usb_fifo_detach(&sc->fifo);
420#endif
421
422	usbd_transfer_unsetup(sc->xfer, UEP_N_TRANSFER);
423
424	mtx_destroy(&sc->mtx);
425
426	return (0);
427}
428
429#ifdef EVDEV_SUPPORT
430
431static int
432uep_ev_close(struct evdev_dev *evdev)
433{
434	struct uep_softc *sc = evdev_get_softc(evdev);
435
436	mtx_assert(&sc->mtx, MA_OWNED);
437	usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
438
439	return (0);
440}
441
442static int
443uep_ev_open(struct evdev_dev *evdev)
444{
445	struct uep_softc *sc = evdev_get_softc(evdev);
446
447	mtx_assert(&sc->mtx, MA_OWNED);
448	usbd_transfer_start(sc->xfer[UEP_INTR_DT]);
449
450	return (0);
451}
452
453#else /* !EVDEV_SUPPORT */
454
455static void
456uep_start_read(struct usb_fifo *fifo)
457{
458	struct uep_softc *sc = usb_fifo_softc(fifo);
459	u_int rate;
460
461	if ((rate = sc->pollrate) > 1000)
462		rate = 1000;
463
464	if (rate > 0 && sc->xfer[UEP_INTR_DT] != NULL) {
465		usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
466		usbd_xfer_set_interval(sc->xfer[UEP_INTR_DT], 1000 / rate);
467		sc->pollrate = 0;
468	}
469
470	usbd_transfer_start(sc->xfer[UEP_INTR_DT]);
471}
472
473static void
474uep_stop_read(struct usb_fifo *fifo)
475{
476	struct uep_softc *sc = usb_fifo_softc(fifo);
477
478	usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
479}
480
481static void
482uep_put_queue(struct uep_softc *sc, u_char *buf)
483{
484	usb_fifo_put_data_linear(sc->fifo.fp[USB_FIFO_RX], buf,
485	    UEP_PACKET_LEN_REPORT, 1);
486}
487
488static int
489uep_open(struct usb_fifo *fifo, int fflags)
490{
491	if (fflags & FREAD) {
492		struct uep_softc *sc = usb_fifo_softc(fifo);
493
494		if (sc->state & UEP_ENABLED)
495			return (EBUSY);
496		if (usb_fifo_alloc_buffer(fifo, UEP_FIFO_BUF_SIZE,
497		    UEP_FIFO_QUEUE_MAXLEN))
498			return (ENOMEM);
499
500		sc->state |= UEP_ENABLED;
501	}
502
503	return (0);
504}
505
506static void
507uep_close(struct usb_fifo *fifo, int fflags)
508{
509	if (fflags & FREAD) {
510		struct uep_softc *sc = usb_fifo_softc(fifo);
511
512		sc->state &= ~(UEP_ENABLED);
513		usb_fifo_free_buffer(fifo);
514	}
515}
516#endif /* !EVDEV_SUPPORT */
517
518static device_method_t uep_methods[] = {
519	DEVMETHOD(device_probe, uep_probe),
520       	DEVMETHOD(device_attach, uep_attach),
521	DEVMETHOD(device_detach, uep_detach),
522	{ 0, 0 },
523};
524
525static driver_t uep_driver = {
526	.name = "uep",
527	.methods = uep_methods,
528	.size = sizeof(struct uep_softc),
529};
530
531DRIVER_MODULE(uep, uhub, uep_driver, NULL, NULL);
532MODULE_DEPEND(uep, usb, 1, 1, 1);
533#ifdef EVDEV_SUPPORT
534MODULE_DEPEND(uep, evdev, 1, 1, 1);
535#endif
536MODULE_VERSION(uep, 1);
537USB_PNP_HOST_INFO(uep_devs);
538