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