1 1.1 jmcneill /* $NetBSD: ikbd.c,v 1.1 2024/12/09 22:05:17 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /* $OpenBSD: ikbd.c,v 1.2 2022/09/03 15:48:16 kettenis Exp $ */ 4 1.1 jmcneill /* 5 1.1 jmcneill * HID-over-i2c keyboard driver 6 1.1 jmcneill * 7 1.1 jmcneill * Copyright (c) 2016 Mark Kettenis <kettenis (at) openbsd.org> 8 1.1 jmcneill * 9 1.1 jmcneill * Permission to use, copy, modify, and distribute this software for any 10 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above 11 1.1 jmcneill * copyright notice and this permission notice appear in all copies. 12 1.1 jmcneill * 13 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 1.1 jmcneill */ 21 1.1 jmcneill 22 1.1 jmcneill #include <sys/param.h> 23 1.1 jmcneill #include <sys/systm.h> 24 1.1 jmcneill #include <sys/kernel.h> 25 1.1 jmcneill #include <sys/device.h> 26 1.1 jmcneill #include <sys/ioctl.h> 27 1.1 jmcneill 28 1.1 jmcneill #include <dev/i2c/i2cvar.h> 29 1.1 jmcneill #include <dev/i2c/ihidev.h> 30 1.1 jmcneill 31 1.1 jmcneill #include <dev/wscons/wsconsio.h> 32 1.1 jmcneill #include <dev/wscons/wskbdvar.h> 33 1.1 jmcneill #include <dev/wscons/wsksymdef.h> 34 1.1 jmcneill 35 1.1 jmcneill #include <dev/hid/hid.h> 36 1.1 jmcneill #include <dev/hid/hidkbdsc.h> 37 1.1 jmcneill 38 1.1 jmcneill extern const struct wscons_keydesc hidkbd_keydesctab[]; 39 1.1 jmcneill static struct wskbd_mapdata ikbd_keymapdata = { 40 1.1 jmcneill hidkbd_keydesctab, 41 1.1 jmcneill KB_US, 42 1.1 jmcneill }; 43 1.1 jmcneill 44 1.1 jmcneill struct ikbd_softc { 45 1.1 jmcneill struct ihidev sc_hdev; 46 1.1 jmcneill struct hidkbd sc_kbd; 47 1.1 jmcneill int sc_spl; 48 1.1 jmcneill }; 49 1.1 jmcneill 50 1.1 jmcneill void ikbd_intr(struct ihidev *addr, void *ibuf, u_int len); 51 1.1 jmcneill 52 1.1 jmcneill void ikbd_cngetc(void *, u_int *, int *); 53 1.1 jmcneill void ikbd_cnpollc(void *, int); 54 1.1 jmcneill 55 1.1 jmcneill const struct wskbd_consops ikbd_consops = { 56 1.1 jmcneill .getc = ikbd_cngetc, 57 1.1 jmcneill .pollc = ikbd_cnpollc, 58 1.1 jmcneill .bell = NULL, 59 1.1 jmcneill }; 60 1.1 jmcneill 61 1.1 jmcneill int ikbd_enable(void *, int); 62 1.1 jmcneill void ikbd_set_leds(void *, int); 63 1.1 jmcneill int ikbd_ioctl(void *, u_long, void *, int, lwp_t *); 64 1.1 jmcneill 65 1.1 jmcneill const struct wskbd_accessops ikbd_accessops = { 66 1.1 jmcneill .enable = ikbd_enable, 67 1.1 jmcneill .set_leds = ikbd_set_leds, 68 1.1 jmcneill .ioctl = ikbd_ioctl, 69 1.1 jmcneill }; 70 1.1 jmcneill 71 1.1 jmcneill int ikbd_match(device_t, cfdata_t, void *); 72 1.1 jmcneill void ikbd_attach(device_t, device_t, void *); 73 1.1 jmcneill int ikbd_detach(device_t, int); 74 1.1 jmcneill 75 1.1 jmcneill CFATTACH_DECL_NEW(ikbd, sizeof(struct ikbd_softc), 76 1.1 jmcneill ikbd_match, ikbd_attach, ikbd_detach, NULL); 77 1.1 jmcneill 78 1.1 jmcneill int 79 1.1 jmcneill ikbd_match(device_t parent, cfdata_t match, void *aux) 80 1.1 jmcneill { 81 1.1 jmcneill struct ihidev_attach_arg *iha = aux; 82 1.1 jmcneill int size; 83 1.1 jmcneill void *desc; 84 1.1 jmcneill 85 1.1 jmcneill ihidev_get_report_desc(iha->parent, &desc, &size); 86 1.1 jmcneill if (!hid_is_collection(desc, size, iha->reportid, 87 1.1 jmcneill HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) 88 1.1 jmcneill return (IMATCH_NONE); 89 1.1 jmcneill 90 1.1 jmcneill return (IMATCH_IFACECLASS); 91 1.1 jmcneill } 92 1.1 jmcneill 93 1.1 jmcneill void 94 1.1 jmcneill ikbd_attach(device_t parent, device_t self, void *aux) 95 1.1 jmcneill { 96 1.1 jmcneill struct ikbd_softc *sc = device_private(self); 97 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 98 1.1 jmcneill struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 99 1.1 jmcneill int dlen, repid; 100 1.1 jmcneill void *desc; 101 1.1 jmcneill 102 1.1 jmcneill sc->sc_hdev.sc_idev = self; 103 1.1 jmcneill sc->sc_hdev.sc_intr = ikbd_intr; 104 1.1 jmcneill sc->sc_hdev.sc_parent = iha->parent; 105 1.1 jmcneill sc->sc_hdev.sc_report_id = iha->reportid; 106 1.1 jmcneill 107 1.1 jmcneill ihidev_get_report_desc(iha->parent, &desc, &dlen); 108 1.1 jmcneill repid = iha->reportid; 109 1.1 jmcneill sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid); 110 1.1 jmcneill sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid); 111 1.1 jmcneill sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid); 112 1.1 jmcneill 113 1.1 jmcneill if (hidkbd_attach(self, kbd, 1, 0, repid, desc, dlen) != 0) 114 1.1 jmcneill return; 115 1.1 jmcneill 116 1.1 jmcneill aprint_naive("\n"); 117 1.1 jmcneill aprint_normal("\n"); 118 1.1 jmcneill 119 1.1 jmcneill if (kbd->sc_console_keyboard) { 120 1.1 jmcneill wskbd_cnattach(&ikbd_consops, sc, &ikbd_keymapdata); 121 1.1 jmcneill ikbd_enable(sc, 1); 122 1.1 jmcneill } 123 1.1 jmcneill 124 1.1 jmcneill hidkbd_attach_wskbd(kbd, KB_US, &ikbd_accessops); 125 1.1 jmcneill } 126 1.1 jmcneill 127 1.1 jmcneill int 128 1.1 jmcneill ikbd_detach(device_t self, int flags) 129 1.1 jmcneill { 130 1.1 jmcneill struct ikbd_softc *sc = device_private(self); 131 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 132 1.1 jmcneill 133 1.1 jmcneill return hidkbd_detach(kbd, flags); 134 1.1 jmcneill } 135 1.1 jmcneill 136 1.1 jmcneill void 137 1.1 jmcneill ikbd_intr(struct ihidev *addr, void *ibuf, u_int len) 138 1.1 jmcneill { 139 1.1 jmcneill struct ikbd_softc *sc = (struct ikbd_softc *)addr; 140 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 141 1.1 jmcneill 142 1.1 jmcneill if (kbd->sc_enabled != 0) 143 1.1 jmcneill hidkbd_input(kbd, (uint8_t *)ibuf, len); 144 1.1 jmcneill } 145 1.1 jmcneill 146 1.1 jmcneill int 147 1.1 jmcneill ikbd_enable(void *v, int on) 148 1.1 jmcneill { 149 1.1 jmcneill struct ikbd_softc *sc = v; 150 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 151 1.1 jmcneill int rv; 152 1.1 jmcneill 153 1.1 jmcneill if ((rv = hidkbd_enable(kbd, on)) != 0) 154 1.1 jmcneill return rv; 155 1.1 jmcneill 156 1.1 jmcneill if (on) { 157 1.1 jmcneill return ihidev_open(&sc->sc_hdev); 158 1.1 jmcneill } else { 159 1.1 jmcneill ihidev_close(&sc->sc_hdev); 160 1.1 jmcneill return 0; 161 1.1 jmcneill } 162 1.1 jmcneill } 163 1.1 jmcneill 164 1.1 jmcneill void 165 1.1 jmcneill ikbd_set_leds(void *v, int leds) 166 1.1 jmcneill { 167 1.1 jmcneill } 168 1.1 jmcneill 169 1.1 jmcneill int 170 1.1 jmcneill ikbd_ioctl(void *v, u_long cmd, void *data, int flag, lwp_t *l) 171 1.1 jmcneill { 172 1.1 jmcneill struct ikbd_softc *sc = v; 173 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 174 1.1 jmcneill 175 1.1 jmcneill switch (cmd) { 176 1.1 jmcneill case WSKBDIO_GTYPE: 177 1.1 jmcneill /* XXX: should we set something else? */ 178 1.1 jmcneill *(u_int *)data = WSKBD_TYPE_USB; 179 1.1 jmcneill return 0; 180 1.1 jmcneill default: 181 1.1 jmcneill return hidkbd_ioctl(kbd, cmd, data, flag, l); 182 1.1 jmcneill } 183 1.1 jmcneill } 184 1.1 jmcneill 185 1.1 jmcneill /* Console interface. */ 186 1.1 jmcneill void 187 1.1 jmcneill ikbd_cngetc(void *v, u_int *type, int *data) 188 1.1 jmcneill { 189 1.1 jmcneill struct ikbd_softc *sc = v; 190 1.1 jmcneill struct hidkbd *kbd = &sc->sc_kbd; 191 1.1 jmcneill 192 1.1 jmcneill kbd->sc_polling = 1; 193 1.1 jmcneill #if notyet 194 1.1 jmcneill while (kbd->sc_npollchar <= 0) { 195 1.1 jmcneill ihidev_poll(sc->sc_hdev.sc_parent); 196 1.1 jmcneill delay(1000); 197 1.1 jmcneill } 198 1.1 jmcneill #endif 199 1.1 jmcneill kbd->sc_polling = 0; 200 1.1 jmcneill hidkbd_cngetc(kbd, type, data); 201 1.1 jmcneill } 202 1.1 jmcneill 203 1.1 jmcneill void 204 1.1 jmcneill ikbd_cnpollc(void *v, int on) 205 1.1 jmcneill { 206 1.1 jmcneill struct ikbd_softc *sc = v; 207 1.1 jmcneill 208 1.1 jmcneill if (on) 209 1.1 jmcneill sc->sc_spl = spltty(); 210 1.1 jmcneill else 211 1.1 jmcneill splx(sc->sc_spl); 212 1.1 jmcneill } 213