1 /* $OpenBSD: ums.c,v 1.38 2013/11/15 08:17:44 pirofti 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 #include <dev/usb/hid.h> 53 54 #include <dev/wscons/wsconsio.h> 55 #include <dev/wscons/wsmousevar.h> 56 57 #include <dev/usb/hidmsvar.h> 58 59 struct ums_softc { 60 struct uhidev sc_hdev; 61 struct hidms sc_ms; 62 }; 63 64 void ums_intr(struct uhidev *addr, void *ibuf, u_int len); 65 66 int ums_enable(void *); 67 void ums_disable(void *); 68 int ums_ioctl(void *, u_long, caddr_t, int, struct proc *); 69 70 const struct wsmouse_accessops ums_accessops = { 71 ums_enable, 72 ums_ioctl, 73 ums_disable, 74 }; 75 76 int ums_match(struct device *, void *, void *); 77 void ums_attach(struct device *, struct device *, void *); 78 int ums_detach(struct device *, int); 79 int ums_activate(struct device *, int); 80 81 struct cfdriver ums_cd = { 82 NULL, "ums", DV_DULL 83 }; 84 85 const struct cfattach ums_ca = { 86 sizeof(struct ums_softc), 87 ums_match, 88 ums_attach, 89 ums_detach, 90 ums_activate, 91 }; 92 93 int 94 ums_match(struct device *parent, void *match, void *aux) 95 { 96 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 97 int size; 98 void *desc; 99 100 uhidev_get_report_desc(uha->parent, &desc, &size); 101 102 if (hid_is_collection(desc, size, uha->reportid, 103 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) 104 return (UMATCH_IFACECLASS); 105 106 if (hid_is_collection(desc, size, uha->reportid, 107 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))) 108 return (UMATCH_IFACECLASS); 109 110 if (hid_is_collection(desc, size, uha->reportid, 111 HID_USAGE2(HUP_DIGITIZERS, HUD_PEN))) 112 return (UMATCH_IFACECLASS); 113 114 return (UMATCH_NONE); 115 } 116 117 void 118 ums_attach(struct device *parent, struct device *self, void *aux) 119 { 120 struct ums_softc *sc = (struct ums_softc *)self; 121 struct hidms *ms = &sc->sc_ms; 122 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 123 struct usb_attach_arg *uaa = uha->uaa; 124 int size, repid; 125 void *desc; 126 u_int32_t quirks; 127 128 sc->sc_hdev.sc_intr = ums_intr; 129 sc->sc_hdev.sc_parent = uha->parent; 130 sc->sc_hdev.sc_udev = uaa->device; 131 sc->sc_hdev.sc_report_id = uha->reportid; 132 133 quirks = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags; 134 uhidev_get_report_desc(uha->parent, &desc, &size); 135 repid = uha->reportid; 136 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 137 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 138 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 139 140 if (hidms_setup(self, ms, quirks, uha->reportid, desc, size) != 0) 141 return; 142 143 /* 144 * The Microsoft Wireless Notebook Optical Mouse 3000 Model 1049 has 145 * five Report IDs: 19, 23, 24, 17, 18 (in the order they appear in 146 * report descriptor), it seems that report 17 contains the necessary 147 * mouse information (3-buttons, X, Y, wheel) so we specify it 148 * manually. 149 */ 150 if (uaa->vendor == USB_VENDOR_MICROSOFT && 151 uaa->product == USB_PRODUCT_MICROSOFT_WLNOTEBOOK3) { 152 ms->sc_flags = HIDMS_Z; 153 ms->sc_num_buttons = 3; 154 /* XXX change sc_hdev isize to 5? */ 155 ms->sc_loc_x.pos = 8; 156 ms->sc_loc_y.pos = 16; 157 ms->sc_loc_z.pos = 24; 158 ms->sc_loc_btn[0].pos = 0; 159 ms->sc_loc_btn[1].pos = 1; 160 ms->sc_loc_btn[2].pos = 2; 161 } 162 163 hidms_attach(ms, &ums_accessops); 164 } 165 166 int 167 ums_activate(struct device *self, int act) 168 { 169 struct ums_softc *sc = (struct ums_softc *)self; 170 struct hidms *ms = &sc->sc_ms; 171 int rv = 0; 172 173 switch (act) { 174 case DVACT_DEACTIVATE: 175 if (ms->sc_wsmousedev != NULL) 176 rv = config_deactivate(ms->sc_wsmousedev); 177 break; 178 } 179 return (rv); 180 } 181 182 int 183 ums_detach(struct device *self, int flags) 184 { 185 struct ums_softc *sc = (struct ums_softc *)self; 186 struct hidms *ms = &sc->sc_ms; 187 188 return hidms_detach(ms, flags); 189 } 190 191 void 192 ums_intr(struct uhidev *addr, void *buf, u_int len) 193 { 194 struct ums_softc *sc = (struct ums_softc *)addr; 195 struct hidms *ms = &sc->sc_ms; 196 197 if (ms->sc_enabled != 0) 198 hidms_input(ms, (uint8_t *)buf, len); 199 } 200 201 int 202 ums_enable(void *v) 203 { 204 struct ums_softc *sc = v; 205 struct hidms *ms = &sc->sc_ms; 206 int rv; 207 208 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 209 return EIO; 210 211 if ((rv = hidms_enable(ms)) != 0) 212 return rv; 213 214 return uhidev_open(&sc->sc_hdev); 215 } 216 217 void 218 ums_disable(void *v) 219 { 220 struct ums_softc *sc = v; 221 struct hidms *ms = &sc->sc_ms; 222 223 hidms_disable(ms); 224 uhidev_close(&sc->sc_hdev); 225 } 226 227 int 228 ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 229 { 230 struct ums_softc *sc = v; 231 struct hidms *ms = &sc->sc_ms; 232 int rc; 233 234 rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p); 235 if (rc != -1) 236 return rc; 237 rc = hidms_ioctl(ms, cmd, data, flag, p); 238 if (rc != -1) 239 return rc; 240 241 switch (cmd) { 242 case WSMOUSEIO_GTYPE: 243 *(u_int *)data = WSMOUSE_TYPE_USB; 244 return 0; 245 default: 246 return -1; 247 } 248 } 249