xref: /openbsd/sys/dev/i2c/icc.c (revision 4bdff4be)
1 /*	$OpenBSD: icc.c,v 1.1 2022/11/11 15:25:13 matthieu 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 };
52 
53 int
54 icc_match(struct device *parent, void *match, void *aux)
55 {
56 	struct ihidev_attach_arg *iha = aux;
57 	void *desc;
58 	int size;
59 
60 	if (iha->reportid == IHIDEV_CLAIM_MULTIPLEID)
61 		return IMATCH_NONE;
62 
63 	ihidev_get_report_desc(iha->parent, &desc, &size);
64 	if (hid_report_size(desc, size, hid_input, iha->reportid) == 0)
65 		return IMATCH_NONE;
66 
67 	if (!hidcc_match(desc, size, iha->reportid))
68 		return IMATCH_NONE;
69 	return IMATCH_IFACECLASS;
70 }
71 
72 void
73 icc_attach(struct device *parent, struct device *self, void *aux)
74 {
75 	struct icc_softc *sc = (struct icc_softc *)self;
76 	struct ihidev_attach_arg *iha = aux;
77 	void *desc;
78 	int repid, size;
79 
80 	sc->sc_hdev.sc_intr = icc_intr;
81 	sc->sc_hdev.sc_parent = iha->parent;
82 	sc->sc_hdev.sc_report_id = iha->reportid;
83 
84 	ihidev_get_report_desc(iha->parent, &desc, &size);
85 	repid = iha->reportid;
86 	sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
87 	sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
88 	sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
89 
90 	struct hidcc_attach_arg hca = {
91 		.device		= &sc->sc_hdev.sc_idev,
92 		.audio_cookie	= iha->iaa->ia_cookie,
93 		.desc		= desc,
94 		.descsiz	= size,
95 		.repid		= repid,
96 		.isize		= sc->sc_hdev.sc_isize,
97 		.enable		= icc_enable,
98 		.arg		= self,
99 	};
100 	sc->sc_cc = hidcc_attach(&hca);
101 }
102 
103 int
104 icc_detach(struct device *self, int flags)
105 {
106 	struct icc_softc *sc = (struct icc_softc *)self;
107 	int error = 0;
108 
109 	ihidev_close(&sc->sc_hdev);
110 	if (sc->sc_cc != NULL)
111 		error = hidcc_detach(sc->sc_cc, flags);
112 	return error;
113 }
114 
115 void
116 icc_intr(struct ihidev *addr, void *data, u_int len)
117 {
118 	struct icc_softc *sc = (struct icc_softc *)addr;
119 
120 	if (sc->sc_cc != NULL)
121 		hidcc_intr(sc->sc_cc, data, len);
122 }
123 
124 int
125 icc_enable(void *v, int on)
126 {
127 	struct icc_softc *sc = v;
128 	int error = 0;
129 
130 	if (on)
131 		error = ihidev_open(&sc->sc_hdev);
132 	else
133 		ihidev_close(&sc->sc_hdev);
134 	return error;
135 }
136