/**
 *
 *  TEX Device Driver  ver 2.02-   for J3100
 *  copyright(c) 1988,89 by TSG, 1990-93 SHIMA, 1991 sempa
 *
 *  PREVIEWER ver 2.02-
 *  device.c : previewer module
 *             4th edition
 *
 *	Ver.2.35 page resume supported by SOLITON
 *
 *  Support EMS by SHIMA, Dec 1992
 *
 *  Of course, this module is device-dependent.
**/

#define	TITLE_COMMENT	""

#include <stdio.h>
#include <ctype.h>
#define _DEF_STDIO_H_
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <conio.h>
#define _DEF_DOS_H_
#include "dd.h"

#include "device.h"
#include "dev_j31.h"

extern int unit_pages;
extern int slow_fact;
extern int slow_fact2;
extern int slow_page;
extern int v_shift0;

extern BOOL f_use_new_size_option;
extern BOOL f_resume;
extern BOOL f_reverse;
extern int num_view;
extern int num_view_buf;
extern uint resume_info;
static int v_shift1 = 1;

#ifndef	NEMS
extern int system_EMS_end;
int view_EMS_top;
int view_EMS_unit;
int set_ems(int);

#endif

const char *const title_comment = TITLE_COMMENT;

long view_buf_size;

struct PALETTE s_color =
{	   /* analog color initial value */
	{63, 63, 63},	/* foreground color */
	{63, 63, 63},	/* background color */
};

int f_machine_unique;
int disp_reso = RES_640_400;	/* resolution is 640 by 400 */
BOOL f_ramdac = FALSE;	/* use palette */
int f_center;

int s_max_width = CRT_DPI * 8;
int s_max_height = CRT_DPI * 11;
int x_shift;
int y_shift;

static struct VIEW view;

#ifndef	NEMS
int view_EMS_top;
int view_EMS_unit;
int set_ems(int);

#endif

static unsigned int key_data[] =
{
	0x0008, 0x0020,
	0x0050, 0x004e,
	0x000d,
	0x001b,
	0x0051,
	0x0042,
	0x0056,
	0x0043,
	0x0052,
	0x0048,
	0x4700,
	0x004d,
	0x0047,
	0x5000, 0x4800, 0x4b00, 0x4d00,
	0x50ff, 0x48ff, 0x4bff, 0x4dff,
	0x001b
};

static unsigned char SAVE_PAL[17];
static unsigned char SAVE_REV_PAL[17];
static unsigned char SAVE_RAMDAC[3 * 3];

static HUGE_BUF *map_top_ptr;

/* pointer of bitmap buffer */
static PIXEL vmax, hmax, hmaxb;

/* size to output. hmaxb is byte-size. */
static GRAM_BUF *g_top_ptr;

/* head pointer of graphic vram */
static int f_div;
static int f_div2;
static int f_box;
static int v_x_shift;
static int v_x_shift2;
static int v_y_shift;
static int v_y_shift2;
static int view_page;

static uint g_width_b;
static uint g_height;
static ulong g_top;

static int video_mode;
static int org_video_mode;
static uint resume_base;
static unsigned video_isr;	/* video input status register */
static unsigned video_crtc;	/* video crt control register */

static BUFFER *v_top;
static BUFFER *v_top2;
static HUGE_BUF *view_buf;

/**

	Proto-types

**/

ulong leftbuffer();	/*	buffer.c */

void device_init(DIMENSION *);
void device_end(void);	/* (in fact, DIMENSION information is given) */
void device_cont(void);
void device_pause(void);
void device_clear(OUTPUT_INFO *);
void pr_new_page(void);
NEXT_ACTION device_out(OUTPUT_INFO *, DIMENSION *);

/* (in fact, OUTPUT_INFO information is given also to this) */
KeyInput extra_inkey(void);
static void first_draw(struct SCROLL *, int, int);
static void draw_screen(struct SCROLL *);
static void move_screen(struct SCROLL *, KeyInput);
static void scroll_up(struct SCROLL *);
static void scroll_down(struct SCROLL *);
static void scroll_right(struct SCROLL *);
static void scroll_left(struct SCROLL *);
static void flskey(void);
static void clear_text_screen(void);
static void program_screen_mode(int);
static void cursor_mode(int);
static void s_up(struct SCROLL *, int);
static void s_down(struct SCROLL *, int);
static void s_left(struct SCROLL *);
static void s_right(struct SCROLL *);
static void hdw_scroll(struct SCROLL *);
static void gshift(uint);
static void cls(int);
static void s_view4(void);
static void s_view8(void);
static void v_box(BUFFER *, int, int, int, int);
static void msg_help(void);
static int  get_view(int, int);
static void vram_hline(GRAM_BUF **);
static GRAM_BUF *vram_adr(GRAM_BUF *);

static void set_start_addr(unsigned int);

static void pallet(int);
static void analog_color(struct PALETTE *);
static void save_palette(unsigned char *);
static void save_a_ramdac(uint, unsigned char *);
static void save_ramdac(unsigned char *);
static void restore_palette(unsigned char *);
static void restore_a_ramdac(uint, unsigned char *);
static void restore_ramdac(unsigned char *);
static void set_a_ramdac(uint pal, struct COLOR_ELEMENT *cp);

static void cls_dcga(int);
static void cls_vga(int);
static void draw_screen_dcga(struct SCROLL *);
static void draw_screen_vga(struct SCROLL *);

