e0cc03a09b
kqueue provides a stateful and efficient event notification framework currently supported events include socket, file, directory, fifo, pipe, tty and device changes, and monitoring of processes and signals kqueue is supported by all writable filesystems in NetBSD tree (with exception of Coda) and all device drivers supporting poll(2) based on work done by Jonathan Lemon for FreeBSD initial NetBSD port done by Luke Mewburn and Jason Thorpe
254 lines
5.5 KiB
C
254 lines
5.5 KiB
C
/* $NetBSD: arcbios_tty.c,v 1.6 2002/10/23 09:13:06 jdolecek Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
|
|
* All rights reserved.
|
|
*
|
|
* Author: Chris G. Demetriou
|
|
*
|
|
* Permission to use, copy, modify and distribute this software and
|
|
* its documentation is hereby granted, provided that both the copyright
|
|
* notice and this permission notice appear in all copies of the
|
|
* software, derivative works or modified versions, and any portions
|
|
* thereof, and that both notices appear in supporting documentation.
|
|
*
|
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
|
|
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
|
*
|
|
* Carnegie Mellon requests users of this software to return to
|
|
*
|
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
|
* School of Computer Science
|
|
* Carnegie Mellon University
|
|
* Pittsburgh PA 15213-3890
|
|
*
|
|
* any improvements or extensions that they make and grant Carnegie the
|
|
* rights to redistribute these changes.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: arcbios_tty.c,v 1.6 2002/10/23 09:13:06 jdolecek Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/user.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/callout.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/termios.h>
|
|
|
|
#include <dev/cons.h>
|
|
|
|
#include <dev/arcbios/arcbios.h>
|
|
#include <dev/arcbios/arcbiosvar.h>
|
|
|
|
struct callout arcbios_tty_ch = CALLOUT_INITIALIZER;
|
|
|
|
static struct tty *arcbios_tty[1];
|
|
|
|
void arcbios_tty_start(struct tty *);
|
|
void arcbios_tty_poll(void *);
|
|
int arcbios_tty_param(struct tty *, struct termios *);
|
|
|
|
dev_type_open(arcbios_ttyopen);
|
|
dev_type_close(arcbios_ttyclose);
|
|
dev_type_read(arcbios_ttyread);
|
|
dev_type_write(arcbios_ttywrite);
|
|
dev_type_ioctl(arcbios_ttyioctl);
|
|
dev_type_stop(arcbios_ttystop);
|
|
dev_type_tty(arcbios_ttytty);
|
|
dev_type_poll(arcbios_ttypoll);
|
|
|
|
const struct cdevsw arcbios_cdevsw = {
|
|
arcbios_ttyopen, arcbios_ttyclose, arcbios_ttyread, arcbios_ttywrite,
|
|
arcbios_ttyioctl, arcbios_ttystop, arcbios_ttytty, arcbios_ttypoll,
|
|
nommap, ttykqfilter, D_TTY,
|
|
};
|
|
|
|
int
|
|
arcbios_ttyopen(dev_t dev, int flag, int mode, struct proc *p)
|
|
{
|
|
int unit = minor(dev);
|
|
struct tty *tp;
|
|
int s, error = 0, setuptimeout = 0;
|
|
|
|
if (unit != 0)
|
|
return (ENODEV);
|
|
|
|
s = spltty();
|
|
|
|
if (arcbios_tty[unit] == NULL) {
|
|
tp = arcbios_tty[unit] = ttymalloc();
|
|
tty_attach(tp);
|
|
} else
|
|
tp = arcbios_tty[unit];
|
|
|
|
tp->t_oproc = arcbios_tty_start;
|
|
tp->t_param = arcbios_tty_param;
|
|
tp->t_dev = dev;
|
|
if ((tp->t_state & TS_ISOPEN) == 0) {
|
|
tp->t_state |= TS_CARR_ON;
|
|
ttychars(tp);
|
|
tp->t_iflag = TTYDEF_IFLAG;
|
|
tp->t_oflag = TTYDEF_OFLAG;
|
|
tp->t_cflag = TTYDEF_CFLAG | CLOCAL;
|
|
tp->t_lflag = TTYDEF_LFLAG;
|
|
tp->t_ispeed = tp->t_ospeed = 9600;
|
|
ttsetwater(tp);
|
|
|
|
setuptimeout = 1;
|
|
} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
|
|
splx(s);
|
|
return (EBUSY);
|
|
}
|
|
|
|
splx(s);
|
|
|
|
error = (*tp->t_linesw->l_open)(dev, tp);
|
|
if (error == 0 && setuptimeout)
|
|
callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp);
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
arcbios_ttyclose(dev_t dev, int flag, int mode, struct proc *p)
|
|
{
|
|
int unit = minor(dev);
|
|
struct tty *tp = arcbios_tty[unit];
|
|
|
|
callout_stop(&arcbios_tty_ch);
|
|
(*tp->t_linesw->l_close)(tp, flag);
|
|
ttyclose(tp);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
arcbios_ttyread(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct tty *tp = arcbios_tty[minor(dev)];
|
|
|
|
return ((*tp->t_linesw->l_read)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
arcbios_ttywrite(dev_t dev, struct uio *uio, int flag)
|
|
{
|
|
struct tty *tp = arcbios_tty[minor(dev)];
|
|
|
|
return ((*tp->t_linesw->l_write)(tp, uio, flag));
|
|
}
|
|
|
|
int
|
|
arcbios_ttypoll(dev_t dev, int events, struct proc *p)
|
|
{
|
|
struct tty *tp = arcbios_tty[minor(dev)];
|
|
|
|
return ((*tp->t_linesw->l_poll)(tp, events, p));
|
|
}
|
|
|
|
int
|
|
arcbios_ttyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|
{
|
|
int unit = minor(dev);
|
|
struct tty *tp = arcbios_tty[unit];
|
|
int error;
|
|
|
|
error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
|
|
if (error != EPASSTHROUGH)
|
|
return (error);
|
|
return (ttioctl(tp, cmd, data, flag, p));
|
|
}
|
|
|
|
int
|
|
arcbios_tty_param(struct tty *tp, struct termios *t)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
arcbios_tty_start(struct tty *tp)
|
|
{
|
|
uint32_t count;
|
|
int s;
|
|
|
|
s = spltty();
|
|
if (tp->t_state & (TS_TTSTOP | TS_BUSY))
|
|
goto out;
|
|
if (tp->t_outq.c_cc <= tp->t_lowat) {
|
|
if (tp->t_state & TS_ASLEEP) {
|
|
tp->t_state &= ~TS_ASLEEP;
|
|
wakeup((caddr_t)&tp->t_outq);
|
|
}
|
|
selwakeup(&tp->t_wsel);
|
|
}
|
|
tp->t_state |= TS_BUSY;
|
|
while (tp->t_outq.c_cc != 0) {
|
|
(*ARCBIOS->Write)(ARCBIOS_STDOUT, tp->t_outq.c_cf,
|
|
ndqb(&tp->t_outq, 0), &count);
|
|
ndflush(&tp->t_outq, count);
|
|
}
|
|
tp->t_state &= ~TS_BUSY;
|
|
out:
|
|
splx(s);
|
|
}
|
|
|
|
void
|
|
arcbios_ttystop(struct tty *tp, int flag)
|
|
{
|
|
int s;
|
|
|
|
s = spltty();
|
|
if (tp->t_state & TS_BUSY)
|
|
if ((tp->t_state & TS_TTSTOP) == 0)
|
|
tp->t_state |= TS_FLUSH;
|
|
splx(s);
|
|
}
|
|
|
|
static int
|
|
arcbios_tty_getchar(int *cp)
|
|
{
|
|
char c;
|
|
int32_t q;
|
|
u_int32_t count;
|
|
|
|
q = ARCBIOS->GetReadStatus(ARCBIOS_STDIN);
|
|
|
|
if (q == 0) {
|
|
ARCBIOS->Read(ARCBIOS_STDIN, &c, 1, &count);
|
|
*cp = c;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
arcbios_tty_poll(void *v)
|
|
{
|
|
struct tty *tp = v;
|
|
int c, l_r;
|
|
|
|
while (arcbios_tty_getchar(&c)) {
|
|
if (tp->t_state & TS_ISOPEN)
|
|
l_r = (*tp->t_linesw->l_rint)(c, tp);
|
|
}
|
|
callout_reset(&arcbios_tty_ch, 1, arcbios_tty_poll, tp);
|
|
}
|
|
|
|
struct tty *
|
|
arcbios_ttytty(dev_t dev)
|
|
{
|
|
|
|
if (minor(dev) != 0)
|
|
panic("arcbios_ttytty: bogus");
|
|
|
|
return (arcbios_tty[0]);
|
|
}
|