/*      $NetBSD: video.c,v 1.7 2005/12/11 12:17:04 christos Exp $       */

/*-
* Copyright (C) 1995-1997 Gary Thomas ([email protected])
* 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.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*      This product includes software developed by Gary Thomas.
* 4. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*/

#ifdef CONS_BE
#include <lib/libsa/stand.h>
#include "boot.h"
#include "iso_font.h"

#define FONT_WIDTH      8
#define FONT_HEIGHT     16
#define VRAM_WIDTH      640
#define VRAM_HEIGHT     480
#define VRAM_SIZE       (VRAM_WIDTH * VRAM_HEIGHT)
#define ROW     (VRAM_WIDTH / FONT_WIDTH)
#define COL     (VRAM_HEIGHT / FONT_HEIGHT)

u_char *VramBase;
u_char save_cursor[FONT_WIDTH];

/*
* The current state of virtual displays
*/
struct screen {
       enum state {
               NORMAL,         /* no pending escape */
               ESC,            /* saw ESC */
               EBRAC,          /* saw ESC[ */
               EBRACEQ         /* saw ESC[= */
       } state;                /* command parser state */
       int     cx;             /* the first escape seq argument */
       int     cy;             /* the second escap seq argument */
       int     *accp;          /* pointer to the current processed argument */
       int     row;
       int     col;
       u_char fgcolor;
       u_char bgcolor;
} screen;


void
video_init(u_char *buffer)
{
       struct screen *d = &screen;

       VramBase = buffer;
       d->fgcolor = 0x1f;      /* WHITE */
       d->bgcolor = 0x00;      /* BLACK */
       d->row = 0;
       d->col = 0;
       d->state = NORMAL;
       memset(VramBase, d->bgcolor, VRAM_SIZE);
       memset(save_cursor, d->bgcolor, FONT_WIDTH);
}

static void
wrtchar(u_char c, struct screen *d)
{
       u_char *p = VramBase +
               (d->col * VRAM_WIDTH * FONT_HEIGHT) + (d->row * FONT_WIDTH);
       int fontbase = c * 16;
       int x, y;

       for (y = 0; y < FONT_HEIGHT; y++) {
               for (x = 0; x < FONT_WIDTH; x++) {
                       if ((font[fontbase + y] >> (FONT_WIDTH - x)) & 1)
                               *(p + x + (y * VRAM_WIDTH)) = d->fgcolor;
                       else
                               *(p + x + (y * VRAM_WIDTH)) = d->bgcolor;
               }
       }
       d->row++;
}

static void
cursor(struct screen *d, int flag)
{
       int x;
       int y = FONT_HEIGHT - 1;

       u_char *p = VramBase +
               (d->col * VRAM_WIDTH * FONT_HEIGHT) + (d->row * FONT_WIDTH);
       for (x = 0; x < FONT_WIDTH - 1; x++) {
               if (flag) {
                       save_cursor[x] = *(p + x + (y * VRAM_WIDTH));
                       *(p + x + (y * VRAM_WIDTH)) = d->fgcolor;
               } else {
                       *(p + x + (y * VRAM_WIDTH)) = save_cursor[x];
               }
       }
}

/*
* vga_putc (nee sput) has support for emulation of the 'ibmpc' termcap entry.
* This is a bare-bones implementation of a bare-bones entry
* One modification: Change li#24 to li#25 to reflect 25 lines
* "ca" is the color/attributes value (left-shifted by 8)
* or 0 if the current regular color for that screen is to be used.
*/
void
video_putc(int c)
{
       struct screen *d = &screen;

       cursor(d, 0);

       switch (d->state) {
       case NORMAL:
               switch (c) {
               case 0x0:               /* Ignore pad characters */
                       return;

               case 0x1B:
                       d->state = ESC;
                       break;

               case '\t':
                       do {
                               wrtchar(' ', d);
                       } while (d->row % 8);
                       break;

               case '\b':  /* non-destructive backspace */
                       d->row--;
                       if (d->row < 0) {
                               if (d->col > 0) {
                                       d->col--;
                                       d->row += ROW;  /* prev column */
                               } else {
                                       d->row = 0;
                               }
                       }
                       break;

               case '\n':
                       d->col++;
                       /* FALLTHROUGH */
               case '\r':
                       d->row = 0;
                       break;

               case '\007':
                       break;

               default:
                       wrtchar(c, d);
                       if (d->row >= ROW) {
                               d->row = 0;
                               d->col++;
                       }
                       break;
               }
               break;

       case ESC:
       case EBRAC:
       case EBRACEQ:
               break;
       }
       if (d->col >= COL) {            /* scroll check */
               memcpy(VramBase, VramBase + VRAM_WIDTH * FONT_HEIGHT,
                       VRAM_SIZE - VRAM_WIDTH * FONT_WIDTH);
               memset(VramBase + VRAM_SIZE - VRAM_WIDTH * FONT_HEIGHT,
                       d->bgcolor, VRAM_WIDTH * FONT_HEIGHT);
               d->col = COL - 1;
       }
       cursor(d, 1);
}
#endif