FreeBSD-5.3/sys/ia64/ia64/ssc.c
/*-
* Copyright (c) 2000 Doug Rabson
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD: src/sys/ia64/ia64/ssc.c,v 1.23 2004/07/15 20:47:40 phk Exp $
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/cons.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <machine/md_var.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
#include <vm/vm_page.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
#include <vm/vm_pageout.h>
#include <vm/vm_pager.h>
#define SSC_GETCHAR 21
#define SSC_PUTCHAR 31
#define SSC_POLL_HZ 50
static d_open_t sscopen;
static d_close_t sscclose;
static struct cdevsw ssc_cdevsw = {
.d_version = D_VERSION,
.d_open = sscopen,
.d_close = sscclose,
.d_name = "ssc",
.d_flags = D_TTY | D_NEEDGIANT,
};
static struct tty *ssc_tp = NULL;
static int polltime;
static struct callout_handle ssctimeouthandle
= CALLOUT_HANDLE_INITIALIZER(&ssctimeouthandle);
static void sscstart(struct tty *);
static void ssctimeout(void *);
static int sscparam(struct tty *, struct termios *);
static void sscstop(struct tty *, int);
static u_int64_t
ssc(u_int64_t in0, u_int64_t in1, u_int64_t in2, u_int64_t in3, int which)
{
register u_int64_t ret0 __asm("r8");
__asm __volatile("mov r15=%1\n\t"
"break 0x80001"
: "=r"(ret0)
: "r"(which), "r"(in0), "r"(in1), "r"(in2), "r"(in3));
return ret0;
}
static void
ssccnprobe(struct consdev *cp)
{
sprintf(cp->cn_name, "ssccons");
cp->cn_pri = CN_INTERNAL;
}
static void
ssccninit(struct consdev *cp)
{
}
static void
ssccnattach(void *arg)
{
make_dev(&ssc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "ssccons");
}
SYSINIT(ssccnattach, SI_SUB_DRIVERS, SI_ORDER_ANY, ssccnattach, 0);
static void
ssccnputc(struct consdev *cp, int c)
{
ssc(c, 0, 0, 0, SSC_PUTCHAR);
}
static int
ssccngetc(struct consdev *cp)
{
int c;
do {
c = ssc(0, 0, 0, 0, SSC_GETCHAR);
} while (c == 0);
return c;
}
static int
ssccncheckc(struct consdev *cp)
{
int c;
c = ssc(0, 0, 0, 0, SSC_GETCHAR);
if (!c)
return -1;
return c;
}
static int
sscopen(struct cdev *dev, int flag, int mode, struct thread *td)
{
struct tty *tp;
int s;
int error = 0, setuptimeout = 0;
tp = ssc_tp = dev->si_tty = ttymalloc(ssc_tp);
s = spltty();
tp->t_oproc = sscstart;
tp->t_param = sscparam;
tp->t_stop = sscstop;
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 = TTYDEF_SPEED;
ttsetwater(tp);
setuptimeout = 1;
} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
splx(s);
return EBUSY;
}
splx(s);
error = ttyld_open(tp, dev);
if (error == 0 && setuptimeout) {
polltime = hz / SSC_POLL_HZ;
if (polltime < 1)
polltime = 1;
ssctimeouthandle = timeout(ssctimeout, tp, polltime);
}
return error;
}
static int
sscclose(struct cdev *dev, int flag, int mode, struct thread *td)
{
int unit = minor(dev);
struct tty *tp = ssc_tp;
if (unit != 0)
return ENXIO;
untimeout(ssctimeout, tp, ssctimeouthandle);
ttyld_close(tp, flag);
tty_close(tp);
return 0;
}
static int
sscparam(struct tty *tp, struct termios *t)
{
return 0;
}
static void
sscstart(struct tty *tp)
{
int s;
s = spltty();
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
ttwwakeup(tp);
splx(s);
return;
}
tp->t_state |= TS_BUSY;
while (tp->t_outq.c_cc != 0)
ssccnputc(NULL, getc(&tp->t_outq));
tp->t_state &= ~TS_BUSY;
ttwwakeup(tp);
splx(s);
}
/*
* Stop output on a line.
*/
static void
sscstop(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 void
ssctimeout(void *v)
{
struct tty *tp = v;
int c;
while ((c = ssccncheckc(NULL)) != -1) {
if (tp->t_state & TS_ISOPEN)
ttyld_rint(tp, c);
}
ssctimeouthandle = timeout(ssctimeout, tp, polltime);
}
CONS_DRIVER(ssc, ssccnprobe, ssccninit, NULL, ssccngetc, ssccncheckc, ssccnputc, NULL);