1 /* Copyright (C) 1990, 1991, 1993 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevherc.c,v 1.2.6.1.2.1 2003/01/17 00:49:00 giles Exp $*/
20 /* IBM PC-compatible Hercules Graphics display driver */
21 /* using direct access to frame buffer */
22 
23 #define FB_RASTER 90
24 #define SCREEN_HEIGHT 350
25 #define SCREEN_ASPECT_RATIO (54.0/35.0)
26 #define VIDEO_MODE 0x07
27 #define regen 0xb0000000L
28 
29 #define interrupt			/* patch ANSI incompatibility */
30 #include "dos_.h"
31 typedef union REGS registers;
32 #include "gx.h"
33 #include "gsmatrix.h"			/* for gxdevice.h */
34 #include "gxbitmap.h"
35 #include "gxdevice.h"
36 
37 /* outportb is defined in dos_.h */
38 #define outport2(port, index, data)\
39   (outportb(port, index), outportb((port)+1, data))
40 /* Define the nominal page height in inches. */
41 #ifdef A4
42 #  define PAGE_HEIGHT_INCHES 11.69
43 #else
44 #  define PAGE_HEIGHT_INCHES 11.0
45 #endif
46 
47 /* Dimensions of screen */
48 #define screen_size_x (FB_RASTER * 8)
49 #define screen_size_y SCREEN_HEIGHT
50 /* Other display parameters */
51 #define raster_x FB_RASTER
52 #define aspect_ratio SCREEN_ASPECT_RATIO
53 #define graphics_video_mode VIDEO_MODE
54 
55 /* Procedures */
56 
57 	/* See gxdevice.h for the definitions of the procedures. */
58 
59 dev_proc_open_device(herc_open);
60 dev_proc_close_device(herc_close);
61 dev_proc_fill_rectangle(herc_fill_rectangle);
62 dev_proc_copy_mono(herc_copy_mono);
63 dev_proc_copy_color(herc_copy_color);
64 
65 /* The device descriptor */
66 private gx_device_procs herc_procs = {
67 	herc_open,
68 	gx_default_get_initial_matrix,
69 	gx_default_sync_output,
70 	gx_default_output_page,
71 	herc_close,
72 	gx_default_map_rgb_color,
73 	gx_default_map_color_rgb,
74 	herc_fill_rectangle,
75 	gx_default_tile_rectangle,
76 	herc_copy_mono,
77 	herc_copy_color
78 };
79 
80 gx_device far_data gs_herc_device = {
81 	std_device_std_body(gx_device, &herc_procs, "herc",
82 	  screen_size_x, screen_size_y,
83 	/* The following parameters map an appropriate fraction of */
84 	/* the screen to a full-page coordinate space. */
85 	/* This may or may not be what is desired! */
86 	  (screen_size_y * aspect_ratio) / PAGE_HEIGHT_INCHES,	/* x dpi */
87 	  screen_size_y / PAGE_HEIGHT_INCHES		/* y dpi */
88 	)
89 };
90 
91 
92 /* Forward declarations */
93 private int herc_get_mode(P0());
94 private void herc_set_mode(P1(int));
95 
96 /* Save the HERC mode */
97 private int herc_save_mode = -1;
98 
99 /* Reinitialize the herc for text mode */
100 int
herc_close(gx_device * dev)101 herc_close(gx_device *dev)
102 {	if ( herc_save_mode >= 0 ) herc_set_mode(herc_save_mode);
103 	return 0;
104 }
105 
106 /* ------ Internal routines ------ */
107 
108 /* Read the device mode */
109 private int
herc_get_mode(void)110 herc_get_mode(void)
111 {	registers regs;
112 	regs.h.ah = 0xf;
113 	int86(0x10, &regs, &regs);
114 	return regs.h.al;
115 }
116 
117 /* Set the device mode */
118 private void
herc_set_mode(int mode)119 herc_set_mode(int mode)
120 {	registers regs;
121 	regs.h.ah = 0;
122 	regs.h.al = mode;
123 	int86(0x10, &regs, &regs);
124 }
125 
126 
127 /****************************************************************/
128 /* Hercules graphics card functions				*/
129 /*								*/
130 /* -- Taken from Jan/Feb 1988 issue of Micro Cornucopia #39	*/
131 /*								*/
132 /* --rewritten for MSC 5.1 on 02/18/91 by Phillip Conrad	*/
133 /****************************************************************/
134 
135 
136 static const char paramg[12] = {0x35, 0x2d, 0x2e, 0x07, 0x5b, 0x02,
137 			      0x57, 0x57, 0x02, 0x03, 0x00, 0x00};
138 /* (Never used)
139 static const char paramt[12] = {0x61, 0x50, 0x52, 0x0f, 0x19, 0x06,
140 			      0x19, 0x19, 0x02, 0x0d, 0x0b, 0x0c};
141 */
142 
143 /* Type and macro for frame buffer pointers. */
144 /*** Intimately tied to the 80x86 (x<2) addressing architecture. ***/
145 typedef byte far *fb_ptr;
146 #  define mk_fb_ptr(x, y)\
147     (fb_ptr)((regen) + ((0x2000 * ((y) % 4) + (90 * ((y) >> 2))) + ((int)(x) >> 3)))
148 
149 
150 /* Structure for operation parameters. */
151 /* Note that this structure is known to assembly code. */
152 /* Not all parameters are used for every operation. */
153 typedef struct rop_params_s {
154 	fb_ptr dest;			/* pointer to frame buffer */
155 	int draster;			/* raster of frame buffer */
156 	const byte far *src;		/* pointer to source data */
157 	int sraster;			/* source raster */
158 	int width;			/* width in bytes */
159 	int height;			/* height in scan lines */
160 	int shift;			/* amount to right shift source */
161 	int invert;			/* 0 or -1 to invert source */
162 	int data;			/* data for fill */
163 	int x_pos;		/*>>added--2/24/91 */
164 	int y_pos;
165 } rop_params;
166 
167 /* Define the device port and register numbers, and the regen map base */
168 #define seq_addr 0x3b4		/* changed for HERC card (6845 ports)*/
169 #define graph_mode 0x3b8
170 #define graph_stat 0x3ba
171 #define graph_config 0x3bf
172 
173 #ifndef regen
174 #define regen 0xa0000000L
175 #endif
176 
177 
178 /* Initialize the display for Hercules graphics mode */
179 int
herc_open(gx_device * dev)180 herc_open(gx_device *dev)
181 {	int i;
182 	if ( herc_save_mode < 0 ) herc_save_mode = herc_get_mode();
183 /*	herc_set_mode(graphics_video_mode);  */
184 	outportb(graph_config,3);
185 	for(i=0;i<sizeof(paramg);i++)
186 	{
187 		outport2(seq_addr,i,paramg[i]);
188 
189 	}
190 	outportb(graph_mode,0x0a);	/* set page 0 */
191 	for(i=0;i<0x3FFFL;i++)	/* clear the screen */
192 		{
193 		int far *loc = (int far *)( regen  +(2L*i));
194 		*loc = 0;
195 		}
196 
197 	return 0;
198 }
199 
200 /* Macro for testing bit-inclusion */
201 #define bit_included_in(x,y) !((x)&~(y))
202 
203 /* Copy a monochrome bitmap.  The colors are given explicitly. */
204 /* Color = gx_no_color_index means transparent (no effect on the image). */
205 int
herc_copy_mono(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index izero,gx_color_index ione)206 herc_copy_mono(gx_device *dev,
207   const byte *base, int sourcex, int raster, gx_bitmap_id id,
208   int x, int y, int w, int h, gx_color_index izero, gx_color_index ione)
209 {	rop_params params;
210 #define czero (int)izero
211 #define cone (int)ione
212 	int dleft, sleft, count;
213 	int invert, zmask, omask;
214 	byte mask, rmask;
215 
216 	if ( cone == czero )		/* vacuous case */
217 		return herc_fill_rectangle(dev, x, y, w, h, izero);
218 
219 	/* clip */
220 	fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
221 	params.dest = mk_fb_ptr(x, y);
222 	params.draster = raster_x;
223 	params.src = base + (sourcex >> 3);
224 	params.sraster = raster;
225 	params.height = h;
226 	params.shift = (x - sourcex) & 7;
227 	params.y_pos = y;
228 	params.x_pos = x;
229 	params.width = w;
230 
231 	if(czero > cone) params.invert = -1;
232 
233 	/* Macros for writing partial bytes. */
234 	/* bits has already been inverted by xor'ing with invert. */
235 
236 #define write_byte_masked(ptr, bits, mask)\
237   *ptr = ((bits | ~mask | zmask) & (*ptr | (bits & mask & omask)))
238 
239 #define write_byte(ptr, bits)\
240   *ptr = ((bits | zmask) & (*ptr | (bits & omask)))
241 
242 	invert = (czero == 1 || cone == 0 ? -1 : 0);
243 /*	invert = (czero == 1 || cone == 1 ? -1 : 0); */
244 	zmask = (czero == 0 || cone == 0 ? 0 : -1);
245 	omask = (czero == 1 || cone == 1 ? -1 : 0);
246 
247 #undef czero
248 #undef cone
249 
250 	/* Actually copy the bits. */
251 
252 	sleft = 8 - (sourcex & 7);
253 	dleft = 8 - (x & 7);
254 	mask = 0xff >> (8 - dleft);
255 	count = w;
256 	if ( w < dleft )
257 		mask -= mask >> w,
258 		rmask = 0;
259 	else
260 		rmask = 0xff00 >> ((w - dleft) & 7);
261 
262 	if (sleft == dleft)		/* optimize the aligned case */
263 	{
264 		w -= dleft;
265 		while ( --h >= 0 )
266 		{
267 			register const byte *bptr = params.src;
268 			register byte *optr = mk_fb_ptr(params.x_pos,params.y_pos);
269 			register int bits = *bptr ^ invert;	/* first partial byte */
270 
271 			count = w;
272 
273 			write_byte_masked(optr, bits, mask);
274 
275 			/* Do full bytes. */
276 
277 			while ((count -= 8) >= 0)
278 			{
279 				bits = *++bptr ^ invert;
280 				params.x_pos += 8;
281 				optr = mk_fb_ptr(params.x_pos,params.y_pos);
282 				write_byte(optr, bits);
283 			}
284 			/* Do last byte */
285 
286 			if (count > -8)
287 			{
288 				bits = *++bptr ^ invert;
289 				params.x_pos += 8;
290 				optr = mk_fb_ptr(params.x_pos,params.y_pos);
291 				write_byte_masked(optr, bits, rmask);
292 			}
293 /*			dest += BPL; */
294 			params.y_pos++;
295 			params.x_pos = x;
296 			params.src += raster;
297 		}
298 	}
299 	else
300 	{
301 		int skew = (sleft - dleft) & 7;
302 		int cskew = 8 - skew;
303 
304 		while (--h >= 0)
305 		{
306 			const byte *bptr = params.src;
307 			byte *optr = mk_fb_ptr(params.x_pos,params.y_pos);
308 			register int bits;
309 
310 			count = w;
311 
312 			/* Do the first partial byte */
313 
314 			if (sleft >= dleft)
315 			{
316 				bits = *bptr >> skew;
317 			}
318 			else /* ( sleft < dleft ) */
319 			{
320 				bits = *bptr++ << cskew;
321 				if (count > sleft)
322 					bits += *bptr >> skew;
323 			}
324 			bits ^= invert;
325 			write_byte_masked(optr, bits, mask);
326 			count -= dleft;
327 			params.x_pos += 8;
328 			optr = mk_fb_ptr(params.x_pos,params.y_pos);
329 
330 			/* Do full bytes. */
331 
332 			while ( count >= 8 )
333 			{
334 				bits = *bptr++ << cskew;
335 				bits += *bptr >> skew;
336 				bits ^= invert;
337 				write_byte(optr, bits);
338 				count -= 8;
339 				params.x_pos += 8;
340 				optr = mk_fb_ptr(params.x_pos,params.y_pos);
341 			}
342 
343 			/* Do last byte */
344 
345 			if (count > 0)
346 			{
347 				bits = *bptr++ << cskew;
348  				if (count > skew)
349 					bits += *bptr >> skew;
350 				bits ^= invert;
351 				write_byte_masked(optr, bits, rmask);
352 			}
353 /*			dest += BPL;
354 			line += raster;
355 */
356 			params.y_pos++;
357 			params.x_pos = x;
358 			params.src += raster;
359 		}
360 	}
361 	return 0;
362 }
363 
364 /* Copy a color pixelmap.  This is just like a bitmap, */
365 int
herc_copy_color(gx_device * dev,const byte * base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)366 herc_copy_color(gx_device *dev,
367   const byte *base, int sourcex, int raster, gx_bitmap_id id,
368   int x, int y, int w, int h)
369 {	return herc_copy_mono(dev, base, sourcex, raster, id,
370 		x, y, w, h,(gx_color_index)0, (gx_color_index)1);
371 }
372 
373 #  define mk_fb_yptr(x, y)\
374     (fb_ptr)((regen) + ((0x2000 * ((y) % 4) + (90 * ((y) >> 2))) + x))
375 
376 /* Fill a rectangle. */
377 int
herc_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)378 herc_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
379   gx_color_index color)
380 {	rop_params params;
381 
382 	int x2, y2, xlen;
383 	byte led, red, d;
384 	byte far *ptr;
385 	int xloc;
386 
387 	fit_fill(dev, x, y, w, h);
388 
389 	params.dest = mk_fb_ptr(x, y);
390 	params.y_pos = y;
391 	params.x_pos = x;
392 
393 	x2 = x + w - 1;
394 	y2 = y + h - 1;
395 
396 	xlen = (x2 >> 3) - (x >> 3) - 1;
397 	led = 0xff >> (x & 7);
398 	red = 0xff << (7 - (x2 & 7));
399 
400 	ptr =  mk_fb_ptr(x,y);
401 
402 	if (color)
403 	{
404 		/* here to set pixels */
405 
406 		if (xlen == -1)
407 		{
408 			/* special for rectangles that fit in a byte */
409 
410 			d = led & red;
411 			for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
412 			{
413 				*ptr |= d;
414 				params.y_pos++;
415 			}
416 			return 0;
417 		}
418 
419 		/* normal fill */
420 
421 		xloc = params.x_pos >> 3;
422 		for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
423 		{	register int x_count = xlen;
424 			register byte far *p = ptr;
425 			*p |= led;
426 /*			 params.x_pos += 8; */
427 			xloc++;
428 			 p = mk_fb_yptr(xloc,params.y_pos);
429 			while ( x_count-- ) {
430 				 *p = 0xff;
431 /*				 params.x_pos += 8; */
432 				xloc++;
433 				 p = mk_fb_yptr(xloc,params.y_pos);
434 				}
435 			*p |= red;
436 /*			params.x_pos = x; */
437 			xloc = params.x_pos >> 3;
438 			params.y_pos++;
439 		}
440 	}
441 
442 	/* here to clear pixels */
443 
444 	led = ~led;
445 	red = ~red;
446 
447 	if (xlen == -1)
448 	{
449 		/* special for rectangles that fit in a byte */
450 
451 		d = led | red;
452 		for(; h >= 0; h--, ptr  = mk_fb_ptr(x,params.y_pos))
453 			{
454 			*ptr &= d;
455 			params.y_pos++;
456 			}
457 		return 0;
458 	}
459 
460 	/* normal fill */
461 
462 	xloc = x >> 3;
463 	for(; h >= 0; h--, ptr = mk_fb_ptr(x,params.y_pos))
464 	{	register int x_count = xlen;
465 		register byte far *p = ptr;
466 		*p &= led;
467 /*		 params.x_pos += 8; */
468 		xloc++;
469 		 p = mk_fb_yptr(xloc,params.y_pos);
470 		while ( x_count-- ) {
471 			 *p = 0x00;
472 /*			 params.x_pos += 8; */
473 			xloc++;
474 			 p = mk_fb_yptr(xloc,params.y_pos);
475 			}
476 		*p &= red;
477 /*		params.x_pos = x; */
478 		xloc = params.x_pos >> 3;
479 		params.y_pos++;
480 	}
481 	return 0;
482 }
483