/*
**  linux/atari/atacon.c
**
**  Copyright (C) 1993 Bj”rn Brauel
**
**
** 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/types.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>

#include <linux/atarihw.h>
#include <linux/atariints.h>

#include <asm/system.h>

/*
** Macros
*/


#define SCR_MAX_WIDTH	640
#define SCR_MAX_HEIGHT	400
#define SCR_WIDTH	640
#define SCR_HEIGHT	400


#define MEM_REQ 	((SCR_WIDTH/8) * SCR_HEIGHT)

#define DIWSTRT_V	(0x18 + (SCR_MAX_HEIGHT - SCR_HEIGHT)/4)
#define DIWSTRT_H	(0x71 + (SCR_MAX_WIDTH - SCR_WIDTH)/4)
#define DIWSTOP_V	((0x108 - (SCR_MAX_HEIGHT - SCR_HEIGHT)/4) & 0xff)
#define DIWSTOP_H	(0xd5 - (SCR_MAX_WIDTH - SCR_WIDTH)/4)

#define DIWSTRT 	((DIWSTRT_V << 8) + DIWSTRT_H)
#define DIWSTOP 	((DIWSTOP_V << 8) + DIWSTOP_H)

#define DDFSTRT 	(((ushort)DIWSTRT_H >> 1) - 4)
#define DDFSTOP 	((ushort)DDFSTRT + (4 * (SCR_WIDTH/16 - 2)))

#define FG_COLOR	0x000 /* black */
#define BG_COLOR	0xaaa /* lt. grey */
#define CURSOR_COLOR	0x00a /* med. blue */

/*
** Externals
*/

extern unsigned char
    fontdata[];

extern int
    fontheight,
    fontwidth;

extern char
    fontname[];

/*
** Local Variables
*/

static struct
{
    ushort scr_height;		/* screen dimensions */
    ushort scr_width;

    ushort diwstrt;		/* display window control */
    ushort diwstop;

    ushort ddfstrt;		/* data fetch control */
    ushort ddfstop;

    ushort mode;		/* display mode */

    ushort fgcol;		/* text colors */
    ushort bgcol;
    ushort crsrcol;

    u_char *bitplane;		/* pointer to display bitplane */

} disp[NR_CONSOLES];

static ushort *cursor, *dummy;

static ushort cursor_data[] =
{
    0x2c81,0x2d00,
    0xf000,0x0000,
    0x0000,0x0000
};

/*
** Functions
*/


static int videl_init(void)
 {
/* Setup Screen Memory */
  shifter.bas_hi=0x00;
  shifter.bas_md=0x01;
  return 0;
 }


static int atacon_init(struct condata *conp)
{
    int i;
    int unit = conp - vc_cons;

    /* set up the display defaults */
    disp[unit].scr_height = SCR_HEIGHT;
    disp[unit].scr_width = SCR_WIDTH;

    disp[unit].diwstrt = DIWSTRT;
    disp[unit].diwstop = DIWSTOP;

    disp[unit].ddfstrt = DDFSTRT;
    disp[unit].ddfstop = DDFSTOP;

    disp[unit].mode = 0;

    disp[unit].fgcol = FG_COLOR;
    disp[unit].bgcol = BG_COLOR;
    disp[unit].crsrcol = CURSOR_COLOR;

    conp->cols = SCR_WIDTH / fontwidth;
    conp->rows = SCR_HEIGHT / fontheight;

     videl_init();
    /* locate the bitplane */
    disp[unit].bitplane = (u_char *)0x380100;

    /* copy the sprite data into Chip mem */
    for (i=0; i<6; i++)
	cursor[i] = cursor_data[i];

    /* set dummy sprite data to a blank sprite */
    for (i=0; i<6; i++)
	dummy[i] = 0x0000;

    /* clear display memory */
    memset (disp[unit].bitplane, 0x00 , MEM_REQ);


    return 0;
}

static int atacon_deinit (struct condata *conp)
{
    return 0;
}

