ums.c revision 207077
1184610Salfred/*- 2184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * This code is derived from software contributed to The NetBSD Foundation 6184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at 7184610Salfred * Carlstedt Research & Technology. 8184610Salfred * 9184610Salfred * Redistribution and use in source and binary forms, with or without 10184610Salfred * modification, are permitted provided that the following conditions 11184610Salfred * are met: 12184610Salfred * 1. Redistributions of source code must retain the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 18184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28184610Salfred * POSSIBILITY OF SUCH DAMAGE. 29184610Salfred */ 30184610Salfred 31184610Salfred#include <sys/cdefs.h> 32184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/input/ums.c 207077 2010-04-22 21:31:34Z thompsa $"); 33184610Salfred 34184610Salfred/* 35184610Salfred * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 36184610Salfred */ 37184610Salfred 38194677Sthompsa#include <sys/stdint.h> 39194677Sthompsa#include <sys/stddef.h> 40194677Sthompsa#include <sys/param.h> 41194677Sthompsa#include <sys/queue.h> 42194677Sthompsa#include <sys/types.h> 43194677Sthompsa#include <sys/systm.h> 44194677Sthompsa#include <sys/kernel.h> 45194677Sthompsa#include <sys/bus.h> 46194677Sthompsa#include <sys/linker_set.h> 47194677Sthompsa#include <sys/module.h> 48194677Sthompsa#include <sys/lock.h> 49194677Sthompsa#include <sys/mutex.h> 50194677Sthompsa#include <sys/condvar.h> 51194677Sthompsa#include <sys/sysctl.h> 52194677Sthompsa#include <sys/sx.h> 53194677Sthompsa#include <sys/unistd.h> 54194677Sthompsa#include <sys/callout.h> 55194677Sthompsa#include <sys/malloc.h> 56194677Sthompsa#include <sys/priv.h> 57194677Sthompsa#include <sys/conf.h> 58194677Sthompsa#include <sys/fcntl.h> 59198373Sthompsa#include <sys/sbuf.h> 60194677Sthompsa 61188942Sthompsa#include <dev/usb/usb.h> 62194677Sthompsa#include <dev/usb/usbdi.h> 63194677Sthompsa#include <dev/usb/usbdi_util.h> 64188942Sthompsa#include <dev/usb/usbhid.h> 65194677Sthompsa#include "usbdevs.h" 66184610Salfred 67184610Salfred#define USB_DEBUG_VAR ums_debug 68188942Sthompsa#include <dev/usb/usb_debug.h> 69184610Salfred 70188942Sthompsa#include <dev/usb/quirk/usb_quirk.h> 71184610Salfred 72184610Salfred#include <sys/ioccom.h> 73184610Salfred#include <sys/filio.h> 74184610Salfred#include <sys/tty.h> 75184610Salfred#include <sys/mouse.h> 76184610Salfred 77207077Sthompsa#ifdef USB_DEBUG 78184610Salfredstatic int ums_debug = 0; 79184610Salfred 80192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums"); 81192502SthompsaSYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RW, 82184610Salfred &ums_debug, 0, "Debug level"); 83184610Salfred#endif 84184610Salfred 85184610Salfred#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) 86184610Salfred#define MOUSE_FLAGS (HIO_RELATIVE) 87184610Salfred 88184610Salfred#define UMS_BUF_SIZE 8 /* bytes */ 89184610Salfred#define UMS_IFQ_MAXLEN 50 /* units */ 90184610Salfred#define UMS_BUTTON_MAX 31 /* exclusive, must be less than 32 */ 91184610Salfred#define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i)) 92190741Sthompsa#define UMS_INFO_MAX 2 /* maximum number of HID sets */ 93184610Salfred 94187259Sthompsaenum { 95187259Sthompsa UMS_INTR_DT, 96188981Sthompsa UMS_N_TRANSFER, 97187259Sthompsa}; 98187259Sthompsa 99190741Sthompsastruct ums_info { 100184610Salfred struct hid_location sc_loc_w; 101184610Salfred struct hid_location sc_loc_x; 102184610Salfred struct hid_location sc_loc_y; 103184610Salfred struct hid_location sc_loc_z; 104184610Salfred struct hid_location sc_loc_t; 105184610Salfred struct hid_location sc_loc_btn[UMS_BUTTON_MAX]; 106184610Salfred 107184610Salfred uint32_t sc_flags; 108184610Salfred#define UMS_FLAG_X_AXIS 0x0001 109184610Salfred#define UMS_FLAG_Y_AXIS 0x0002 110184610Salfred#define UMS_FLAG_Z_AXIS 0x0004 111184610Salfred#define UMS_FLAG_T_AXIS 0x0008 112184610Salfred#define UMS_FLAG_SBU 0x0010 /* spurious button up events */ 113188981Sthompsa#define UMS_FLAG_REVZ 0x0020 /* Z-axis is reversed */ 114188981Sthompsa#define UMS_FLAG_W_AXIS 0x0040 115184610Salfred 116189583Sthompsa uint8_t sc_iid_w; 117189583Sthompsa uint8_t sc_iid_x; 118189583Sthompsa uint8_t sc_iid_y; 119189583Sthompsa uint8_t sc_iid_z; 120189583Sthompsa uint8_t sc_iid_t; 121189583Sthompsa uint8_t sc_iid_btn[UMS_BUTTON_MAX]; 122190741Sthompsa uint8_t sc_buttons; 123190741Sthompsa}; 124190741Sthompsa 125190741Sthompsastruct ums_softc { 126192984Sthompsa struct usb_fifo_sc sc_fifo; 127190741Sthompsa struct mtx sc_mtx; 128192984Sthompsa struct usb_callout sc_callout; 129190741Sthompsa struct ums_info sc_info[UMS_INFO_MAX]; 130190741Sthompsa 131190741Sthompsa mousehw_t sc_hw; 132190741Sthompsa mousemode_t sc_mode; 133190741Sthompsa mousestatus_t sc_status; 134190741Sthompsa 135192984Sthompsa struct usb_xfer *sc_xfer[UMS_N_TRANSFER]; 136190741Sthompsa 137195959Salfred int sc_pollrate; 138195959Salfred 139190741Sthompsa uint8_t sc_buttons; 140190741Sthompsa uint8_t sc_iid; 141184610Salfred uint8_t sc_temp[64]; 142184610Salfred}; 143184610Salfred 144184610Salfredstatic void ums_put_queue_timeout(void *__sc); 145184610Salfred 146193045Sthompsastatic usb_callback_t ums_intr_callback; 147184610Salfred 148184610Salfredstatic device_probe_t ums_probe; 149184610Salfredstatic device_attach_t ums_attach; 150184610Salfredstatic device_detach_t ums_detach; 151184610Salfred 152193045Sthompsastatic usb_fifo_cmd_t ums_start_read; 153193045Sthompsastatic usb_fifo_cmd_t ums_stop_read; 154193045Sthompsastatic usb_fifo_open_t ums_open; 155193045Sthompsastatic usb_fifo_close_t ums_close; 156193045Sthompsastatic usb_fifo_ioctl_t ums_ioctl; 157184610Salfred 158198373Sthompsastatic void ums_put_queue(struct ums_softc *, int32_t, int32_t, 159198373Sthompsa int32_t, int32_t, int32_t); 160198373Sthompsastatic int ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS); 161184610Salfred 162192984Sthompsastatic struct usb_fifo_methods ums_fifo_methods = { 163184610Salfred .f_open = &ums_open, 164184610Salfred .f_close = &ums_close, 165184610Salfred .f_ioctl = &ums_ioctl, 166184610Salfred .f_start_read = &ums_start_read, 167184610Salfred .f_stop_read = &ums_stop_read, 168184610Salfred .basename[0] = "ums", 169184610Salfred}; 170184610Salfred 171184610Salfredstatic void 172184610Salfredums_put_queue_timeout(void *__sc) 173184610Salfred{ 174184610Salfred struct ums_softc *sc = __sc; 175184610Salfred 176184610Salfred mtx_assert(&sc->sc_mtx, MA_OWNED); 177184610Salfred 178184610Salfred ums_put_queue(sc, 0, 0, 0, 0, 0); 179184610Salfred} 180184610Salfred 181184610Salfredstatic void 182194677Sthompsaums_intr_callback(struct usb_xfer *xfer, usb_error_t error) 183184610Salfred{ 184194677Sthompsa struct ums_softc *sc = usbd_xfer_softc(xfer); 185190741Sthompsa struct ums_info *info = &sc->sc_info[0]; 186194677Sthompsa struct usb_page_cache *pc; 187184610Salfred uint8_t *buf = sc->sc_temp; 188184610Salfred int32_t buttons = 0; 189195959Salfred int32_t buttons_found = 0; 190190741Sthompsa int32_t dw = 0; 191190741Sthompsa int32_t dx = 0; 192190741Sthompsa int32_t dy = 0; 193190741Sthompsa int32_t dz = 0; 194190741Sthompsa int32_t dt = 0; 195184610Salfred uint8_t i; 196189583Sthompsa uint8_t id; 197194677Sthompsa int len; 198184610Salfred 199194677Sthompsa usbd_xfer_status(xfer, &len, NULL, NULL, NULL); 200194677Sthompsa 201184610Salfred switch (USB_GET_STATE(xfer)) { 202184610Salfred case USB_ST_TRANSFERRED: 203184610Salfred DPRINTFN(6, "sc=%p actlen=%d\n", sc, len); 204184610Salfred 205184610Salfred if (len > sizeof(sc->sc_temp)) { 206184610Salfred DPRINTFN(6, "truncating large packet to %zu bytes\n", 207184610Salfred sizeof(sc->sc_temp)); 208184610Salfred len = sizeof(sc->sc_temp); 209184610Salfred } 210188981Sthompsa if (len == 0) 211184610Salfred goto tr_setup; 212188981Sthompsa 213194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 214194677Sthompsa usbd_copy_out(pc, 0, buf, len); 215184610Salfred 216184610Salfred DPRINTFN(6, "data = %02x %02x %02x %02x " 217184610Salfred "%02x %02x %02x %02x\n", 218184610Salfred (len > 0) ? buf[0] : 0, (len > 1) ? buf[1] : 0, 219184610Salfred (len > 2) ? buf[2] : 0, (len > 3) ? buf[3] : 0, 220184610Salfred (len > 4) ? buf[4] : 0, (len > 5) ? buf[5] : 0, 221184610Salfred (len > 6) ? buf[6] : 0, (len > 7) ? buf[7] : 0); 222184610Salfred 223184610Salfred if (sc->sc_iid) { 224189583Sthompsa id = *buf; 225184610Salfred 226184610Salfred len--; 227184610Salfred buf++; 228184610Salfred 229184610Salfred } else { 230189583Sthompsa id = 0; 231190741Sthompsa if (sc->sc_info[0].sc_flags & UMS_FLAG_SBU) { 232184610Salfred if ((*buf == 0x14) || (*buf == 0x15)) { 233184610Salfred goto tr_setup; 234184610Salfred } 235184610Salfred } 236184610Salfred } 237184610Salfred 238190741Sthompsa repeat: 239190741Sthompsa if ((info->sc_flags & UMS_FLAG_W_AXIS) && 240190741Sthompsa (id == info->sc_iid_w)) 241190741Sthompsa dw += hid_get_data(buf, len, &info->sc_loc_w); 242184610Salfred 243190741Sthompsa if ((info->sc_flags & UMS_FLAG_X_AXIS) && 244190741Sthompsa (id == info->sc_iid_x)) 245190741Sthompsa dx += hid_get_data(buf, len, &info->sc_loc_x); 246184610Salfred 247190741Sthompsa if ((info->sc_flags & UMS_FLAG_Y_AXIS) && 248190741Sthompsa (id == info->sc_iid_y)) 249190741Sthompsa dy = -hid_get_data(buf, len, &info->sc_loc_y); 250184610Salfred 251190741Sthompsa if ((info->sc_flags & UMS_FLAG_Z_AXIS) && 252190741Sthompsa (id == info->sc_iid_z)) { 253190741Sthompsa int32_t temp; 254190741Sthompsa temp = hid_get_data(buf, len, &info->sc_loc_z); 255190741Sthompsa if (info->sc_flags & UMS_FLAG_REVZ) 256190741Sthompsa temp = -temp; 257190741Sthompsa dz -= temp; 258190741Sthompsa } 259184610Salfred 260190741Sthompsa if ((info->sc_flags & UMS_FLAG_T_AXIS) && 261190741Sthompsa (id == info->sc_iid_t)) 262190741Sthompsa dt -= hid_get_data(buf, len, &info->sc_loc_t); 263184610Salfred 264190741Sthompsa for (i = 0; i < info->sc_buttons; i++) { 265195959Salfred uint32_t mask; 266195959Salfred mask = 1UL << UMS_BUT(i); 267195959Salfred /* check for correct button ID */ 268190741Sthompsa if (id != info->sc_iid_btn[i]) 269189583Sthompsa continue; 270195959Salfred /* check for button pressed */ 271195959Salfred if (hid_get_data(buf, len, &info->sc_loc_btn[i])) 272195959Salfred buttons |= mask; 273195959Salfred /* register button mask */ 274195959Salfred buttons_found |= mask; 275184610Salfred } 276184610Salfred 277190741Sthompsa if (++info != &sc->sc_info[UMS_INFO_MAX]) 278190741Sthompsa goto repeat; 279190741Sthompsa 280195959Salfred /* keep old button value(s) for non-detected buttons */ 281195959Salfred buttons |= sc->sc_status.button & ~buttons_found; 282195959Salfred 283184610Salfred if (dx || dy || dz || dt || dw || 284184610Salfred (buttons != sc->sc_status.button)) { 285184610Salfred 286184610Salfred DPRINTFN(6, "x:%d y:%d z:%d t:%d w:%d buttons:0x%08x\n", 287184610Salfred dx, dy, dz, dt, dw, buttons); 288184610Salfred 289184610Salfred sc->sc_status.button = buttons; 290184610Salfred sc->sc_status.dx += dx; 291184610Salfred sc->sc_status.dy += dy; 292184610Salfred sc->sc_status.dz += dz; 293184610Salfred /* 294184610Salfred * sc->sc_status.dt += dt; 295184610Salfred * no way to export this yet 296184610Salfred */ 297184610Salfred 298184610Salfred /* 299188981Sthompsa * The Qtronix keyboard has a built in PS/2 300188981Sthompsa * port for a mouse. The firmware once in a 301188981Sthompsa * while posts a spurious button up 302188981Sthompsa * event. This event we ignore by doing a 303188981Sthompsa * timeout for 50 msecs. If we receive 304188981Sthompsa * dx=dy=dz=buttons=0 before we add the event 305188981Sthompsa * to the queue. In any other case we delete 306188981Sthompsa * the timeout event. 307184610Salfred */ 308190741Sthompsa if ((sc->sc_info[0].sc_flags & UMS_FLAG_SBU) && 309184610Salfred (dx == 0) && (dy == 0) && (dz == 0) && (dt == 0) && 310184610Salfred (dw == 0) && (buttons == 0)) { 311184610Salfred 312194228Sthompsa usb_callout_reset(&sc->sc_callout, hz / 20, 313184610Salfred &ums_put_queue_timeout, sc); 314184610Salfred } else { 315184610Salfred 316194228Sthompsa usb_callout_stop(&sc->sc_callout); 317184610Salfred 318184610Salfred ums_put_queue(sc, dx, dy, dz, dt, buttons); 319184610Salfred } 320184610Salfred } 321184610Salfred case USB_ST_SETUP: 322184610Salfredtr_setup: 323188981Sthompsa /* check if we can put more data into the FIFO */ 324194228Sthompsa if (usb_fifo_put_bytes_max( 325188981Sthompsa sc->sc_fifo.fp[USB_FIFO_RX]) != 0) { 326194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 327194228Sthompsa usbd_transfer_submit(xfer); 328184610Salfred } 329188981Sthompsa break; 330184610Salfred 331184610Salfred default: /* Error */ 332194677Sthompsa if (error != USB_ERR_CANCELLED) { 333188981Sthompsa /* try clear stall first */ 334194677Sthompsa usbd_xfer_set_stall(xfer); 335188981Sthompsa goto tr_setup; 336184610Salfred } 337188981Sthompsa break; 338184610Salfred } 339184610Salfred} 340184610Salfred 341192984Sthompsastatic const struct usb_config ums_config[UMS_N_TRANSFER] = { 342184610Salfred 343187259Sthompsa [UMS_INTR_DT] = { 344184610Salfred .type = UE_INTERRUPT, 345184610Salfred .endpoint = UE_ADDR_ANY, 346184610Salfred .direction = UE_DIR_IN, 347190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 348190734Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 349190734Sthompsa .callback = &ums_intr_callback, 350184610Salfred }, 351184610Salfred}; 352184610Salfred 353184610Salfredstatic int 354184610Salfredums_probe(device_t dev) 355184610Salfred{ 356192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 357184610Salfred void *d_ptr; 358188981Sthompsa int error; 359184610Salfred uint16_t d_len; 360184610Salfred 361184610Salfred DPRINTFN(11, "\n"); 362184610Salfred 363192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 364184610Salfred return (ENXIO); 365188981Sthompsa 366194068Sthompsa if (uaa->info.bInterfaceClass != UICLASS_HID) 367184610Salfred return (ENXIO); 368188981Sthompsa 369194068Sthompsa if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) && 370194068Sthompsa (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE)) 371199169Snwhitehorn return (BUS_PROBE_GENERIC); 372194068Sthompsa 373194228Sthompsa error = usbd_req_get_hid_desc(uaa->device, NULL, 374184610Salfred &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); 375184610Salfred 376188981Sthompsa if (error) 377184610Salfred return (ENXIO); 378188981Sthompsa 379184610Salfred if (hid_is_collection(d_ptr, d_len, 380188981Sthompsa HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) 381199169Snwhitehorn error = BUS_PROBE_GENERIC; 382188981Sthompsa else 383184610Salfred error = ENXIO; 384184610Salfred 385184610Salfred free(d_ptr, M_TEMP); 386184610Salfred return (error); 387184610Salfred} 388184610Salfred 389190741Sthompsastatic void 390190741Sthompsaums_hid_parse(struct ums_softc *sc, device_t dev, const uint8_t *buf, 391190741Sthompsa uint16_t len, uint8_t index) 392184610Salfred{ 393190741Sthompsa struct ums_info *info = &sc->sc_info[index]; 394184610Salfred uint32_t flags; 395184610Salfred uint8_t i; 396184610Salfred 397190741Sthompsa if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), 398190741Sthompsa hid_input, index, &info->sc_loc_x, &flags, &info->sc_iid_x)) { 399184610Salfred 400184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 401190741Sthompsa info->sc_flags |= UMS_FLAG_X_AXIS; 402184610Salfred } 403184610Salfred } 404190741Sthompsa if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), 405190741Sthompsa hid_input, index, &info->sc_loc_y, &flags, &info->sc_iid_y)) { 406184610Salfred 407184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 408190741Sthompsa info->sc_flags |= UMS_FLAG_Y_AXIS; 409184610Salfred } 410184610Salfred } 411184610Salfred /* Try the wheel first as the Z activator since it's tradition. */ 412190741Sthompsa if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, 413190741Sthompsa HUG_WHEEL), hid_input, index, &info->sc_loc_z, &flags, 414190741Sthompsa &info->sc_iid_z) || 415190741Sthompsa hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, 416190741Sthompsa HUG_TWHEEL), hid_input, index, &info->sc_loc_z, &flags, 417190741Sthompsa &info->sc_iid_z)) { 418184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 419190741Sthompsa info->sc_flags |= UMS_FLAG_Z_AXIS; 420184610Salfred } 421184610Salfred /* 422184610Salfred * We might have both a wheel and Z direction, if so put 423184610Salfred * put the Z on the W coordinate. 424184610Salfred */ 425190741Sthompsa if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, 426190741Sthompsa HUG_Z), hid_input, index, &info->sc_loc_w, &flags, 427190741Sthompsa &info->sc_iid_w)) { 428184610Salfred 429184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 430190741Sthompsa info->sc_flags |= UMS_FLAG_W_AXIS; 431184610Salfred } 432184610Salfred } 433190741Sthompsa } else if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, 434190741Sthompsa HUG_Z), hid_input, index, &info->sc_loc_z, &flags, 435190741Sthompsa &info->sc_iid_z)) { 436184610Salfred 437184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 438190741Sthompsa info->sc_flags |= UMS_FLAG_Z_AXIS; 439184610Salfred } 440184610Salfred } 441184610Salfred /* 442184610Salfred * The Microsoft Wireless Intellimouse 2.0 reports it's wheel 443184610Salfred * using 0x0048, which is HUG_TWHEEL, and seems to expect you 444184610Salfred * to know that the byte after the wheel is the tilt axis. 445184610Salfred * There are no other HID axis descriptors other than X,Y and 446184610Salfred * TWHEEL 447184610Salfred */ 448190741Sthompsa if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, 449190741Sthompsa HUG_TWHEEL), hid_input, index, &info->sc_loc_t, 450190741Sthompsa &flags, &info->sc_iid_t)) { 451184610Salfred 452190741Sthompsa info->sc_loc_t.pos += 8; 453184610Salfred 454184610Salfred if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { 455190741Sthompsa info->sc_flags |= UMS_FLAG_T_AXIS; 456184610Salfred } 457184610Salfred } 458184610Salfred /* figure out the number of buttons */ 459184610Salfred 460184610Salfred for (i = 0; i < UMS_BUTTON_MAX; i++) { 461190741Sthompsa if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)), 462190741Sthompsa hid_input, index, &info->sc_loc_btn[i], NULL, 463190741Sthompsa &info->sc_iid_btn[i])) { 464184610Salfred break; 465184610Salfred } 466184610Salfred } 467190741Sthompsa info->sc_buttons = i; 468184610Salfred 469190741Sthompsa if (i > sc->sc_buttons) 470190741Sthompsa sc->sc_buttons = i; 471184610Salfred 472190741Sthompsa if (info->sc_flags == 0) 473190741Sthompsa return; 474190741Sthompsa 475190741Sthompsa /* announce information about the mouse */ 476190741Sthompsa device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n", 477190741Sthompsa (info->sc_buttons), 478190741Sthompsa (info->sc_flags & UMS_FLAG_X_AXIS) ? "X" : "", 479190741Sthompsa (info->sc_flags & UMS_FLAG_Y_AXIS) ? "Y" : "", 480190741Sthompsa (info->sc_flags & UMS_FLAG_Z_AXIS) ? "Z" : "", 481190741Sthompsa (info->sc_flags & UMS_FLAG_T_AXIS) ? "T" : "", 482190741Sthompsa (info->sc_flags & UMS_FLAG_W_AXIS) ? "W" : "", 483190741Sthompsa info->sc_iid_x); 484190741Sthompsa} 485190741Sthompsa 486190741Sthompsastatic int 487190741Sthompsaums_attach(device_t dev) 488190741Sthompsa{ 489192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 490190741Sthompsa struct ums_softc *sc = device_get_softc(dev); 491190741Sthompsa struct ums_info *info; 492190741Sthompsa void *d_ptr = NULL; 493190741Sthompsa int isize; 494190741Sthompsa int err; 495190741Sthompsa uint16_t d_len; 496190741Sthompsa uint8_t i; 497207077Sthompsa#ifdef USB_DEBUG 498190741Sthompsa uint8_t j; 499207077Sthompsa#endif 500190741Sthompsa 501190741Sthompsa DPRINTFN(11, "sc=%p\n", sc); 502190741Sthompsa 503194228Sthompsa device_set_usb_desc(dev); 504190741Sthompsa 505190741Sthompsa mtx_init(&sc->sc_mtx, "ums lock", NULL, MTX_DEF | MTX_RECURSE); 506190741Sthompsa 507194228Sthompsa usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0); 508190741Sthompsa 509190741Sthompsa /* 510190741Sthompsa * Force the report (non-boot) protocol. 511190741Sthompsa * 512190741Sthompsa * Mice without boot protocol support may choose not to implement 513190741Sthompsa * Set_Protocol at all; Ignore any error. 514190741Sthompsa */ 515194228Sthompsa err = usbd_req_set_protocol(uaa->device, NULL, 516190741Sthompsa uaa->info.bIfaceIndex, 1); 517190741Sthompsa 518194228Sthompsa err = usbd_transfer_setup(uaa->device, 519190741Sthompsa &uaa->info.bIfaceIndex, sc->sc_xfer, ums_config, 520190741Sthompsa UMS_N_TRANSFER, sc, &sc->sc_mtx); 521190741Sthompsa 522190741Sthompsa if (err) { 523194228Sthompsa DPRINTF("error=%s\n", usbd_errstr(err)); 524190741Sthompsa goto detach; 525190741Sthompsa } 526195959Salfred 527195959Salfred /* Get HID descriptor */ 528194228Sthompsa err = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr, 529190741Sthompsa &d_len, M_TEMP, uaa->info.bIfaceIndex); 530190741Sthompsa 531190741Sthompsa if (err) { 532190741Sthompsa device_printf(dev, "error reading report description\n"); 533190741Sthompsa goto detach; 534190741Sthompsa } 535190741Sthompsa 536189583Sthompsa isize = hid_report_size(d_ptr, d_len, hid_input, &sc->sc_iid); 537184610Salfred 538184610Salfred /* 539184610Salfred * The Microsoft Wireless Notebook Optical Mouse seems to be in worse 540184610Salfred * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and 541184610Salfred * all of its other button positions are all off. It also reports that 542184610Salfred * it has two addional buttons and a tilt wheel. 543184610Salfred */ 544194228Sthompsa if (usb_test_quirk(uaa, UQ_MS_BAD_CLASS)) { 545195959Salfred 546195959Salfred sc->sc_iid = 0; 547195959Salfred 548190741Sthompsa info = &sc->sc_info[0]; 549190741Sthompsa info->sc_flags = (UMS_FLAG_X_AXIS | 550184610Salfred UMS_FLAG_Y_AXIS | 551184610Salfred UMS_FLAG_Z_AXIS | 552184610Salfred UMS_FLAG_SBU); 553190741Sthompsa info->sc_buttons = 3; 554184610Salfred isize = 5; 555184610Salfred /* 1st byte of descriptor report contains garbage */ 556190741Sthompsa info->sc_loc_x.pos = 16; 557195959Salfred info->sc_loc_x.size = 8; 558190741Sthompsa info->sc_loc_y.pos = 24; 559195959Salfred info->sc_loc_y.size = 8; 560190741Sthompsa info->sc_loc_z.pos = 32; 561195959Salfred info->sc_loc_z.size = 8; 562190741Sthompsa info->sc_loc_btn[0].pos = 8; 563195959Salfred info->sc_loc_btn[0].size = 1; 564190741Sthompsa info->sc_loc_btn[1].pos = 9; 565195959Salfred info->sc_loc_btn[1].size = 1; 566190741Sthompsa info->sc_loc_btn[2].pos = 10; 567195959Salfred info->sc_loc_btn[2].size = 1; 568188981Sthompsa 569190741Sthompsa /* Announce device */ 570190741Sthompsa device_printf(dev, "3 buttons and [XYZ] " 571190741Sthompsa "coordinates ID=0\n"); 572190741Sthompsa 573190741Sthompsa } else { 574190741Sthompsa /* Search the HID descriptor and announce device */ 575190741Sthompsa for (i = 0; i < UMS_INFO_MAX; i++) { 576190741Sthompsa ums_hid_parse(sc, dev, d_ptr, d_len, i); 577190741Sthompsa } 578184610Salfred } 579188981Sthompsa 580194228Sthompsa if (usb_test_quirk(uaa, UQ_MS_REVZ)) { 581190741Sthompsa info = &sc->sc_info[0]; 582184610Salfred /* Some wheels need the Z axis reversed. */ 583190741Sthompsa info->sc_flags |= UMS_FLAG_REVZ; 584184610Salfred } 585194677Sthompsa if (isize > usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT])) { 586184610Salfred DPRINTF("WARNING: report size, %d bytes, is larger " 587194677Sthompsa "than interrupt size, %d bytes!\n", isize, 588194677Sthompsa usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT])); 589184610Salfred } 590184610Salfred free(d_ptr, M_TEMP); 591184610Salfred d_ptr = NULL; 592184610Salfred 593207077Sthompsa#ifdef USB_DEBUG 594190741Sthompsa for (j = 0; j < UMS_INFO_MAX; j++) { 595190741Sthompsa info = &sc->sc_info[j]; 596184610Salfred 597190741Sthompsa DPRINTF("sc=%p, index=%d\n", sc, j); 598190741Sthompsa DPRINTF("X\t%d/%d id=%d\n", info->sc_loc_x.pos, 599190741Sthompsa info->sc_loc_x.size, info->sc_iid_x); 600190741Sthompsa DPRINTF("Y\t%d/%d id=%d\n", info->sc_loc_y.pos, 601190741Sthompsa info->sc_loc_y.size, info->sc_iid_y); 602190741Sthompsa DPRINTF("Z\t%d/%d id=%d\n", info->sc_loc_z.pos, 603190741Sthompsa info->sc_loc_z.size, info->sc_iid_z); 604190741Sthompsa DPRINTF("T\t%d/%d id=%d\n", info->sc_loc_t.pos, 605190741Sthompsa info->sc_loc_t.size, info->sc_iid_t); 606190741Sthompsa DPRINTF("W\t%d/%d id=%d\n", info->sc_loc_w.pos, 607190741Sthompsa info->sc_loc_w.size, info->sc_iid_w); 608190741Sthompsa 609190741Sthompsa for (i = 0; i < info->sc_buttons; i++) { 610190741Sthompsa DPRINTF("B%d\t%d/%d id=%d\n", 611190741Sthompsa i + 1, info->sc_loc_btn[i].pos, 612190741Sthompsa info->sc_loc_btn[i].size, info->sc_iid_btn[i]); 613190741Sthompsa } 614184610Salfred } 615184610Salfred DPRINTF("size=%d, id=%d\n", isize, sc->sc_iid); 616184610Salfred#endif 617184610Salfred 618184610Salfred if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON) 619184610Salfred sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON; 620184610Salfred else 621184610Salfred sc->sc_hw.buttons = sc->sc_buttons; 622184610Salfred 623184610Salfred sc->sc_hw.iftype = MOUSE_IF_USB; 624184610Salfred sc->sc_hw.type = MOUSE_MOUSE; 625184610Salfred sc->sc_hw.model = MOUSE_MODEL_GENERIC; 626184610Salfred sc->sc_hw.hwid = 0; 627184610Salfred 628184610Salfred sc->sc_mode.protocol = MOUSE_PROTO_MSC; 629184610Salfred sc->sc_mode.rate = -1; 630184610Salfred sc->sc_mode.resolution = MOUSE_RES_UNKNOWN; 631184610Salfred sc->sc_mode.accelfactor = 0; 632184610Salfred sc->sc_mode.level = 0; 633184610Salfred sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 634184610Salfred sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 635184610Salfred sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 636184610Salfred 637194228Sthompsa err = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, 638184610Salfred &ums_fifo_methods, &sc->sc_fifo, 639190741Sthompsa device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, 640189110Sthompsa UID_ROOT, GID_OPERATOR, 0644); 641184610Salfred if (err) { 642184610Salfred goto detach; 643184610Salfred } 644198373Sthompsa SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 645198373Sthompsa SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 646198373Sthompsa OID_AUTO, "parseinfo", CTLTYPE_STRING|CTLFLAG_RD, 647198373Sthompsa sc, 0, ums_sysctl_handler_parseinfo, 648198373Sthompsa "", "Dump UMS report parsing information"); 649198373Sthompsa 650184610Salfred return (0); 651184610Salfred 652184610Salfreddetach: 653184610Salfred if (d_ptr) { 654184610Salfred free(d_ptr, M_TEMP); 655184610Salfred } 656184610Salfred ums_detach(dev); 657184610Salfred return (ENOMEM); 658184610Salfred} 659184610Salfred 660184610Salfredstatic int 661184610Salfredums_detach(device_t self) 662184610Salfred{ 663184610Salfred struct ums_softc *sc = device_get_softc(self); 664184610Salfred 665184610Salfred DPRINTF("sc=%p\n", sc); 666184610Salfred 667194228Sthompsa usb_fifo_detach(&sc->sc_fifo); 668184610Salfred 669194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER); 670184610Salfred 671194228Sthompsa usb_callout_drain(&sc->sc_callout); 672184610Salfred 673184610Salfred mtx_destroy(&sc->sc_mtx); 674184610Salfred 675184610Salfred return (0); 676184610Salfred} 677184610Salfred 678184610Salfredstatic void 679192984Sthompsaums_start_read(struct usb_fifo *fifo) 680184610Salfred{ 681194677Sthompsa struct ums_softc *sc = usb_fifo_softc(fifo); 682195959Salfred int rate; 683184610Salfred 684195959Salfred /* Check if we should override the default polling interval */ 685195959Salfred rate = sc->sc_pollrate; 686195959Salfred /* Range check rate */ 687195959Salfred if (rate > 1000) 688195959Salfred rate = 1000; 689195959Salfred /* Check for set rate */ 690195959Salfred if ((rate > 0) && (sc->sc_xfer[UMS_INTR_DT] != NULL)) { 691195959Salfred DPRINTF("Setting pollrate = %d\n", rate); 692195959Salfred /* Stop current transfer, if any */ 693195959Salfred usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]); 694195959Salfred /* Set new interval */ 695195959Salfred usbd_xfer_set_interval(sc->sc_xfer[UMS_INTR_DT], 1000 / rate); 696195959Salfred /* Only set pollrate once */ 697195959Salfred sc->sc_pollrate = 0; 698195959Salfred } 699195959Salfred 700194228Sthompsa usbd_transfer_start(sc->sc_xfer[UMS_INTR_DT]); 701184610Salfred} 702184610Salfred 703184610Salfredstatic void 704192984Sthompsaums_stop_read(struct usb_fifo *fifo) 705184610Salfred{ 706194677Sthompsa struct ums_softc *sc = usb_fifo_softc(fifo); 707184610Salfred 708194228Sthompsa usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]); 709194228Sthompsa usb_callout_stop(&sc->sc_callout); 710184610Salfred} 711184610Salfred 712184610Salfred 713184610Salfred#if ((MOUSE_SYS_PACKETSIZE != 8) || \ 714184610Salfred (MOUSE_MSC_PACKETSIZE != 5)) 715184610Salfred#error "Software assumptions are not met. Please update code." 716184610Salfred#endif 717184610Salfred 718184610Salfredstatic void 719184610Salfredums_put_queue(struct ums_softc *sc, int32_t dx, int32_t dy, 720184610Salfred int32_t dz, int32_t dt, int32_t buttons) 721184610Salfred{ 722184610Salfred uint8_t buf[8]; 723184610Salfred 724184610Salfred if (1) { 725184610Salfred 726184610Salfred if (dx > 254) 727184610Salfred dx = 254; 728184610Salfred if (dx < -256) 729184610Salfred dx = -256; 730184610Salfred if (dy > 254) 731184610Salfred dy = 254; 732184610Salfred if (dy < -256) 733184610Salfred dy = -256; 734184610Salfred if (dz > 126) 735184610Salfred dz = 126; 736184610Salfred if (dz < -128) 737184610Salfred dz = -128; 738184610Salfred if (dt > 126) 739184610Salfred dt = 126; 740184610Salfred if (dt < -128) 741184610Salfred dt = -128; 742184610Salfred 743184610Salfred buf[0] = sc->sc_mode.syncmask[1]; 744184610Salfred buf[0] |= (~buttons) & MOUSE_MSC_BUTTONS; 745184610Salfred buf[1] = dx >> 1; 746184610Salfred buf[2] = dy >> 1; 747184610Salfred buf[3] = dx - (dx >> 1); 748184610Salfred buf[4] = dy - (dy >> 1); 749184610Salfred 750184610Salfred if (sc->sc_mode.level == 1) { 751184610Salfred buf[5] = dz >> 1; 752184610Salfred buf[6] = dz - (dz >> 1); 753184610Salfred buf[7] = (((~buttons) >> 3) & MOUSE_SYS_EXTBUTTONS); 754184610Salfred } 755194228Sthompsa usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, 756184610Salfred sc->sc_mode.packetsize, 1); 757184610Salfred 758184610Salfred } else { 759184610Salfred DPRINTF("Buffer full, discarded packet\n"); 760184610Salfred } 761184610Salfred} 762184610Salfred 763184610Salfredstatic void 764184610Salfredums_reset_buf(struct ums_softc *sc) 765184610Salfred{ 766184610Salfred /* reset read queue */ 767194228Sthompsa usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]); 768184610Salfred} 769184610Salfred 770184610Salfredstatic int 771192984Sthompsaums_open(struct usb_fifo *fifo, int fflags) 772184610Salfred{ 773194677Sthompsa struct ums_softc *sc = usb_fifo_softc(fifo); 774184610Salfred 775184610Salfred DPRINTFN(2, "\n"); 776184610Salfred 777184610Salfred if (fflags & FREAD) { 778184610Salfred 779184610Salfred /* reset status */ 780184610Salfred 781184610Salfred sc->sc_status.flags = 0; 782184610Salfred sc->sc_status.button = 0; 783184610Salfred sc->sc_status.obutton = 0; 784184610Salfred sc->sc_status.dx = 0; 785184610Salfred sc->sc_status.dy = 0; 786184610Salfred sc->sc_status.dz = 0; 787184610Salfred /* sc->sc_status.dt = 0; */ 788184610Salfred 789194228Sthompsa if (usb_fifo_alloc_buffer(fifo, 790184610Salfred UMS_BUF_SIZE, UMS_IFQ_MAXLEN)) { 791184610Salfred return (ENOMEM); 792184610Salfred } 793184610Salfred } 794184610Salfred return (0); 795184610Salfred} 796184610Salfred 797184610Salfredstatic void 798192984Sthompsaums_close(struct usb_fifo *fifo, int fflags) 799184610Salfred{ 800184610Salfred if (fflags & FREAD) { 801194228Sthompsa usb_fifo_free_buffer(fifo); 802184610Salfred } 803184610Salfred} 804184610Salfred 805184610Salfredstatic int 806192984Sthompsaums_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) 807184610Salfred{ 808194677Sthompsa struct ums_softc *sc = usb_fifo_softc(fifo); 809184610Salfred mousemode_t mode; 810184610Salfred int error = 0; 811184610Salfred 812184610Salfred DPRINTFN(2, "\n"); 813184610Salfred 814184610Salfred mtx_lock(&sc->sc_mtx); 815184610Salfred 816184610Salfred switch (cmd) { 817184610Salfred case MOUSE_GETHWINFO: 818184610Salfred *(mousehw_t *)addr = sc->sc_hw; 819184610Salfred break; 820184610Salfred 821184610Salfred case MOUSE_GETMODE: 822184610Salfred *(mousemode_t *)addr = sc->sc_mode; 823184610Salfred break; 824184610Salfred 825184610Salfred case MOUSE_SETMODE: 826184610Salfred mode = *(mousemode_t *)addr; 827184610Salfred 828184610Salfred if (mode.level == -1) { 829184610Salfred /* don't change the current setting */ 830184610Salfred } else if ((mode.level < 0) || (mode.level > 1)) { 831184610Salfred error = EINVAL; 832184610Salfred goto done; 833184610Salfred } else { 834184610Salfred sc->sc_mode.level = mode.level; 835184610Salfred } 836184610Salfred 837195959Salfred /* store polling rate */ 838195959Salfred sc->sc_pollrate = mode.rate; 839195959Salfred 840184610Salfred if (sc->sc_mode.level == 0) { 841184610Salfred if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON) 842184610Salfred sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON; 843184610Salfred else 844184610Salfred sc->sc_hw.buttons = sc->sc_buttons; 845184610Salfred sc->sc_mode.protocol = MOUSE_PROTO_MSC; 846184610Salfred sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 847184610Salfred sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 848184610Salfred sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 849184610Salfred } else if (sc->sc_mode.level == 1) { 850184610Salfred if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON) 851184610Salfred sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON; 852184610Salfred else 853184610Salfred sc->sc_hw.buttons = sc->sc_buttons; 854184610Salfred sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 855184610Salfred sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 856184610Salfred sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 857184610Salfred sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 858184610Salfred } 859184610Salfred ums_reset_buf(sc); 860184610Salfred break; 861184610Salfred 862184610Salfred case MOUSE_GETLEVEL: 863184610Salfred *(int *)addr = sc->sc_mode.level; 864184610Salfred break; 865184610Salfred 866184610Salfred case MOUSE_SETLEVEL: 867184610Salfred if (*(int *)addr < 0 || *(int *)addr > 1) { 868184610Salfred error = EINVAL; 869184610Salfred goto done; 870184610Salfred } 871184610Salfred sc->sc_mode.level = *(int *)addr; 872184610Salfred 873184610Salfred if (sc->sc_mode.level == 0) { 874184610Salfred if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON) 875184610Salfred sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON; 876184610Salfred else 877184610Salfred sc->sc_hw.buttons = sc->sc_buttons; 878184610Salfred sc->sc_mode.protocol = MOUSE_PROTO_MSC; 879184610Salfred sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE; 880184610Salfred sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK; 881184610Salfred sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; 882184610Salfred } else if (sc->sc_mode.level == 1) { 883184610Salfred if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON) 884184610Salfred sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON; 885184610Salfred else 886184610Salfred sc->sc_hw.buttons = sc->sc_buttons; 887184610Salfred sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE; 888184610Salfred sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE; 889184610Salfred sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK; 890184610Salfred sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC; 891184610Salfred } 892184610Salfred ums_reset_buf(sc); 893184610Salfred break; 894184610Salfred 895184610Salfred case MOUSE_GETSTATUS:{ 896184610Salfred mousestatus_t *status = (mousestatus_t *)addr; 897184610Salfred 898184610Salfred *status = sc->sc_status; 899184610Salfred sc->sc_status.obutton = sc->sc_status.button; 900184610Salfred sc->sc_status.button = 0; 901184610Salfred sc->sc_status.dx = 0; 902184610Salfred sc->sc_status.dy = 0; 903184610Salfred sc->sc_status.dz = 0; 904184610Salfred /* sc->sc_status.dt = 0; */ 905184610Salfred 906184610Salfred if (status->dx || status->dy || status->dz /* || status->dt */ ) { 907184610Salfred status->flags |= MOUSE_POSCHANGED; 908184610Salfred } 909184610Salfred if (status->button != status->obutton) { 910184610Salfred status->flags |= MOUSE_BUTTONSCHANGED; 911184610Salfred } 912184610Salfred break; 913184610Salfred } 914184610Salfred default: 915184610Salfred error = ENOTTY; 916184610Salfred } 917184610Salfred 918184610Salfreddone: 919184610Salfred mtx_unlock(&sc->sc_mtx); 920184610Salfred return (error); 921184610Salfred} 922184610Salfred 923198373Sthompsastatic int 924198373Sthompsaums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS) 925198373Sthompsa{ 926198373Sthompsa struct ums_softc *sc = arg1; 927198373Sthompsa struct ums_info *info; 928198373Sthompsa struct sbuf *sb; 929198373Sthompsa int i, j, err; 930198373Sthompsa 931198373Sthompsa sb = sbuf_new_auto(); 932198373Sthompsa for (i = 0; i < UMS_INFO_MAX; i++) { 933198373Sthompsa info = &sc->sc_info[i]; 934198373Sthompsa 935198373Sthompsa /* Don't emit empty info */ 936198373Sthompsa if ((info->sc_flags & 937198373Sthompsa (UMS_FLAG_X_AXIS | UMS_FLAG_Y_AXIS | UMS_FLAG_Z_AXIS | 938198373Sthompsa UMS_FLAG_T_AXIS | UMS_FLAG_W_AXIS)) == 0 && 939198373Sthompsa info->sc_buttons == 0) 940198373Sthompsa continue; 941198373Sthompsa 942198373Sthompsa sbuf_printf(sb, "i%d:", i + 1); 943198373Sthompsa if (info->sc_flags & UMS_FLAG_X_AXIS) 944198373Sthompsa sbuf_printf(sb, " X:r%d, p%d, s%d;", 945198373Sthompsa (int)info->sc_iid_x, 946198373Sthompsa (int)info->sc_loc_x.pos, 947198373Sthompsa (int)info->sc_loc_x.size); 948198373Sthompsa if (info->sc_flags & UMS_FLAG_Y_AXIS) 949198373Sthompsa sbuf_printf(sb, " Y:r%d, p%d, s%d;", 950198373Sthompsa (int)info->sc_iid_y, 951198373Sthompsa (int)info->sc_loc_y.pos, 952198373Sthompsa (int)info->sc_loc_y.size); 953198373Sthompsa if (info->sc_flags & UMS_FLAG_Z_AXIS) 954198373Sthompsa sbuf_printf(sb, " Z:r%d, p%d, s%d;", 955198373Sthompsa (int)info->sc_iid_z, 956198373Sthompsa (int)info->sc_loc_z.pos, 957198373Sthompsa (int)info->sc_loc_z.size); 958198373Sthompsa if (info->sc_flags & UMS_FLAG_T_AXIS) 959198373Sthompsa sbuf_printf(sb, " T:r%d, p%d, s%d;", 960198373Sthompsa (int)info->sc_iid_t, 961198373Sthompsa (int)info->sc_loc_t.pos, 962198373Sthompsa (int)info->sc_loc_t.size); 963198373Sthompsa if (info->sc_flags & UMS_FLAG_W_AXIS) 964198373Sthompsa sbuf_printf(sb, " W:r%d, p%d, s%d;", 965198373Sthompsa (int)info->sc_iid_w, 966198373Sthompsa (int)info->sc_loc_w.pos, 967198373Sthompsa (int)info->sc_loc_w.size); 968198373Sthompsa 969198373Sthompsa for (j = 0; j < info->sc_buttons; j++) { 970198373Sthompsa sbuf_printf(sb, " B%d:r%d, p%d, s%d;", j + 1, 971198373Sthompsa (int)info->sc_iid_btn[j], 972198373Sthompsa (int)info->sc_loc_btn[j].pos, 973198373Sthompsa (int)info->sc_loc_btn[j].size); 974198373Sthompsa } 975198373Sthompsa sbuf_printf(sb, "\n"); 976198373Sthompsa } 977198373Sthompsa sbuf_finish(sb); 978198373Sthompsa err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); 979198373Sthompsa sbuf_delete(sb); 980198373Sthompsa 981198373Sthompsa return (err); 982198373Sthompsa} 983198373Sthompsa 984184610Salfredstatic devclass_t ums_devclass; 985184610Salfred 986184610Salfredstatic device_method_t ums_methods[] = { 987184610Salfred DEVMETHOD(device_probe, ums_probe), 988184610Salfred DEVMETHOD(device_attach, ums_attach), 989184610Salfred DEVMETHOD(device_detach, ums_detach), 990184610Salfred {0, 0} 991184610Salfred}; 992184610Salfred 993184610Salfredstatic driver_t ums_driver = { 994184610Salfred .name = "ums", 995184610Salfred .methods = ums_methods, 996184610Salfred .size = sizeof(struct ums_softc), 997184610Salfred}; 998184610Salfred 999189275SthompsaDRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, NULL, 0); 1000188942SthompsaMODULE_DEPEND(ums, usb, 1, 1, 1); 1001