1*650700c9Smglocker /* $OpenBSD: ikbd.c,v 1.3 2025/01/07 19:26:14 mglocker Exp $ */ 215a9a86aSkettenis /* 315a9a86aSkettenis * HID-over-i2c keyboard driver 415a9a86aSkettenis * 515a9a86aSkettenis * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> 615a9a86aSkettenis * 715a9a86aSkettenis * Permission to use, copy, modify, and distribute this software for any 815a9a86aSkettenis * purpose with or without fee is hereby granted, provided that the above 915a9a86aSkettenis * copyright notice and this permission notice appear in all copies. 1015a9a86aSkettenis * 1115a9a86aSkettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1215a9a86aSkettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1315a9a86aSkettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1415a9a86aSkettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1515a9a86aSkettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1615a9a86aSkettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1715a9a86aSkettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1815a9a86aSkettenis */ 1915a9a86aSkettenis 2015a9a86aSkettenis #include <sys/param.h> 2115a9a86aSkettenis #include <sys/systm.h> 2215a9a86aSkettenis #include <sys/kernel.h> 2315a9a86aSkettenis #include <sys/device.h> 2415a9a86aSkettenis #include <sys/ioctl.h> 2515a9a86aSkettenis #include <sys/timeout.h> 2615a9a86aSkettenis 2715a9a86aSkettenis #include <dev/i2c/i2cvar.h> 2815a9a86aSkettenis #include <dev/i2c/ihidev.h> 2915a9a86aSkettenis 3015a9a86aSkettenis #include <dev/wscons/wsconsio.h> 3115a9a86aSkettenis #include <dev/wscons/wskbdvar.h> 3215a9a86aSkettenis #include <dev/wscons/wsksymdef.h> 3315a9a86aSkettenis 3415a9a86aSkettenis #include <dev/hid/hid.h> 3515a9a86aSkettenis #include <dev/hid/hidkbdsc.h> 3615a9a86aSkettenis 3715a9a86aSkettenis struct ikbd_softc { 3815a9a86aSkettenis struct ihidev sc_hdev; 39*650700c9Smglocker #define sc_ledsize sc_hdev.sc_osize 4015a9a86aSkettenis struct hidkbd sc_kbd; 4130c38fb1Skettenis int sc_spl; 4215a9a86aSkettenis }; 4315a9a86aSkettenis 4415a9a86aSkettenis void ikbd_intr(struct ihidev *addr, void *ibuf, u_int len); 4515a9a86aSkettenis 4630c38fb1Skettenis void ikbd_cngetc(void *, u_int *, int *); 4730c38fb1Skettenis void ikbd_cnpollc(void *, int); 4830c38fb1Skettenis void ikbd_cnbell(void *, u_int, u_int, u_int); 4930c38fb1Skettenis 5030c38fb1Skettenis const struct wskbd_consops ikbd_consops = { 5130c38fb1Skettenis ikbd_cngetc, 5230c38fb1Skettenis ikbd_cnpollc, 5330c38fb1Skettenis ikbd_cnbell, 5430c38fb1Skettenis }; 5530c38fb1Skettenis 5615a9a86aSkettenis int ikbd_enable(void *, int); 5715a9a86aSkettenis void ikbd_set_leds(void *, int); 5815a9a86aSkettenis int ikbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 5915a9a86aSkettenis 6015a9a86aSkettenis const struct wskbd_accessops ikbd_accessops = { 6115a9a86aSkettenis ikbd_enable, 6215a9a86aSkettenis ikbd_set_leds, 6315a9a86aSkettenis ikbd_ioctl, 6415a9a86aSkettenis }; 6515a9a86aSkettenis 6615a9a86aSkettenis int ikbd_match(struct device *, void *, void *); 6715a9a86aSkettenis void ikbd_attach(struct device *, struct device *, void *); 6815a9a86aSkettenis int ikbd_detach(struct device *, int); 6915a9a86aSkettenis 7015a9a86aSkettenis struct cfdriver ikbd_cd = { 7115a9a86aSkettenis NULL, "ikbd", DV_DULL 7215a9a86aSkettenis }; 7315a9a86aSkettenis 7415a9a86aSkettenis const struct cfattach ikbd_ca = { 7515a9a86aSkettenis sizeof(struct ikbd_softc), 7615a9a86aSkettenis ikbd_match, 7715a9a86aSkettenis ikbd_attach, 7815a9a86aSkettenis ikbd_detach 7915a9a86aSkettenis }; 8015a9a86aSkettenis 8115a9a86aSkettenis int 8215a9a86aSkettenis ikbd_match(struct device *parent, void *match, void *aux) 8315a9a86aSkettenis { 8415a9a86aSkettenis struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 8515a9a86aSkettenis int size; 8615a9a86aSkettenis void *desc; 8715a9a86aSkettenis 8815a9a86aSkettenis ihidev_get_report_desc(iha->parent, &desc, &size); 8915a9a86aSkettenis if (!hid_is_collection(desc, size, iha->reportid, 9015a9a86aSkettenis HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) 9115a9a86aSkettenis return (IMATCH_NONE); 9215a9a86aSkettenis 9315a9a86aSkettenis return (IMATCH_IFACECLASS); 9415a9a86aSkettenis } 9515a9a86aSkettenis 9615a9a86aSkettenis void 9715a9a86aSkettenis ikbd_attach(struct device *parent, struct device *self, void *aux) 9815a9a86aSkettenis { 9915a9a86aSkettenis struct ikbd_softc *sc = (struct ikbd_softc *)self; 10015a9a86aSkettenis struct hidkbd *kbd = &sc->sc_kbd; 10115a9a86aSkettenis struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 10215a9a86aSkettenis int dlen, repid; 10315a9a86aSkettenis void *desc; 10415a9a86aSkettenis 10515a9a86aSkettenis sc->sc_hdev.sc_intr = ikbd_intr; 10615a9a86aSkettenis sc->sc_hdev.sc_parent = iha->parent; 10715a9a86aSkettenis sc->sc_hdev.sc_report_id = iha->reportid; 10815a9a86aSkettenis 10915a9a86aSkettenis ihidev_get_report_desc(iha->parent, &desc, &dlen); 11015a9a86aSkettenis repid = iha->reportid; 11115a9a86aSkettenis sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid); 11215a9a86aSkettenis sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid); 11315a9a86aSkettenis sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid); 11415a9a86aSkettenis 11530c38fb1Skettenis if (hidkbd_attach(self, kbd, 1, 0, repid, desc, dlen) != 0) 11615a9a86aSkettenis return; 11715a9a86aSkettenis 11815a9a86aSkettenis printf("\n"); 11915a9a86aSkettenis 12030c38fb1Skettenis if (kbd->sc_console_keyboard) { 12130c38fb1Skettenis extern struct wskbd_mapdata ukbd_keymapdata; 12230c38fb1Skettenis 12330c38fb1Skettenis ukbd_keymapdata.layout = KB_US | KB_DEFAULT; 12430c38fb1Skettenis wskbd_cnattach(&ikbd_consops, sc, &ukbd_keymapdata); 12530c38fb1Skettenis ikbd_enable(sc, 1); 12630c38fb1Skettenis } 12730c38fb1Skettenis 12815a9a86aSkettenis hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &ikbd_accessops); 12915a9a86aSkettenis } 13015a9a86aSkettenis 13115a9a86aSkettenis int 13215a9a86aSkettenis ikbd_detach(struct device *self, int flags) 13315a9a86aSkettenis { 13415a9a86aSkettenis struct ikbd_softc *sc = (struct ikbd_softc *)self; 13515a9a86aSkettenis struct hidkbd *kbd = &sc->sc_kbd; 13615a9a86aSkettenis 13715a9a86aSkettenis return hidkbd_detach(kbd, flags); 13815a9a86aSkettenis } 13915a9a86aSkettenis 14015a9a86aSkettenis void 14115a9a86aSkettenis ikbd_intr(struct ihidev *addr, void *ibuf, u_int len) 14215a9a86aSkettenis { 14315a9a86aSkettenis struct ikbd_softc *sc = (struct ikbd_softc *)addr; 14415a9a86aSkettenis struct hidkbd *kbd = &sc->sc_kbd; 14515a9a86aSkettenis 14615a9a86aSkettenis if (kbd->sc_enabled != 0) 14715a9a86aSkettenis hidkbd_input(kbd, (uint8_t *)ibuf, len); 14815a9a86aSkettenis } 14915a9a86aSkettenis 15015a9a86aSkettenis int 15115a9a86aSkettenis ikbd_enable(void *v, int on) 15215a9a86aSkettenis { 15315a9a86aSkettenis struct ikbd_softc *sc = v; 15415a9a86aSkettenis struct hidkbd *kbd = &sc->sc_kbd; 15515a9a86aSkettenis int rv; 15615a9a86aSkettenis 15715a9a86aSkettenis if ((rv = hidkbd_enable(kbd, on)) != 0) 15815a9a86aSkettenis return rv; 15915a9a86aSkettenis 16015a9a86aSkettenis if (on) { 16115a9a86aSkettenis return ihidev_open(&sc->sc_hdev); 16215a9a86aSkettenis } else { 16315a9a86aSkettenis ihidev_close(&sc->sc_hdev); 16415a9a86aSkettenis return 0; 16515a9a86aSkettenis } 16615a9a86aSkettenis } 16715a9a86aSkettenis 16815a9a86aSkettenis void 16915a9a86aSkettenis ikbd_set_leds(void *v, int leds) 17015a9a86aSkettenis { 171*650700c9Smglocker struct ikbd_softc *sc = v; 172*650700c9Smglocker struct hidkbd *kbd = &sc->sc_kbd; 173*650700c9Smglocker uint8_t res; 174*650700c9Smglocker 175*650700c9Smglocker if (sc->sc_ledsize && hidkbd_set_leds(kbd, leds, &res) != 0) { 176*650700c9Smglocker ihidev_send_report((struct device *)sc->sc_hdev.sc_parent, 177*650700c9Smglocker sc->sc_hdev.sc_report_id, &res, 1); 178*650700c9Smglocker } 17915a9a86aSkettenis } 18015a9a86aSkettenis 18115a9a86aSkettenis int 18215a9a86aSkettenis ikbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 18315a9a86aSkettenis { 18415a9a86aSkettenis struct ikbd_softc *sc = v; 18515a9a86aSkettenis struct hidkbd *kbd = &sc->sc_kbd; 18615a9a86aSkettenis int rc; 18715a9a86aSkettenis 18815a9a86aSkettenis switch (cmd) { 18915a9a86aSkettenis case WSKBDIO_GTYPE: 19015a9a86aSkettenis /* XXX: should we set something else? */ 19115a9a86aSkettenis *(u_int *)data = WSKBD_TYPE_USB; 19215a9a86aSkettenis return 0; 193*650700c9Smglocker case WSKBDIO_SETLEDS: 194*650700c9Smglocker ikbd_set_leds(v, *(int *)data); 195*650700c9Smglocker return 0; 19615a9a86aSkettenis default: 19715a9a86aSkettenis rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p); 19815a9a86aSkettenis if (rc != -1) 19915a9a86aSkettenis return rc; 20015a9a86aSkettenis else 20115a9a86aSkettenis return hidkbd_ioctl(kbd, cmd, data, flag, p); 20215a9a86aSkettenis } 20315a9a86aSkettenis } 20430c38fb1Skettenis 20530c38fb1Skettenis /* Console interface. */ 20630c38fb1Skettenis void 20730c38fb1Skettenis ikbd_cngetc(void *v, u_int *type, int *data) 20830c38fb1Skettenis { 20930c38fb1Skettenis struct ikbd_softc *sc = v; 21030c38fb1Skettenis struct hidkbd *kbd = &sc->sc_kbd; 21130c38fb1Skettenis 21230c38fb1Skettenis kbd->sc_polling = 1; 21330c38fb1Skettenis while (kbd->sc_npollchar <= 0) { 21430c38fb1Skettenis ihidev_poll(sc->sc_hdev.sc_parent); 21530c38fb1Skettenis delay(1000); 21630c38fb1Skettenis } 21730c38fb1Skettenis kbd->sc_polling = 0; 21830c38fb1Skettenis hidkbd_cngetc(kbd, type, data); 21930c38fb1Skettenis } 22030c38fb1Skettenis 22130c38fb1Skettenis void 22230c38fb1Skettenis ikbd_cnpollc(void *v, int on) 22330c38fb1Skettenis { 22430c38fb1Skettenis struct ikbd_softc *sc = v; 22530c38fb1Skettenis 22630c38fb1Skettenis if (on) 22730c38fb1Skettenis sc->sc_spl = spltty(); 22830c38fb1Skettenis else 22930c38fb1Skettenis splx(sc->sc_spl); 23030c38fb1Skettenis } 23130c38fb1Skettenis 23230c38fb1Skettenis void 23330c38fb1Skettenis ikbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 23430c38fb1Skettenis { 23530c38fb1Skettenis hidkbd_bell(pitch, period, volume, 1); 23630c38fb1Skettenis } 237