Line data Source code
1 : /* $OpenBSD: ikbd.c,v 1.1 2016/01/14 21:01:49 kettenis Exp $ */
2 : /*
3 : * HID-over-i2c keyboard driver
4 : *
5 : * Copyright (c) 2016 Mark Kettenis <kettenis@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 : #include <sys/timeout.h>
26 :
27 : #include <dev/i2c/i2cvar.h>
28 : #include <dev/i2c/ihidev.h>
29 :
30 : #include <dev/wscons/wsconsio.h>
31 : #include <dev/wscons/wskbdvar.h>
32 : #include <dev/wscons/wsksymdef.h>
33 :
34 : #include <dev/hid/hid.h>
35 : #include <dev/hid/hidkbdsc.h>
36 :
37 : struct ikbd_softc {
38 : struct ihidev sc_hdev;
39 : struct hidkbd sc_kbd;
40 : };
41 :
42 : void ikbd_intr(struct ihidev *addr, void *ibuf, u_int len);
43 :
44 : int ikbd_enable(void *, int);
45 : void ikbd_set_leds(void *, int);
46 : int ikbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
47 :
48 : const struct wskbd_accessops ikbd_accessops = {
49 : ikbd_enable,
50 : ikbd_set_leds,
51 : ikbd_ioctl,
52 : };
53 :
54 : int ikbd_match(struct device *, void *, void *);
55 : void ikbd_attach(struct device *, struct device *, void *);
56 : int ikbd_detach(struct device *, int);
57 :
58 : struct cfdriver ikbd_cd = {
59 : NULL, "ikbd", DV_DULL
60 : };
61 :
62 : const struct cfattach ikbd_ca = {
63 : sizeof(struct ikbd_softc),
64 : ikbd_match,
65 : ikbd_attach,
66 : ikbd_detach
67 : };
68 :
69 : int
70 0 : ikbd_match(struct device *parent, void *match, void *aux)
71 : {
72 0 : struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
73 0 : int size;
74 0 : void *desc;
75 :
76 0 : ihidev_get_report_desc(iha->parent, &desc, &size);
77 0 : if (!hid_is_collection(desc, size, iha->reportid,
78 : HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
79 0 : return (IMATCH_NONE);
80 :
81 0 : return (IMATCH_IFACECLASS);
82 0 : }
83 :
84 : void
85 0 : ikbd_attach(struct device *parent, struct device *self, void *aux)
86 : {
87 0 : struct ikbd_softc *sc = (struct ikbd_softc *)self;
88 0 : struct hidkbd *kbd = &sc->sc_kbd;
89 0 : struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
90 0 : int dlen, repid;
91 0 : void *desc;
92 :
93 0 : sc->sc_hdev.sc_intr = ikbd_intr;
94 0 : sc->sc_hdev.sc_parent = iha->parent;
95 0 : sc->sc_hdev.sc_report_id = iha->reportid;
96 :
97 0 : ihidev_get_report_desc(iha->parent, &desc, &dlen);
98 0 : repid = iha->reportid;
99 0 : sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid);
100 0 : sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid);
101 0 : sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid);
102 :
103 0 : if (hidkbd_attach(self, kbd, 0, 0, repid, desc, dlen) != 0)
104 0 : return;
105 :
106 0 : printf("\n");
107 :
108 0 : hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &ikbd_accessops);
109 0 : }
110 :
111 : int
112 0 : ikbd_detach(struct device *self, int flags)
113 : {
114 0 : struct ikbd_softc *sc = (struct ikbd_softc *)self;
115 0 : struct hidkbd *kbd = &sc->sc_kbd;
116 :
117 0 : return hidkbd_detach(kbd, flags);
118 : }
119 :
120 : void
121 0 : ikbd_intr(struct ihidev *addr, void *ibuf, u_int len)
122 : {
123 0 : struct ikbd_softc *sc = (struct ikbd_softc *)addr;
124 0 : struct hidkbd *kbd = &sc->sc_kbd;
125 :
126 0 : if (kbd->sc_enabled != 0)
127 0 : hidkbd_input(kbd, (uint8_t *)ibuf, len);
128 0 : }
129 :
130 : int
131 0 : ikbd_enable(void *v, int on)
132 : {
133 0 : struct ikbd_softc *sc = v;
134 0 : struct hidkbd *kbd = &sc->sc_kbd;
135 : int rv;
136 :
137 0 : if ((rv = hidkbd_enable(kbd, on)) != 0)
138 0 : return rv;
139 :
140 0 : if (on) {
141 0 : return ihidev_open(&sc->sc_hdev);
142 : } else {
143 0 : ihidev_close(&sc->sc_hdev);
144 0 : return 0;
145 : }
146 0 : }
147 :
148 : void
149 0 : ikbd_set_leds(void *v, int leds)
150 : {
151 0 : }
152 :
153 : int
154 0 : ikbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
155 : {
156 0 : struct ikbd_softc *sc = v;
157 0 : struct hidkbd *kbd = &sc->sc_kbd;
158 : int rc;
159 :
160 0 : switch (cmd) {
161 : case WSKBDIO_GTYPE:
162 : /* XXX: should we set something else? */
163 0 : *(u_int *)data = WSKBD_TYPE_USB;
164 0 : return 0;
165 : default:
166 0 : rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
167 0 : if (rc != -1)
168 0 : return rc;
169 : else
170 0 : return hidkbd_ioctl(kbd, cmd, data, flag, p);
171 : }
172 0 : }
|