xref: /openbsd-src/sys/dev/usb/umstc.c (revision c020cf82e0cc147236f01a8dca7052034cf9d30d)
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