static void atacon_movedata (u_char *src,
			     ushort srcx, ushort srcy, ushort srcmod,
			     u_char *dst,
			     ushort dstx, ushort dsty, ushort dstmod,
			     ushort height, ushort width, ushort dmode)
{
    int i;

    src += srcmod * srcy + (srcx >> 3);
    dst += dstmod * dsty + (dstx >> 3);

    if ((srcx & 7) || (dstx & 7) || (width & 7))
	panic ("atacon: bad offset");

    width >>= 3;
    while (height--) {
	if (src > dst)
	    for (i = 0; i < width; i++)
		switch (dmode) {
		  case DM_COPY:
		    dst[i] = src[i];
		    break;
		  case DM_CLEAR:
		    dst[i] = 0x00;
		    break;
		  case DM_XOR:
		    dst[i] ^= src[i];
		    break;
		  case DM_INVERSE:
		    dst[i] = ~src[i];
		    break;
		}
	else
	    for (i = width - 1; i >= 0; i--)
		switch (dmode) {
		  case DM_COPY:
		    dst[i] = src[i];
		    break;
		  case DM_CLEAR:
		    dst[i] = 0x00;
		    break;
		  case DM_XOR:
		    dst[i] ^= src[i];
		    break;
		  case DM_INVERSE:
		    dst[i] = ~src[i];
		    break;
		}

	src += srcmod;
	dst += dstmod;
    }
}

static void atacon_bmove (struct condata *conp,
			 int sy, int sx, int dy, int dx,
			 int height, int width)
{
    int unit = conp - vc_cons;

    atacon_movedata (disp[unit].bitplane, sx * fontwidth,
		     sy * fontheight, disp[unit].scr_width >> 3,
		     disp[unit].bitplane, dx * fontwidth,
		     dy * fontheight, disp[unit].scr_width >> 3,
		     height * fontheight, width * fontwidth, DM_COPY);
}

static int atacon_clear (struct condata *conp,
		  int sy, int sx, int height, int width)
{
    int unit = conp - vc_cons;

    atacon_movedata (0, 0, 0, 0,
		     disp[unit].bitplane, sx * fontwidth, sy * fontheight,
		     disp[unit].scr_width >> 3,
		     height * fontheight, width * fontwidth, DM_CLEAR);

    return 0;
}

static int atacon_putc (struct condata *conp,
		 int c, int y, int x, int mode)
{
    int unit = conp - vc_cons;

    if ((c >= 32) && (c < 127))
	/* lower half of charset -- normal ASCII */
	c -=  32;
    else if ((c >= 160) && (c < 255))
	/* upper half of charset -- special characters */
	c -= 64;
    else
	/* not defined in charset -- non-printable character */
	return 0;

    atacon_movedata (fontdata, 0, c * fontheight, 1,
		     disp[unit].bitplane, x * fontwidth,
		     y * fontheight, disp[unit].scr_width >> 3,
		     fontheight, fontwidth, DM_COPY);

    return 0;
}

static int atacon_cursor (struct condata *conp,
			  int mode)
{
    int unit = conp - vc_cons;
    int vs, hs;

    if (mode == CM_ERASE) {
/*	*(long *)cursor = 0;*/
    } else {
	vs = (disp[unit].diwstrt >> 8) +
	    ((conp->cury + 1) * fontheight) / 2 - 1;
	hs = (disp[unit].diwstrt & 0x00ff) +
	    (conp->curx * fontwidth) / 2 - 1;
	*(long *)cursor = (vs << 24) + ((hs & 0x000001fe) << 15) +
	    (((vs+1) & 0x000000ff) << 8) + (vs & 0x00000100) +
		(((vs+1) & 0x00000100) >> 1) + (hs & 0x00000001);

	conp->cursorx = conp->curx;
	conp->cursory = conp->cury;
    }

    return 0;
}

static int atacon_scroll (struct condata *conp,
		   int sy, int sx, int count, int dir)
{
    int height, dy, i;

    atacon_cursor (conp, CM_ERASE);

    if (dir == SM_UP) {
	dy = sy - count;
	height = conp->rows - sy;
	for (i = 0; i < height; i++)
	    atacon_bmove (conp, sy + i, 0, dy + i, 0, 1, conp->cols);
    }

    return 0;
}

static int atacon_switch (struct condata *conp)
{
    return 0;
}

/*
 * The console "switch" structure for the Amiga native console
 */

struct consw ata_con =
{
    atacon_init, atacon_deinit, atacon_clear, atacon_putc,
    atacon_cursor, atacon_scroll, atacon_switch
};

