4.4BSD/usr/src/sys/news3400/bm/kb_ctrl.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
 *
 * 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. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
 *
 * from: $Hdr: kb_ctrl.c,v 4.300 91/06/09 06:14:49 root Rel41 $ SONY
 *
 *	@(#)kb_ctrl.c	8.1 (Berkeley) 6/10/93
 */

/*
 *	Keyboard driver
 */

#ifdef IPC_MRX
#include <sys/ioctl.h>
#include <news3400/iop/keyboard.h>
#include <news3400/iop/kbreg.h>
#else
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <news3400/iop/keyboard.h>
#include <news3400/iop/kbreg.h>
#endif

extern int tmode;
extern int kbd_status;

int iscaps = 0;
int change_country = K_JAPANESE_J;
int country;

extern Key_table default_table[];

#ifdef CPU_SINGLE
extern Key_table key_table[];
Key_table *key_table_addr = key_table;
#endif

#ifdef CPU_DOUBLE
Key_table *key_table_addr = default_table;
#endif

#ifdef CPU_SINGLE
#include "ms.h"
#include <sys/clist.h>	
#include <sys/ttydev.h>
#include <sys/tty.h>
#include <news3400/sio/scc.h>
#include <sys/time.h>
#include <news3400/iop/mouse.h>

extern int cnrint();

kbd_open(chan)
	int chan;
{
	register int i;

#if defined(news3400)
	kbm_open(chan);
#endif
	return (0);
}

kbd_read(chan, buf, n)
	int chan;
	char *buf;
	int n;
{
#if defined(news1700) || defined(news1200)

	return (kbd_read_raw(chan, buf, n));
#endif
}

kbd_write(chan, buf, n)
	int chan;
	char *buf;
	int n;
{

#if defined(news3400)
	return (kbm_write(SCC_KEYBOARD, buf, n));
#endif
}

kbd_back(buf, len)
	register char *buf;
	register int len;
{
	int s;

	while (--len >= 0) {
		s = spltty();
		cnrint(*buf++);
		(void) splx(s);
	}
	return (0);
}

#define	KBPRI	(PZERO+1)

struct clist scode_buf;
struct clist keyboard_buf;
char	kb_rwait;

kbd_flush()
{

	ndflush(&scode_buf, scode_buf.c_cc);
	return (0);
}

static
kbd_put_raw(scode)
	int scode;
{
	extern char kb_busy;

	if (kb_busy) {
		if (scode_buf.c_cc < CBSIZE)
			putc(scode, &scode_buf);
		if (kb_rwait) {
			kb_rwait = 0;
			wakeup((caddr_t)&kb_rwait);
		}
	}
	return (scode);
	
}

kbd_read_raw(chan, buf, count)
	int chan;
	char *buf;
	register int count;
{
	register int i;
	register int n;
	register int s;

	if (count <= 0)
		return (count);
	s = splscc();
	while ((n = min(scode_buf.c_cc, count)) == 0) {
		kb_rwait = 1;
		sleep((caddr_t)&kb_rwait, KBPRI);
		kb_rwait = 0;
	}
	(void) splx(s);
	for (i = n; i > 0 ; i--)
		*buf++ = getc(&scode_buf);
	return (n);
}

kbd_nread()
{

	return (scode_buf.c_cc);
}

kbd_bell(n)
	register int n;
{

#if defined(news3400)
	(void) kbm_write(SCC_KEYBOARD, NULL, n);
#endif
	return (0);
}

kbd_putcode(code)
	int code;
{
	int c;

	kbd_put_raw(code);
	kbd_encode(code);
	while ((c = getc(&keyboard_buf)) != -1)
		cnrint(c); 
}

put_code(buf, cnt)
	register char *buf;
	register int cnt;
{

	while (--cnt >= 0)
		putc(*buf++, &keyboard_buf);
}

kb_softint()
{
	int code;
	extern int tty00_is_console;

	while ((code = xgetc(SCC_KEYBOARD)) >= 0) {
#if defined(news3200)		/* BEGIN reiko */
		if ((code & 0x7f) == KEY_EISUU) {
			int up = code & OFF;
			static int kana = 0;

			if (kana) {
				if (up) {
					kana = 0;
				}
			} else {
				if (up) {
					code = KEY_KANA | OFF;
					kana = 1;
				} else {
					code = KEY_KANA;
				}
			}
		}
#endif

#ifdef NOTDEF /* KU:XXX */
		if (!tty00_is_console) 
#endif
			rst_dimmer_cnt();
#if NMS > 0
		if (!mskeytrigger(0, code & OFF, code & 0x7f))
#endif
		kbd_putcode(code);
	}
}
#endif /* CPU_SINGLE */

#ifdef IPC_MRX
#include "mrx.h"
#include "queue.h"
#include "process.h"
#include "buffer.h"
#include "port.h"
#include "message.h"
#include "machdep.h"
#include "malloc.h"
#include "config.h"
#include "kbms.h"

static struct buffer *kbd_buf;
static int port_kbd_intr;
static int port_kbd_back;
static int port_kbd_ctrl;

keyboard(chan)
	int chan;
{
	int kbd_ctrl(), kbd_output();
	int kbd_read(), kbd_ioctl(), kbd_io();

#ifdef news3800
	extern int (*Xkb_intr)();
	int kb_intr();

	Xkb_intr = kb_intr;
#endif
	kb_ioctl = kbd_ioctl;
	kb_read = kbd_read;
	kbd_init();
	proc_create("kbd_ctrl", kbd_ctrl, 300, DEFAULT_STACK_SIZE, 0);
	proc_create("kbd_output", kbd_output, 300, DEFAULT_STACK_SIZE, 0);
	proc_create("kbd_io", kbd_io, 300, DEFAULT_STACK_SIZE, 0);
}

int (*reset_dimmer)();

kbd_ctrl()
{
	register int m, n;
	register int select;
	int *len, from, count;
	char *addr;
	int ports[3];
	static char buf[16];

	ports[0] = port_kbd_intr = port_create("kb_intr");
	ports[1] = port_kbd_back = port_create("kb_echoback");
	ports[2] = port_kbd_ctrl = STDPORT;

#ifdef news3800
	*(char *)KEYBD_RESET = 0;
	*(char *)KEYBD_INTE = 1;
#endif

	kbd_buf = buffer_alloc(32);
	(void) spl0();
	for (;;) {
		if (buffer_status(kbd_buf) > 0)
			m = 3;
		else
			m = 2;
		if ((select = msg_select(m, ports)) == 0) {
			msg_recv(ports[0], NULL, &addr, &count, 0);
			if (reset_dimmer)
				(*reset_dimmer)();
			while (--count >= 0) {
				if (send_mouse == 0 || (*send_mouse)(*addr) == 0)
					kbd_encode(*addr);
				addr++;
			}
		} else if (select == 1) {	/* ESC [ 6 n */
			msg_recv(ports[select], NULL, &addr, &count, 0);
			put(kbd_buf, addr, count);
		} else {
			msg_recv(ports[select], &from, &len, NULL, 0); 
			n = buffer_status(kbd_buf);
			n = min(n, *len);
			n = get(kbd_buf, buf, min(n, sizeof (buf)));
			msg_send(from, ports[select], buf, n, 0);
		}
	}
}

kbd_output()
{
	char *addr;
	int from, len;

	(void) spl0();
	for (;;) {
		msg_recv(STDPORT, &from, &addr, &len, 0);
#ifdef news3800
		len = kbd_write(0, addr, len);
#endif
		msg_send(from, STDPORT, &len, sizeof(len), 0);
	}
}

kbd_io()
{
	struct kb_ctrl_req *req;
	int from, reply;

	(void) spl0();
	for (;;) {
		msg_recv(STDPORT, &from, &req, NULL, 0);
		if (req->kb_func == KIOCCHTBL || req->kb_func == KIOCOYATBL)
			kbd_ioctl(0, req->kb_func, req->kb_arg);
		else
			kbd_ioctl(0, req->kb_func, &req->kb_arg);
		reply = req->kb_arg;
		msg_send(from, STDPORT, &reply, sizeof(reply), 0);
	}
}

kbd_read(chan, buf, n)
	int chan;
	char *buf;
	int n;
{
	static int port;
	char *addr;
	int len;

	if (port == 0)
		port = port_create("port_kbd_read");
	if (n <= 0)
		return (0);
	msg_send(port_kbd_ctrl, port, &n, sizeof (n), 0);
	msg_recv(port, NULL, &addr, &len, 0);
	bcopy(addr, buf, len);
	msg_free(port);
	return (len);
}

kbd_write(chan, buf, n)
	int chan;
	char *buf;
	int n;
{

#ifdef news3800
	*(char *)BEEP_FREQ = ~(n & 1);
	*(char *)KEYBD_BEEP = 1;
	return (n);
#endif
}

kbd_back(buf, len)
	char *buf;
	int len;
{

	msg_send(port_kbd_back, 0, buf, len, 0);
	return (0);
}

kbd_nread()
{

	return (buffer_status(kbd_buf));
}

kbd_flush()
{

	buffer_flush(kbd_buf);
	return (0);
}

#ifdef news3800
kb_intr()
{
	char c;

	if (port_kbd_intr > 0)
		while (*(char *)KBMS_STAT & (1 << b_KBREADY)) {
			c = *(char *)KEYBD_DATA;
			msg_send(port_kbd_intr, 0, &c, sizeof (char), 0);
		}
}
#endif /* news3800 */

kbd_bell(n, port)
	int n, port;
{

#ifdef news3800
	(void) kbd_write(0, NULL, n);
#else
	kbd_bell_scc(n, port);
#endif
	return (0);
}

put_code(buf, cnt)
	char *buf;
	int cnt;
{

	put(kbd_buf, buf, cnt);
}
#endif /* IPC_MRX */

kbd_ioctl(chan, cmd, argp)
	int chan;
	int cmd;
	int *argp;
{
	switch (cmd) {

	case KIOCFLUSH:
		return (kbd_flush());

	case KIOCSETS:
	case KIOCGETS:
		return (kbd_string(cmd, (Pfk_string *)argp));

	case KIOCBELL:
		return (kbd_bell(*argp));

	case KIOCBACK:
		if (argp == NULL)
			return (-1);
		if ((int)((Key_string *)argp)->key_string == NULL)
			return (-1);
		if ((int)((Key_string *)argp)->key_length <= 0)
			return (-1);
		return (kbd_back(((Key_string *)argp)->key_string,
		    ((Key_string *)argp)->key_length));

	case KIOCREPT:
		return (kbd_repeat(1));

	case KIOCNRPT:
		return (kbd_repeat(0));

	case KIOCNREAD:
		*argp = kbd_nread();
		return (0);

	case KIOCSETLOCK:
		iscaps = *argp;
		return (0);

	case KIOCGETCNUM:
		*argp = country;
		return (0);

	case KIOCSETCNUM:
		country = *argp;
		change_country = country;
		return (0);

	case KIOCDEFTBL:
		key_table_addr = default_table;
		country = K_JAPANESE_J;
		return (0);

	case KIOCCHTBL:
		key_table_addr = (Key_table *)argp;
		country = change_country;
		return (0);

	case KIOCGETSTAT:
		*argp = kbd_status;
		return (0);

	case KIOCSETSTAT:
		kbd_status = *argp;
		return (0);

	default:
		return (-1);
	}
}

kbd_bell_scc(n)
	register int n;
{
	register int i;
	static char bell_data[] = {
		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0
	};

	while (n > 0) {
		i = min(n, sizeof (bell_data));
		(void) kbd_write(0, bell_data, i);
		n -= i;
	}
}

#ifdef KBDEBUG
scc_error_puts(chan, buf)
	int chan;
	char *buf;
{
	while (*buf) {
		scc_error_write(chan, *buf++, 1);
	}
}

scc_error_write_hex(chan, n, zs)
	int chan;
	unsigned int n;
	int zs;
{
	int i;
	int tmp, al;
	static char hex[] = "0123456789abcdef";

	al = 0;

	for (i = 28; i >= 0; i -= 4) {
		tmp = (n >> i) & 0x0f;
		if (tmp || al || !zs || !i) {
			al++;
			scc_error_write(chan, hex[tmp], 1);
		}
	}
}
#endif /* KBDEBUG */