void s_up_dcga(struct SCROLL *s_dat, int v_shift)
	/* scroll up by v_shift dots */
{
	int i, j, off1;
	HUGE_BUF *mptr_tmp;
	HUGE_BUF *mptr_tmp_1;
	GRAM_BUF *gptr_tmp;
	GRAM_BUF *gptr_tmp_1;

	if (s_dat->x_lock == TRUE) {
		gptr_tmp = g_top_ptr + 20 * s_dat->r_line;
		gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);
		for (i = 0; i < v_shift; i++) {
			if ((FP_OFF(gptr_tmp) % G_DEPTH + hmaxb) <= G_DEPTH)
				for (j = 0; j < hmaxb; j++)
					gptr_tmp[j] = 0;
			else {
				off1 = G_DEPTH - FP_OFF(gptr_tmp) % G_DEPTH;
				for (j = 0; j < off1; j++)
					gptr_tmp[j] = 0;
				gptr_tmp_1 = gptr_tmp + off1 - G_DEPTH;
				for (j = 0; j < hmaxb - off1; j++)
					gptr_tmp_1[j] = 0;
			}
			vram_hline(&gptr_tmp);
		}
	}
	mptr_tmp = s_dat->mptr + (ulong)hmaxb *(G_HEIGHT_DCGA - v_shift);

	gptr_tmp = g_top_ptr + s_dat->offset + 20 * (s_dat->r_line + G_HEIGHT_DCGA);
	gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);
	s_dat->r_line += v_shift;

	for (i = 0; i < v_shift; i++) {
		if ((FP_OFF(gptr_tmp) % G_DEPTH + s_dat->gw_act) <= G_DEPTH)
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp), FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), s_dat->gw_act);
		else {
			off1 = G_DEPTH - FP_OFF(gptr_tmp) % G_DEPTH;
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp), FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), off1);
			mptr_tmp_1 = mptr_tmp + off1;
			gptr_tmp_1 = gptr_tmp + off1 - G_DEPTH;
			movedata(FP_SEG(mptr_tmp_1), FP_OFF(mptr_tmp_1), FP_SEG(gptr_tmp_1), FP_OFF(gptr_tmp_1), s_dat->gw_act - off1);
		}
		if (s_dat->x_lock == TRUE) {
			for (j = s_dat->h_spc; j > 0; j--) {
				gptr_tmp[-j] = 0;
				gptr_tmp[hmaxb + j - 1] = 0;
			}
		}
		vram_hline(&gptr_tmp);
		mptr_tmp += hmaxb;
	}
	hdw_scroll(s_dat);
}

static void s_down_dcga(struct SCROLL *s_dat, int v_shift)
	/* scroll down by v_shift dots */
{
	int ins, i, j;
	HUGE_BUF *mptr_tmp;
	HUGE_BUF *mptr_tmp_1;
	GRAM_BUF *gptr_tmp;
	GRAM_BUF *gptr_tmp_1;

	if (s_dat->x_lock == TRUE) {
		gptr_tmp = g_top_ptr + 20 * (s_dat->r_line + G_HEIGHT_DCGA);
		gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);
		for (i = 0; i < v_shift; i++) {
			if ((FP_OFF(gptr_tmp) % G_DEPTH + s_dat->gw_act) <= G_DEPTH)
				for (j = 0; j < hmaxb; j++)
					gptr_tmp[j] = 0;
			else {
				ins = G_DEPTH - FP_OFF(gptr_tmp) % G_DEPTH;
				for (j = 0; j < ins; j++)
					gptr_tmp[j] = 0;
				gptr_tmp_1 = gptr_tmp + ins - G_DEPTH;
				for (j = 0; j < hmaxb - ins; j++)
					gptr_tmp_1[j] = 0;
			}
			vram_hline(&gptr_tmp);
		}
	}
	mptr_tmp = s_dat->mptr;
	s_dat->r_line -= v_shift;
	gptr_tmp = g_top_ptr + s_dat->offset + 20 * s_dat->r_line;
	gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);

	for (i = 0; i < v_shift; i++) {
		if ((FP_OFF(gptr_tmp) % G_DEPTH + s_dat->gw_act) <= G_DEPTH)
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp), FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), s_dat->gw_act);
		else {
			ins = G_DEPTH - FP_OFF(gptr_tmp) % G_DEPTH;
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp), FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), ins);
			gptr_tmp_1 = gptr_tmp + ins - G_DEPTH;
			mptr_tmp_1 = mptr_tmp + ins;
			movedata(FP_SEG(mptr_tmp_1), FP_OFF(mptr_tmp_1), FP_SEG(gptr_tmp_1), FP_OFF(gptr_tmp_1), s_dat->gw_act - ins);
		}
		if (s_dat->x_lock == TRUE) {
			for (j = s_dat->h_spc; j > 0; j--) {
				gptr_tmp[-j] = 0;
				gptr_tmp[hmaxb + j - 1] = 0;
			}
		}
		mptr_tmp += hmaxb;
		vram_hline(&gptr_tmp);
	}
	hdw_scroll(s_dat);
}

void s_right_dcga(struct SCROLL *s_dat)
	/* scroll right by 16 dots */
{
	HUGE_BUF *mptr_tmp;
	GRAM_BUF *gptr_tmp;
	int i, count;

	s_dat->offset -= 2;

	mptr_tmp = s_dat->mptr;
	gptr_tmp = (GRAM_BUF *) G_TOP_DCGA + s_dat->offset + 20 * s_dat->r_line;
	gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);
	hdw_scroll(s_dat);
	count = 0;
	for (i = G_HEIGHT_DCGA; i > 0; i--) {
		if (count++ < s_dat->v_spc || count > s_dat->v_spc + s_dat->gh_act)
			*((int far *)gptr_tmp) = 0;
		else {
			*((int far *)gptr_tmp) = *((int far *)mptr_tmp);
			mptr_tmp += hmaxb;
		}
		vram_hline(&gptr_tmp);
	}
}

void s_left_dcga(struct SCROLL *s_dat)
	/* scroll left by 16 dots */
{
	HUGE_BUF *mptr_tmp;
	GRAM_BUF *gptr_tmp;
	int i, count;

	s_dat->offset += 2;

	mptr_tmp = s_dat->mptr + (G_WIDTH_B_DCGA - 2);
	gptr_tmp = (GRAM_BUF *) G_TOP_DCGA + s_dat->offset + 20 * s_dat->r_line + (G_WIDTH_B_DCGA - 2);
	gptr_tmp = MK_FP(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp) % 0x2000);
	hdw_scroll(s_dat);
	count = 0;
	for (i = G_HEIGHT_DCGA; i > 0; i--) {
		if (count++ < s_dat->v_spc || count > s_dat->v_spc + s_dat->gh_act)
			*((int far *)gptr_tmp) = 0;
		else {
			*((int far *)gptr_tmp) = *((int far *)mptr_tmp);
			mptr_tmp += hmaxb;
		}
		vram_hline(&gptr_tmp);
	}
}

static void hdw_scroll(struct SCROLL *s_dat)
	/* hardware scroll */
{
	gshift((s_dat->offset / 2) + ((G_WIDTH_B_DCGA * s_dat->r_line) >> 3));
}

void gshift(uint adr_1)
	/* output to crtc  */
{
	int crtc = peek(0, 0x463);	/* get crtc port address */

	disable();					/* cli */
	(void)outp(crtc, 12);
	(void)outp(crtc + 1, (adr_1 / 256));
	(void)outp(crtc, 13);
	(void)outp(crtc + 1, (adr_1 % 256));

	poke(0, 0x4D6, (adr_1 * 2)); /* set vram offset address for video bios */
	enable();					 /* sti */
}

