Home | History | Annotate | Line # | Download | only in i2c
      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