1 /* $NetBSD: hidms.c,v 1.2 2018/05/25 15:52:45 ryoon Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net) at 9 * Carlstedt Research & Technology. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: hidms.c,v 1.2 2018/05/25 15:52:45 ryoon Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/device.h> 44 45 #include <dev/hid/hid.h> 46 #include <dev/hid/hidms.h> 47 48 #ifdef HIDMS_DEBUG 49 #define DPRINTF(x) if (hidmsdebug) printf x 50 #define DPRINTFN(n,x) if (hidmsdebug>(n)) printf x 51 int hidmsdebug = 0; 52 #else 53 #define DPRINTF(x) 54 #define DPRINTFN(n,x) 55 #endif 56 57 #define HIDMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i) 58 59 #define PS2LBUTMASK x01 60 #define PS2RBUTMASK x02 61 #define PS2MBUTMASK x04 62 #define PS2BUTMASK 0x0f 63 64 static const struct { 65 u_int feature; 66 u_int flag; 67 } digbut[] = { 68 { HUD_TIP_SWITCH, HIDMS_TIP_SWITCH }, 69 { HUD_SEC_TIP_SWITCH, HIDMS_SEC_TIP_SWITCH }, 70 { HUD_BARREL_SWITCH, HIDMS_BARREL_SWITCH }, 71 { HUD_ERASER, HIDMS_ERASER }, 72 }; 73 74 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) 75 76 bool 77 hidms_setup(device_t self, struct hidms *ms, int id, void *desc, int size) 78 { 79 uint32_t flags; 80 struct hid_location *zloc; 81 bool isdigitizer; 82 int i, hl; 83 84 isdigitizer = hid_is_collection(desc, size, id, 85 HID_USAGE2(HUP_DIGITIZERS, 0x0002)); 86 87 if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), 88 id, hid_input, &ms->hidms_loc_x, &flags)) { 89 aprint_error("\n%s: mouse has no X report\n", 90 device_xname(self)); 91 return false; 92 } 93 switch (flags & MOUSE_FLAGS_MASK) { 94 case 0: 95 ms->flags |= HIDMS_ABS; 96 break; 97 case HIO_RELATIVE: 98 break; 99 default: 100 aprint_error("\n%s: X report 0x%04x not supported\n", 101 device_xname(self), flags); 102 return false; 103 } 104 105 if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), 106 id, hid_input, &ms->hidms_loc_y, &flags)) { 107 aprint_error("\n%s: mouse has no Y report\n", 108 device_xname(self)); 109 return false; 110 } 111 switch (flags & MOUSE_FLAGS_MASK) { 112 case 0: 113 ms->flags |= HIDMS_ABS; 114 break; 115 case HIO_RELATIVE: 116 break; 117 default: 118 aprint_error("\n%s: Y report 0x%04x not supported\n", 119 device_xname(self), flags); 120 return false; 121 } 122 123 /* Try the wheel first as the Z activator since it's tradition. */ 124 hl = hid_locate(desc, 125 size, 126 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), 127 id, 128 hid_input, 129 &ms->hidms_loc_z, 130 &flags); 131 132 zloc = &ms->hidms_loc_z; 133 if (hl) { 134 if ((flags & MOUSE_FLAGS_MASK) != HIO_RELATIVE) { 135 aprint_verbose("\n%s: Wheel report 0x%04x not " 136 "supported\n", device_xname(self), 137 flags); 138 ms->hidms_loc_z.size = 0; /* Bad Z coord, ignore it */ 139 } else { 140 ms->flags |= HIDMS_Z; 141 /* Wheels need the Z axis reversed. */ 142 ms->flags ^= HIDMS_REVZ; 143 /* Put Z on the W coordinate */ 144 zloc = &ms->hidms_loc_w; 145 } 146 } 147 148 hl = hid_locate(desc, 149 size, 150 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), 151 id, 152 hid_input, 153 zloc, 154 &flags); 155 156 /* 157 * The horizontal component of the scrollball can also be given by 158 * Application Control Pan in the Consumer page, so if we didnt see 159 * any Z then check that. 160 */ 161 if (!hl) { 162 hl = hid_locate(desc, 163 size, 164 HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), 165 id, 166 hid_input, 167 zloc, 168 &flags); 169 } 170 171 if (hl) { 172 if ((flags & MOUSE_FLAGS_MASK) != HIO_RELATIVE) { 173 aprint_verbose("\n%s: Z report 0x%04x not supported\n", 174 device_xname(self), flags); 175 zloc->size = 0; /* Bad Z coord, ignore it */ 176 } else { 177 if (ms->flags & HIDMS_Z) 178 ms->flags |= HIDMS_W; 179 else 180 ms->flags |= HIDMS_Z; 181 } 182 } 183 184 /* figure out the number of buttons */ 185 for (i = 1; i <= MAX_BUTTONS; i++) 186 if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), 187 id, hid_input, &ms->hidms_loc_btn[i - 1], 0)) 188 break; 189 190 if (isdigitizer) { 191 ms->flags |= HIDMS_DIGITIZER; 192 for (size_t j = 0; j < __arraycount(digbut); j++) { 193 if (hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS, 194 digbut[j].feature), id, hid_input, 195 &ms->hidms_loc_btn[i - 1], 0)) { 196 if (i <= MAX_BUTTONS) { 197 i++; 198 ms->flags |= digbut[j].flag; 199 } else 200 aprint_error_dev(self, 201 "ran out of buttons\n"); 202 } 203 } 204 } 205 ms->nbuttons = i - 1; 206 return true; 207 } 208 209 void 210 hidms_attach(device_t self, struct hidms *ms, 211 const struct wsmouse_accessops *ops) 212 { 213 struct wsmousedev_attach_args a; 214 #ifdef HIDMS_DEBUG 215 int i; 216 #endif 217 aprint_normal(": %d button%s%s%s%s%s%s%s%s%s\n", 218 ms->nbuttons, ms->nbuttons == 1 ? "" : "s", 219 ms->flags & HIDMS_W ? ", W" : "", 220 ms->flags & HIDMS_Z ? " and Z dir" : "", 221 ms->flags & HIDMS_W ? "s" : "", 222 ms->flags & HIDMS_DIGITIZER ? " digitizer" : "", 223 ms->flags & HIDMS_TIP_SWITCH ? ", tip" : "", 224 ms->flags & HIDMS_SEC_TIP_SWITCH ? ", sec tip" : "", 225 ms->flags & HIDMS_BARREL_SWITCH ? ", barrel" : "", 226 ms->flags & HIDMS_ERASER ? ", eraser" : ""); 227 228 #ifdef HIDMS_DEBUG 229 DPRINTF(("hidms_attach: ms=%p\n", ms)); 230 DPRINTF(("hidms_attach: X\t%d/%d\n", 231 ms->hidms_loc_x.pos, ms->hidms_loc_x.size)); 232 DPRINTF(("hidms_attach: Y\t%d/%d\n", 233 ms->hidms_loc_y.pos, ms->hidms_loc_y.size)); 234 if (ms->flags & HIDMS_Z) 235 DPRINTF(("hidms_attach: Z\t%d/%d\n", 236 ms->hidms_loc_z.pos, ms->hidms_loc_z.size)); 237 if (ms->flags & HIDMS_W) 238 DPRINTF(("hidms_attach: W\t%d/%d\n", 239 ms->hidms_loc_w.pos, ms->hidms_loc_w.size)); 240 for (i = 1; i <= ms->nbuttons; i++) { 241 DPRINTF(("hidms_attach: B%d\t%d/%d\n", 242 i, ms->hidms_loc_btn[i-1].pos,ms->hidms_loc_btn[i-1].size)); 243 } 244 #endif 245 246 a.accessops = ops; 247 a.accesscookie = device_private(self); 248 249 ms->hidms_wsmousedev = config_found(self, &a, wsmousedevprint); 250 251 return; 252 } 253 254 255 void 256 hidms_intr(struct hidms *ms, void *ibuf, u_int len) 257 { 258 int dx, dy, dz, dw; 259 uint32_t buttons = 0; 260 int i, flags, s; 261 262 DPRINTFN(5,("hidms_intr: len=%d\n", len)); 263 264 flags = WSMOUSE_INPUT_DELTA; /* equals 0 */ 265 266 dx = hid_get_data(ibuf, &ms->hidms_loc_x); 267 if (ms->flags & HIDMS_ABS) { 268 flags |= (WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y); 269 dy = hid_get_data(ibuf, &ms->hidms_loc_y); 270 } else 271 dy = -hid_get_data(ibuf, &ms->hidms_loc_y); 272 dz = hid_get_data(ibuf, &ms->hidms_loc_z); 273 dw = hid_get_data(ibuf, &ms->hidms_loc_w); 274 275 if (ms->flags & HIDMS_REVZ) 276 dz = -dz; 277 for (i = 0; i < ms->nbuttons; i++) 278 if (hid_get_data(ibuf, &ms->hidms_loc_btn[i])) 279 buttons |= (1 << HIDMS_BUT(i)); 280 281 if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || 282 buttons != ms->hidms_buttons) { 283 DPRINTFN(10, ("hidms_intr: x:%d y:%d z:%d w:%d buttons:0x%x\n", 284 dx, dy, dz, dw, buttons)); 285 ms->hidms_buttons = buttons; 286 if (ms->hidms_wsmousedev != NULL) { 287 s = spltty(); 288 wsmouse_input(ms->hidms_wsmousedev, buttons, dx, dy, dz, 289 dw, flags); 290 splx(s); 291 } 292 } 293 } 294