/* VGA 用スクロール処理
 */

static void s_up_vga(struct SCROLL *s_dat, int v_shift)
/* スムース・スクロール・アップ by v_shift dots */
{
	HUGE_BUF *mptr_tmp;
	unsigned char back[G_WIDTH_B_MAX];
	unsigned temp;
	int i;

#if defined(LOOK_SMOOTH)
	int j;

#endif

	for (i = 0; i < G_WIDTH_B_VGA; i++) {
		back[i] = 0;
	}
	mptr_tmp = s_dat->mptr + (ulong)hmaxb *G_HEIGHT_VGA;

	temp = s_dat->offset + (unsigned)(G_HEIGHT_VGA * G_WIDTH_B_VGA);
	for (i = 0; i < v_shift; i++) {
		movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp),
				 FP_SEG(back), FP_OFF(back) + s_dat->h_spc, s_dat->gw_act);
		movedata(FP_SEG(back), FP_OFF(back),
				 G_SEG_VGA, temp, G_WIDTH_B_VGA);
		mptr_tmp += (ulong)hmaxb;
		temp += G_WIDTH_B_VGA;
		s_dat->offset += G_WIDTH_B_VGA;
#if defined( LOOK_SMOOTH)
		for (j = 0; j < WEIGHT; j++);	/*  insert weight to look smoother */
#endif
		set_start_addr(s_dat->offset);
	}

}

static void s_down_vga(struct SCROLL *s_dat, int v_shift)
/* スムース・スクロール・ダウン by v_shift dots */
{
	HUGE_BUF *mptr_tmp;
	unsigned temp;
	unsigned char back[G_WIDTH_B_VGA];
	int i;

#if defined(LOOK_SMOOTH)
	int j;

#endif

	for (i = 0; i < G_WIDTH_B_VGA; i++) {
		back[i] = 0;
	}
	mptr_tmp = s_dat->mptr - (ulong)hmaxb *v_shift;

	temp = s_dat->offset - G_WIDTH_B_VGA * v_shift;
	for (i = 0; i < v_shift; i++) {
		movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp),
				 FP_SEG(back), FP_OFF(back) + s_dat->h_spc, s_dat->gw_act);
		movedata(FP_SEG(back), FP_OFF(back),
				 G_SEG_VGA, temp, G_WIDTH_B_VGA);
		mptr_tmp += (ulong)hmaxb;
		temp += G_WIDTH_B_VGA;
		s_dat->offset -= G_WIDTH_B_VGA;
#if defined(LOOK_SMOOTH)
		for (j = 0; j < WEIGHT; j++);	/*  insert weight to look smoother */
#endif
		set_start_addr(s_dat->offset);
	}
}

static void s_right_vga(struct SCROLL *s_dat)
/* 左方向　スムース・スクロール by 16 dots */
{
	HUGE_BUF *mptr_tmp;
	GRAM_BUF *gptr_tmp;
	uint temp;
	int i;

	s_dat->offset -= 2;

	mptr_tmp = s_dat->mptr;
	gptr_tmp = (GRAM_BUF *)g_top + s_dat->offset;

	for (i = 0; i < G_HEIGHT_VGA; i++) {
		*((int far *)gptr_tmp) = *((int far *)mptr_tmp);
		mptr_tmp += (ulong)hmaxb;
		gptr_tmp += G_WIDTH_B_VGA;
	}
	set_start_addr(s_dat->offset);
}

static void s_left_vga(struct SCROLL *s_dat)
/* 右方向　スムース・スクロール by 16 dots */
{
	HUGE_BUF *mptr_tmp;

	GRAM_BUF *gptr_tmp;
	int i;

	s_dat->offset += 2;

	mptr_tmp = s_dat->mptr + (G_WIDTH_B_VGA - 2);
	gptr_tmp = (GRAM_BUF *)g_top + s_dat->offset + G_WIDTH_B_VGA - 2;

	for (i = 0; i < G_HEIGHT_VGA; i++) {
		*((int far *)gptr_tmp) = *((int far *)mptr_tmp);
		mptr_tmp += (ulong)hmaxb;
		gptr_tmp += G_WIDTH_B_VGA;
	}
	set_start_addr(s_dat->offset);
}

static void s_up(struct SCROLL *s_dat, int v_shift)
{
	switch (disp_reso) {
	  case RES_640_480:
		  s_up_vga(s_dat, v_shift);
		  break;
	  default:
		  s_up_dcga(s_dat, v_shift);
		  break;
	}
}

static void s_down(struct SCROLL *s_dat, int v_shift)
{
	switch (disp_reso) {
	  case RES_640_480:
		  s_down_vga(s_dat, v_shift);
		  break;
	  default:
		  s_down_dcga(s_dat, v_shift);
		  break;
	}
}

static void s_right(struct SCROLL *s_dat)
{
	switch (disp_reso) {
	  case RES_640_480:
		  s_right_vga(s_dat);
		  break;
	  default:
		  s_right_dcga(s_dat);
		  break;
	}
}

static void s_left(struct SCROLL *s_dat)
{
	switch (disp_reso) {
	  case RES_640_480:
		  s_left_vga(s_dat);
		  break;
	  default:
		  s_left_dcga(s_dat);
		  break;
	}
}

KeyInput
extra_inkey(void)
	/* realtime key scanning. waiting until one of KeyInput is pressed.
     * and if the key is a cursor-key, I check at the same time whether Shift-
     * key is hit or not.
     */
{
	int num = 0;
	int f_num = 0;
	unsigned int k_dat;
	KeyInput key_d;

	union REGS regs;

	while (TRUE) {
		regs.h.ah = 0;
		int86(0x16, &regs, &regs);
		k_dat = regs.x.ax;
/*		k_dat = bioskey(0);	*/
		if ((k_dat & 0xff) != 0)
			k_dat = toupper(k_dat & 0xff);
		else {					/* Extend code */
			regs.h.ah = 2;
			int86(0x16, &regs, &regs);
			if ((regs.x.ax & 0x03) != 0)
/*			if ((bioskey(2) & 0x03) != 0)	*/
				k_dat |= 0xff;
		}
		switch (k_dat) {
		  case 0x4900:
		  case 0x0042:
			  k_dat = (int)'P';	/* PagUp */
			  break;
		  case 0x5100:
			  k_dat = (int)'N';	/* PagDn */
			  break;
		}
		if (k_dat >= '0' && k_dat <= '9') {
			f_num = 1;
			num -= (num / 100) * 100;
			num = num * 10 + k_dat - '0';
			if (num >= 1)
				unit_pages = num;
		}
		else {
			for (key_d = (KeyInput) 0; key_d != LoopEnd; ++key_d)
				if (key_data[(int)key_d] == k_dat)
					break;
			if (key_d == LoopEnd)
				continue;
			if ((key_d == Key_M || key_d == Key_G) && f_num == 0)
				continue;
			break;
		}
	}
	return (key_d);
}

