xref: /openbsd-src/sys/dev/i2c/ims.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
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 
35 struct ims_softc {
36 	struct ihidev	sc_hdev;
37 	struct hidms	sc_ms;
38 };
39 
40 void	ims_intr(struct ihidev *addr, void *ibuf, u_int len);
41 
42 int	ims_enable(void *);
43 void	ims_disable(void *);
44 int	ims_ioctl(void *, u_long, caddr_t, int, struct proc *);
45 
46 const struct wsmouse_accessops ims_accessops = {
47 	ims_enable,
48 	ims_ioctl,
49 	ims_disable,
50 };
51 
52 int	ims_match(struct device *, void *, void *);
53 void	ims_attach(struct device *, struct device *, void *);
54 int	ims_detach(struct device *, int);
55 
56 struct cfdriver ims_cd = {
57 	NULL, "ims", DV_DULL
58 };
59 
60 const struct cfattach ims_ca = {
61 	sizeof(struct ims_softc),
62 	ims_match,
63 	ims_attach,
64 	ims_detach
65 };
66 
67 int
68 ims_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 
91 void
92 ims_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 
116 int
117 ims_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 
125 void
126 ims_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 
135 int
136 ims_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 
148 void
149 ims_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 
158 int
159 ims_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