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, ®s, ®s);
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, ®s, ®s);
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