void device_pause()
{
	union REGS regs;

	regs.x.cx = 0x1500;
	regs.h.ah = 0x1;
	int86(CRT_BIOS, &regs, &regs);	/* graphic OFF */
}

void device_cont()
{
	union REGS regs;

	regs.x.cx = 0x0015;
	regs.h.ah = 0x1;
	int86(CRT_BIOS, &regs, &regs);	/* graphic ON */
}

void resume_page(DIMENSION *dim)
{
	switch (f_machine_unique) {
	  case DYNAV:
		  resume_base = 0x00EB;
		  break;
	  default:
		  resume_base = 0x00F0;
		  break;
	}
	if (f_resume) {
					/* Check resume information starting from 0040:00F0 */
		if (peekb(BIOS_WORK, resume_base) == 'R'
			&& peek(BIOS_WORK, resume_base + 1) == resume_info)
				dim->start_page = peek(BIOS_WORK, resume_base + 3);
		pokeb(BIOS_WORK, resume_base, 'R');
		poke(BIOS_WORK, resume_base + 1, resume_info);
	}
}

uint get_vmode_org(void)
{
	union REGS regs;
	uchar video_mode;

	/* get BIOS video mode */
	regs.h.ah = 0x0f;
	int86(V_BIOS, &regs, &regs);
	video_mode = regs.h.al;

	return video_mode;
}

uint get_vmode_preview(void)
{
	uint vmode;

	switch (disp_reso) {
	  case RES_640_480:
		  vmode = VMODE_DYNAV;
		  break;
	  case RES_640_400:
		  vmode = VMODE_DCGA;
		  break;
	  default:
		  vmode = VMODE_UNKNOWN;
	}

	return vmode;
}

void set_vmode_preview(uint vmode)
{
	union REGS regs;

	regs.h.ah = 0x00;			/* use basic BIOS function */
	regs.h.al = vmode;
	int86(V_BIOS, &regs, &regs);

	regs.h.ah = 130;			/* set scroll mode */
	regs.h.al = 0;
	regs.h.bl = 1;				/* normal(slow) scroll mode */
	int86(CRT_BIOS, &regs, &regs);
}

void set_disp_reso(void)
{
	switch (disp_reso) {
	  case RES_640_480:
		  g_top = G_TOP_VGA;
		  g_width_b = G_WIDTH_B_VGA;
		  g_height = G_HEIGHT_VGA;
		  break;
	  default:
		  g_top = G_TOP_DCGA;
		  g_width_b = G_WIDTH_B_DCGA;
		  g_height = G_HEIGHT_DCGA;
		  break;
	}
	view_buf_size = (ulong)g_width_b *(ulong)g_height / 2;
}

void device_init(DIMENSION *dim)
	/* initialize graphic screen */
{
	union REGS regs;
	uint x, x2, y, y2, i;
	uint vmode;

	if (v_shift0 < 0){
		if((v_shift1 = - v_shift0) <= 1) v_shift1 = 1;
		if(v_shift1 > 8) v_shift1 = 8;
		v_shift0 = 0;
	}
	v_shift1 *= 4;

	resume_page(dim);

	org_video_mode = get_vmode_org();	/* save current video mode */
	vmode = get_vmode_preview();
	switch (vmode) {
	  case VMODE_UNKNOWN:
		  fprintf(stderr, "-reso=%d: 解像度の指定が間違っています\n"
						  "          0:DCGA 640 x 400, 1:VGA 640 x 480\n",
				  disp_reso);
		  exit(1);
	}

	video_isr = 0x03da;
	video_crtc = video_isr - 6;

	set_vmode_preview(vmode);

	device_cont();

	if (f_ramdac)
		analog_color(&s_color);
	else if (f_reverse)
		pallet(1);

	if (dim->split == 1) {
		x = x_shift + dim->text_width;
		if (x < s_max_width)
			x = s_max_width;
		if (x_shift < 0)
			x -= x_shift;

		y = y_shift + dim->text_height;
		if (y < s_max_height)
			y = s_max_height;
		if (y_shift < 0)
			y -= y_shift;
	}
	else
		return;

	num_view_buf = (leftbuffer() - 0x80L) / view_buf_size;

	if (x < (g_width_b - 12) * 32 && y < (g_height - 4) * 4) {
		f_div = 4;
	}
	else if (x < (g_width_b - 12) * 64 && y < (g_height - 4) * 8) {
		f_div = 8;
	}
	if (f_div > 0 && x > (g_width_b - 6) * 4 * f_div) {
		if (f_div == 4)
			f_div2 = 8;
	}
	else
		f_div2 = f_div;

	if (!f_use_new_size_option && s_max_height > 0 && s_max_width > 0)
		f_box = 1;

	if (num_view_buf > MAX_VIEW)
		num_view_buf = MAX_VIEW;
	if (num_view == 0)
		num_view = num_view_buf;
	if (f_div) {
		v_x_shift = x_shift >> 2;
		v_x_shift2 = x_shift >> 3;
		v_y_shift = y_shift >> 2;
		v_y_shift2 = y_shift >> 3;
		x = x2 = 5;
		y = y2 = 2;
		if (v_x_shift > 0) {
			x += (v_x_shift >> 3);
			x2 += (v_x_shift2 >> 3);
		}
		if (v_y_shift > 0) {
			y += v_y_shift;
			y2 += v_y_shift2;
		}
		switch (disp_reso) {
		  case RES_640_480:
			v_top = (BUFFER *)G_TOP_VGA + x + (g_width_b * y);
			v_top2 = (BUFFER *)G_TOP_VGA + x2 + (g_width_b * y2);
			break;
		  default:
			v_top = (BUFFER *)G_TOP_DCGA + x + (g_width_b * y);
			v_top2 = (BUFFER *)G_TOP_DCGA + x2 + (g_width_b * y2);
			break;
		}
		if (!f_div2) goto nv;
#ifndef	NEMS
		if (num_view < 0 && num_view >= -MAX_VIEW) {
			num_view_buf = -num_view;
			view_EMS_top = system_EMS_end;
			max_user_page -= view_EMS_unit*num_view_buf;
			system_EMS_end += view_EMS_unit*num_view_buf;
			view_buf = pf_addr;
			return;
		}
#endif
		if (num_view_buf > 0) {
			view_buf = (HUGE_BUF *)farmalloc(view_buf_size * num_view_buf);
		}
	}
	else
nv:		num_view_buf = 0;
}

