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