1 /*
2  * PROJECT:         ReactOS VGA display driver
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            win32ss/drivers/displays/vga/vgavideo/vgavideo.c
5  * PURPOSE:
6  * PROGRAMMERS:
7  */
8 
9 #include <vgaddi.h>
10 
11 UCHAR PreCalcReverseByte[256];
12 int maskbit[640];
13 int y80[480];
14 int xconv[640];
15 int bit8[640];
16 int startmasks[8];
17 int endmasks[8];
18 PBYTE vidmem;
19 static ULONG UnpackPixel[256];
20 
21 static unsigned char leftMask;
22 static int byteCounter;
23 static unsigned char rightMask;
24 
bytesPerPixel(ULONG Format)25 UCHAR bytesPerPixel(ULONG Format)
26 {
27     /* This function is taken from /subsys/win32k/eng/surface.c
28      * FIXME: GDI bitmaps are supposed to be pixel-packed. Right now if the
29      * pixel size if < 1 byte we expand it to 1 byte for simplicities sake */
30 
31     switch (Format)
32     {
33         case BMF_1BPP:
34             return 1;
35 
36         case BMF_4BPP:
37         case BMF_4RLE:
38             return 1;
39 
40         case BMF_8BPP:
41         case BMF_8RLE:
42             return 1;
43 
44         case BMF_16BPP:
45             return 2;
46 
47         case BMF_24BPP:
48             return 3;
49 
50         case BMF_32BPP:
51             return 4;
52 
53         default:
54             return 0;
55     }
56 }
57 
vgaPreCalc()58 VOID vgaPreCalc()
59 {
60     ULONG j;
61 
62     startmasks[0] = 255;
63     startmasks[1] = 1;
64     startmasks[2] = 3;
65     startmasks[3] = 7;
66     startmasks[4] = 15;
67     startmasks[5] = 31;
68     startmasks[6] = 63;
69     startmasks[7] = 127;
70 
71     endmasks[0] = 0;
72     endmasks[1] = 128;
73     endmasks[2] = 192;
74     endmasks[3] = 224;
75     endmasks[4] = 240;
76     endmasks[5] = 248;
77     endmasks[6] = 252;
78     endmasks[7] = 254;
79 
80     for (j = 0; j < 80; j++)
81     {
82         maskbit[j*8]   = 128;
83         maskbit[j*8+1] = 64;
84         maskbit[j*8+2] = 32;
85         maskbit[j*8+3] = 16;
86         maskbit[j*8+4] = 8;
87         maskbit[j*8+5] = 4;
88         maskbit[j*8+6] = 2;
89         maskbit[j*8+7] = 1;
90 
91         bit8[j*8]   = 7;
92         bit8[j*8+1] = 6;
93         bit8[j*8+2] = 5;
94         bit8[j*8+3] = 4;
95         bit8[j*8+4] = 3;
96         bit8[j*8+5] = 2;
97         bit8[j*8+6] = 1;
98         bit8[j*8+7] = 0;
99     }
100     for (j = 0; j < SCREEN_Y; j++)
101         y80[j]  = j*80;
102     for (j = 0; j < SCREEN_X; j++)
103         xconv[j] = j >> 3;
104 
105     for (j = 0; j < 256; j++)
106     {
107         PreCalcReverseByte[j] =
108             (((j >> 0) & 0x1) << 7) |
109             (((j >> 1) & 0x1) << 6) |
110             (((j >> 2) & 0x1) << 5) |
111             (((j >> 3) & 0x1) << 4) |
112             (((j >> 4) & 0x1) << 3) |
113             (((j >> 5) & 0x1) << 2) |
114             (((j >> 6) & 0x1) << 1) |
115             (((j >> 7) & 0x1) << 0);
116     }
117 
118     for (j = 0; j < 256; j++)
119     {
120         UnpackPixel[j] =
121             (((j >> 0) & 0x1) << 4) |
122             (((j >> 1) & 0x1) << 0) |
123             (((j >> 2) & 0x1) << 12) |
124             (((j >> 3) & 0x1) << 8) |
125             (((j >> 4) & 0x1) << 20) |
126             (((j >> 5) & 0x1) << 16) |
127             (((j >> 6) & 0x1) << 28) |
128             (((j >> 7) & 0x1) << 24);
129     }
130 }
131 
132 void
get_masks(int x,int w)133 get_masks(int x, int w)
134 {
135     register int tmp;
136 
137     leftMask = rightMask = 0;
138     byteCounter = w;
139     /* right margin */
140     tmp = (x+w) & 7;
141     if (tmp)
142     {
143         byteCounter -= tmp;
144         rightMask = (unsigned char)(0xff00 >> tmp);
145     }
146     /* left margin */
147     tmp = x & 7;
148     if (tmp)
149     {
150         byteCounter -= (8 - tmp);
151         leftMask = (0xff >> tmp);
152     }
153     /* too small ? */
154     if (byteCounter < 0)
155     {
156         leftMask &= rightMask;
157         rightMask = 0;
158         byteCounter = 0;
159     }
160     byteCounter /= 8;
161 }
162 
vgaPutPixel(INT x,INT y,UCHAR c)163 VOID vgaPutPixel(INT x, INT y, UCHAR c)
164 {
165     ULONG offset;
166 
167     offset = xconv[x]+y80[y];
168 
169     WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
170     WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);
171 
172     READ_REGISTER_UCHAR(vidmem + offset);
173     WRITE_REGISTER_UCHAR(vidmem + offset, c);
174 }
175 
vgaPutByte(INT x,INT y,UCHAR c)176 VOID vgaPutByte(INT x, INT y, UCHAR c)
177 {
178     ULONG offset;
179 
180     offset = xconv[x]+y80[y];
181 
182     /* Set the write mode */
183     WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);
184     WRITE_PORT_UCHAR((PUCHAR)GRA_D,0xff);
185 
186     WRITE_REGISTER_UCHAR(vidmem + offset, c);
187 }
188 
vgaGetByte(IN ULONG offset,OUT UCHAR * b,OUT UCHAR * g,OUT UCHAR * r,OUT UCHAR * i)189 VOID vgaGetByte(
190     IN ULONG offset,
191     OUT UCHAR *b,
192     OUT UCHAR *g,
193     OUT UCHAR *r,
194     OUT UCHAR *i)
195 {
196     WRITE_PORT_USHORT((PUSHORT)GRA_I, 0x0304);
197     *i = READ_REGISTER_UCHAR(vidmem + offset);
198     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
199     *r = READ_REGISTER_UCHAR(vidmem + offset);
200     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x01);
201     *g = READ_REGISTER_UCHAR(vidmem + offset);
202     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
203     *b = READ_REGISTER_UCHAR(vidmem + offset);
204 }
205 
vgaGetPixel(IN INT x,IN INT y)206 INT vgaGetPixel(
207     IN INT x,
208     IN INT y)
209 {
210     UCHAR mask, b, g, r, i;
211     ULONG offset;
212 
213     offset = xconv[x] + y80[y];
214     vgaGetByte(offset, &b, &g, &r, &i);
215 
216     mask = maskbit[x];
217     b = b & mask;
218     g = g & mask;
219     r = r & mask;
220     i = i & mask;
221 
222     mask = bit8[x];
223     g = g >> mask;
224     b = b >> mask;
225     r = r >> mask;
226     i = i >> mask;
227 
228     return (b + 2 * g + 4 * r + 8 * i);
229 }
230 
vgaHLine(INT x,INT y,INT len,UCHAR c)231 BOOL vgaHLine(INT x, INT y, INT len, UCHAR c)
232 {
233     ULONG orgx, pre1, midpre1;
234     //ULONG orgpre1;
235     LONG ileftpix, imidpix, irightpix;
236 
237     orgx = x;
238 
239     /*if ( len < 8 )
240     {
241         for (i = x; i < x+len; i++ )
242             vgaPutPixel ( i, y, c );
243 
244         return TRUE;
245     }*/
246 
247     /* Calculate the left mask pixels, middle bytes and right mask pixel */
248     ileftpix = 7 - mod8(x-1);
249     irightpix = mod8(x+len);
250     imidpix = (len-ileftpix-irightpix) / 8;
251 
252     pre1 = xconv[(x-1)&~7] + y80[y];
253     //orgpre1=pre1;
254 
255     /* check for overlap ( very short line ) */
256     if ( (ileftpix+irightpix) > len )
257     {
258         int mask = startmasks[ileftpix] & endmasks[irightpix];
259         /* Write left pixels */
260         WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask
261         WRITE_PORT_UCHAR((PUCHAR)GRA_D,mask);
262 
263         READ_REGISTER_UCHAR(vidmem + pre1);
264         WRITE_REGISTER_UCHAR(vidmem + pre1, c);
265 
266         return TRUE;
267     }
268 
269     /* Left */
270     if ( ileftpix > 0 )
271     {
272         /* Write left pixels */
273         WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask
274         WRITE_PORT_UCHAR((PUCHAR)GRA_D,startmasks[ileftpix]);
275 
276         READ_REGISTER_UCHAR(vidmem + pre1);
277         WRITE_REGISTER_UCHAR(vidmem + pre1, c);
278 
279         /* Prepare new x for the middle */
280         x = orgx + 8;
281     }
282 
283     if ( imidpix > 0 )
284     {
285         midpre1 = xconv[x] + y80[y];
286 
287         /* Set mask to all pixels in byte */
288         WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
289         WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xff);
290         memset(vidmem+midpre1, c, imidpix); // write middle pixels, no need to read in latch because of the width
291     }
292 
293     if ( irightpix > 0 )
294     {
295         x = orgx + len - irightpix;
296         pre1 = xconv[x] + y80[y];
297 
298         /* Write right pixels */
299         WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);     // set the mask bits
300         WRITE_PORT_UCHAR((PUCHAR)GRA_D, endmasks[irightpix]);
301         READ_REGISTER_UCHAR(vidmem + pre1);
302         WRITE_REGISTER_UCHAR(vidmem + pre1, c);
303     }
304 
305     return TRUE;
306 }
307 
vgaVLine(INT x,INT y,INT len,UCHAR c)308 BOOL vgaVLine(INT x, INT y, INT len, UCHAR c)
309 {
310     INT offset, i;
311 
312     offset = xconv[x]+y80[y];
313 
314 #ifdef VGA_PERF
315     vgaSetBitMaskRegister ( maskbit[x] );
316 #else
317     WRITE_PORT_UCHAR((PUCHAR)GRA_I,0x08);       // set the mask
318     WRITE_PORT_UCHAR((PUCHAR)GRA_D,maskbit[x]);
319 #endif
320 
321     for(i=y; i<y+len; i++)
322     {
323         READ_REGISTER_UCHAR(vidmem + offset);
324         WRITE_REGISTER_UCHAR(vidmem + offset, c);
325         offset += 80;
326     }
327 
328     return TRUE;
329 }
330 
331 static const RECTL rclEmpty = { 0, 0, 0, 0 };
332 
VGADDIIntersectRect(PRECTL prcDst,PRECTL prcSrc1,PRECTL prcSrc2)333 BOOL VGADDIIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2)
334 {
335     prcDst->left  = max(prcSrc1->left, prcSrc2->left);
336     prcDst->right = min(prcSrc1->right, prcSrc2->right);
337 
338     if (prcDst->left < prcDst->right)
339     {
340         prcDst->top = max(prcSrc1->top, prcSrc2->top);
341         prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
342 
343        if (prcDst->top < prcDst->bottom)
344            return TRUE;
345     }
346 
347     *prcDst = rclEmpty;
348 
349     return FALSE;
350 }
351 
DIB_BltFromVGA(int x,int y,int w,int h,void * b,int Dest_lDelta)352 void DIB_BltFromVGA(int x, int y, int w, int h, void *b, int Dest_lDelta)
353 {
354     ULONG plane;
355     ULONG left = x >> 3;
356     ULONG shift = x - (x & ~0x7);
357     UCHAR pixel, nextpixel;
358     LONG rightcount;
359     INT i, j;
360     LONG stride = w >> 3;
361 
362     /* Calculate the number of rightmost bytes not in a dword block. */
363     if (w >= 8)
364     {
365         rightcount = w % 8;
366     }
367     else
368     {
369         stride = 0;
370         rightcount = w;
371     }
372     rightcount = (rightcount + 1) / 2;
373 
374     /* Reset the destination. */
375     for (j = 0; j < h; j++)
376         memset((PVOID)((ULONG_PTR)b + (j * Dest_lDelta)), 0, abs(Dest_lDelta));
377 
378     for (plane = 0; plane < 4; plane++)
379     {
380         PUCHAR dest = b;
381 
382         /* Select the plane we are reading in this iteration. */
383         WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);
384         WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);
385 
386         for (j = 0; j < h; j++)
387         {
388             PULONG destline = (PULONG)dest;
389             PUCHAR src = vidmem + (y + j) * SCREEN_STRIDE + left;
390             /* Read the data for one plane for an eight aligned pixel block. */
391             nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src)];
392             for (i = 0; i < stride; i++, src++, destline++)
393             {
394                 /* Form the data for one plane for an aligned block in the destination. */
395                 pixel = nextpixel;
396                 pixel >>= shift;
397 
398                 nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
399                 pixel |= (nextpixel << (8 - shift));
400 
401                 /* Expand the plane data to 'chunky' format and store. */
402                 *destline |= (UnpackPixel[pixel] << plane);
403             }
404             /* Handle any pixels not falling into a full block. */
405             if (rightcount != 0)
406             {
407                 ULONG row;
408 
409                 /* Form the data for a complete block. */
410                 pixel = nextpixel;
411                 pixel >>= shift;
412 
413                 nextpixel = PreCalcReverseByte[READ_REGISTER_UCHAR(src + 1)];
414                 pixel |= (nextpixel << (8 - shift));
415 
416                 row = UnpackPixel[pixel] << plane;
417 
418                 /* Store the data for each byte in the destination. */
419                 for (i = 0; i < rightcount; i++)
420                 {
421                     ((PUCHAR)destline)[i] |= (row & 0xFF);
422                     row >>= 8;
423                 }
424             }
425             dest += Dest_lDelta;
426         }
427     }
428 
429 #ifdef VGA_VERIFY
430     for (j = 0; j < h; j++)
431     {
432         for (i = 0; i < w; i += 2)
433         {
434             UCHAR c1, c2;
435             ULONG mask = (i < (w - 1)) ? 0xFF : 0xF0;
436 
437             c1 = (vgaGetPixel(x + i, y + j) << 4) | (vgaGetPixel(x + i + 1, y + j));
438             c2 = ((PUCHAR)b)[(j * Dest_lDelta) + (i >> 1)];
439             if ((c1 & mask) != (c2 & mask))
440                 EngDebugBreak();
441         }
442     }
443 #endif /* VGA_VERIFY */
444 }
445 
446 /* DIB blt to the VGA. */
DIB_BltToVGA(int x,int y,int w,int h,void * b,int Source_lDelta,int StartMod)447 void DIB_BltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, int StartMod)
448 {
449     PUCHAR pb, opb = b;
450     LONG i, j;
451     LONG x2 = x + w;
452     LONG y2 = y + h;
453     ULONG offset;
454 
455     for (i = x; i < x2; i++)
456     {
457         pb = opb;
458         offset = xconv[i] + y80[y];
459 
460         WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);       // set the mask
461         WRITE_PORT_UCHAR((PUCHAR)GRA_D, maskbit[i]);
462 
463         if (StartMod == ((i - x) % 2))
464         {
465             for (j = y; j < y2; j++)
466             {
467                 READ_REGISTER_UCHAR(vidmem + offset);
468                 WRITE_REGISTER_UCHAR(vidmem + offset, (*pb & 0xf0) >> 4);
469                 offset += 80;
470                 pb += Source_lDelta;
471             }
472         }
473         else
474         {
475             for (j = y; j < y2; j++)
476             {
477                 READ_REGISTER_UCHAR(vidmem + offset);
478                 WRITE_REGISTER_UCHAR(vidmem + offset, *pb & 0x0f);
479                 offset += 80;
480                 pb += Source_lDelta;
481             }
482         }
483 
484         if (StartMod != ((i - x) % 2))
485             opb++;
486     }
487 }
488 
489 
490 /* DIB blt to the VGA. */
DIB_BltToVGAWithXlate(int x,int y,int w,int h,void * b,int Source_lDelta,XLATEOBJ * Xlate)491 void DIB_BltToVGAWithXlate(int x, int y, int w, int h, void *b, int Source_lDelta, XLATEOBJ* Xlate)
492 {
493     PUCHAR pb, opb = b;
494     ULONG i, j;
495     ULONG x2 = x + w;
496     ULONG y2 = y + h;
497     ULONG offset;
498 
499     for (i = x; i < x2; i++)
500     {
501         pb = opb;
502         offset = xconv[i] + y80[y];
503 
504         WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);       // set the mask
505         WRITE_PORT_UCHAR((PUCHAR)GRA_D, maskbit[i]);
506 
507         if (0 == ((i - x) % 2))
508         {
509             for (j = y; j < y2; j++)
510             {
511                 READ_REGISTER_UCHAR(vidmem + offset);
512                 WRITE_REGISTER_UCHAR(vidmem + offset, XLATEOBJ_iXlate(Xlate, (*pb & 0xf0) >> 4));
513                 offset += 80;
514                 pb += Source_lDelta;
515             }
516         }
517         else
518         {
519             for (j = y; j < y2; j++)
520             {
521                 READ_REGISTER_UCHAR(vidmem + offset);
522                 WRITE_REGISTER_UCHAR(vidmem + offset, XLATEOBJ_iXlate(Xlate, *pb & 0x0f));
523                 offset += 80;
524                 pb += Source_lDelta;
525             }
526         }
527 
528         if (0 != ((i - x) % 2))
529             opb++;
530     }
531 }
532 
533 /* DIB blt to the VGA.
534  * For now we just do slow writes -- pixel by pixel,
535  * packing each one into the correct 4BPP format. */
DIB_TransparentBltToVGA(int x,int y,int w,int h,void * b,int Source_lDelta,ULONG trans)536 void DIB_TransparentBltToVGA(int x, int y, int w, int h, void *b, int Source_lDelta, ULONG trans)
537 
538 {
539     PUCHAR pb = b, opb = b;
540     BOOLEAN edgePixel = FALSE;
541     ULONG i, j;
542     ULONG x2 = x + w;
543     ULONG y2 = y + h;
544     UCHAR b1, b2;
545 
546     /* Check if the width is odd */
547     if(mod2(w) > 0)
548     {
549         edgePixel = TRUE;
550         x2 -= 1;
551     }
552 
553     for (j=y; j<y2; j++)
554     {
555         for (i=x; i<x2; i+=2)
556         {
557             b1 = (*pb & 0xf0) >> 4;
558             b2 = *pb & 0x0f;
559             if(b1 != trans) vgaPutPixel(i,   j, b1);
560             if(b2 != trans) vgaPutPixel(i+1, j, b2);
561             pb++;
562         }
563 
564         if (edgePixel)
565         {
566             b1 = *pb;
567             if(b1 != trans) vgaPutPixel(x2, j, b1);
568             pb++;
569         }
570 
571         opb += Source_lDelta;
572         pb = opb; // new test code
573     }
574 }
575 
576 // This algorithm goes from left to right, storing each 4BPP pixel
577 // in an entire byte.
578 void FASTCALL
vgaReadScan(int x,int y,int w,void * b)579 vgaReadScan( int x, int y, int w, void *b )
580 {
581     unsigned char *vp, *vpP;
582     unsigned char data, mask, maskP;
583     unsigned char *bp;
584     unsigned char plane_mask;
585     int plane, i;
586 
587     ASSIGNVP4(x, y, vpP)
588     ASSIGNMK4(x, y, maskP)
589     get_masks(x, w);
590     WRITE_PORT_USHORT((PUSHORT)GRA_I, 0x0005);  // read mode 0
591     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);  // read map select
592 
593     memset ( b, 0, w );
594 
595     for ( plane=0, plane_mask=1; plane < 4; plane++, plane_mask<<=1 )
596     {
597         WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);  // read map select
598 
599         vp = vpP;
600         bp = b;
601         if ( leftMask )
602         {
603             mask = maskP;
604             data = *vp++;
605             do
606             {
607                 if (data & mask)
608                     *bp |= plane_mask;
609                 bp++;
610                 mask >>= 1;
611             } while (mask & leftMask);
612         }
613         if (byteCounter)
614         {
615             for (i=byteCounter; i>0; i--)
616             {
617                 data = *vp++;
618                 if (data & 0x80) *bp |= plane_mask;
619                 bp++;
620 
621                 if (data & 0x40) *bp |= plane_mask;
622                 bp++;
623                 if (data & 0x20) *bp |= plane_mask;
624                 bp++;
625                 if (data & 0x10) *bp |= plane_mask;
626                 bp++;
627                 if (data & 0x08) *bp |= plane_mask;
628                 bp++;
629                 if (data & 0x04) *bp |= plane_mask;
630                 bp++;
631                 if (data & 0x02) *bp |= plane_mask;
632                 bp++;
633                 if (data & 0x01) *bp |= plane_mask;
634                 bp++;
635             }
636         }
637         if (rightMask)
638         {
639             mask = 0x80;
640             data = *vp;
641             do
642             {
643                 if (data & mask)
644                 *bp |= plane_mask;
645                 bp++;
646                 mask >>= 1;
647             } while (mask & rightMask);
648         }
649     }
650 }
651 
652 /* This algorithm goes from left to right
653  * It stores each 4BPP pixel in an entire byte. */
654 void FASTCALL
vgaWriteScan(int x,int y,int w,void * b)655 vgaWriteScan ( int x, int y, int w, void *b )
656 {
657     unsigned char *bp;
658     unsigned char *vp;
659     //unsigned char init_mask;
660     volatile unsigned char dummy;
661     //int byte_per_line;
662     int i, j, off, init_off = x&7;
663 
664     bp = b;
665     ASSIGNVP4(x, y, vp)
666     //ASSIGNMK4(x, y, init_mask)
667     //byte_per_line = SCREEN_X >> 3;
668 
669     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
670     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
671     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
672     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
673     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
674 
675     for ( j = 0; j < 8; j++)
676     {
677         unsigned int mask = 0x80 >> j;
678         WRITE_PORT_UCHAR ( (PUCHAR)GRA_D, (unsigned char)mask );
679         i = j - init_off;
680         off = 0;
681         if (j < init_off)
682             i += 8, off++;
683         while (i < w)
684         {
685             /*
686              * In write mode 2, the incoming data is 4-bit and represents the
687              * value of entire bytes on each of the 4 memory planes. First, VGA
688              * performs a logical operation on these bytes and the value of the
689              * latch register, but in this case there is none. Then, only the
690              * bits that are set in the bit mask are used from the resulting
691              * bytes, and the other bits are taken from the latch register.
692              *
693              * The latch register always contains the value previously read from
694              * VGA memory, and therefore, we must first read from vp[off] to
695              * load the latch register, and then write bp[i] to vp[off], which
696              * will be converted to 4 bytes of VGA memory as described.
697              */
698             dummy = vp[off];
699             dummy = bp[i];
700             vp[off] = dummy;
701             i += 8;
702             off++;
703         }
704     }
705 }
706 
707 /* This algorithm goes from left to right, and inside that loop, top to bottom.
708  * It also stores each 4BPP pixel in an entire byte. */
DFB_BltFromVGA(int x,int y,int w,int h,void * b,int bw)709 void DFB_BltFromVGA(int x, int y, int w, int h, void *b, int bw)
710 {
711     unsigned char *vp, *vpY, *vpP;
712     unsigned char data, mask, maskP;
713     unsigned char *bp, *bpY;
714     unsigned char plane_mask;
715     int byte_per_line = SCREEN_X >> 3;
716     int plane, i, j;
717 
718     ASSIGNVP4(x, y, vpP)
719     ASSIGNMK4(x, y, maskP)
720     get_masks(x, w);
721     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);  // read mode 0
722     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
723     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x04);  // read map select
724 
725     /* clear buffer */
726     bp = b;
727     for (j = h; j > 0; j--)
728     {
729         memset(bp, 0, w);
730         bp += bw;
731     }
732 
733     for (plane = 0, plane_mask = 1; plane < 4; plane++, plane_mask <<= 1)
734     {
735         WRITE_PORT_UCHAR((PUCHAR)GRA_D, plane);  // read map select
736         vpY = vpP;
737         bpY = b;
738         for (j = h; j > 0; j--)
739         {
740             vp = vpY;
741             bp = bpY;
742             if (leftMask)
743             {
744                 mask = maskP;
745                 data = *vp++;
746                 do
747                 {
748                     if (data & mask)
749                         *bp |= plane_mask;
750                     bp++;
751                     mask >>= 1;
752                 } while (mask & leftMask);
753             }
754             if (byteCounter)
755             {
756                 for (i=byteCounter; i>0; i--)
757                 {
758                     data = *vp++;
759                     if (data & 0x80) *bp |= plane_mask;
760                     bp++;
761                     if (data & 0x40) *bp |= plane_mask;
762                     bp++;
763                     if (data & 0x20) *bp |= plane_mask;
764                     bp++;
765                     if (data & 0x10) *bp |= plane_mask;
766                     bp++;
767                     if (data & 0x08) *bp |= plane_mask;
768                     bp++;
769                     if (data & 0x04) *bp |= plane_mask;
770                     bp++;
771                     if (data & 0x02) *bp |= plane_mask;
772                     bp++;
773                     if (data & 0x01) *bp |= plane_mask;
774                     bp++;
775                 }
776             }
777             if (rightMask)
778             {
779                 mask = 0x80;
780                 data = *vp;
781                 do
782                 {
783                     if (data & mask) *bp |= plane_mask;
784                     bp++;
785                     mask >>= 1;
786                 } while (mask & rightMask);
787             }
788             bpY += bw;
789             vpY += byte_per_line;
790         }
791     }
792 
793     // We don't need this if the next call is a DFB blt to VGA (as in the case of moving the mouse pointer)
794     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
795     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
796     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
797     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
798 }
799 
800 /* This algorithm goes from left to right, and inside that loop, top to bottom.
801  * It also stores each 4BPP pixel in an entire byte. */
DFB_BltToVGA(int x,int y,int w,int h,void * b,int bw)802 void DFB_BltToVGA(int x, int y, int w, int h, void *b, int bw)
803 {
804     unsigned char *bp, *bpX;
805     unsigned char *vp, *vpX;
806     unsigned char mask;
807     //volatile unsigned char dummy;
808     int byte_per_line;
809     int i, j;
810 
811     bpX = b;
812     ASSIGNVP4(x, y, vpX)
813     ASSIGNMK4(x, y, mask)
814     byte_per_line = SCREEN_X >> 3;
815 
816     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
817     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
818     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
819     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
820     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
821 
822     for (i=w; i>0; i--)
823     {
824         WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
825         bp = bpX;
826         vp = vpX;
827         for (j = h; j > 0; j--)
828         {
829             //dummy = *vp;
830             *vp = *bp;
831             bp += bw;
832             vp += byte_per_line;
833         }
834         bpX++;
835         if ((mask >>= 1) == 0)
836         {
837             vpX++;
838             mask = 0x80;
839         }
840     }
841 }
842 
843 /* This algorithm goes from goes from left to right, and inside that loop, top to bottom.
844  * It also stores each 4BPP pixel in an entire byte. */
DFB_BltToVGA_Transparent(int x,int y,int w,int h,void * b,int bw,char Trans)845 void DFB_BltToVGA_Transparent(int x, int y, int w, int h, void *b, int bw, char Trans)
846 {
847     unsigned char *bp, *bpX;
848     unsigned char *vp, *vpX;
849     unsigned char mask;
850     //volatile unsigned char dummy;
851     int byte_per_line;
852     int i, j;
853 
854     bpX = b;
855     ASSIGNVP4(x, y, vpX)
856     ASSIGNMK4(x, y, mask)
857     byte_per_line = SCREEN_X >> 3;
858 
859     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);      // write mode 2
860     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
861     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);      // replace
862     WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
863     WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);      // bit mask
864 
865     for (i=w; i>0; i--)
866     {
867         WRITE_PORT_UCHAR((PUCHAR)GRA_D, mask);
868         bp = bpX;
869         vp = vpX;
870         for (j=h; j>0; j--)
871         {
872             if (*bp != Trans)
873             {
874                 //dummy = *vp;
875                 *vp = *bp;
876             }
877             bp += bw;
878             vp += byte_per_line;
879         }
880         bpX++;
881         if ((mask >>= 1) == 0)
882         {
883             vpX++;
884             mask = 0x80;
885         }
886     }
887 }
888 
889 /* This algorithm converts a DFB into a DIB
890  * WARNING: This algorithm is buggy */
DFB_BltToDIB(int x,int y,int w,int h,void * b,int bw,void * bdib,int dibw)891 void DFB_BltToDIB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
892 {
893     unsigned char *bp, *bpX, *dib, *dibTmp;
894     int i, j, dib_shift;
895 
896     bpX = b;
897     dib = (unsigned char *)bdib + y * dibw + (x / 2);
898 
899     for (i=w; i>0; i--)
900     {
901         /* determine the bit shift for the DIB pixel */
902         dib_shift = mod2(w-i);
903         if(dib_shift > 0)
904             dib_shift = 4;
905         dibTmp = dib;
906 
907         bp = bpX;
908         for (j = h; j > 0; j--)
909         {
910             *dibTmp = *bp << dib_shift | *(bp + 1);
911             dibTmp += dibw;
912             bp += bw;
913         }
914         bpX++;
915         if(dib_shift == 0)
916             dib++;
917     }
918 }
919 
920 /* This algorithm converts a DIB into a DFB */
DIB_BltToDFB(int x,int y,int w,int h,void * b,int bw,void * bdib,int dibw)921 void DIB_BltToDFB(int x, int y, int w, int h, void *b, int bw, void *bdib, int dibw)
922 {
923     unsigned char *bp, *bpX, *dib, *dibTmp;
924     int i, j, dib_shift, dib_and;
925 
926     bpX = b;
927     dib = (unsigned char *)bdib + y * dibw + (x / 2);
928 
929     for (i=w; i>0; i--)
930     {
931         /* determine the bit shift for the DIB pixel */
932         dib_shift = mod2(w-i);
933         if(dib_shift > 0)
934         {
935             dib_shift = 0;
936             dib_and = 0x0f;
937         }
938         else
939         {
940             dib_shift = 4;
941             dib_and = 0xf0;
942         }
943 
944         dibTmp = dib;
945         bp = bpX;
946 
947         for (j=h; j>0; j--)
948         {
949             *bp = (*dibTmp & dib_and) >> dib_shift;
950             dibTmp += dibw;
951             bp += bw;
952         }
953 
954         bpX++;
955         if (dib_shift == 0)
956             dib++;
957     }
958 }
959