static void cls(int mode)
{
	switch (disp_reso) {
	  case RES_640_480:
		  cls_vga(mode);
		  break;
	  default:
		  cls_dcga(mode);
		  break;
	}
}

void device_end()
{
	union REGS regs;
	struct SREGS sregs;

	regs.h.ah = 0x00;
	regs.h.al = org_video_mode & 0xFF;
	int86(V_BIOS, &regs, &regs);

	cls(1);
	clear_text_screen();
	program_screen_mode(OFF);
	cursor_mode(ON);

	flskey();

	regs.h.ah = 130;			/* Fast scroll mode  */
	regs.h.al = 0;
	regs.h.bl = 0;
	int86(V_BIOS, &regs, &regs);

	restore_palette(SAVE_PAL);
}

void device_clear(OUTPUT_INFO *out)
	/* clear screen and initialize variables */
{
	/* intialize variables */
	map_top_ptr = out->bitmap_ptr;
	hmax = out->width;
	vmax = out->height;
	hmaxb = out->byte_width;

	/* clear screen */
	if (out->split > 1)
		cls(0);
	program_screen_mode(ON);
	clear_text_screen();
	cursor_mode(OFF);
}

static void s_view8(void)
{
	int i, j, vm, v;
	uint ch, gptr_off, x, y;
	HUGE_BUF *ptr0;
	BUFFER *ptr1;
	BUFFER *ptr;
	BUFFER *ptrg0;
	BUFFER *ptrg;

	ptrg0 = vram_adr(v_top2);
	ptr0 = map_top_ptr;

	for (ch = v = 0; v < vmax; v += 8) {
		vm = ((vmax - v) < 8) ? vmax - v : 8;
		ptr1 = (BUFFER *)ptr0;
		ptr0 += (hmaxb << 3);
		ptrg = ptrg0;
		vram_hline(&ptrg0);
		for (i = 0; i < hmaxb; i++) {
			ptr = ptr1++;
			for (j = vm; j != 0; j--) {
				if (*ptr != 0) {
					ch |= 1;
					break;
				}
				ptr += hmaxb;
			}
			if ((i & 7) == 7)
				*ptrg++ = ch;
			ch += ch;
		}
		if ((i = (hmaxb & 7)) != 0)
			*ptrg++ = (ch << (7 - i));
	}
	if (f_box)
		v_box(v_top2, -v_x_shift2, -v_y_shift2,
			  s_max_width / 8, s_max_height / 8);
}

static void s_view4(void)
{
	int i, j, vm, v;
	uint ch, gptr_off, x, y;
	HUGE_BUF *ptr0;
	BUFFER *ptr1;
	BUFFER *ptr;
	BUFFER *ptrg0;
	BUFFER *ptrg;

	ptrg0 = vram_adr(v_top);
	ptr0 = map_top_ptr;

	for (ch = v = 0; v < vmax; v += 4) {
		vm = ((vmax - v) < 4) ? vmax - v : 4;
		ptr1 = (BUFFER *)ptr0;
		ptr0 += (hmaxb << 2);
		ptrg = ptrg0;
		vram_hline(&ptrg0);
		for (i = 0; i < hmaxb; i++) {
			ptr = ptr1++;
			for (j = vm; j != 0; j--) {
				if ((*ptr & 0xf0) != 0) {
					ch |= 2;
				}
				if ((*ptr & 0x0f) != 0) {
					ch |= 1;
				}
				if ((ch & 3) == 3)
					break;
				ptr += hmaxb;
			}
			if ((i & 3) == 3)
				*ptrg++ = ch;
			ch <<= 2;
		}
		if ((i = (hmaxb & 3)) != 0)
			*ptrg++ = (ch << ((3 - i) * 2));
	}
	if (f_box)
		v_box(v_top, -v_x_shift, -v_y_shift,
			s_max_width / 4, s_max_height / 4);
}

static void v_box(BUFFER *orig, int x, int y, int w, int h)
{
	BUFFER *ptr;
	int i, b, ch, dif;

	orig += (x + g_width_b * 8) / 8 + g_width_b * (y - 1);
	b = (x & 7);

	ch = (1 << (7 - b));
	ptr = vram_adr(orig);
	for (i = h; i > 0; vram_hline(&ptr), i--)
		*ptr |= ch;

	dif = g_width_b * (h - 1);
	ch = (0xff >> b);
	ptr = orig;
	*(vram_adr(ptr + dif)) |= ch;
	*(vram_adr(ptr)) |= ch;

	ptr++;
	for (i = w + b - 8; i > 8; ptr++, i -= 8) {
		*(vram_adr(ptr)) |= 0xff;
		*(vram_adr(ptr + dif)) |= 0xff;
	}
	ch = (0xff << (8 - i));
	*(vram_adr(ptr)) |= ch;
	*(vram_adr(ptr + dif)) |= ch;

	ptr = vram_adr(ptr);
	ch = (1 << (8 - i));
	for (i = h; i > 0; vram_hline(&ptr), i--)
		*ptr |= ch;
}

void msg_help()
{
	cls(0);

	if (!f_ramdac && f_reverse)
		pallet(0);

	fprintf(stderr,
			"\x1b" "[5;H"
			"\t\t\t\t<<< Help >>>\n\n"
			"\t(SHIFT + ) → ← ↑ ↓\t: Scroll in a page\n"
			"\tN\t\t\t: Next page\n"
			"\tP, B\t\t\t: Previous page\n"
			"\tG, M\t\t\t: Move to a page\n"
			"\tnumbers\t\t\t: pages (skipped) by next B, G, M, N, P\n"
			"\tSpace\t\t\t: Next part\n"
			"\tBack Space\t\t: Previous part\n"
			"\tC, V\t\t\t: (Compressed) View outline\n"
			"\tR\t\t\t: Reverse Screen(toggle)\n"
			"\tH, HOME\t\t\t: Help message\n"
			"\tReturn\t\t\t: Next block or quit\n"
			"\tEscape\t\t\t: Quit\n"
		);

	flskey();
	getch();

	if (!f_ramdac && f_reverse)
		pallet(1);

	fprintf(stderr, "\x1b" "[5;H" "\x1b" "[0J" "\x1e");

}

void slow(int fact)
{
	int	  i, j;

	i = (fact<6)?5:fact;
	while(fact-- > 0){
		for(j = 0; j < 6*i; j++) slow( 0 );
	}
}

