/*
**  linux/kernel/chr_drv/console.c
**
**  Copyright (C) 1993 Hamish Macdonald and Greg Harp
**
**  Last Modified 2/22/93 by Greg Harp
**
** This file is subject to the terms and conditions of the GNU General Public
** License.  See the file README.legal in the main directory of this archive
** for more details.
*/

#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/console.h>

#include "vt_kern.h"

/*
** Global Variables
*/

struct condata vc_cons[NR_CONSOLES];
struct consw   *conswitchp;

/*
** Prototypes
*/

void onecon_init(unsigned int num);
void console_print(const char *str);
extern void register_console (void (*proc)(const char *));

static int can_do_color = 1;

/*
** Functions
*/

long con_init(long mem_start)
{
	char *display_desc = "????";

	display_desc = "ECS";

	/*
	 * initialize the first virtual console so that the console
	 * device can use it.
	 */
	onecon_init (0);

	register_console(console_print);

#if 0
	printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
		can_do_color?"colour":"mono",
		display_desc,
		video_num_columns,video_num_lines,
		NR_CONSOLES);
#else
	printk("Console: %s %s %dx%d, %d virtual consoles\n",
	       can_do_color?"colour":"mono",
	       display_desc,
	       vc_cons[0].rows, vc_cons[0].cols,
	       NR_CONSOLES);
#endif

	return(mem_start);
}

void onecon_init (unsigned int connum)
{
    struct condata *conp;

    if (connum >= NR_CONSOLES)
	panic ("onecon_init: Bad console number");

    conp = &vc_cons[connum];

    if (conp->flags & CON_INITED)
	return;

    conp->sw = conswitchp;
    conp->curx = 0;
    conp->cury = 0;
    conp->cursorx = 0;
    conp->cursory = 0;

    conp->sw->con_init (conp);
    conp->sw->con_cursor (conp, CM_DRAW);

    conp->flags |= CON_INITED;
}

void do_keyboard_interrupt(void)
{
    TTY_READ_FLUSH(TTY_TABLE(0));
#if 0
    timer_active &= ~(1<<BLANK_TIMER);
    if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
	return;
    if (console_blanked)
	{
	timer_table[BLANK_TIMER].expires = 0;
	timer_active |= 1<<BLANK_TIMER;
	}
    else if (blankinterval)
	{
	timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
	timer_active |= 1<<BLANK_TIMER;
	}
#endif
}

void scrollfront (int lines)
{
}

void scrollback (int lines)
{
}

void con_putc (int c, unsigned int con)
{
    struct condata *conp = &vc_cons[con];

    switch(c)
    {
      case '\f':
	/* home and clear screen */
	conp->curx = conp->cury = 0;
	conp->sw->con_clear (conp, 0, 0, conp->rows, conp->cols);
	conp->sw->con_cursor (conp, CM_DRAW);
	break;

      case '\b':
	if (conp->curx > 0)
	    conp->curx--;
	conp->sw->con_cursor (conp, CM_MOVE);
	break;

      case '\t':
	conp->curx = (conp->curx + 8) & ~7;
	conp->sw->con_cursor (conp, CM_MOVE);
	break;

      case '\n':
	/* newline */
	conp->curx = 0;
	if (++conp->cury == conp->rows) {
	    --conp->cury;
	    conp->sw->con_scroll (conp, 1, 0, 1, SM_UP);
	    conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols);
	}
	conp->sw->con_cursor (conp, CM_DRAW);
	break;

      case '\r':
	/* carriage return */
	conp->curx = 0;
	conp->sw->con_cursor (conp, CM_MOVE);
	break;

      case 7:
	/* bell */
	break;

      case 127:
	/* delete */
	break;

      default:
	conp->sw->con_putc (conp, c, conp->cury, conp->curx, DM_COPY);
	if (conp->curx < conp->cols - 1)
	    conp->curx++;
	else {
	    conp->curx = 0;
	    if (++conp->cury == conp->rows) {
		--conp->cury;
		conp->sw->con_scroll (conp, 0, 0, 1, SM_UP);
		conp->sw->con_clear (conp, conp->cury, 0, 1, conp->cols);
	    }
	}
	conp->sw->con_cursor (conp, CM_DRAW);
	break;
    }
}

void con_write (struct tty_struct *tty)
{
    int c;
    unsigned int currcons;

    currcons = tty->line - 1;
    if (currcons >= NR_CONSOLES) {
	printk("con_write: illegal tty (%d)\n", currcons);
	return;
    }

    while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0)
	con_putc (c, currcons);
}

void blank_screen (void)
{
}

void unblank_screen (void)
{
}

void update_screen(int new_console)
{
    static int lock = 0;

    if (new_console == fg_console || lock)
	return;
    lock = 1;
#if 0
    kbdsave(new_console);
    get_scrmem(fg_console);
    fg_console = new_console;
    set_scrmem(fg_console);
    set_origin(fg_console);
    set_cursor(new_console);
    set_leds();
#endif
    lock = 0;
}

void console_print(const char *str)
{
    while(*str)
	con_putc(*str++, 0);
}

/*
 * All we do is set the write and ioctl subroutines; later on maybe we'll
 * dynamically allocate the console screen memory.
 */
int con_open(struct tty_struct *tty, struct file *filp)
{
    tty->write = con_write;
    tty->ioctl = vt_ioctl;

    if (tty->line > NR_CONSOLES)
	return -ENODEV;

    onecon_init (tty->line-1);

    tty->winsize.ws_row = vc_cons[tty->line-1].rows;
    tty->winsize.ws_col = vc_cons[tty->line-1].cols;

    return 0;
}
