#include <sys/param.h>
#include <sys/tty.h>
#include <machine/cons.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/msgbuf.h>
#include <sys/time.h>
#include <dev/kmreg_com.h>
#include <pexpert/pexpert.h>
#include <pexpert/i386/boot.h>
extern int hz;
extern void cnputcusr(char);
extern int cngetc(void);
void kminit(void);
void cons_cinput(char ch);
struct tty *km_tty[1] = { 0 };
int disableConsoleOutput;
int initialized = 0;
static int kmoutput(struct tty *tp);
static void kmstart(struct tty *tp);
extern void KeyboardOpen(void);
void
kminit(void)
{
km_tty[0] = ttymalloc();
km_tty[0]->t_dev = makedev(12, 0);
initialized = 1;
}
int
kmopen(dev_t dev, int flag, __unused int devtype, proc_t pp)
{
int unit;
struct tty *tp;
struct winsize *wp;
int ret;
unit = minor(dev);
if(unit >= 1)
return (ENXIO);
tp = km_tty[unit];
tty_lock(tp);
tp->t_oproc = kmstart;
tp->t_param = NULL;
tp->t_dev = dev;
if ( !(tp->t_state & TS_ISOPEN) ) {
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
tp->t_cflag = (CREAD | CS8 | CLOCAL);
tp->t_lflag = TTYDEF_LFLAG;
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
termioschars(&tp->t_termios);
ttsetwater(tp);
} else if ((tp->t_state & TS_XCLUDE) && proc_suser(pp)) {
ret = EBUSY;
goto out;
}
tp->t_state |= TS_CARR_ON;
ret = ((*linesw[tp->t_line].l_open)(dev, tp));
{
PE_Video video;
wp = &tp->t_winsize;
wp->ws_xpixel = 8;
wp->ws_ypixel = 16;
tty_unlock(tp);
if (flag & O_POPUP)
PE_initialize_console(0, kPETextScreen);
bzero(&video, sizeof(video));
PE_current_console(&video);
tty_lock(tp);
if( video.v_display == FB_TEXT_MODE && video.v_width != 0 && video.v_height != 0 ) {
wp->ws_col = video.v_width / wp->ws_xpixel;
wp->ws_row = video.v_height / wp->ws_ypixel;
} else {
wp->ws_col = 100;
wp->ws_row = 36;
}
}
out:
tty_unlock(tp);
return ret;
}
int
kmclose(dev_t dev, int flag, __unused int mode, __unused proc_t p)
{
int ret;
struct tty *tp = km_tty[minor(dev)];
tty_lock(tp);
ret = (*linesw[tp->t_line].l_close)(tp,flag);
ttyclose(tp);
tty_unlock(tp);
return (ret);
}
int
kmread(dev_t dev, struct uio *uio, int ioflag)
{
int ret;
struct tty *tp = km_tty[minor(dev)];
tty_lock(tp);
ret = (*linesw[tp->t_line].l_read)(tp, uio, ioflag);
tty_unlock(tp);
return (ret);
}
int
kmwrite(dev_t dev, struct uio *uio, int ioflag)
{
int ret;
struct tty *tp = km_tty[minor(dev)];
tty_lock(tp);
ret = (*linesw[tp->t_line].l_write)(tp, uio, ioflag);
tty_unlock(tp);
return (ret);
}
int
kmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, proc_t p)
{
int error = 0;
struct tty *tp = km_tty[minor(dev)];
struct winsize *wp;
tty_lock(tp);
switch (cmd) {
case KMIOCSIZE:
wp = (struct winsize *)data;
*wp = tp->t_winsize;
break;
case TIOCSWINSZ:
error = EINVAL;
break;
case TIOCSETA_32:
case TIOCSETAW_32:
case TIOCSETAF_32:
{
struct termios32 *t = (struct termios32 *)data;
t->c_cflag |= CLOCAL;
}
goto fallthrough;
case TIOCSETA_64:
case TIOCSETAW_64:
case TIOCSETAF_64:
{
struct user_termios *t = (struct user_termios *)data;
t->c_cflag |= CLOCAL;
}
fallthrough:
default:
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
if (ENOTTY != error)
break;
error = ttioctl_locked(tp, cmd, data, flag, p);
break;
}
tty_unlock(tp);
return (error);
}
int
kmputc(__unused dev_t dev, char c)
{
if(!disableConsoleOutput && initialized) {
if(c == '\n')
cnputcusr('\r');
cnputcusr(c);
}
return (0);
}
#define KM_LOWAT_DELAY ((ns_time_t)1000)
static void
kmstart(struct tty *tp)
{
if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
goto out;
if (tp->t_outq.c_cc == 0)
goto out;
tp->t_state |= TS_BUSY;
kmoutput(tp);
return;
out:
(*linesw[tp->t_line].l_start)(tp);
return;
}
static void
kmtimeout(void *arg)
{
struct tty *tp = (struct tty *)arg;
tty_lock(tp);
(void)kmoutput(tp);
tty_unlock(tp);
}
static int
kmoutput(struct tty *tp)
{
unsigned char buf[80];
unsigned char *cp;
int cc = -1;
while (tp->t_outq.c_cc > 0) {
cc = ndqb(&tp->t_outq, 0);
if (cc == 0)
break;
cc = min(cc, sizeof(buf));
(void) q_to_b(&tp->t_outq, buf, cc);
for (cp = buf; cp < &buf[cc]; cp++) {
kmputc(tp->t_dev, *cp & 0x7f);
}
}
if (tp->t_outq.c_cc > 0) {
timeout(kmtimeout, tp, hz);
}
tp->t_state &= ~TS_BUSY;
(*linesw[tp->t_line].l_start)(tp);
return 0;
}
void
cons_cinput(char ch)
{
struct tty *tp = km_tty[0];
tty_lock(tp);
(*linesw[tp->t_line].l_rint) (ch, tp);
tty_unlock(tp);
}