/* $NetBSD: skbd.c,v 1.5 2000/05/04 08:19:00 takemura Exp $ */ /*- * Copyright (c) 1999, 2000 UCHIYAMA Yasushi. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opt_tx39xx.h" #include #include #include #include #include #include #include #include #include #include "opt_wsdisplay_compat.h" #include #include #include #include #include #include #ifdef WSDISPLAY_COMPAT_RAWKBD #include #endif #include #include #ifdef TX39XX #include #include #endif struct skbd_softc; struct skbd_chip { skbd_tag_t sk_ic; const u_int8_t *sk_keymap; const int *sk_special; int sk_polling; int sk_console; u_int sk_type; int sk_data; int sk_enabled; struct device *sk_wskbddev; struct skbd_softc* sk_sc; /* back link */ #ifdef WSDISPLAY_COMPAT_RAWKBD int sk_rawkbd; #endif }; struct skbd_softc { struct device sc_dev; struct skbd_chip *sc_sk; }; int skbd_match __P((struct device*, struct cfdata*, void*)); void skbd_attach __P((struct device*, struct device*, void*)); int __skbd_input __P((void*, int, int)); void __skbd_input_hook __P((void*)); int skbd_keymap_lookup __P((struct skbd_chip*)); struct cfattach skbd_ca = { sizeof(struct skbd_softc), skbd_match, skbd_attach }; /* wskbd accessopts */ int skbd_enable __P((void *, int)); void skbd_set_leds __P((void *, int)); int skbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); /* consopts */ struct skbd_chip skbd_consdata; void skbd_cngetc __P((void*, u_int*, int*)); void skbd_cnpollc __P((void *, int)); const struct wskbd_accessops skbd_accessops = { skbd_enable, skbd_set_leds, skbd_ioctl, }; const struct wskbd_consops skbd_consops = { skbd_cngetc, skbd_cnpollc, }; struct wskbd_mapdata skbd_keymapdata = { pckbd_keydesctab, KB_US }; int skbd_match(parent, cf, aux) struct device *parent; struct cfdata *cf; void *aux; { return (1); } void skbd_attach(parent, self, aux) struct device *parent; struct device *self; void *aux; { struct skbd_attach_args *saa = aux; struct skbd_softc *sc = (void*)self; struct skbd_chip *sk; struct wskbddev_attach_args wa; sc->sc_sk = sk = &skbd_consdata; sk->sk_polling = 0; /* back link */ sk->sk_sc = sc; /* buffer/controller chip */ sk->sk_ic = saa->saa_ic; /* * platform dependent keymapping */ if (skbd_keymap_lookup(sk)) { printf(": no keymap."); } printf("\n"); /* * register skbd function to parent controller. */ skbdif_establish(sk->sk_ic, __skbd_input, __skbd_input_hook, sk); wa.console = sk->sk_console; wa.keymap = &skbd_keymapdata; wa.accessops = &skbd_accessops; wa.accesscookie = sk; sk->sk_wskbddev = config_found(self, &wa, wskbddevprint); } int skbd_print(aux, pnp) void *aux; const char *pnp; { return (pnp ? QUIET : UNCONF); } int skbd_keymap_lookup(sk) struct skbd_chip *sk; { const struct skbd_keymap_table *tab; platid_mask_t mask; for (tab = skbd_keymap_table; tab->st_keymap; tab++) { mask = PLATID_DEREF(&tab->st_platform); if (platid_match(&platid, &mask)) { sk->sk_keymap = tab->st_keymap; sk->sk_special = tab->st_special; skbd_keymapdata.layout = tab->st_layout; return (0); } } /* no keymap. use default. */ sk->sk_keymap = default_keymap; sk->sk_special = default_special_keymap; skbd_keymapdata.layout = KB_US; return (1); } void __skbd_input_hook(arg) void *arg; { struct skbd_chip *sk = arg; if (sk->sk_polling) { sk->sk_type = WSCONS_EVENT_ALL_KEYS_UP; } } int __skbd_input(arg, flag, scancode) void *arg; int flag, scancode; { struct skbd_chip *sk = arg; int type, key; if (flag) { #ifdef TX39XX tx_sound_click(tx_conf_get_tag()); #endif type = WSCONS_EVENT_KEY_DOWN; } else { type = WSCONS_EVENT_KEY_UP; } if ((key = sk->sk_keymap[scancode]) == UNK) { printf("skbd: unknown scan code %#x\n", scancode); return (0); } if (key == IGN) { return (0); } if (key == SPL) { if (!flag) return (0); if (scancode == sk->sk_special[KEY_SPECIAL_OFF]) printf("off button\n"); else if (scancode == sk->sk_special[KEY_SPECIAL_LIGHT]) config_hook_call(CONFIG_HOOK_BUTTONEVENT, CONFIG_HOOK_BUTTONEVENT_LIGHT, 0); else printf("unknown special key %d\n", scancode); return (0); } if (sk->sk_polling) { sk->sk_type = type; sk->sk_data = sk->sk_keymap[scancode]; } else { #ifdef WSDISPLAY_COMPAT_RAWKBD if (sk->sk_rawkbd) { int n; u_char data[16]; n = pckbd_encode(type, sk->sk_keymap[scancode], data); wskbd_rawinput(sk->sk_wskbddev, data, n); } else #endif wskbd_input(sk->sk_wskbddev, type, sk->sk_keymap[scancode]); } return (0); } /* * console support routines */ int skbd_cnattach(ic) struct skbd_controller *ic; { struct skbd_chip *sk = &skbd_consdata; sk->sk_console = 1; skbd_keymap_lookup(sk); /* attach controller */ sk->sk_ic = ic; skbdif_establish(sk->sk_ic, __skbd_input, __skbd_input_hook, sk); wskbd_cnattach(&skbd_consops, sk, &skbd_keymapdata); return (0); } void skbd_cngetc(arg, type, data) void *arg; u_int *type; int *data; { struct skbd_chip *sk = arg; int s; if (!sk->sk_console || !sk->sk_polling || !sk->sk_ic) { return; } s = splimp(); if (sk->sk_type == WSCONS_EVENT_ALL_KEYS_UP) { /* inquire of controller */ skbdif_poll(sk->sk_ic); } *type = sk->sk_type; *data = sk->sk_data; sk->sk_type = WSCONS_EVENT_ALL_KEYS_UP; splx(s); } void skbd_cnpollc(arg, on) void *arg; int on; { struct skbd_chip *sk = arg; int s = splimp(); sk->sk_polling = on; splx(s); } int skbd_enable(arg, on) void *arg; int on; { struct skbd_chip *sk = arg; if (on) { if (sk->sk_enabled) { return (EBUSY); } sk->sk_enabled = 1; } else { if (sk->sk_console) { return (EBUSY); } sk->sk_enabled = 0; } return (0); } void skbd_set_leds(arg, leds) void *arg; int leds; { /* No LEDs */ } int skbd_ioctl(arg, cmd, data, flag, p) void *arg; u_long cmd; caddr_t data; int flag; struct proc *p; { #ifdef WSDISPLAY_COMPAT_RAWKBD struct skbd_chip *sk = arg; #endif switch (cmd) { #ifdef WSDISPLAY_COMPAT_RAWKBD case WSKBDIO_SETMODE: sk->sk_rawkbd = (*(int *)data == WSKBD_RAW); return (0); #endif } return (-1); }