NEXT_ACTION device_out(OUTPUT_INFO *out, DIMENSION *dim)
{
	static struct SCROLL s_dat;
	KeyInput key;
	int i, j;

	s_dat.mptr = map_top_ptr;

	first_draw(&s_dat, out->page, dim->split);
	slow(slow_page);

	for (;;) {
		switch (key = extra_inkey()) {
		  case Key_V:
		  case Key_C:
			  if (!f_div)
				  break;
			  cls(0);
			  gshift(0);
			  s_dat.r_line = 0;
			  i = s_dat.offset;
			  s_dat.offset = 0;
			  if (f_div == 4 && key != Key_C) {
				  s_view4();
				  j = get_view(out->page, 4);
			  }
			  else {
				  s_view8();
				  j = get_view(out->page, 8);
			  }
			  s_dat.offset = i;
			  cls(0);
			  if (j) goto disp_m;
disp_0:		  draw_screen(&s_dat);
			  slow(slow_page);
			  break;
		  case Key_R:
			  switch (disp_reso) {
				case RES_640_480:
					if (!f_ramdac)
						pallet((f_reverse = TRUE - f_reverse) == TRUE ? 1 : 0);
					break;
			  default:
				break;
			  }
			  goto disp2;
		  case Key_H:
		  case HELP:
			  msg_help();
			  goto disp_0;
		  case Key_M:
		  case Key_G:
disp_m:		  unit_pages -= out->page;
			  return ((NEXT_ACTION)Key_N);
		  case ArrowDown:
			  scroll_up(&s_dat);
			  goto sl0;
		  case ArrowLeft:
			  scroll_right(&s_dat);
			  goto sl2;
		  case ArrowRight:
			  scroll_left(&s_dat);
sl2:		  slow(slow_fact2);
			  break;
		  case ArrowUp:
			  scroll_down(&s_dat);
sl0:		  slow(v_shift0);
			  break;
		  case ShiftUp:
		  case ShiftDown:
		  case ShiftLeft:
		  case ShiftRight:
			  move_screen(&s_dat, key);
			disp2:slow(slow_fact);
			  break;
		  default:
			  return ((NEXT_ACTION)key);
		}
	}
}

static void first_draw(struct SCROLL *s_dat, int page, int split)
	/* at first, set variables and put to screen */
{
	if (f_resume)
		poke(BIOS_WORK, resume_base + 3, page);
	s_dat->x_lock = s_dat->y_lock = FALSE;
	s_dat->offset = 0;

	if (hmaxb < g_width_b) {
		/* can't scroll horizontally */
		s_dat->gw_act = hmaxb;
		s_dat->x_lock = TRUE;
	}
	else
		s_dat->gw_act = g_width_b;

	if (vmax < g_height) {
		/* can't scroll vertically */
		s_dat->gh_act = vmax;
		s_dat->y_lock = TRUE;
	}
	else
		s_dat->gh_act = g_height;

	s_dat->h_spc = (g_width_b - s_dat->gw_act) / 2;
	s_dat->v_spc = (split == 1) ? (g_height - s_dat->gh_act) / 2 : 0;
	g_top_ptr = (GRAM_BUF *)g_top + s_dat->h_spc + (ulong)s_dat->v_spc * g_width_b;

	s_dat->x = -s_dat->h_spc;
	s_dat->y = -s_dat->v_spc;

	draw_screen(s_dat);
	fprintf(stderr, "\x1b" "[;H" "[%d]", page);
}

static void draw_screen(struct SCROLL *s_dat)
{
	switch (disp_reso) {
	  case RES_640_480:
		  draw_screen_vga(s_dat);
		  break;
	  default:
		  draw_screen_dcga(s_dat);
		  break;
	}
}

static int get_view(page, div)
{
	int i, pt, pg;
	uchar tmp[G_WIDTH_B_MAX / 2];
	GRAM_BUF *gptr_tmp;
	HUGE_BUF *buf_tmp;

	union REGS regs;

	pg = -1;
	fprintf(stderr, "\x1b" "[;H" "[%d]" "\x1b" "[;H", page);
	if (num_view_buf <= 0) {
		regs.h.ah = 0;
		int86(0x16, &regs, &regs);
/*		bioskey(0);	*/
		return;
	}
	pt = view.current;
	while (TRUE) {
		if (div != f_div2)
			goto skip;
		if (--pt < 0)
			pt = view.total - 1;
		if (pt >= 0) {
#ifndef	NEMS
			if (view_EMS_unit) {
				buf_tmp = view_buf;
				set_ems(view_EMS_top + view_EMS_unit * pt);
			}
			else
#endif
				buf_tmp = view_buf + view_buf_size * pt;

			gptr_tmp = vram_adr((GRAM_BUF *) (g_top + (ulong)g_width_b / 2));

			for (i = g_height; i > 0; i--) {
				movedata(FP_SEG(buf_tmp), FP_OFF(buf_tmp),
						 FP_SEG(gptr_tmp), FP_OFF(gptr_tmp),
						 g_width_b / 2);
				buf_tmp += g_width_b / 2;
				vram_hline(&gptr_tmp);
			}
			pg = view.page[pt];
		}
skip:	flskey();
		regs.h.ah = 0;
		int86(0x16, &regs, &regs);
		i = regs.h.al;
/*		i = (uchar)bioskey(0);	*/
		if (i != 'm' && i != 'M' && i != 'ﾓ')
			pg = -1;
		if (i != 'v' && i != 'V' && i != 'ﾋ')
			break;
	}
	fprintf(stderr, "\x1a" "[%d]", page);
	if (div != f_div2)
		return 0;
	for (pt = view.total; pt > 0;) {
		if (view.page[--pt] == page) {
			view.current = pt + 1;
			goto nxt;
		}
	}
	if (view.total < num_view_buf)
		view.current = view.total++;
	if (view.current >= num_view_buf)
		view.current = 0;
	view.page[view.current] = page;

#ifndef	NEMS
	if (view_EMS_unit) {
		buf_tmp = view_buf;
		set_ems(view_EMS_top + view_EMS_unit * view.current);
	}
	else
#endif
		buf_tmp = view_buf + view_buf_size * view.current;
	view.current++;

	gptr_tmp = (GRAM_BUF *)g_top;

	for (i = g_height; i > 0; i--) {
		movedata(FP_SEG(gptr_tmp), FP_OFF(gptr_tmp),
				 FP_SEG(buf_tmp), FP_OFF(buf_tmp), g_width_b / 2);
		buf_tmp += g_width_b / 2;
		vram_hline(&gptr_tmp);
	}
nxt:
	if (pg >= 0)
		unit_pages = pg;
	return pg+1;
}

