icc.c revision 1.1
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
30struct icc_softc {
31	struct ihidev	 sc_hdev;
32	struct hidcc	*sc_cc;
33	int		 sc_keydown;
34};
35
36int	icc_match(struct device *, void *, void *);
37void	icc_attach(struct device *, struct device *, void *);
38int	icc_detach(struct device *, int);
39void	icc_intr(struct ihidev *, void *, u_int);
40
41int	icc_enable(void *, int);
42
43struct cfdriver icc_cd = {
44	NULL, "icc", DV_DULL
45};
46
47const struct cfattach icc_ca = {
48	sizeof(struct icc_softc),
49	icc_match,
50	icc_attach,
51};
52
53int
54icc_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
72void
73icc_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
103int
104icc_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
115void
116icc_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
124int
125icc_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