xref: /openbsd-src/sys/dev/i2c/icc.c (revision d27ecf16d2ff08a0f90dc58b618b3644d2dca279)
1 /*	$OpenBSD: icc.c,v 1.2 2024/08/17 15:10:00 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org>
5  * Copyright (c) 2022 Matthieu Herrb <matthieu@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/device.h>
23 
24 #include <dev/i2c/i2cvar.h>
25 #include <dev/i2c/ihidev.h>
26 
27 #include <dev/hid/hid.h>
28 #include <dev/hid/hidccvar.h>
29 
30 struct icc_softc {
31 	struct ihidev	 sc_hdev;
32 	struct hidcc	*sc_cc;
33 	int		 sc_keydown;
34 };
35 
36 int	icc_match(struct device *, void *, void *);
37 void	icc_attach(struct device *, struct device *, void *);
38 int	icc_detach(struct device *, int);
39 void	icc_intr(struct ihidev *, void *, u_int);
40 
41 int	icc_enable(void *, int);
42 
43 struct cfdriver icc_cd = {
44 	NULL, "icc", DV_DULL
45 };
46 
47 const struct cfattach icc_ca = {
48 	sizeof(struct icc_softc),
49 	icc_match,
50 	icc_attach,
51 	icc_detach
52 };
53 
54 int
55 icc_match(struct device *parent, void *match, void *aux)
56 {
57 	struct ihidev_attach_arg *iha = aux;
58 	void *desc;
59 	int size;
60 
61 	if (iha->reportid == IHIDEV_CLAIM_MULTIPLEID)
62 		return IMATCH_NONE;
63 
64 	ihidev_get_report_desc(iha->parent, &desc, &size);
65 	if (hid_report_size(desc, size, hid_input, iha->reportid) == 0)
66 		return IMATCH_NONE;
67 
68 	if (!hidcc_match(desc, size, iha->reportid))
69 		return IMATCH_NONE;
70 	return IMATCH_IFACECLASS;
71 }
72 
73 void
74 icc_attach(struct device *parent, struct device *self, void *aux)
75 {
76 	struct icc_softc *sc = (struct icc_softc *)self;
77 	struct ihidev_attach_arg *iha = aux;
78 	void *desc;
79 	int repid, size;
80 
81 	sc->sc_hdev.sc_intr = icc_intr;
82 	sc->sc_hdev.sc_parent = iha->parent;
83 	sc->sc_hdev.sc_report_id = iha->reportid;
84 
85 	ihidev_get_report_desc(iha->parent, &desc, &size);
86 	repid = iha->reportid;
87 	sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
88 	sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
89 	sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
90 
91 	struct hidcc_attach_arg hca = {
92 		.device		= &sc->sc_hdev.sc_idev,
93 		.audio_cookie	= iha->iaa->ia_cookie,
94 		.desc		= desc,
95 		.descsiz	= size,
96 		.repid		= repid,
97 		.isize		= sc->sc_hdev.sc_isize,
98 		.enable		= icc_enable,
99 		.arg		= self,
100 	};
101 	sc->sc_cc = hidcc_attach(&hca);
102 }
103 
104 int
105 icc_detach(struct device *self, int flags)
106 {
107 	struct icc_softc *sc = (struct icc_softc *)self;
108 	int error = 0;
109 
110 	ihidev_close(&sc->sc_hdev);
111 	if (sc->sc_cc != NULL)
112 		error = hidcc_detach(sc->sc_cc, flags);
113 	return error;
114 }
115 
116 void
117 icc_intr(struct ihidev *addr, void *data, u_int len)
118 {
119 	struct icc_softc *sc = (struct icc_softc *)addr;
120 
121 	if (sc->sc_cc != NULL)
122 		hidcc_intr(sc->sc_cc, data, len);
123 }
124 
125 int
126 icc_enable(void *v, int on)
127 {
128 	struct icc_softc *sc = v;
129 	int error = 0;
130 
131 	if (on)
132 		error = ihidev_open(&sc->sc_hdev);
133 	else
134 		ihidev_close(&sc->sc_hdev);
135 	return error;
136 }
137