1117397Skan/* $OpenBSD: ims.c,v 1.3 2021/01/22 17:35:00 jcs Exp $ */
2117397Skan/*
3169691Skan * HID-over-i2c mouse/trackpad driver
4117397Skan *
5117397Skan * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org>
6117397Skan *
7117397Skan * Permission to use, copy, modify, and distribute this software for any
8117397Skan * purpose with or without fee is hereby granted, provided that the above
9117397Skan * copyright notice and this permission notice appear in all copies.
10117397Skan *
11117397Skan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12117397Skan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13117397Skan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14117397Skan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15117397Skan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16117397Skan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17117397Skan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18169691Skan */
19117397Skan
20117397Skan#include <sys/param.h>
21117397Skan#include <sys/systm.h>
22117397Skan#include <sys/kernel.h>
23117397Skan#include <sys/device.h>
24117397Skan#include <sys/ioctl.h>
25117397Skan
26117397Skan#include <dev/i2c/i2cvar.h>
27117397Skan#include <dev/i2c/ihidev.h>
28117397Skan
29117397Skan#include <dev/wscons/wsconsio.h>
30117397Skan#include <dev/wscons/wsmousevar.h>
31117397Skan
32117397Skan#include <dev/hid/hid.h>
33117397Skan#include <dev/hid/hidmsvar.h>
34117397Skan
35117397Skanstruct ims_softc {
36117397Skan	struct ihidev	sc_hdev;
37117397Skan	struct hidms	sc_ms;
38117397Skan};
39117397Skan
40117397Skanvoid	ims_intr(struct ihidev *addr, void *ibuf, u_int len);
41117397Skan
42117397Skanint	ims_enable(void *);
43117397Skanvoid	ims_disable(void *);
44117397Skanint	ims_ioctl(void *, u_long, caddr_t, int, struct proc *);
45117397Skan
46117397Skanconst struct wsmouse_accessops ims_accessops = {
47117397Skan	ims_enable,
48117397Skan	ims_ioctl,
49117397Skan	ims_disable,
50117397Skan};
51117397Skan
52117397Skanint	ims_match(struct device *, void *, void *);
53117397Skanvoid	ims_attach(struct device *, struct device *, void *);
54117397Skanint	ims_detach(struct device *, int);
55117397Skan
56117397Skanstruct cfdriver ims_cd = {
57117397Skan	NULL, "ims", DV_DULL
58117397Skan};
59117397Skan
60117397Skanconst struct cfattach ims_ca = {
61132720Skan	sizeof(struct ims_softc),
62132720Skan	ims_match,
63117397Skan	ims_attach,
64169691Skan	ims_detach
65169691Skan};
66117397Skan
67117397Skanint
68169691Skanims_match(struct device *parent, void *match, void *aux)
69117397Skan{
70117397Skan	struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
71117397Skan	int size;
72132720Skan	void *desc;
73117397Skan
74117397Skan	ihidev_get_report_desc(iha->parent, &desc, &size);
75117397Skan
76169691Skan	if (hid_is_collection(desc, size, iha->reportid,
77132720Skan	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER)))
78169691Skan		return (IMATCH_IFACECLASS);
79169691Skan
80132720Skan	if (hid_is_collection(desc, size, iha->reportid,
81169691Skan	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
82169691Skan		return (IMATCH_IFACECLASS);
83132720Skan
84132720Skan	if (hid_is_collection(desc, size, iha->reportid,
85132720Skan	    HID_USAGE2(HUP_DIGITIZERS, HUD_PEN)))
86117397Skan		return (IMATCH_IFACECLASS);
87117397Skan
88132720Skan	if (hid_is_collection(desc, size, iha->reportid,
89117397Skan	    HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)) &&
90169691Skan	    hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
91169691Skan	    iha->reportid, hid_input, NULL, NULL))
92117397Skan		return (IMATCH_IFACECLASS);
93117397Skan
94169691Skan	return (IMATCH_NONE);
95169691Skan}
96169691Skan
97169691Skanvoid
98169691Skanims_attach(struct device *parent, struct device *self, void *aux)
99169691Skan{
100169691Skan	struct ims_softc *sc = (struct ims_softc *)self;
101117397Skan	struct hidms *ms = &sc->sc_ms;
102117397Skan	struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
103169691Skan	int size, repid;
104117397Skan	void *desc;
105132720Skan
106117397Skan	sc->sc_hdev.sc_intr = ims_intr;
107169691Skan	sc->sc_hdev.sc_parent = iha->parent;
108169691Skan	sc->sc_hdev.sc_report_id = iha->reportid;
109117397Skan
110117397Skan	ihidev_get_report_desc(iha->parent, &desc, &size);
111117397Skan	repid = iha->reportid;
112132720Skan	sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
113132720Skan	sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
114169691Skan	sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
115117397Skan
116117397Skan	if (hidms_setup(self, ms, 0, iha->reportid, desc, size) != 0)
117132720Skan		return;
118117397Skan
119169691Skan	hidms_attach(ms, &ims_accessops);
120169691Skan}
121117397Skan
122117397Skanint
123169691Skanims_detach(struct device *self, int flags)
124169691Skan{
125169691Skan	struct ims_softc *sc = (struct ims_softc *)self;
126117397Skan	struct hidms *ms = &sc->sc_ms;
127117397Skan
128132720Skan	return hidms_detach(ms, flags);
129117397Skan}
130169691Skan
131169691Skanvoid
132169691Skanims_intr(struct ihidev *addr, void *buf, u_int len)
133117397Skan{
134117397Skan	struct ims_softc *sc = (struct ims_softc *)addr;
135169691Skan	struct hidms *ms = &sc->sc_ms;
136169691Skan
137169691Skan	if (ms->sc_enabled != 0)
138169691Skan		hidms_input(ms, (uint8_t *)buf, len);
139169691Skan}
140169691Skan
141169691Skanint
142169691Skanims_enable(void *v)
143169691Skan{
144169691Skan	struct ims_softc *sc = v;
145169691Skan	struct hidms *ms = &sc->sc_ms;
146169691Skan	int rv;
147169691Skan
148169691Skan	if ((rv = hidms_enable(ms)) != 0)
149169691Skan		return rv;
150169691Skan
151169691Skan	return ihidev_open(&sc->sc_hdev);
152169691Skan}
153169691Skan
154169691Skanvoid
155169691Skanims_disable(void *v)
156169691Skan{
157169691Skan	struct ims_softc *sc = v;
158169691Skan	struct hidms *ms = &sc->sc_ms;
159169691Skan
160169691Skan	hidms_disable(ms);
161169691Skan	ihidev_close(&sc->sc_hdev);
162169691Skan}
163169691Skan
164169691Skanint
165117397Skanims_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
166117397Skan{
167132720Skan	struct ims_softc *sc = v;
168117397Skan	struct hidms *ms = &sc->sc_ms;
169117397Skan	int rc;
170169691Skan
171117397Skan#if 0
172117397Skan	rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
173117397Skan	if (rc != -1)
174169691Skan		return rc;
175169691Skan#endif
176169691Skan
177169691Skan	rc = hidms_ioctl(ms, cmd, data, flag, p);
178117397Skan	if (rc != -1)
179169691Skan		return rc;
180169691Skan
181169691Skan	switch (cmd) {
182169691Skan	case WSMOUSEIO_GTYPE:
183169691Skan		*(u_int *)data = WSMOUSE_TYPE_TOUCHPAD;
184169691Skan		return 0;
185169691Skan	default:
186117397Skan		return -1;
187169691Skan	}
188117397Skan}
189132720Skan