/*
 * console.c
 *
 * Copyright (C) 1994 by Waldorf Electronic,
 * written by Ralf Baechle and Andreas Busse
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive for
 * more details.
 */

#include <linux/tty.h>
#include <asm/bootinfo.h>
#include <stand/console.h>

unsigned char font[] = {
#include "8x16.fnt"
};

#define FONTSIZE_X	8	/* 8 pixels wide */
#define FONTSIZE_Y	16	/* 16 pixels high */

/* Prototypes */

static __inline__ void gscroll(void);

/* Local variables */

static unsigned int size_x;	/* text resolution */
static unsigned int size_y;
static unsigned int graphmode;	/* true if video adapter is in graphics mode */
static unsigned int res_x;	/* graphics resolution */
static unsigned int res_y;
static unsigned short cursor_x;
static unsigned short cursor_y;
static volatile unsigned short *vram_addr;
static int console_needs_init = 1;

extern struct bootinfo boot_info;
extern struct screen_info screen_info;

int dump_font()
{
  volatile unsigned char *caddr;
  int x;
  int y;
  int c;
  int i,j;
  char *faddr;

  c = 0;
  for (y=0; y<8; y++)
    {
      for (x=0; x<32; x++)
	{
	  caddr = (char *)vram_addr + (y * FONTSIZE_Y * res_x) + (x * FONTSIZE_X);
	  faddr = font + (c * 128); /* 128 bytes/char */
	  
	  for (i=0; i<16; i++)
	    {
	      for (j=0; j<8; j++)
		{
		  *(caddr+j) = *(faddr++);
		}
	      caddr += res_x;
	    }
	  c++;
	}
    }
  return(0);
}
	      
void
init_console(void)
{
  vram_addr = (unsigned short *)boot_info.vram_base;
  
  if (boot_info.machtype == MACH_MIPS_MAGNUM_4000)
    {
      graphmode = 1;
      size_x  = screen_info.orig_video_cols;
      size_y  = screen_info.orig_video_lines;
      res_x = size_x * FONTSIZE_X;
      res_y = size_y * FONTSIZE_Y;
    }
  else
    {
      graphmode = 0;		/* default is text mode */
      res_x  = 0;
      res_y  = 0;
      size_x = screen_info.orig_video_cols;
      size_y = screen_info.orig_video_lines;
    }
  
  cursor_x = screen_info.orig_x;
  cursor_y = screen_info.orig_y;
  
  console_needs_init = 0;
}

void
set_size_x(unsigned int x)
{
  size_x = x;
}

void
set_size_y(unsigned int y)
{
  size_y = y;
}

void
set_vram(unsigned short *vram)
{
  vram_addr = vram;
}

void
set_cursor(unsigned int x, unsigned int y)
{
  cursor_x = x;
  cursor_y = y;
}


void print_char(unsigned int x, unsigned int y, unsigned char c)
{
  volatile unsigned short *caddr;

  if (graphmode)
    {
      gprint_char(x, y, c);
      return;
    }

  caddr = vram_addr + (y * size_x) + x;
  *caddr = (*caddr & 0xff00) | 0x0f00 | (unsigned short) c;
}

/*
 * used for graphic consoles. FIXME: SLOOOOOOOW !
 */
void gprint_char(unsigned int x, unsigned int y, unsigned char c)
{
  volatile unsigned char *caddr;
  unsigned char *faddr;
  int i,j;

  caddr = (char *)vram_addr + (y * FONTSIZE_Y * res_x) + (x * FONTSIZE_X);
  faddr = font + (c * 128); /* 128 bytes/char */
	  
  for (i=0; i<FONTSIZE_Y; i++)
    {
      for (j=0; j<FONTSIZE_X; j++)
	{
	  *(caddr+j) = *(faddr++);
	}
      caddr += res_x;
    }
}

static void
scroll()
{
  volatile unsigned short *caddr;
  register int i;

  if (graphmode)
    {
      gscroll();
      return;
    }
  
  caddr = vram_addr;
  for(i=0; i<size_x * (size_y-1); i++)
    *(caddr++) = *(caddr + size_x);
  
  /* blank last line */
  
  caddr = vram_addr + (size_x * (size_y-1));
  for(i=0; i<size_x; i++)
    *(caddr++) = (*caddr & 0xff00) | (unsigned short) ' ';
}

static void
gscroll(void)
{
  volatile unsigned int *caddr;
  int nblk;			/* no. of 64-byte-blocks to copy */
  int wpl;			/* no. of words per line */

  nblk  = (res_x * (res_y - FONTSIZE_Y)) >> 6;
  wpl = (res_x * FONTSIZE_Y) >> 2;
  
  caddr = (int *)vram_addr;
  while (nblk--)
    {
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
      *(caddr++) = *(caddr+wpl);
    }
  
  /* blank last line */
  
  caddr = (int *)vram_addr + wpl * (size_y-1);
  while (wpl--)
    *(caddr++) = 0x04040404;	/* Magnum 4000 specific */
}		       

  
void print_string(const unsigned char *str)
{
  unsigned char c;

  if (console_needs_init)
    init_console();

  while(c = *str++)
    switch(c)
      {
      case '\n':
	cursor_x = 0;
	cursor_y++;
	if(cursor_y == size_y)
	  {
	    scroll();
	    cursor_y = size_y - 1;
	  }
	break;

      default:
	print_char(cursor_x, cursor_y, c);
	cursor_x++;
	if(cursor_x == size_x)
	  {
	    cursor_x = 0;
	    cursor_y++;
	    if(cursor_y == size_y)
	      {
		scroll();
		cursor_y = size_y - 1;
	      }
	  }
	break;
      }
}
