1 /* $OpenBSD: umstc.c,v 1.1 2020/05/31 18:15:37 jcs Exp $ */ 2 3 /* 4 * Copyright (c) 2020 joshua stein <jcs@jcs.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Microsoft Surface Type Cover driver to respond to F1-F7 keys, but also to 21 * keep the USB HID pipes open or else the Type Cover will detach and reattach 22 * each time one of these buttons is pressed. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/kernel.h> 28 #include <sys/device.h> 29 30 #include <dev/usb/usb.h> 31 #include <dev/usb/usbhid.h> 32 #include <dev/usb/usbdi.h> 33 #include <dev/usb/usbdevs.h> 34 #include <dev/usb/uhidev.h> 35 36 #include <dev/wscons/wsconsio.h> 37 #include <dev/wscons/wsdisplayvar.h> 38 39 #include "audio.h" 40 #include "wsdisplay.h" 41 42 struct umstc_softc { 43 struct uhidev sc_hdev; 44 }; 45 46 void umstc_intr(struct uhidev *addr, void *ibuf, u_int len); 47 int umstc_match(struct device *, void *, void *); 48 void umstc_attach(struct device *, struct device *, void *); 49 int umstc_detach(struct device *, int flags); 50 51 extern int wskbd_set_mixervolume(long, long); 52 53 struct cfdriver umstc_cd = { 54 NULL, "umstc", DV_DULL 55 }; 56 57 const struct cfattach umstc_ca = { 58 sizeof(struct umstc_softc), 59 umstc_match, 60 umstc_attach, 61 umstc_detach, 62 }; 63 64 static const struct usb_devno umstc_devs[] = { 65 { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_TYPECOVER }, 66 { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_TYPECOVER2 }, 67 }; 68 69 int 70 umstc_match(struct device *parent, void *match, void *aux) 71 { 72 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 73 int size; 74 void *desc; 75 76 if (!usb_lookup(umstc_devs, uha->uaa->vendor, uha->uaa->product)) 77 return UMATCH_NONE; 78 79 uhidev_get_report_desc(uha->parent, &desc, &size); 80 81 if (hid_is_collection(desc, size, uha->reportid, 82 HID_USAGE2(HUP_CONSUMER, HUC_CONTROL))) 83 return UMATCH_IFACECLASS; 84 85 return UMATCH_NONE; 86 } 87 88 void 89 umstc_attach(struct device *parent, struct device *self, void *aux) 90 { 91 struct umstc_softc *sc = (struct umstc_softc *)self; 92 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 93 struct usb_attach_arg *uaa = uha->uaa; 94 int size, repid; 95 void *desc; 96 97 sc->sc_hdev.sc_intr = umstc_intr; 98 sc->sc_hdev.sc_parent = uha->parent; 99 sc->sc_hdev.sc_udev = uaa->device; 100 sc->sc_hdev.sc_report_id = uha->reportid; 101 102 uhidev_get_report_desc(uha->parent, &desc, &size); 103 repid = uha->reportid; 104 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 105 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 106 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 107 108 uhidev_open(&sc->sc_hdev); 109 110 printf("\n"); 111 } 112 113 int 114 umstc_detach(struct device *self, int flags) 115 { 116 struct umstc_softc *sc = (struct umstc_softc *)self; 117 118 uhidev_close(&sc->sc_hdev); 119 120 return 0; 121 } 122 123 void 124 umstc_intr(struct uhidev *addr, void *buf, u_int len) 125 { 126 struct umstc_softc *sc = (struct umstc_softc *)addr; 127 int i; 128 129 if (!len) 130 return; 131 132 switch (((unsigned char *)buf)[0]) { 133 case HUC_PLAY_PAUSE: 134 /* 135 * It would be nice to pass this through to userland but we'd 136 * need to attach a wskbd 137 */ 138 break; 139 case HUC_MUTE: 140 #if NAUDIO > 0 141 wskbd_set_mixervolume(0, 1); 142 #endif 143 break; 144 case HUC_VOL_INC: 145 #if NAUDIO > 0 146 wskbd_set_mixervolume(1, 1); 147 #endif 148 break; 149 case HUC_VOL_DEC: 150 #if NAUDIO > 0 151 wskbd_set_mixervolume(-1, 1); 152 #endif 153 break; 154 case 0x70: /* brightness down */ 155 #if NWSDISPLAY > 0 156 wsdisplay_brightness_step(NULL, -1); 157 #endif 158 break; 159 case 0x6f: /* brightness up */ 160 #if NWSDISPLAY > 0 161 wsdisplay_brightness_step(NULL, 1); 162 #endif 163 break; 164 case 0: 165 break; 166 default: 167 printf("%s: unhandled key ", sc->sc_hdev.sc_dev.dv_xname); 168 for (i = 0; i < len; i++) 169 printf(" 0x%02x", ((unsigned char *)buf)[i]); 170 printf("\n"); 171 } 172 } 173