/* Console handling
   
   Copyright (C) 1996 Pete A. Zaitcev
   		 1996 Jakub Jelinek
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "silo.h"

#define SUN4_PROM_MAGIC     0x10010407

#define SUN4__PROM_VECTOR    0xFFE81000
#define SUN4__PRINTF         0x84	/* offset into a PROM vector */

typedef void (*Print) (const char *);
typedef int (*Write) (int, const char *, int);

/* Console class */
typedef struct console {
    /* Underscores at the end of class member are cool.   */
    /* The idea belongs to Paul Calder. --P3              */
    unsigned magic_;		/* For crash analisys */
    Print print_;
    Write write_;
    int (*read1_) ();
    int fd0_;			/* Read file descriptor */
    int fd1_;			/* Write file descriptor */
    const struct linux_romvec *promvec_;
} Console;

static Console cons0;

static int dpread1_v0 ()
{
    return cons0.promvec_->pv_getchar ();
}

static int dpread1_v3 ()
{
    static char c0;
    int rc;

    for (;;) {
	rc = cons0.promvec_->pv_v2devops.v2_dev_read (cons0.fd0_, &c0, 1);
	if (rc == -1)
	    return -1;
	if (rc == 1)
	    return c0 & 0xFF;
    }
}

void dpset (const struct linux_romvec *promvec)
{
    cons0.magic_ = 0;
    cons0.print_ = 0;
    cons0.write_ = 0;
    cons0.read1_ = 0;
    cons0.fd0_ = 0;
    cons0.fd1_ = 0;
    cons0.promvec_ = promvec;
    if ((((unsigned) promvec) & 0xF0000000) == 0) {
	/* sun4, no PROM vector passed */
	promvec = (struct linux_romvec *) SUN4__PROM_VECTOR;
	cons0.print_ = (Print) promvec->pv_printf;
	cons0.read1_ = dpread1_v0;
    } else if (promvec->pv_romvers == 3) {
	cons0.magic_ = promvec->pv_magic_cookie;
	cons0.write_ = (Write) promvec->pv_v2devops.v2_dev_write;
	cons0.read1_ = dpread1_v3;
	cons0.fd0_ = *promvec->pv_v2bootargs.fd_stdin;
	cons0.fd1_ = *promvec->pv_v2bootargs.fd_stdout;
    } else {
	/* Version 2 or 0. Who ever seen V.1? --P3 */
	cons0.magic_ = promvec->pv_magic_cookie;
	cons0.print_ = (Print) promvec->pv_printf;
	cons0.read1_ = dpread1_v0;
    }
}

void dpout (register const char *data, int leng)
{
    if (leng <= 0)
	return;
    if (cons0.write_ != 0) {
	(*cons0.write_) (cons0.fd1_, data, leng);
    } else {
	(*cons0.print_) (data);
    }
    return;
}

char dpin ()
{
    return cons0.read1_ ();
}

int nbgetchar (struct linux_romvec *promvec)
{
    static char inc;
    if (promvec->pv_romvers < 2)
	return (*(promvec->pv_nbgetchar)) ();
    else if ((*(promvec->pv_v2devops).v2_dev_read) (*promvec->pv_v2bootargs.fd_stdin, &inc, 0x1) == 1)
	return inc;
    return -1;
}