1 /* $OpenBSD: uts.c,v 1.2 2007/03/23 14:35:19 robert Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Robert Nagy <robert@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/sockio.h> 21 #include <sys/sysctl.h> 22 #include <sys/mbuf.h> 23 #include <sys/kernel.h> 24 #include <sys/socket.h> 25 #include <sys/systm.h> 26 #include <sys/malloc.h> 27 #include <sys/timeout.h> 28 #include <sys/conf.h> 29 #include <sys/device.h> 30 31 #include <machine/bus.h> 32 #include <machine/endian.h> 33 #include <machine/intr.h> 34 35 #include <dev/usb/usb.h> 36 #include <dev/usb/usbdi.h> 37 #include <dev/usb/usbdi_util.h> 38 #include <dev/usb/usbdevs.h> 39 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wscons/wsmousevar.h> 42 43 #define UTS_CONFIG_INDEX 0 44 45 struct uts_softc { 46 USBBASEDEVICE sc_dev; 47 usbd_device_handle sc_udev; 48 usbd_interface_handle sc_iface; 49 int sc_iface_number; 50 int sc_product; 51 52 int sc_intr_number; 53 usbd_pipe_handle sc_intr_pipe; 54 u_char *sc_ibuf; 55 int sc_isize; 56 u_int8_t sc_pkts; 57 58 device_ptr_t sc_wsmousedev; 59 60 int sc_enabled; 61 int sc_buttons; 62 int sc_dying; 63 int sc_oldx; 64 int sc_oldy; 65 }; 66 67 /* Settable via sysctl */ 68 int uts_rawmode; 69 struct utsscale { 70 int ts_minx; 71 int ts_maxx; 72 int ts_miny; 73 int ts_maxy; 74 int ts_swapxy; 75 int ts_resx; 76 int ts_resy; 77 } uts_scale = { 78 3800, 500, 450, 3800, 1, 1024, 768 79 }; 80 81 struct uts_pos { 82 int x; 83 int y; 84 int z; /* touch pressure */ 85 }; 86 87 Static const struct usb_devno uts_devs[] = { 88 { USB_VENDOR_FTDI, USB_PRODUCT_FTDI_ITM_TOUCH }, 89 { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL }, 90 { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2 }, 91 { 0, 0 } 92 }; 93 94 Static void uts_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 95 struct uts_pos uts_get_pos(usbd_private_handle addr, struct uts_pos tp); 96 97 Static int uts_enable(void *); 98 Static void uts_disable(void *); 99 Static int uts_ioctl(void *, u_long, caddr_t, int, struct proc *); 100 101 const struct wsmouse_accessops uts_accessops = { 102 uts_enable, 103 uts_ioctl, 104 uts_disable, 105 }; 106 107 USB_DECLARE_DRIVER(uts); 108 109 USB_MATCH(uts) 110 { 111 USB_MATCH_START(uts, uaa); 112 113 if (uaa->iface == NULL) 114 return UMATCH_NONE; 115 116 return (usb_lookup(uts_devs, uaa->vendor, uaa->product) != NULL) ? 117 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 118 } 119 120 USB_ATTACH(uts) 121 { 122 USB_ATTACH_START(uts, sc, uaa); 123 usb_config_descriptor_t *cdesc; 124 usb_interface_descriptor_t *id; 125 usb_endpoint_descriptor_t *ed; 126 struct wsmousedev_attach_args a; 127 char *devinfop; 128 int i, found; 129 130 sc->sc_udev = uaa->device; 131 sc->sc_product = uaa->product; 132 sc->sc_intr_number = -1; 133 sc->sc_intr_pipe = NULL; 134 sc->sc_enabled = sc->sc_isize = 0; 135 136 /* Display device info string */ 137 USB_ATTACH_SETUP; 138 if ((devinfop = usbd_devinfo_alloc(uaa->device, 0)) != NULL) { 139 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop); 140 usbd_devinfo_free(devinfop); 141 } 142 143 /* Move the device into the configured state. */ 144 if (usbd_set_config_index(uaa->device, UTS_CONFIG_INDEX, 1) != 0) { 145 printf("%s: could not set configuartion no\n", 146 USBDEVNAME(sc->sc_dev)); 147 sc->sc_dying = 1; 148 USB_ATTACH_ERROR_RETURN; 149 } 150 151 /* get the config descriptor */ 152 cdesc = usbd_get_config_descriptor(sc->sc_udev); 153 if (cdesc == NULL) { 154 printf("%s: failed to get configuration descriptor\n", 155 USBDEVNAME(sc->sc_dev)); 156 sc->sc_dying = 1; 157 USB_ATTACH_ERROR_RETURN; 158 } 159 160 /* get the interface */ 161 if (usbd_device2interface_handle(uaa->device, 0, &sc->sc_iface) != 0) { 162 printf("%s: failed to get interface\n", 163 USBDEVNAME(sc->sc_dev)); 164 sc->sc_dying = 1; 165 USB_ATTACH_ERROR_RETURN; 166 } 167 168 /* Find the interrupt endpoint */ 169 id = usbd_get_interface_descriptor(sc->sc_iface); 170 sc->sc_iface_number = id->bInterfaceNumber; 171 found = 0; 172 173 for (i = 0; i < id->bNumEndpoints; i++) { 174 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 175 if (ed == NULL) { 176 printf("%s: no endpoint descriptor for %d\n", 177 USBDEVNAME(sc->sc_dev), i); 178 sc->sc_dying = 1; 179 USB_ATTACH_ERROR_RETURN; 180 } 181 182 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 183 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 184 sc->sc_intr_number = ed->bEndpointAddress; 185 sc->sc_isize = UGETW(ed->wMaxPacketSize); 186 } 187 } 188 189 if (sc->sc_intr_number== -1) { 190 printf("%s: Could not find interrupt in\n", 191 USBDEVNAME(sc->sc_dev)); 192 sc->sc_dying = 1; 193 USB_ATTACH_ERROR_RETURN; 194 } 195 196 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 197 USBDEV(sc->sc_dev)); 198 199 a.accessops = &uts_accessops; 200 a.accesscookie = sc; 201 202 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 203 204 USB_ATTACH_SUCCESS_RETURN; 205 } 206 207 USB_DETACH(uts) 208 { 209 USB_DETACH_START(uts, sc); 210 int rv = 0; 211 212 if (sc->sc_intr_pipe != NULL) { 213 usbd_abort_pipe(sc->sc_intr_pipe); 214 usbd_close_pipe(sc->sc_intr_pipe); 215 sc->sc_intr_pipe = NULL; 216 } 217 218 sc->sc_dying = 1; 219 220 if (sc->sc_wsmousedev != NULL) { 221 rv = config_detach(sc->sc_wsmousedev, flags); 222 sc->sc_wsmousedev = NULL; 223 } 224 225 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 226 USBDEV(sc->sc_dev)); 227 228 return (rv); 229 } 230 231 int 232 uts_activate(device_ptr_t self, enum devact act) 233 { 234 struct uts_softc *sc = (struct uts_softc *)self; 235 int rv = 0; 236 237 switch (act) { 238 case DVACT_ACTIVATE: 239 break; 240 241 case DVACT_DEACTIVATE: 242 if (sc->sc_wsmousedev != NULL) 243 rv = config_deactivate(sc->sc_wsmousedev); 244 sc->sc_dying = 1; 245 break; 246 } 247 248 return (rv); 249 } 250 251 Static int 252 uts_enable(void *v) 253 { 254 struct uts_softc *sc = v; 255 int err; 256 257 if (sc->sc_dying) 258 return (EIO); 259 260 if (sc->sc_enabled) 261 return (EBUSY); 262 263 if (sc->sc_isize == 0) 264 return 0; 265 sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 266 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number, 267 USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_ibuf, 268 sc->sc_isize, uts_intr, USBD_DEFAULT_INTERVAL); 269 if (err) { 270 free(sc->sc_ibuf, M_USBDEV); 271 sc->sc_intr_pipe = NULL; 272 return EIO; 273 } 274 275 sc->sc_enabled = 1; 276 sc->sc_buttons = 0; 277 278 return (0); 279 } 280 281 Static void 282 uts_disable(void *v) 283 { 284 struct uts_softc *sc = v; 285 286 if (!sc->sc_enabled) { 287 printf("uts_disable: already disabled!\n"); 288 return; 289 } 290 291 /* Disable interrupts. */ 292 if (sc->sc_intr_pipe != NULL) { 293 usbd_abort_pipe(sc->sc_intr_pipe); 294 usbd_close_pipe(sc->sc_intr_pipe); 295 sc->sc_intr_pipe = NULL; 296 } 297 298 if (sc->sc_ibuf != NULL) { 299 free(sc->sc_ibuf, M_USBDEV); 300 sc->sc_ibuf = NULL; 301 } 302 303 sc->sc_enabled = 0; 304 } 305 306 Static int 307 uts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *l) 308 { 309 switch (cmd) { 310 case WSMOUSEIO_GTYPE: 311 *(u_int *)data = WSMOUSE_TYPE_TPANEL; 312 return (0); 313 } 314 315 return (-1); 316 } 317 318 struct uts_pos 319 uts_get_pos(usbd_private_handle addr, struct uts_pos tp) 320 { 321 struct uts_softc *sc = addr; 322 struct utsscale *tsp = &uts_scale; 323 u_char *p = sc->sc_ibuf; 324 int down, x, y; 325 326 switch (sc->sc_product) { 327 case USB_PRODUCT_FTDI_ITM_TOUCH: 328 down = (p[7] & 0x20); 329 x = ((p[0] & 0x1f) << 7) | (p[3] & 0x7f); 330 y = ((p[1] & 0x1f) << 7) | (p[4] & 0x7f); 331 sc->sc_pkts = 8; 332 break; 333 case USB_PRODUCT_EGALAX_TPANEL: 334 case USB_PRODUCT_EGALAX_TPANEL2: 335 down = (p[0] & 0x01); 336 x = ((p[3] & 0x0f) << 7) | (p[4] & 0x7f); 337 y = ((p[1] & 0x0f) << 7) | (p[2] & 0x7f); 338 sc->sc_pkts = 5; 339 break; 340 } 341 342 if (!down) { 343 if (tsp->ts_swapxy) { /* Swap X/Y-Axis */ 344 tp.y = x; 345 tp.x = y; 346 } else { 347 tp.x = x; 348 tp.y = y; 349 } 350 351 if (!uts_rawmode) { 352 /* Scale down to the screen resolution. */ 353 tp.x = ((tp.x - tsp->ts_minx) * tsp->ts_resx) / 354 (tsp->ts_maxx - tsp->ts_minx); 355 tp.y = ((tp.y - tsp->ts_miny) * tsp->ts_resy) / 356 (tsp->ts_maxy - tsp->ts_miny); 357 } 358 tp.z = 1; 359 } else { 360 /* x/y values are not reliable if there is no pressure */ 361 tp.x = sc->sc_oldx; 362 tp.y = sc->sc_oldy; 363 tp.z = 0; 364 } 365 366 return (tp); 367 } 368 369 Static void 370 uts_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) 371 { 372 struct uts_softc *sc = addr; 373 u_int32_t len; 374 int s; 375 struct uts_pos tp; 376 377 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 378 379 s = spltty(); 380 381 if (status == USBD_CANCELLED) 382 return; 383 384 if (status != USBD_NORMAL_COMPLETION) { 385 printf("%s: status %d\n", USBDEVNAME(sc->sc_dev), status); 386 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 387 return; 388 } 389 390 tp = uts_get_pos(sc, tp); 391 392 if (len != sc->sc_pkts) { 393 printf("%s: bad input length %d != %d\n", 394 USBDEVNAME(sc->sc_dev), len, sc->sc_isize); 395 return; 396 } 397 398 wsmouse_input(sc->sc_wsmousedev, tp.z, tp.x, tp.y, 0, 399 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 400 WSMOUSE_INPUT_ABSOLUTE_Z); 401 sc->sc_oldy = tp.y; 402 sc->sc_oldx = tp.x; 403 404 splx(s); 405 } 406