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