File:  [DragonFly] / src / sys / dev / misc / kbd / kbd.c
Revision 1.9: download - view: text, annotated - select for diffs
Thu May 13 23:49:16 2004 UTC (9 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

    1: /*-
    2:  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer as
   10:  *    the first lines of this file unmodified.
   11:  * 2. Redistributions in binary form must reproduce the above copyright
   12:  *    notice, this list of conditions and the following disclaimer in the
   13:  *    documentation and/or other materials provided with the distribution.
   14:  *
   15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   16:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   19:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25:  *
   26:  * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $
   27:  * $DragonFly: src/sys/dev/misc/kbd/kbd.c,v 1.9 2004/05/13 23:49:16 dillon Exp $
   28:  */
   29: 
   30: #include "opt_kbd.h"
   31: 
   32: #include <sys/param.h>
   33: #include <sys/systm.h>
   34: #include <sys/kernel.h>
   35: #include <sys/malloc.h>
   36: #include <sys/conf.h>
   37: #include <sys/proc.h>
   38: #include <sys/tty.h>
   39: #include <sys/poll.h>
   40: #include <sys/vnode.h>
   41: #include <sys/uio.h>
   42: 
   43: #include <machine/console.h>
   44: 
   45: #include "kbdreg.h"
   46: 
   47: #define KBD_INDEX(dev)	minor(dev)
   48: 
   49: typedef struct genkbd_softc {
   50: 	int		gkb_flags;	/* flag/status bits */
   51: #define KB_ASLEEP	(1 << 0)
   52: 	struct clist	gkb_q;		/* input queue */
   53: 	struct selinfo	gkb_rsel;
   54: } genkbd_softc_t;
   55: 
   56: static	SLIST_HEAD(, keyboard_driver) keyboard_drivers =
   57:  	SLIST_HEAD_INITIALIZER(keyboard_drivers);
   58: 
   59: SET_DECLARE(kbddriver_set, const keyboard_driver_t);
   60: 
   61: /* local arrays */
   62: 
   63: /*
   64:  * We need at least one entry each in order to initialize a keyboard
   65:  * for the kernel console.  The arrays will be increased dynamically
   66:  * when necessary.
   67:  */
   68: 
   69: static int		keyboards = 1;
   70: static keyboard_t	*kbd_ini;
   71: static keyboard_t	**keyboard = &kbd_ini;
   72: static keyboard_switch_t *kbdsw_ini;
   73:        keyboard_switch_t **kbdsw = &kbdsw_ini;
   74: 
   75: #define ARRAY_DELTA	4
   76: 
   77: static int
   78: kbd_realloc_array(void)
   79: {
   80: 	keyboard_t **new_kbd;
   81: 	keyboard_switch_t **new_kbdsw;
   82: 	int newsize;
   83: 	int s;
   84: 
   85: 	s = spltty();
   86: 	newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
   87: 	new_kbd = malloc(sizeof(*new_kbd) * newsize, M_DEVBUF,
   88: 				M_WAITOK | M_ZERO);
   89: 	new_kbdsw = malloc(sizeof(*new_kbdsw) * newsize, M_DEVBUF,
   90: 				M_WAITOK | M_ZERO);
   91: 	bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
   92: 	bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
   93: 	if (keyboards > 1) {
   94: 		free(keyboard, M_DEVBUF);
   95: 		free(kbdsw, M_DEVBUF);
   96: 	}
   97: 	keyboard = new_kbd;
   98: 	kbdsw = new_kbdsw;
   99: 	keyboards = newsize;
  100: 	splx(s);
  101: 
  102: 	if (bootverbose)
  103: 		printf("kbd: new array size %d\n", keyboards);
  104: 
  105: 	return 0;
  106: }
  107: 
  108: /*
  109:  * Low-level keyboard driver functions
  110:  * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard
  111:  * driver, call these functions to initialize the keyboard_t structure
  112:  * and register it to the virtual keyboard driver `kbd'.
  113:  */
  114: 
  115: /* initialize the keyboard_t structure */
  116: void
  117: kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config,
  118: 		int port, int port_size)
  119: {
  120: 	kbd->kb_flags = KB_NO_DEVICE;	/* device has not been found */
  121: 	kbd->kb_name = name;
  122: 	kbd->kb_type = type;
  123: 	kbd->kb_unit = unit;
  124: 	kbd->kb_config = config & ~KB_CONF_PROBE_ONLY;
  125: 	kbd->kb_led = 0;		/* unknown */
  126: 	kbd->kb_io_base = port;
  127: 	kbd->kb_io_size = port_size;
  128: 	kbd->kb_data = NULL;
  129: 	kbd->kb_keymap = NULL;
  130: 	kbd->kb_accentmap = NULL;
  131: 	kbd->kb_fkeytab = NULL;
  132: 	kbd->kb_fkeytab_size = 0;
  133: 	kbd->kb_delay1 = KB_DELAY1;	/* these values are advisory only */
  134: 	kbd->kb_delay2 = KB_DELAY2;
  135: 	kbd->kb_count = 0L;
  136: 	bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact));
  137: }
  138: 
  139: void
  140: kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap,
  141: 	     fkeytab_t *fkeymap, int fkeymap_size)
  142: {
  143: 	kbd->kb_keymap = keymap;
  144: 	kbd->kb_accentmap = accmap;
  145: 	kbd->kb_fkeytab = fkeymap;
  146: 	kbd->kb_fkeytab_size = fkeymap_size;
  147: }
  148: 
  149: /* declare a new keyboard driver */
  150: int
  151: kbd_add_driver(keyboard_driver_t *driver)
  152: {
  153: 	if (SLIST_NEXT(driver, link))
  154: 		return EINVAL;
  155: 	SLIST_INSERT_HEAD(&keyboard_drivers, driver, link);
  156: 	return 0;
  157: }
  158: 
  159: int
  160: kbd_delete_driver(keyboard_driver_t *driver)
  161: {
  162: 	SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link);
  163: 	SLIST_NEXT(driver, link) = NULL;
  164: 	return 0;
  165: }
  166: 
  167: /* register a keyboard and associate it with a function table */
  168: int
  169: kbd_register(keyboard_t *kbd)
  170: {
  171: 	const keyboard_driver_t **list;
  172: 	const keyboard_driver_t *p;
  173: 	int index;
  174: 
  175: 	for (index = 0; index < keyboards; ++index) {
  176: 		if (keyboard[index] == NULL)
  177: 			break;
  178: 	}
  179: 	if (index >= keyboards) {
  180: 		if (kbd_realloc_array())
  181: 			return -1;
  182: 	}
  183: 
  184: 	kbd->kb_index = index;
  185: 	KBD_UNBUSY(kbd);
  186: 	KBD_VALID(kbd);
  187: 	kbd->kb_active = 0;	/* disabled until someone calls kbd_enable() */
  188: 	kbd->kb_token = NULL;
  189: 	kbd->kb_callback.kc_func = NULL;
  190: 	kbd->kb_callback.kc_arg = NULL;
  191: 
  192: 	SLIST_FOREACH(p, &keyboard_drivers, link) {
  193: 		if (strcmp(p->name, kbd->kb_name) == 0) {
  194: 			keyboard[index] = kbd;
  195: 			kbdsw[index] = p->kbdsw;
  196: 			return index;
  197: 		}
  198: 	}
  199: 	SET_FOREACH(list, kbddriver_set) {
  200: 		p = *list;
  201: 		if (strcmp(p->name, kbd->kb_name) == 0) {
  202: 			keyboard[index] = kbd;
  203: 			kbdsw[index] = p->kbdsw;
  204: 			return index;
  205: 		}
  206: 	}
  207: 
  208: 	return -1;
  209: }
  210: 
  211: int
  212: kbd_unregister(keyboard_t *kbd)
  213: {
  214: 	int error;
  215: 	int s;
  216: 
  217: 	if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards))
  218: 		return ENOENT;
  219: 	if (keyboard[kbd->kb_index] != kbd)
  220: 		return ENOENT;
  221: 
  222: 	s = spltty();
  223: 	if (KBD_IS_BUSY(kbd)) {
  224: 		error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING,
  225: 						    kbd->kb_callback.kc_arg);
  226: 		if (error) {
  227: 			splx(s);
  228: 			return error;
  229: 		}
  230: 		if (KBD_IS_BUSY(kbd)) {
  231: 			splx(s);
  232: 			return EBUSY;
  233: 		}
  234: 	}
  235: 	KBD_INVALID(kbd);
  236: 	keyboard[kbd->kb_index] = NULL;
  237: 	kbdsw[kbd->kb_index] = NULL;
  238: 
  239: 	splx(s);
  240: 	return 0;
  241: }
  242: 
  243: /* find a funciton table by the driver name */
  244: keyboard_switch_t
  245: *kbd_get_switch(char *driver)
  246: {
  247: 	const keyboard_driver_t **list;
  248: 	const keyboard_driver_t *p;
  249: 
  250: 	SLIST_FOREACH(p, &keyboard_drivers, link) {
  251: 		if (strcmp(p->name, driver) == 0)
  252: 			return p->kbdsw;
  253: 	}
  254: 	SET_FOREACH(list, kbddriver_set) {
  255: 		p = *list;
  256: 		if (strcmp(p->name, driver) == 0)
  257: 			return p->kbdsw;
  258: 	}
  259: 
  260: 	return NULL;
  261: }
  262: 
  263: /*
  264:  * Keyboard client functions
  265:  * Keyboard clients, such as the console driver `syscons' and the keyboard
  266:  * cdev driver, use these functions to claim and release a keyboard for
  267:  * exclusive use.
  268:  */
  269: 
  270: /* find the keyboard specified by a driver name and a unit number */
  271: int
  272: kbd_find_keyboard(char *driver, int unit)
  273: {
  274: 	int i;
  275: 
  276: 	for (i = 0; i < keyboards; ++i) {
  277: 		if (keyboard[i] == NULL)
  278: 			continue;
  279: 		if (!KBD_IS_VALID(keyboard[i]))
  280: 			continue;
  281: 		if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver))
  282: 			continue;
  283: 		if ((unit != -1) && (keyboard[i]->kb_unit != unit))
  284: 			continue;
  285: 		return i;
  286: 	}
  287: 	return -1;
  288: }
  289: 
  290: /* allocate a keyboard */
  291: int
  292: kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func,
  293: 	     void *arg)
  294: {
  295: 	int index;
  296: 	int s;
  297: 
  298: 	if (func == NULL)
  299: 		return -1;
  300: 
  301: 	s = spltty();
  302: 	index = kbd_find_keyboard(driver, unit);
  303: 	if (index >= 0) {
  304: 		if (KBD_IS_BUSY(keyboard[index])) {
  305: 			splx(s);
  306: 			return -1;
  307: 		}
  308: 		keyboard[index]->kb_token = id;
  309: 		KBD_BUSY(keyboard[index]);
  310: 		keyboard[index]->kb_callback.kc_func = func;
  311: 		keyboard[index]->kb_callback.kc_arg = arg;
  312: 		(*kbdsw[index]->clear_state)(keyboard[index]);
  313: 	}
  314: 	splx(s);
  315: 	return index;
  316: }
  317: 
  318: int
  319: kbd_release(keyboard_t *kbd, void *id)
  320: {
  321: 	int error;
  322: 	int s;
  323: 
  324: 	s = spltty();
  325: 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
  326: 		error = EINVAL;
  327: 	} else if (kbd->kb_token != id) {
  328: 		error = EPERM;
  329: 	} else {
  330: 		kbd->kb_token = NULL;
  331: 		KBD_UNBUSY(kbd);
  332: 		kbd->kb_callback.kc_func = NULL;
  333: 		kbd->kb_callback.kc_arg = NULL;
  334: 		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
  335: 		error = 0;
  336: 	}
  337: 	splx(s);
  338: 	return error;
  339: }
  340: 
  341: int
  342: kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func,
  343: 		    void *arg)
  344: {
  345: 	int error;
  346: 	int s;
  347: 
  348: 	s = spltty();
  349: 	if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) {
  350: 		error = EINVAL;
  351: 	} else if (kbd->kb_token != id) {
  352: 		error = EPERM;
  353: 	} else if (func == NULL) {
  354: 		error = EINVAL;
  355: 	} else {
  356: 		kbd->kb_callback.kc_func = func;
  357: 		kbd->kb_callback.kc_arg = arg;
  358: 		error = 0;
  359: 	}
  360: 	splx(s);
  361: 	return error;
  362: }
  363: 
  364: /* get a keyboard structure */
  365: keyboard_t
  366: *kbd_get_keyboard(int index)
  367: {
  368: 	if ((index < 0) || (index >= keyboards))
  369: 		return NULL;
  370: 	if (keyboard[index] == NULL)
  371: 		return NULL;
  372: 	if (!KBD_IS_VALID(keyboard[index]))
  373: 		return NULL;
  374: 	return keyboard[index];
  375: }
  376: 
  377: /*
  378:  * The back door for the console driver; configure keyboards
  379:  * This function is for the kernel console to initialize keyboards
  380:  * at very early stage.
  381:  */
  382: 
  383: int
  384: kbd_configure(int flags)
  385: {
  386: 	const keyboard_driver_t **list;
  387: 	const keyboard_driver_t *p;
  388: 
  389: 	SLIST_FOREACH(p, &keyboard_drivers, link) {
  390: 		if (p->configure != NULL)
  391: 			(*p->configure)(flags);
  392: 	}
  393: 	SET_FOREACH(list, kbddriver_set) {
  394: 		p = *list;
  395: 		if (p->configure != NULL)
  396: 			(*p->configure)(flags);
  397: 	}
  398: 
  399: 	return 0;
  400: }
  401: 
  402: #ifdef KBD_INSTALL_CDEV
  403: 
  404: /*
  405:  * Virtual keyboard cdev driver functions
  406:  * The virtual keyboard driver dispatches driver functions to
  407:  * appropriate subdrivers.
  408:  */
  409: 
  410: #define KBD_UNIT(dev)	minor(dev)
  411: 
  412: static d_open_t		genkbdopen;
  413: static d_close_t	genkbdclose;
  414: static d_read_t		genkbdread;
  415: static d_write_t	genkbdwrite;
  416: static d_ioctl_t	genkbdioctl;
  417: static d_poll_t		genkbdpoll;
  418: 
  419: #define CDEV_MAJOR	112
  420: 
  421: static struct cdevsw kbd_cdevsw = {
  422: 	/* name */	"kbd",
  423: 	/* maj */	CDEV_MAJOR,
  424: 	/* flags */	0,
  425: 	/* port */	NULL,
  426: 	/* clone */	NULL,
  427: 
  428: 	/* open */	genkbdopen,
  429: 	/* close */	genkbdclose,
  430: 	/* read */	genkbdread,
  431: 	/* write */	genkbdwrite,
  432: 	/* ioctl */	genkbdioctl,
  433: 	/* poll */	genkbdpoll,
  434: 	/* mmap */	nommap,
  435: 	/* strategy */	nostrategy,
  436: 	/* dump */	nodump,
  437: 	/* psize */	nopsize
  438: };
  439: 
  440: int
  441: kbd_attach(keyboard_t *kbd)
  442: {
  443: 	dev_t dev;
  444: 
  445: 	if (kbd->kb_index >= keyboards)
  446: 		return EINVAL;
  447: 	if (keyboard[kbd->kb_index] != kbd)
  448: 		return EINVAL;
  449: 
  450: 	dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
  451: 		       "kbd%r", kbd->kb_index);
  452: 	if (dev->si_drv1 == NULL)
  453: 		dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
  454: 				      M_WAITOK);
  455: 	bzero(dev->si_drv1, sizeof(genkbd_softc_t));
  456: 
  457: 	printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
  458: 	return 0;
  459: }
  460: 
  461: int
  462: kbd_detach(keyboard_t *kbd)
  463: {
  464: 	dev_t dev;
  465: 
  466: 	if (kbd->kb_index >= keyboards)
  467: 		return EINVAL;
  468: 	if (keyboard[kbd->kb_index] != kbd)
  469: 		return EINVAL;
  470: 
  471: 	dev = makedev(kbd_cdevsw.d_maj, kbd->kb_index);
  472: 	if (dev->si_drv1)
  473: 		free(dev->si_drv1, M_DEVBUF);
  474: 	destroy_dev(dev);
  475: 	return 0;
  476: }
  477: 
  478: /*
  479:  * Generic keyboard cdev driver functions
  480:  * Keyboard subdrivers may call these functions to implement common
  481:  * driver functions.
  482:  */
  483: 
  484: #define KB_QSIZE	512
  485: #define KB_BUFSIZE	64
  486: 
  487: static kbd_callback_func_t genkbd_event;
  488: 
  489: static int
  490: genkbdopen(dev_t dev, int mode, int flag, d_thread_t *td)
  491: {
  492: 	keyboard_t *kbd;
  493: 	genkbd_softc_t *sc;
  494: 	int s;
  495: 	int i;
  496: 
  497: 	s = spltty();
  498: 	sc = dev->si_drv1;
  499: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  500: 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  501: 		splx(s);
  502: 		return ENXIO;
  503: 	}
  504: 	i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc,
  505: 			 genkbd_event, (void *)sc);
  506: 	if (i < 0) {
  507: 		splx(s);
  508: 		return EBUSY;
  509: 	}
  510: 	/* assert(i == kbd->kb_index) */
  511: 	/* assert(kbd == kbd_get_keyboard(i)) */
  512: 
  513: 	/*
  514: 	 * NOTE: even when we have successfully claimed a keyboard,
  515: 	 * the device may still be missing (!KBD_HAS_DEVICE(kbd)).
  516: 	 */
  517: 
  518: #if 0
  519: 	bzero(&sc->gkb_q, sizeof(sc->gkb_q));
  520: #endif
  521: 	clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */
  522: 	sc->gkb_rsel.si_flags = 0;
  523: 	sc->gkb_rsel.si_pid = 0;
  524: 	splx(s);
  525: 
  526: 	return 0;
  527: }
  528: 
  529: static int
  530: genkbdclose(dev_t dev, int mode, int flag, d_thread_t *td)
  531: {
  532: 	keyboard_t *kbd;
  533: 	genkbd_softc_t *sc;
  534: 	int s;
  535: 
  536: 	/*
  537: 	 * NOTE: the device may have already become invalid.
  538: 	 * kbd == NULL || !KBD_IS_VALID(kbd)
  539: 	 */
  540: 	s = spltty();
  541: 	sc = dev->si_drv1;
  542: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  543: 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  544: 		/* XXX: we shall be forgiving and don't report error... */
  545: 	} else {
  546: 		kbd_release(kbd, (void *)sc);
  547: #if 0
  548: 		clist_free_cblocks(&sc->gkb_q);
  549: #endif
  550: 	}
  551: 	splx(s);
  552: 	return 0;
  553: }
  554: 
  555: static int
  556: genkbdread(dev_t dev, struct uio *uio, int flag)
  557: {
  558: 	keyboard_t *kbd;
  559: 	genkbd_softc_t *sc;
  560: 	u_char buffer[KB_BUFSIZE];
  561: 	int len;
  562: 	int error;
  563: 	int s;
  564: 
  565: 	/* wait for input */
  566: 	s = spltty();
  567: 	sc = dev->si_drv1;
  568: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  569: 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  570: 		splx(s);
  571: 		return ENXIO;
  572: 	}
  573: 	while (sc->gkb_q.c_cc == 0) {
  574: 		if (flag & IO_NDELAY) {
  575: 			splx(s);
  576: 			return EWOULDBLOCK;
  577: 		}
  578: 		sc->gkb_flags |= KB_ASLEEP;
  579: 		error = tsleep((caddr_t)sc, PCATCH, "kbdrea", 0);
  580: 		kbd = kbd_get_keyboard(KBD_INDEX(dev));
  581: 		if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
  582: 			splx(s);
  583: 			return ENXIO;	/* our keyboard has gone... */
  584: 		}
  585: 		if (error) {
  586: 			sc->gkb_flags &= ~KB_ASLEEP;
  587: 			splx(s);
  588: 			return error;
  589: 		}
  590: 	}
  591: 	splx(s);
  592: 
  593: 	/* copy as much input as possible */
  594: 	error = 0;
  595: 	while (uio->uio_resid > 0) {
  596: 		len = imin(uio->uio_resid, sizeof(buffer));
  597: 		len = q_to_b(&sc->gkb_q, buffer, len);
  598: 		if (len <= 0)
  599: 			break;
  600: 		error = uiomove(buffer, len, uio);
  601: 		if (error)
  602: 			break;
  603: 	}
  604: 
  605: 	return error;
  606: }
  607: 
  608: static int
  609: genkbdwrite(dev_t dev, struct uio *uio, int flag)
  610: {
  611: 	keyboard_t *kbd;
  612: 
  613: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  614: 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
  615: 		return ENXIO;
  616: 	return ENODEV;
  617: }
  618: 
  619: static int
  620: genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
  621: {
  622: 	keyboard_t *kbd;
  623: 	int error;
  624: 
  625: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  626: 	if ((kbd == NULL) || !KBD_IS_VALID(kbd))
  627: 		return ENXIO;
  628: 	error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
  629: 	if (error == ENOIOCTL)
  630: 		error = ENODEV;
  631: 	return error;
  632: }
  633: 
  634: static int
  635: genkbdpoll(dev_t dev, int events, d_thread_t *td)
  636: {
  637: 	keyboard_t *kbd;
  638: 	genkbd_softc_t *sc;
  639: 	int revents;
  640: 	int s;
  641: 
  642: 	revents = 0;
  643: 	s = spltty();
  644: 	sc = dev->si_drv1;
  645: 	kbd = kbd_get_keyboard(KBD_INDEX(dev));
  646: 	if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
  647: 		revents =  POLLHUP;	/* the keyboard has gone */
  648: 	} else if (events & (POLLIN | POLLRDNORM)) {
  649: 		if (sc->gkb_q.c_cc > 0)
  650: 			revents = events & (POLLIN | POLLRDNORM);
  651: 		else
  652: 			selrecord(td, &sc->gkb_rsel);
  653: 	}
  654: 	splx(s);
  655: 	return revents;
  656: }
  657: 
  658: static int
  659: genkbd_event(keyboard_t *kbd, int event, void *arg)
  660: {
  661: 	genkbd_softc_t *sc;
  662: 	size_t len;
  663: 	u_char *cp;
  664: 	int mode;
  665: 	int c;
  666: 
  667: 	/* assert(KBD_IS_VALID(kbd)) */
  668: 	sc = (genkbd_softc_t *)arg;
  669: 
  670: 	switch (event) {
  671: 	case KBDIO_KEYINPUT:
  672: 		break;
  673: 	case KBDIO_UNLOADING:
  674: 		/* the keyboard is going... */
  675: 		kbd_release(kbd, (void *)sc);
  676: 		if (sc->gkb_flags & KB_ASLEEP) {
  677: 			sc->gkb_flags &= ~KB_ASLEEP;
  678: 			wakeup((caddr_t)sc);
  679: 		}
  680: 		selwakeup(&sc->gkb_rsel);
  681: 		return 0;
  682: 	default:
  683: 		return EINVAL;
  684: 	}
  685: 
  686: 	/* obtain the current key input mode */
  687: 	if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode))
  688: 		mode = K_XLATE;
  689: 
  690: 	/* read all pending input */
  691: 	while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) {
  692: 		c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE);
  693: 		if (c == NOKEY)
  694: 			continue;
  695: 		if (c == ERRKEY)	/* XXX: ring bell? */
  696: 			continue;
  697: 		if (!KBD_IS_BUSY(kbd))
  698: 			/* the device is not open, discard the input */
  699: 			continue;
  700: 
  701: 		/* store the byte as is for K_RAW and K_CODE modes */
  702: 		if (mode != K_XLATE) {
  703: 			putc(KEYCHAR(c), &sc->gkb_q);
  704: 			continue;
  705: 		}
  706: 
  707: 		/* K_XLATE */
  708: 		if (c & RELKEY)	/* key release is ignored */
  709: 			continue;
  710: 
  711: 		/* process special keys; most of them are just ignored... */
  712: 		if (c & SPCLKEY) {
  713: 			switch (KEYCHAR(c)) {
  714: 			default:
  715: 				/* ignore them... */
  716: 				continue;
  717: 			case BTAB:	/* a backtab: ESC [ Z */
  718: 				putc(0x1b, &sc->gkb_q);
  719: 				putc('[', &sc->gkb_q);
  720: 				putc('Z', &sc->gkb_q);
  721: 				continue;
  722: 			}
  723: 		}
  724: 
  725: 		/* normal chars, normal chars with the META, function keys */
  726: 		switch (KEYFLAGS(c)) {
  727: 		case 0:			/* a normal char */
  728: 			putc(KEYCHAR(c), &sc->gkb_q);
  729: 			break;
  730: 		case MKEY:		/* the META flag: prepend ESC */
  731: 			putc(0x1b, &sc->gkb_q);
  732: 			putc(KEYCHAR(c), &sc->gkb_q);
  733: 			break;
  734: 		case FKEY | SPCLKEY:	/* a function key, return string */
  735: 			cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd,
  736: 							KEYCHAR(c), &len);
  737: 			if (cp != NULL) {
  738: 				while (len-- >  0)
  739: 					putc(*cp++, &sc->gkb_q);
  740: 			}
  741: 			break;
  742: 		}
  743: 	}
  744: 
  745: 	/* wake up sleeping/polling processes */
  746: 	if (sc->gkb_q.c_cc > 0) {
  747: 		if (sc->gkb_flags & KB_ASLEEP) {
  748: 			sc->gkb_flags &= ~KB_ASLEEP;
  749: 			wakeup((caddr_t)sc);
  750: 		}
  751: 		selwakeup(&sc->gkb_rsel);
  752: 	}
  753: 
  754: 	return 0;
  755: }
  756: 
  757: #endif /* KBD_INSTALL_CDEV */
  758: 
  759: /*
  760:  * Generic low-level keyboard functions
  761:  * The low-level functions in the keyboard subdriver may use these
  762:  * functions.
  763:  */
  764: 
  765: int
  766: genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
  767: {
  768: 	keyarg_t *keyp;
  769: 	fkeyarg_t *fkeyp;
  770: 	int s;
  771: 	int i;
  772: 
  773: 	s = spltty();
  774: 	switch (cmd) {
  775: 
  776: 	case KDGKBINFO:		/* get keyboard information */
  777: 		((keyboard_info_t *)arg)->kb_index = kbd->kb_index;
  778: 		i = imin(strlen(kbd->kb_name) + 1,
  779: 			 sizeof(((keyboard_info_t *)arg)->kb_name));
  780: 		bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i);
  781: 		((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit;
  782: 		((keyboard_info_t *)arg)->kb_type = kbd->kb_type;
  783: 		((keyboard_info_t *)arg)->kb_config = kbd->kb_config;
  784: 		((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags;
  785: 		break;
  786: 
  787: 	case KDGKBTYPE:		/* get keyboard type */
  788: 		*(int *)arg = kbd->kb_type;
  789: 		break;
  790: 
  791: 	case KDGETREPEAT:	/* get keyboard repeat rate */
  792: 		((int *)arg)[0] = kbd->kb_delay1;
  793: 		((int *)arg)[1] = kbd->kb_delay2; 
  794: 		break;
  795: 
  796: 	case GIO_KEYMAP:	/* get keyboard translation table */
  797: 		bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap));
  798: 		break;
  799: 	case PIO_KEYMAP:	/* set keyboard translation table */
  800: #ifndef KBD_DISABLE_KEYMAP_LOAD
  801: 		bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
  802: 		bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
  803: 		break;
  804: #else
  805: 		splx(s);
  806: 		return ENODEV;
  807: #endif
  808: 
  809: 	case GIO_KEYMAPENT:	/* get keyboard translation table entry */
  810: 		keyp = (keyarg_t *)arg;
  811: 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
  812: 					/sizeof(kbd->kb_keymap->key[0])) {
  813: 			splx(s);
  814: 			return EINVAL;
  815: 		}
  816: 		bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key,
  817: 		      sizeof(keyp->key));
  818: 		break;
  819: 	case PIO_KEYMAPENT:	/* set keyboard translation table entry */
  820: #ifndef KBD_DISABLE_KEYMAP_LOAD
  821: 		keyp = (keyarg_t *)arg;
  822: 		if (keyp->keynum >= sizeof(kbd->kb_keymap->key)
  823: 					/sizeof(kbd->kb_keymap->key[0])) {
  824: 			splx(s);
  825: 			return EINVAL;
  826: 		}
  827: 		bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
  828: 		      sizeof(keyp->key));
  829: 		break;
  830: #else
  831: 		splx(s);
  832: 		return ENODEV;
  833: #endif
  834: 
  835: 	case GIO_DEADKEYMAP:	/* get accent key translation table */
  836: 		bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap));
  837: 		break;
  838: 	case PIO_DEADKEYMAP:	/* set accent key translation table */
  839: #ifndef KBD_DISABLE_KEYMAP_LOAD
  840: 		bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
  841: 		break;
  842: #else
  843: 		splx(s);
  844: 		return ENODEV;
  845: #endif
  846: 
  847: 	case GETFKEY:		/* get functionkey string */
  848: 		fkeyp = (fkeyarg_t *)arg;
  849: 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
  850: 			splx(s);
  851: 			return EINVAL;
  852: 		}
  853: 		bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef,
  854: 		      kbd->kb_fkeytab[fkeyp->keynum].len);
  855: 		fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len;
  856: 		break;
  857: 	case SETFKEY:		/* set functionkey string */
  858: #ifndef KBD_DISABLE_KEYMAP_LOAD
  859: 		fkeyp = (fkeyarg_t *)arg;
  860: 		if (fkeyp->keynum >= kbd->kb_fkeytab_size) {
  861: 			splx(s);
  862: 			return EINVAL;
  863: 		}
  864: 		kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
  865: 		bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
  866: 		      kbd->kb_fkeytab[fkeyp->keynum].len);
  867: 		break;
  868: #else
  869: 		splx(s);
  870: 		return ENODEV;
  871: #endif
  872: 
  873: 	default:
  874: 		splx(s);
  875: 		return ENOIOCTL;
  876: 	}
  877: 
  878: 	splx(s);
  879: 	return 0;
  880: }
  881: 
  882: /* get a pointer to the string associated with the given function key */
  883: u_char
  884: *genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len)
  885: {
  886: 	if (kbd == NULL)
  887: 		return NULL;
  888: 	fkey -= F_FN;
  889: 	if (fkey > kbd->kb_fkeytab_size)
  890: 		return NULL;
  891: 	*len = kbd->kb_fkeytab[fkey].len;
  892: 	return kbd->kb_fkeytab[fkey].str;
  893: }
  894: 
  895: /* diagnostic dump */
  896: static char
  897: *get_kbd_type_name(int type)
  898: {
  899: 	static struct {
  900: 		int type;
  901: 		char *name;
  902: 	} name_table[] = {
  903: 		{ KB_84,	"AT 84" },
  904: 		{ KB_101,	"AT 101/102" },
  905: 		{ KB_OTHER,	"generic" },
  906: 	};
  907: 	int i;
  908: 
  909: 	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
  910: 		if (type == name_table[i].type)
  911: 			return name_table[i].name;
  912: 	}
  913: 	return "unknown";
  914: }
  915: 
  916: void
  917: genkbd_diag(keyboard_t *kbd, int level)
  918: {
  919: 	if (level > 0) {
  920: 		printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 
  921: 		       kbd->kb_index, kbd->kb_name, kbd->kb_unit,
  922: 		       get_kbd_type_name(kbd->kb_type), kbd->kb_type,
  923: 		       kbd->kb_config, kbd->kb_flags);
  924: 		if (kbd->kb_io_base > 0)
  925: 			printf(", port:0x%x-0x%x", kbd->kb_io_base, 
  926: 			       kbd->kb_io_base + kbd->kb_io_size - 1);
  927: 		printf("\n");
  928: 	}
  929: }
  930: 
  931: #define set_lockkey_state(k, s, l)				\
  932: 	if (!((s) & l ## DOWN)) {				\
  933: 		int i;						\
  934: 		(s) |= l ## DOWN;				\
  935: 		(s) ^= l ## ED;					\
  936: 		i = (s) & LOCK_MASK;				\
  937: 		(*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \
  938: 	}
  939: 
  940: static u_int
  941: save_accent_key(keyboard_t *kbd, u_int key, int *accents)
  942: {
  943: 	int i;
  944: 
  945: 	/* make an index into the accent map */
  946: 	i = key - F_ACC + 1;
  947: 	if ((i > kbd->kb_accentmap->n_accs)
  948: 	    || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) {
  949: 		/* the index is out of range or pointing to an empty entry */
  950: 		*accents = 0;
  951: 		return ERRKEY;
  952: 	}
  953: 
  954: 	/* 
  955: 	 * If the same accent key has been hit twice, produce the accent char
  956: 	 * itself.
  957: 	 */
  958: 	if (i == *accents) {
  959: 		key = kbd->kb_accentmap->acc[i - 1].accchar;
  960: 		*accents = 0;
  961: 		return key;
  962: 	}
  963: 
  964: 	/* remember the index and wait for the next key  */
  965: 	*accents = i; 
  966: 	return NOKEY;
  967: }
  968: 
  969: static u_int
  970: make_accent_char(keyboard_t *kbd, u_int ch, int *accents)
  971: {
  972: 	struct acc_t *acc;
  973: 	int i;
  974: 
  975: 	acc = &kbd->kb_accentmap->acc[*accents - 1];
  976: 	*accents = 0;
  977: 
  978: 	/* 
  979: 	 * If the accent key is followed by the space key,
  980: 	 * produce the accent char itself.
  981: 	 */
  982: 	if (ch == ' ')
  983: 		return acc->accchar;
  984: 
  985: 	/* scan the accent map */
  986: 	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
  987: 		if (acc->map[i][0] == 0)	/* end of table */
  988: 			break;
  989: 		if (acc->map[i][0] == ch)
  990: 			return acc->map[i][1];
  991: 	}
  992: 	/* this char cannot be accented... */
  993: 	return ERRKEY;
  994: }
  995: 
  996: int
  997: genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate,
  998: 		 int *accents)
  999: {
 1000: 	struct keyent_t *key;
 1001: 	int state = *shiftstate;
 1002: 	int action;
 1003: 	int f;
 1004: 	int i;
 1005: 
 1006: 	i = keycode;
 1007: 	f = state & (AGRS | ALKED);
 1008: 	if ((f == AGRS1) || (f == AGRS2) || (f == ALKED))
 1009: 		i += ALTGR_OFFSET;
 1010: 	key = &kbd->kb_keymap->key[i];
 1011: 	i = ((state & SHIFTS) ? 1 : 0)
 1012: 	    | ((state & CTLS) ? 2 : 0)
 1013: 	    | ((state & ALTS) ? 4 : 0);
 1014: 	if (((key->flgs & FLAG_LOCK_C) && (state & CLKED))
 1015: 		|| ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) )
 1016: 		i ^= 1;
 1017: 
 1018: 	if (up) {	/* break: key released */
 1019: 		action = kbd->kb_lastact[keycode];
 1020: 		kbd->kb_lastact[keycode] = NOP;
 1021: 		switch (action) {
 1022: 		case LSHA:
 1023: 			if (state & SHIFTAON) {
 1024: 				set_lockkey_state(kbd, state, ALK);
 1025: 				state &= ~ALKDOWN;
 1026: 			}
 1027: 			action = LSH;
 1028: 			/* FALL THROUGH */
 1029: 		case LSH:
 1030: 			state &= ~SHIFTS1;
 1031: 			break;
 1032: 		case RSHA:
 1033: 			if (state & SHIFTAON) {
 1034: 				set_lockkey_state(kbd, state, ALK);
 1035: 				state &= ~ALKDOWN;
 1036: 			}
 1037: 			action = RSH;
 1038: 			/* FALL THROUGH */
 1039: 		case RSH:
 1040: 			state &= ~SHIFTS2;
 1041: 			break;
 1042: 		case LCTRA:
 1043: 			if (state & SHIFTAON) {
 1044: 				set_lockkey_state(kbd, state, ALK);
 1045: 				state &= ~ALKDOWN;
 1046: 			}
 1047: 			action = LCTR;
 1048: 			/* FALL THROUGH */
 1049: 		case LCTR:
 1050: 			state &= ~CTLS1;
 1051: 			break;
 1052: 		case RCTRA:
 1053: 			if (state & SHIFTAON) {
 1054: 				set_lockkey_state(kbd, state, ALK);
 1055: 				state &= ~ALKDOWN;
 1056: 			}
 1057: 			action = RCTR;
 1058: 			/* FALL THROUGH */
 1059: 		case RCTR:
 1060: 			state &= ~CTLS2;
 1061: 			break;
 1062: 		case LALTA:
 1063: 			if (state & SHIFTAON) {
 1064: 				set_lockkey_state(kbd, state, ALK);
 1065: 				state &= ~ALKDOWN;
 1066: 			}
 1067: 			action = LALT;
 1068: 			/* FALL THROUGH */
 1069: 		case LALT:
 1070: 			state &= ~ALTS1;
 1071: 			break;
 1072: 		case RALTA:
 1073: 			if (state & SHIFTAON) {
 1074: 				set_lockkey_state(kbd, state, ALK);
 1075: 				state &= ~ALKDOWN;
 1076: 			}
 1077: 			action = RALT;
 1078: 			/* FALL THROUGH */
 1079: 		case RALT:
 1080: 			state &= ~ALTS2;
 1081: 			break;
 1082: 		case ASH:
 1083: 			state &= ~AGRS1;
 1084: 			break;
 1085: 		case META:
 1086: 			state &= ~METAS1;
 1087: 			break;
 1088: 		case NLK:
 1089: 			state &= ~NLKDOWN;
 1090: 			break;
 1091: 		case CLK:
 1092: #ifndef PC98
 1093: 			state &= ~CLKDOWN;
 1094: #else
 1095: 			state &= ~CLKED;
 1096: 			i = state & LOCK_MASK;
 1097: 			(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
 1098: 						       (caddr_t)&i);
 1099: #endif
 1100: 			break;
 1101: 		case SLK:
 1102: 			state &= ~SLKDOWN;
 1103: 			break;
 1104: 		case ALK:
 1105: 			state &= ~ALKDOWN;
 1106: 			break;
 1107: 		case NOP:
 1108: 			/* release events of regular keys are not reported */
 1109: 			*shiftstate &= ~SHIFTAON;
 1110: 			return NOKEY;
 1111: 		}
 1112: 		*shiftstate = state & ~SHIFTAON;
 1113: 		return (SPCLKEY | RELKEY | action);
 1114: 	} else {	/* make: key pressed */
 1115: 		action = key->map[i];
 1116: 		state &= ~SHIFTAON;
 1117: 		if (key->spcl & (0x80 >> i)) {
 1118: 			/* special keys */
 1119: 			if (kbd->kb_lastact[keycode] == NOP)
 1120: 				kbd->kb_lastact[keycode] = action;
 1121: 			if (kbd->kb_lastact[keycode] != action)
 1122: 				action = NOP;
 1123: 			switch (action) {
 1124: 			/* LOCKING KEYS */
 1125: 			case NLK:
 1126: 				set_lockkey_state(kbd, state, NLK);
 1127: 				break;
 1128: 			case CLK:
 1129: #ifndef PC98
 1130: 				set_lockkey_state(kbd, state, CLK);
 1131: #else
 1132: 				state |= CLKED;
 1133: 				i = state & LOCK_MASK;
 1134: 				(*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED,
 1135: 							       (caddr_t)&i);
 1136: #endif
 1137: 				break;
 1138: 			case SLK:
 1139: 				set_lockkey_state(kbd, state, SLK);
 1140: 				break;
 1141: 			case ALK:
 1142: 				set_lockkey_state(kbd, state, ALK);
 1143: 				break;
 1144: 			/* NON-LOCKING KEYS */
 1145: 			case SPSC: case RBT:  case SUSP: case STBY:
 1146: 			case DBG:  case NEXT: case PREV: case PNC:
 1147: 			case HALT: case PDWN:
 1148: 				*accents = 0;
 1149: 				break;
 1150: 			case BTAB:
 1151: 				*accents = 0;
 1152: 				action |= BKEY;
 1153: 				break;
 1154: 			case LSHA:
 1155: 				state |= SHIFTAON;
 1156: 				action = LSH;
 1157: 				/* FALL THROUGH */
 1158: 			case LSH:
 1159: 				state |= SHIFTS1;
 1160: 				break;
 1161: 			case RSHA:
 1162: 				state |= SHIFTAON;
 1163: 				action = RSH;
 1164: 				/* FALL THROUGH */
 1165: 			case RSH:
 1166: 				state |= SHIFTS2;
 1167: 				break;
 1168: 			case LCTRA:
 1169: 				state |= SHIFTAON;
 1170: 				action = LCTR;
 1171: 				/* FALL THROUGH */
 1172: 			case LCTR:
 1173: 				state |= CTLS1;
 1174: 				break;
 1175: 			case RCTRA:
 1176: 				state |= SHIFTAON;
 1177: 				action = RCTR;
 1178: 				/* FALL THROUGH */
 1179: 			case RCTR:
 1180: 				state |= CTLS2;
 1181: 				break;
 1182: 			case LALTA:
 1183: 				state |= SHIFTAON;
 1184: 				action = LALT;
 1185: 				/* FALL THROUGH */
 1186: 			case LALT:
 1187: 				state |= ALTS1;
 1188: 				break;
 1189: 			case RALTA:
 1190: 				state |= SHIFTAON;
 1191: 				action = RALT;
 1192: 				/* FALL THROUGH */
 1193: 			case RALT:
 1194: 				state |= ALTS2;
 1195: 				break;
 1196: 			case ASH:
 1197: 				state |= AGRS1;
 1198: 				break;
 1199: 			case META:
 1200: 				state |= METAS1;
 1201: 				break;
 1202: 			case NOP:
 1203: 				*shiftstate = state;
 1204: 				return NOKEY;
 1205: 			default:
 1206: 				/* is this an accent (dead) key? */
 1207: 				*shiftstate = state;
 1208: 				if (action >= F_ACC && action <= L_ACC) {
 1209: 					action = save_accent_key(kbd, action,
 1210: 								 accents);
 1211: 					switch (action) {
 1212: 					case NOKEY:
 1213: 					case ERRKEY:
 1214: 						return action;
 1215: 					default:
 1216: 						if (state & METAS)
 1217: 							return (action | MKEY);
 1218: 						else
 1219: 							return action;
 1220: 					}
 1221: 					/* NOT REACHED */
 1222: 				}
 1223: 				/* other special keys */
 1224: 				if (*accents > 0) {
 1225: 					*accents = 0;
 1226: 					return ERRKEY;
 1227: 				}
 1228: 				if (action >= F_FN && action <= L_FN)
 1229: 					action |= FKEY;
 1230: 				/* XXX: return fkey string for the FKEY? */
 1231: 				return (SPCLKEY | action);
 1232: 			}
 1233: 			*shiftstate = state;
 1234: 			return (SPCLKEY | action);
 1235: 		} else {
 1236: 			/* regular keys */
 1237: 			kbd->kb_lastact[keycode] = NOP;
 1238: 			*shiftstate = state;
 1239: 			if (*accents > 0) {
 1240: 				/* make an accented char */
 1241: 				action = make_accent_char(kbd, action, accents);
 1242: 				if (action == ERRKEY)
 1243: 					return action;
 1244: 			}
 1245: 			if (state & METAS)
 1246: 				action |= MKEY;
 1247: 			return action;
 1248: 		}
 1249: 	}
 1250: 	/* NOT REACHED */
 1251: }