static void move_screen(struct SCROLL *s_dat, KeyInput direct)
{
	int x_step, y_step;

	x_step = y_step = 0;
	switch (direct) {
	  case ShiftDown:
		  y_step = (s_dat->gh_act) >> 1;
		  break;
	  case ShiftUp:
		  y_step = -((s_dat->gh_act) >> 1);
		  break;
	  case ShiftLeft:
		  x_step = -(s_dat->gw_act) >> 1;
		  break;
	  case ShiftRight:
		  x_step = (s_dat->gw_act) >> 1;
		  break;
	}

	if (x_step != 0 && !s_dat->x_lock) {
		if (s_dat->x + x_step <= 0)
			x_step = -s_dat->x;
		if (s_dat->x + x_step + g_width_b >= hmaxb)
			x_step = hmaxb - (s_dat->x + g_width_b);
		x_step &= 0xfffe;
		s_dat->x += x_step;
		s_dat->mptr += x_step;
		s_dat->offset = s_dat->h_spc + s_dat->x;
		draw_screen(s_dat);
	}
	else if (y_step != 0 && !s_dat->y_lock) {
		if (s_dat->y + y_step <= 0)
			y_step = -s_dat->y;
		if (s_dat->y + y_step + g_height >= vmax)
			y_step = vmax - (s_dat->y + g_height);
		s_dat->y += y_step;
		s_dat->mptr += (long)y_step *hmaxb;

		draw_screen(s_dat);
	}
}

static void scroll_up(struct SCROLL *s_dat)
{
	int shift;

	if ((shift = vmax - s_dat->y - g_height) > 0) {
		switch (disp_reso) {
		case RES_640_480:
			if (shift > v_shift1)
				shift = v_shift1;
			s_up(s_dat, shift);
			s_dat->mptr += (ulong)hmaxb *shift;
			s_dat->y += shift;
			break;
		default:
			shift = (shift / 4) * 4;
			if (shift > v_shift1)
				shift = v_shift1;
			s_dat->mptr += hmaxb * shift;
			s_dat->y += shift;
			s_up(s_dat, shift);
			break;
		}
	}
}

static void scroll_down(struct SCROLL *s_dat)
{
	int shift;

	if ((shift = s_dat->y) > 0) {
		switch (disp_reso) {
		case RES_640_480:
			if (shift > v_shift1)
				shift = v_shift1;
			s_down(s_dat, shift);
			s_dat->mptr -= (ulong)hmaxb *shift;
			s_dat->y -= shift;
			break;
		default:
			shift = (shift / 4) * 4;
			if (shift > v_shift1)
				shift = v_shift1;
			s_dat->mptr -= hmaxb * shift;
			s_dat->y -= shift;
			s_down(s_dat, shift);
			break;
		}
	}
}

static void scroll_right(struct SCROLL *s_dat)
{
	if (s_dat->x > 0) {
		s_dat->mptr -= 2;
		s_dat->x -= 2;
		s_right(s_dat);
	}
}

static void scroll_left(struct SCROLL *s_dat)
{
	if (s_dat->x + g_width_b < hmaxb) {
		s_dat->mptr += 2;
		s_dat->x += 2;
		s_left(s_dat);
	}
}

static void flskey(void)
	/*  flush key-buffer. by calling dos function */
{
	bdos(12, 0, 0);
}

static void clear_text_screen()
	/* clear text screen */
{
	fprintf(stderr, "\x1b" "[2J");
}

void program_screen_mode(int mode)
	/* to use the bottom line for user */
{
	fprintf(stderr, mode ? "\x1b" "[>1l" : "\x1b" "[>1h");
}

static void cursor_mode(int flg)
	/* Cursor on or off */
{
	fprintf(stderr, flg ? "\x1b" "[>5l" : "\x1b" "[>5h");
}

static GRAM_BUF *
    vram_adr(GRAM_BUF * ptr)
	/* Convert streight address to J31 Vram address */
{
	unsigned int gptr_off, x, y;

	switch (disp_reso) {
	case RES_640_480:
		return ptr;
	default:
		gptr_off = FP_OFF(ptr);
		x = gptr_off % 80;
		y = gptr_off / 80;
		gptr_off = (y % 4) * 0x2000 + (y / 4) * 80 + x;
		return MK_FP(FP_SEG(ptr), gptr_off);
	}
}

static void vram_hline(GRAM_BUF ** ptr)
	/* Add 1 line to J31 Vram address */
{
	uint ptr_off;

	switch (disp_reso) {
	  case RES_640_480:
		  *ptr += G_WIDTH_B_VGA;
		  break;
	  default:
		  if ((uint)(FP_OFF(*ptr) + 0x2000) >= 0x8000) {
			  *ptr = MK_FP(FP_SEG(*ptr), ptr_off = ((FP_OFF(*ptr) + 0x2000) & 0x7fff));
			  if ((ptr_off % G_DEPTH) < ((ptr_off + G_WIDTH_B_DCGA) % G_DEPTH))
				  *ptr += G_WIDTH_B_DCGA;
			  else
				  *ptr -= G_DEPTH - G_WIDTH_B_DCGA;
		  }
		  else
			  *ptr = MK_FP(FP_SEG(*ptr), FP_OFF(*ptr) + 0x2000);
		  break;
	}
}

void pr_new_page(void)
{
}

static void cls_dcga(int mode)
{
	static BUF_INFO vram_dcga =
	{
		(BUFFER *)0xb8000000L,
		(BUFFER *)0xb8000000L,
		(BUFFER *)0xb8007fffL,
		0x7ff0L
	};

	clear_buf(&vram_dcga);
}

static void cls_vga(int mode)
{
	static BUF_INFO vram_vga =
	{
		(BUFFER *)0xa0000000L,
		(BUFFER *)0xa0000000L,
		(BUFFER *)0xa0000000L,
		0xffffL
	};

	clear_buf(&vram_vga);
}

void save_palette(unsigned char *palette)
{
	struct SREGS sregs;
	union REGS regs;

	regs.x.ax = 0x1009;
	sregs.es = FP_SEG(palette);
	regs.x.dx = FP_OFF(palette);
	int86x(0x10, &regs, &regs, &sregs);
}

static void save_a_ramdac(uint number, unsigned char *p)
{
	struct SREGS sregs;
	union REGS regs;

	regs.x.ax = 0x1017;
	regs.x.bx = number;
	regs.x.cx = 1;
	sregs.es = FP_SEG(p);
	regs.x.dx = FP_OFF(p);
	int86x(0x10, &regs, &regs, &sregs);
}

