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