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