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