static void save_ramdac(unsigned char *ramdac)
{
	save_a_ramdac(0x0000, ramdac);
	save_a_ramdac(0x0007, ramdac + 3);
	save_a_ramdac(0x000F, ramdac + 3 * 2);
}

void restore_palette(unsigned char *palette)
{
	struct SREGS sregs;
	union REGS regs;

	regs.x.ax = 0x1002;
	sregs.es = FP_SEG(palette);
	regs.x.dx = FP_OFF(palette);
	int86x(0x10, &regs, &regs, &sregs);
}

static void restore_a_ramdac(uint number, unsigned char *p)
{
	struct SREGS sregs;
	union REGS regs;

	regs.x.ax = 0x1012;
	regs.x.bx = number;
	regs.x.cx = 1;
	sregs.es = FP_SEG(p);
	regs.x.dx = FP_OFF(p);
	int86x(0x10, &regs, &regs, &sregs);
}

static void restore_ramdac(unsigned char *ramdac)
{
	restore_a_ramdac(0x0000, ramdac);
	restore_a_ramdac(0x0007, ramdac + 3);
	restore_a_ramdac(0x000F, ramdac + 3 * 2);
}

static void set_a_ramdac(uint pal, struct COLOR_ELEMENT *cp)
{
	union REGS regs;

	/* assign palette */
	regs.x.ax = 0x1000;
	regs.h.bl = pal;
	regs.h.bh = pal;
	int86(V_BIOS, &regs, &regs);
	/* set color element */
	regs.x.ax = 0x1010;
	regs.x.bx = pal;
	regs.h.ch = cp->g;
	regs.h.cl = cp->b;
	regs.h.dh = cp->r;
	int86(V_BIOS, &regs, &regs);
}

static void pallet(int mode)
{
	union REGS regs;

	if (mode == 1) {			/*	exchange black and white	*/
		save_palette(SAVE_REV_PAL);

		/* foreground color */
		regs.x.ax = 0x1000;
		regs.h.bl = 0x0f;
		regs.h.bh = 0x00;
		int86(V_BIOS, &regs, &regs);
		regs.x.ax = 0x1000;
		regs.h.bl = 0x07;
		regs.h.bh = 0x00;
		int86(V_BIOS, &regs, &regs);

		/* background color */
		regs.x.ax = 0x1000;
		regs.h.bl = 0x00;
		regs.h.bh = 0xff;
		int86(V_BIOS, &regs, &regs);
	}
	else {						/*	reset palette setting	*/
		restore_palette(SAVE_REV_PAL);
	}
}

static void analog_color(struct PALETTE *color)
{
	union REGS regs;

	/* set foreground color */
	set_a_ramdac(0x0007, &color->fg);
	set_a_ramdac(0x000F, &color->fg);
	/* set background color */
	set_a_ramdac(0x0000, &color->bg);
}

void set_start_addr(unsigned int start_addr)
/*	画面表示先頭のVRAMのアドレス設定	*/
{
	outport(video_crtc, (start_addr & 0XFF00) | START_ADDRESS_HIGH);
	outport(video_crtc, (start_addr << 8) | START_ADDRESS_LOW);
}

void draw_screen_dcga(struct SCROLL *s_dat)
	/* put bitmap-image to screen */
{
	int i, j;
	HUGE_BUF *mptr_tmp;
	GRAM_BUF *gptr_tmp;

	gptr_tmp = g_top_ptr;
	if (s_dat->y_lock == TRUE && s_dat->x_lock == FALSE) {
		gptr_tmp = g_top_ptr;
		for (i = s_dat->offset; --i >= 0;)
			gptr_tmp[i] = 0;
		gptr_tmp += (G_WIDTH_B_DCGA * s_dat->gh_act + s_dat->gw_act);
		j = hmaxb - s_dat->offset - G_WIDTH_B_DCGA;
		for (i = 0; i < j;)
			gptr_tmp[i++] = 0;
	}
	s_dat->r_line = 0;
	hdw_scroll(s_dat);
	mptr_tmp = s_dat->mptr;
	gptr_tmp = g_top_ptr + s_dat->offset;
	for (i = 0; i < s_dat->gh_act; i++) {
		movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp),
				 FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), s_dat->gw_act);
		if (s_dat->x_lock == TRUE) {
			for (j = s_dat->h_spc; j > 0; j--) {
				gptr_tmp[-j] = 0;
				gptr_tmp[hmaxb + j - 1] = 0;
			}
		}
		vram_hline(&gptr_tmp);
		mptr_tmp += (ulong)hmaxb;
	}
}

static void draw_screen_vga(struct SCROLL *s_dat)
{
	int i, j;
	HUGE_BUF *mptr_tmp;
	GRAM_BUF *gptr_tmp;
	unsigned temp = 0;
	char back[G_WIDTH_B_VGA];

	if (s_dat->y_lock == TRUE && s_dat->x_lock == FALSE) {
		gptr_tmp = g_top_ptr;
		for (i = s_dat->offset; --i >= 0;)
			gptr_tmp[i] = 0;
		gptr_tmp += (G_WIDTH_B_VGA * s_dat->gh_act + s_dat->gw_act);
		j = hmaxb - s_dat->offset - G_WIDTH_B_VGA;
		for (i = 0; i < j;)
			gptr_tmp[i++] = 0;
	}
	mptr_tmp = s_dat->mptr;
	if (s_dat->x_lock == TRUE) {
		temp = s_dat->offset;
		for (i = 0; i < G_WIDTH_B_VGA; i++)
			back[i] = 0;
	}
	else {
		gptr_tmp = g_top_ptr + s_dat->offset;
	}
	for (i = 0; i < s_dat->gh_act; i++) {
		if (s_dat->x_lock == TRUE) {
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp),
				  FP_SEG(back), FP_OFF(back) + s_dat->h_spc, s_dat->gw_act);
			movedata(FP_SEG(back), FP_OFF(back),
					 G_SEG_VGA, temp, g_width_b);
			temp += g_width_b;
		}
		else {
			movedata(FP_SEG(mptr_tmp), FP_OFF(mptr_tmp),
					 FP_SEG(gptr_tmp), FP_OFF(gptr_tmp), s_dat->gw_act);
			gptr_tmp += G_WIDTH_B_VGA;
		}
		mptr_tmp += (ulong)hmaxb;
	}
	set_start_addr(s_dat->offset);
}
/* end of file : device.c */
