1 /* $OpenBSD: ims.c,v 1.3 2021/01/22 17:35:00 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
ims_match(struct device * parent,void * match,void * aux)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 if (hid_is_collection(desc, size, iha->reportid,
89 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)) &&
90 hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
91 iha->reportid, hid_input, NULL, NULL))
92 return (IMATCH_IFACECLASS);
93
94 return (IMATCH_NONE);
95 }
96
97 void
ims_attach(struct device * parent,struct device * self,void * aux)98 ims_attach(struct device *parent, struct device *self, void *aux)
99 {
100 struct ims_softc *sc = (struct ims_softc *)self;
101 struct hidms *ms = &sc->sc_ms;
102 struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
103 int size, repid;
104 void *desc;
105
106 sc->sc_hdev.sc_intr = ims_intr;
107 sc->sc_hdev.sc_parent = iha->parent;
108 sc->sc_hdev.sc_report_id = iha->reportid;
109
110 ihidev_get_report_desc(iha->parent, &desc, &size);
111 repid = iha->reportid;
112 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
113 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
114 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
115
116 if (hidms_setup(self, ms, 0, iha->reportid, desc, size) != 0)
117 return;
118
119 hidms_attach(ms, &ims_accessops);
120 }
121
122 int
ims_detach(struct device * self,int flags)123 ims_detach(struct device *self, int flags)
124 {
125 struct ims_softc *sc = (struct ims_softc *)self;
126 struct hidms *ms = &sc->sc_ms;
127
128 return hidms_detach(ms, flags);
129 }
130
131 void
ims_intr(struct ihidev * addr,void * buf,u_int len)132 ims_intr(struct ihidev *addr, void *buf, u_int len)
133 {
134 struct ims_softc *sc = (struct ims_softc *)addr;
135 struct hidms *ms = &sc->sc_ms;
136
137 if (ms->sc_enabled != 0)
138 hidms_input(ms, (uint8_t *)buf, len);
139 }
140
141 int
ims_enable(void * v)142 ims_enable(void *v)
143 {
144 struct ims_softc *sc = v;
145 struct hidms *ms = &sc->sc_ms;
146 int rv;
147
148 if ((rv = hidms_enable(ms)) != 0)
149 return rv;
150
151 return ihidev_open(&sc->sc_hdev);
152 }
153
154 void
ims_disable(void * v)155 ims_disable(void *v)
156 {
157 struct ims_softc *sc = v;
158 struct hidms *ms = &sc->sc_ms;
159
160 hidms_disable(ms);
161 ihidev_close(&sc->sc_hdev);
162 }
163
164 int
ims_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)165 ims_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
166 {
167 struct ims_softc *sc = v;
168 struct hidms *ms = &sc->sc_ms;
169 int rc;
170
171 #if 0
172 rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
173 if (rc != -1)
174 return rc;
175 #endif
176
177 rc = hidms_ioctl(ms, cmd, data, flag, p);
178 if (rc != -1)
179 return rc;
180
181 switch (cmd) {
182 case WSMOUSEIO_GTYPE:
183 *(u_int *)data = WSMOUSE_TYPE_TOUCHPAD;
184 return 0;
185 default:
186 return -1;
187 }
188 }
189