Line data Source code
1 : /* $OpenBSD: ums.c,v 1.43 2016/01/12 19:16:21 jcs Exp $ */
2 : /* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 : * All rights reserved.
7 : *
8 : * This code is derived from software contributed to The NetBSD Foundation
9 : * by Lennart Augustsson (lennart@augustsson.net) at
10 : * Carlstedt Research & Technology.
11 : *
12 : * Redistribution and use in source and binary forms, with or without
13 : * modification, are permitted provided that the following conditions
14 : * are met:
15 : * 1. Redistributions of source code must retain the above copyright
16 : * notice, this list of conditions and the following disclaimer.
17 : * 2. Redistributions in binary form must reproduce the above copyright
18 : * notice, this list of conditions and the following disclaimer in the
19 : * documentation and/or other materials provided with the distribution.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 : * POSSIBILITY OF SUCH DAMAGE.
32 : */
33 :
34 : /*
35 : * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
36 : */
37 :
38 : #include <sys/param.h>
39 : #include <sys/systm.h>
40 : #include <sys/kernel.h>
41 : #include <sys/device.h>
42 : #include <sys/ioctl.h>
43 :
44 : #include <dev/usb/usb.h>
45 : #include <dev/usb/usbhid.h>
46 :
47 : #include <dev/usb/usbdi.h>
48 : #include <dev/usb/usbdi_util.h>
49 : #include <dev/usb/usbdevs.h>
50 : #include <dev/usb/usb_quirks.h>
51 : #include <dev/usb/uhidev.h>
52 :
53 : #include <dev/wscons/wsconsio.h>
54 : #include <dev/wscons/wsmousevar.h>
55 :
56 : #include <dev/hid/hidmsvar.h>
57 :
58 : struct ums_softc {
59 : struct uhidev sc_hdev;
60 : struct hidms sc_ms;
61 : };
62 :
63 : void ums_intr(struct uhidev *addr, void *ibuf, u_int len);
64 :
65 : int ums_enable(void *);
66 : void ums_disable(void *);
67 : int ums_ioctl(void *, u_long, caddr_t, int, struct proc *);
68 :
69 : const struct wsmouse_accessops ums_accessops = {
70 : ums_enable,
71 : ums_ioctl,
72 : ums_disable,
73 : };
74 :
75 : int ums_match(struct device *, void *, void *);
76 : void ums_attach(struct device *, struct device *, void *);
77 : int ums_detach(struct device *, int);
78 :
79 : struct cfdriver ums_cd = {
80 : NULL, "ums", DV_DULL
81 : };
82 :
83 : const struct cfattach ums_ca = {
84 : sizeof(struct ums_softc), ums_match, ums_attach, ums_detach
85 : };
86 :
87 : int
88 0 : ums_match(struct device *parent, void *match, void *aux)
89 : {
90 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
91 0 : int size;
92 0 : void *desc;
93 :
94 0 : uhidev_get_report_desc(uha->parent, &desc, &size);
95 :
96 0 : if (hid_is_collection(desc, size, uha->reportid,
97 : HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER)))
98 0 : return (UMATCH_IFACECLASS);
99 :
100 0 : if (hid_is_collection(desc, size, uha->reportid,
101 : HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
102 0 : return (UMATCH_IFACECLASS);
103 :
104 0 : if (hid_is_collection(desc, size, uha->reportid,
105 : HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)))
106 0 : return (UMATCH_IFACECLASS);
107 :
108 0 : if (hid_is_collection(desc, size, uha->reportid,
109 : HID_USAGE2(HUP_DIGITIZERS, HUD_PEN)))
110 0 : return (UMATCH_IFACECLASS);
111 :
112 0 : return (UMATCH_NONE);
113 0 : }
114 :
115 : void
116 0 : ums_attach(struct device *parent, struct device *self, void *aux)
117 : {
118 0 : struct ums_softc *sc = (struct ums_softc *)self;
119 0 : struct hidms *ms = &sc->sc_ms;
120 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
121 0 : struct usb_attach_arg *uaa = uha->uaa;
122 0 : int size, repid;
123 0 : void *desc;
124 : u_int32_t quirks, qflags = 0;
125 :
126 0 : sc->sc_hdev.sc_intr = ums_intr;
127 0 : sc->sc_hdev.sc_parent = uha->parent;
128 0 : sc->sc_hdev.sc_udev = uaa->device;
129 0 : sc->sc_hdev.sc_report_id = uha->reportid;
130 :
131 0 : quirks = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags;
132 0 : uhidev_get_report_desc(uha->parent, &desc, &size);
133 0 : repid = uha->reportid;
134 0 : sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
135 0 : sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
136 0 : sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
137 :
138 0 : if (quirks & UQ_MS_REVZ)
139 0 : qflags |= HIDMS_REVZ;
140 0 : if (quirks & UQ_SPUR_BUT_UP)
141 0 : qflags |= HIDMS_SPUR_BUT_UP;
142 0 : if (quirks & UQ_MS_BAD_CLASS)
143 0 : qflags |= HIDMS_MS_BAD_CLASS;
144 0 : if (quirks & UQ_MS_LEADING_BYTE)
145 0 : qflags |= HIDMS_LEADINGBYTE;
146 :
147 0 : if (hidms_setup(self, ms, qflags, uha->reportid, desc, size) != 0)
148 0 : return;
149 :
150 : /*
151 : * The Microsoft Wireless Notebook Optical Mouse 3000 Model 1049 has
152 : * five Report IDs: 19, 23, 24, 17, 18 (in the order they appear in
153 : * report descriptor), it seems that report 17 contains the necessary
154 : * mouse information (3-buttons, X, Y, wheel) so we specify it
155 : * manually.
156 : */
157 0 : if (uaa->vendor == USB_VENDOR_MICROSOFT &&
158 0 : uaa->product == USB_PRODUCT_MICROSOFT_WLNOTEBOOK3) {
159 0 : ms->sc_flags = HIDMS_Z;
160 0 : ms->sc_num_buttons = 3;
161 : /* XXX change sc_hdev isize to 5? */
162 0 : ms->sc_loc_x.pos = 8;
163 0 : ms->sc_loc_y.pos = 16;
164 0 : ms->sc_loc_z.pos = 24;
165 0 : ms->sc_loc_btn[0].pos = 0;
166 0 : ms->sc_loc_btn[1].pos = 1;
167 0 : ms->sc_loc_btn[2].pos = 2;
168 0 : }
169 :
170 0 : hidms_attach(ms, &ums_accessops);
171 0 : }
172 :
173 : int
174 0 : ums_detach(struct device *self, int flags)
175 : {
176 0 : struct ums_softc *sc = (struct ums_softc *)self;
177 0 : struct hidms *ms = &sc->sc_ms;
178 :
179 0 : return hidms_detach(ms, flags);
180 : }
181 :
182 : void
183 0 : ums_intr(struct uhidev *addr, void *buf, u_int len)
184 : {
185 0 : struct ums_softc *sc = (struct ums_softc *)addr;
186 0 : struct hidms *ms = &sc->sc_ms;
187 :
188 0 : if (ms->sc_enabled != 0)
189 0 : hidms_input(ms, (uint8_t *)buf, len);
190 0 : }
191 :
192 : int
193 0 : ums_enable(void *v)
194 : {
195 0 : struct ums_softc *sc = v;
196 0 : struct hidms *ms = &sc->sc_ms;
197 : int rv;
198 :
199 0 : if (usbd_is_dying(sc->sc_hdev.sc_udev))
200 0 : return EIO;
201 :
202 0 : if ((rv = hidms_enable(ms)) != 0)
203 0 : return rv;
204 :
205 0 : return uhidev_open(&sc->sc_hdev);
206 0 : }
207 :
208 : void
209 0 : ums_disable(void *v)
210 : {
211 0 : struct ums_softc *sc = v;
212 0 : struct hidms *ms = &sc->sc_ms;
213 :
214 0 : hidms_disable(ms);
215 0 : uhidev_close(&sc->sc_hdev);
216 0 : }
217 :
218 : int
219 0 : ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
220 : {
221 0 : struct ums_softc *sc = v;
222 0 : struct hidms *ms = &sc->sc_ms;
223 : int rc;
224 :
225 0 : rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
226 0 : if (rc != -1)
227 0 : return rc;
228 0 : rc = hidms_ioctl(ms, cmd, data, flag, p);
229 0 : if (rc != -1)
230 0 : return rc;
231 :
232 0 : switch (cmd) {
233 : case WSMOUSEIO_GTYPE:
234 0 : *(u_int *)data = WSMOUSE_TYPE_USB;
235 0 : return 0;
236 : default:
237 0 : return -1;
238 : }
239 0 : }
|