xref: /plan9/sys/src/cmd/gs/src/gdevherc.c (revision a84536681645e23c630ce4ef2e5c3b284d4c590b)
1 /* Copyright (C) 1990, 1991, 1993 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: gdevherc.c,v 1.2 2000/09/19 19:00:13 lpd 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
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
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
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
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
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
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
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