ims.c revision 1.1
1/* $OpenBSD: ims.c,v 1.1 2016/01/12 01:11:15 jcs Exp $ */
2/*
3 * HID-over-i2c mouse/trackpad driver
4 *
5 * Copyright (c) 2015, 2016 joshua stein <jcs@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/kernel.h>
23#include <sys/device.h>
24#include <sys/ioctl.h>
25
26#include <dev/i2c/i2cvar.h>
27#include <dev/i2c/ihidev.h>
28
29#include <dev/wscons/wsconsio.h>
30#include <dev/wscons/wsmousevar.h>
31
32#include <dev/hid/hid.h>
33#include <dev/hid/hidmsvar.h>
34
35struct ims_softc {
36	struct ihidev	sc_hdev;
37	struct hidms	sc_ms;
38};
39
40void	ims_intr(struct ihidev *addr, void *ibuf, u_int len);
41
42int	ims_enable(void *);
43void	ims_disable(void *);
44int	ims_ioctl(void *, u_long, caddr_t, int, struct proc *);
45
46const struct wsmouse_accessops ims_accessops = {
47	ims_enable,
48	ims_ioctl,
49	ims_disable,
50};
51
52int	ims_match(struct device *, void *, void *);
53void	ims_attach(struct device *, struct device *, void *);
54int	ims_detach(struct device *, int);
55
56struct cfdriver ims_cd = {
57	NULL, "ims", DV_DULL
58};
59
60const struct cfattach ims_ca = {
61	sizeof(struct ims_softc),
62	ims_match,
63	ims_attach,
64	ims_detach
65};
66
67int
68ims_match(struct device *parent, void *match, void *aux)
69{
70	struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
71	int size;
72	void *desc;
73
74	ihidev_get_report_desc(iha->parent, &desc, &size);
75
76	if (hid_is_collection(desc, size, iha->reportid,
77	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER)))
78		return (IMATCH_IFACECLASS);
79
80	if (hid_is_collection(desc, size, iha->reportid,
81	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
82		return (IMATCH_IFACECLASS);
83
84	if (hid_is_collection(desc, size, iha->reportid,
85	    HID_USAGE2(HUP_DIGITIZERS, HUD_PEN)))
86		return (IMATCH_IFACECLASS);
87
88	return (IMATCH_NONE);
89}
90
91void
92ims_attach(struct device *parent, struct device *self, void *aux)
93{
94	struct ims_softc *sc = (struct ims_softc *)self;
95	struct hidms *ms = &sc->sc_ms;
96	struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
97	int size, repid;
98	void *desc;
99
100	sc->sc_hdev.sc_intr = ims_intr;
101	sc->sc_hdev.sc_parent = iha->parent;
102	sc->sc_hdev.sc_report_id = iha->reportid;
103
104	ihidev_get_report_desc(iha->parent, &desc, &size);
105	repid = iha->reportid;
106	sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
107	sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
108	sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
109
110	if (hidms_setup(self, ms, 0, iha->reportid, desc, size) != 0)
111		return;
112
113	hidms_attach(ms, &ims_accessops);
114}
115
116int
117ims_detach(struct device *self, int flags)
118{
119	struct ims_softc *sc = (struct ims_softc *)self;
120	struct hidms *ms = &sc->sc_ms;
121
122	return hidms_detach(ms, flags);
123}
124
125void
126ims_intr(struct ihidev *addr, void *buf, u_int len)
127{
128	struct ims_softc *sc = (struct ims_softc *)addr;
129	struct hidms *ms = &sc->sc_ms;
130
131	if (ms->sc_enabled != 0)
132		hidms_input(ms, (uint8_t *)buf, len);
133}
134
135int
136ims_enable(void *v)
137{
138	struct ims_softc *sc = v;
139	struct hidms *ms = &sc->sc_ms;
140	int rv;
141
142	if ((rv = hidms_enable(ms)) != 0)
143		return rv;
144
145	return ihidev_open(&sc->sc_hdev);
146}
147
148void
149ims_disable(void *v)
150{
151	struct ims_softc *sc = v;
152	struct hidms *ms = &sc->sc_ms;
153
154	hidms_disable(ms);
155	ihidev_close(&sc->sc_hdev);
156}
157
158int
159ims_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
160{
161	struct ims_softc *sc = v;
162	struct hidms *ms = &sc->sc_ms;
163	int rc;
164
165#if 0
166	rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
167	if (rc != -1)
168		return rc;
169#endif
170
171	rc = hidms_ioctl(ms, cmd, data, flag, p);
172	if (rc != -1)
173		return rc;
174
175	switch (cmd) {
176	case WSMOUSEIO_GTYPE:
177		/* XXX: should we set something else? */
178		*(u_int *)data = WSMOUSE_TYPE_USB;
179		return 0;
180	default:
181		return -1;
182	}
183}
184