1 /*
2  * $XFree86: mit/server/ddx/x386/vga256/drivers/cirrus/cir_im.c,v 2.2 1993/10/02 16:09:18 dawes Exp $
3  *
4  * Copyright 1993 by Bill Reynolds, Santa Fe, New Mexico
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Bill Reynolds not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Bill Reynolds makes no representations
13  * about the suitability of this software for any purpose.  It is provided
14  * "as is" without express or implied warranty.
15  *
16  * BILL REYNOLDS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL BILL REYNOLDS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Author:  Bill Reynolds, bill@goshawk.lanl.gov
25  *
26  * Reworked by: Simon P. Cooper, <scooper@vizlab.rutgers.edu>
27  *
28  * Id: cir_im.c,v 0.7 1993/09/16 01:07:25 scooper Exp
29  */
30 
31 #include "misc.h"
32 #include "x386.h"
33 #include "X.h"
34 #include "Xos.h"
35 #include "Xmd.h"
36 #include "Xproto.h"
37 #include "gcstruct.h"
38 #include "windowstr.h"
39 #include "scrnintstr.h"
40 #include "pixmapstr.h"
41 #include "regionstr.h"
42 #include "cfb.h"
43 #include "cfbmskbits.h"
44 #include "cfb8bit.h"
45 
46 #include "mergerop.h"
47 #include "vgaBank.h"
48 #include "compiler.h"
49 #include "os.h"		/* For FatalError */
50 
51 #include "cir_driver.h"
52 
53 extern pointer vgaBase;
54 
55 #define BLITADDRESS (vgaBase+4)
56 
57 extern void vgaImageWrite ();
58 extern void vgaImageRead ();
59 extern void SpeedUpBitBlt ();
60 
CirrusBltLine(dstAddr,srcAddr,dstPitch,srcPitch,w,h,dir)61 CirrusBltLine (dstAddr, srcAddr, dstPitch, srcPitch, w, h, dir)
62      unsigned int dstAddr, srcAddr;
63      unsigned int dstPitch, srcPitch;
64      unsigned int w, h;
65      int dir;			/* >0, increase adrresses, <0, decrease */
66 {
67   volatile unsigned char tmpreg;
68 
69   /* Set the SrcAddress */
70 
71   outw (0x3CE, ((srcAddr & 0x000000FF) << 8) | 0x2C);
72   outw (0x3CE, ((srcAddr & 0x0000FF00)) | 0x2D);
73   outw (0x3CE, ((srcAddr & 0x001F0000) >> 8) | 0x2E);
74 
75   /* Set the Src Pitch */
76 
77   outw (0x3CE, ((srcPitch & 0x000000FF) << 8) | 0x26);
78   outw (0x3CE, ((srcPitch & 0x00000F00)) | 0x27);
79 
80   /* Set the DstAddress */
81 
82   outw (0x3CE, ((dstAddr & 0x000000FF) << 8) | 0x28);
83   outw (0x3CE, ((dstAddr & 0x0000FF00)) | 0x29);
84   outw (0x3CE, ((dstAddr & 0x001F0000) >> 8) | 0x2A);
85 
86   /* Set the Dest Pitch */
87 
88   outw (0x3CE, ((dstPitch & 0x000000FF) << 8) | 0x24);
89   outw (0x3CE, ((dstPitch & 0x00000F00)) | 0x25);
90 
91   /* Set the Width */
92 
93   w--;
94   outw (0x3CE, ((w & 0x000000FF) << 8) | 0x20);
95   outw (0x3CE, ((w & 0x00000700)) | 0x21);
96 
97   /* Set the Height */
98 
99   h--;
100   outw (0x3CE, ((h & 0x000000FF) << 8) | 0x22);
101   outw (0x3CE, ((h & 0x00000300)) | 0x23);
102 
103   /* Set the direction */
104   if (dir > 0)
105     {
106       outw (0x3CE, (0x00 << 8) | 0x30);
107     }
108   else
109     {
110       outw (0x3CE, (0x01 << 8) | 0x30);
111     }
112 
113   /* Set the ROP: Copy = 0x0D */
114   outw (0x3CE, (CROP_SRC << 8) | 0x32);
115 
116   /* Ok, we're all loaded up, let's do it */
117   outw (0x3CE, (0x02 << 8) | 0x31);
118 
119   do
120     {
121       outb (0x3CE, 0x31);
122       tmpreg = inb (0x3CF);
123     }
124   while (tmpreg & 0x01);
125 
126 }
127 
128 void
CirrusBitBlt(pdstBase,psrcBase,widthSrc,widthDst,x,y,x1,y1,w,h,xdir,ydir,alu,planemask)129 CirrusBitBlt (pdstBase, psrcBase, widthSrc, widthDst, x, y,
130 	      x1, y1, w, h, xdir, ydir, alu, planemask)
131      pointer pdstBase, psrcBase;	/* start of src bitmap */
132      int widthSrc, widthDst;
133      int x, y, x1, y1, w, h;	/* Src x,y; Dst x1,y1; Dst (w)idth,(h)eight */
134      int xdir, ydir;
135      int alu;
136      unsigned long planemask;
137 {
138   unsigned int psrc, pdst, ppdst;
139   int i;
140 
141   if (widthSrc < 0)
142     widthSrc *= -1;
143   if (widthDst < 0)
144     widthDst *= -1;
145 
146   if (alu == GXcopy && (planemask & 0xFF) == 0xFF)
147     {
148       if (xdir == 1)		/* left to right */
149 	{
150 	  if (ydir == 1)	/* top to bottom */
151 	    {
152 	      psrc = (y * widthSrc) + x;
153 	      pdst = (y1 * widthDst) + x1;
154 	    }
155 	  else
156 	    /* bottom to top */
157 	    {
158 	      psrc = ((y + h - 1) * widthSrc) + x;
159 	      pdst = ((y1 + h - 1) * widthDst) + x1;
160 	    }
161 	}
162       else
163 	/* right to left */
164 	{
165 	  if (ydir == 1)	/* top to bottom */
166 	    {
167 	      psrc = (y * widthSrc) + x + w - 1;
168 	      pdst = (y1 * widthDst) + x1 + w - 1;
169 	    }
170 	  else
171 	    /* bottom to top */
172 	    {
173 	      psrc = ((y + h - 1) * widthSrc) + x + w - 1;
174 	      pdst = ((y1 + h - 1) * widthDst) + x1 + w - 1;
175 	    }
176 	}
177 
178       /* I could probably do the line by line */
179       /* blits a little faster by breaking the */
180       /* blit regions into rectangles */
181       /* and blitting those, making sure I don't */
182       /* overwrite stuff. However, the */
183       /* difference between the line by line */
184       /* and block blits isn't noticable to */
185       /* me, so I think I'll blow it off. */
186 
187       if (xdir == 1)
188 	{
189 	  if (ydir == 1)
190 	    {			/* Nothing special, straight blit */
191 	      CirrusBltLine (pdst, psrc, widthDst, widthSrc, w, h, 1);
192 	    }
193 	  else
194 	    /* Line by line, going up. */
195 	    {
196 	      for (i = 0; i < h; i++)
197 		{
198 		  CirrusBltLine (pdst, psrc, widthDst, widthSrc, w, 1, 1);
199 		  psrc -= widthSrc;
200 		  pdst -= widthDst;
201 		}
202 	    }
203 	}
204       else
205 	{
206 
207 	  if (ydir == 1)	/* Line by line, going down and to the left */
208 	    {
209 	      for (i = 0; i < h; i++)
210 		{
211 		  CirrusBltLine (pdst, psrc, widthDst, widthSrc, w, 1, -1);
212 		  psrc += widthSrc;
213 		  pdst += widthDst;
214 		}
215 	    }
216 	  else
217 	    /* Another stock blit, albeit backwards */
218 	    {
219 	      CirrusBltLine (pdst, psrc, widthDst, widthSrc, w, h, -1);
220 	    }
221 	}
222     }
223 }
224 
225 void
CirrusImageWrite(pdstBase,psrcBase,widthSrc,widthDst,x,y,x1,y1,w,h,xdir,ydir,alu,planemask)226 CirrusImageWrite (pdstBase, psrcBase, widthSrc, widthDst, x, y,
227 		  x1, y1, w, h, xdir, ydir, alu, planemask)
228      pointer pdstBase, psrcBase;	/* start of src bitmap */
229      int widthSrc, widthDst;
230      int x, y, x1, y1, w, h;	/* Src x,y; Dst x1,y1; Dst (w)idth,(h)eight */
231      int xdir, ydir;
232      int alu;
233      unsigned long planemask;
234 {
235   unsigned long *plSrc;
236   volatile unsigned char status;
237   volatile unsigned long *pDst;
238   pointer psrc;
239   unsigned int dstAddr;
240   unsigned int word_count, word_rem;
241   int i, j;
242 
243   if (alu == GXcopy && (planemask & 0xFF) == 0xFF)
244     {
245       int width, height;
246 
247       psrc = psrcBase + (y * widthSrc) + x;
248       dstAddr = (y1 * widthDst) + x1;
249 
250       /* Set the DstAddress */
251 
252       outw (0x3CE, ((dstAddr & 0x000000FF) << 8) | 0x28);
253       outw (0x3CE, ((dstAddr & 0x0000FF00)) | 0x29);
254       outw (0x3CE, ((dstAddr & 0x001F0000) >> 8) | 0x2A);
255 
256       /* Set the Dest Pitch */
257 
258       outw (0x3CE, ((widthDst & 0x000000FF) << 8) | 0x24);
259       outw (0x3CE, ((widthDst & 0x00000F00)) | 0x25);
260 
261       /* Set the Width */
262 
263       width = w - 1;
264       outw (0x3CE, ((width & 0x000000FF) << 8) | 0x20);
265       outw (0x3CE, ((width & 0x00000700)) | 0x21);
266 
267       /* Set the Height */
268 
269       height = h - 1;
270       outw (0x3CE, ((height & 0x000000FF) << 8) | 0x22);
271       outw (0x3CE, ((height & 0x00000300)) | 0x23);
272 
273       /* Set the direction and source (System Memory) */
274 
275       outw (0x3CE, (0x04 << 8) | 0x30);
276 
277       /* Set the ROP: Copy = 0x0D */
278       outw (0x3CE, (0x0D << 8) | 0x32);
279 
280       /* Lets play DMA controller ... */
281       outw (0x3CE, (0x02 << 8) | 0x31);
282 
283       /*
284        * We must transfer 4 bytes per blit line.  This is cautious code and I
285        * do not read from outside of the pixmap... The 386/486 allows
286        * unaligned memory acceses, and has little endian word ordering.  This
287        * is used to our advantage when dealing with the 3 byte remainder.
288        * Don't try this on your Sparc :-)
289        */
290 
291       pDst = (unsigned long *) BLITADDRESS;
292 
293       word_count = w >> 2;
294       word_rem = w & 0x3;
295 
296       switch (word_rem)
297 	{
298 
299 	case 0:
300 	  for (i = 0; i < h; i++)
301 	    {
302 	      plSrc = (unsigned long *) psrc;
303 	      for (j = 0; j < word_count; j++)
304 		*pDst = *plSrc++;
305 	      psrc += widthSrc;
306 	    }
307 	  break;
308 
309 	case 1:		/* One byte extra */
310 	  for (i = 0; i < h; i++)
311 	    {
312 	      plSrc = (unsigned long *) psrc;
313 	      for (j = 0; j < word_count; j++)
314 		*pDst = *plSrc++;
315 
316 	      *pDst = (unsigned long) (*(unsigned char *) plSrc);
317 
318 	      psrc += widthSrc;
319 	    }
320 	  break;
321 
322 	case 2:		/* Two bytes extra */
323 	  for (i = 0; i < h; i++)
324 	    {
325 	      plSrc = (unsigned long *) psrc;
326 	      for (j = 0; j < word_count; j++)
327 		*pDst = *plSrc++;
328 
329 	      *pDst = (unsigned long) (*(unsigned short *) plSrc);
330 
331 	      psrc += widthSrc;
332 	    }
333 	  break;
334 
335 	case 3:
336 
337 	  for (i = 0; i < h; i++)
338 	    {
339 	      plSrc = (unsigned long *) psrc;
340 	      for (j = 0; j < word_count; j++)
341 		*pDst = *plSrc++;
342 
343 	      (*(unsigned char **)&plSrc)--;
344 	      *pDst = (*plSrc) >> 8;
345 
346 	      psrc += widthSrc;
347 	    }
348 	  break;
349 
350 	}
351 
352       do
353 	{
354 	  outb (0x3CE, 0x31);
355 	  status = inb (0x3CF);
356 	}
357       while (status & 0x01);
358     }
359   else
360     {
361       vgaImageWrite(pdstBase, psrcBase, widthSrc, widthDst, x, y,
362 		    x1, y1, w, h, xdir, ydir, alu, planemask);
363     }
364 
365 }
366 
367 
368 void
CirrusImageRead(pdstBase,psrcBase,widthSrc,widthDst,x,y,x1,y1,w,h,xdir,ydir,alu,planemask)369 CirrusImageRead (pdstBase, psrcBase, widthSrc, widthDst, x, y,
370 		 x1, y1, w, h, xdir, ydir, alu, planemask)
371      pointer pdstBase, psrcBase;	/* start of src bitmap */
372      int widthSrc, widthDst;
373      int x, y, x1, y1, w, h;	/* Src x,y; Dst x1,y1; Dst (w)idth,(h)eight */
374      int xdir, ydir;
375      int alu;
376      unsigned long planemask;
377 {
378   unsigned long *plDst;
379   volatile unsigned char status;
380   volatile unsigned long *pSrc;
381   pointer pdst;
382   unsigned int srcAddr;
383   unsigned int word_count, word_rem;
384   int i, j;
385 
386   if (alu == GXcopy && (planemask & 0xFF) == 0xFF)
387     {
388       int width, height;
389 
390       pdst = pdstBase + (y1 * widthDst) + x1;
391       srcAddr = (y * widthSrc) + x;
392 
393       /* Set the SrcAddress */
394 
395       outw (0x3CE, ((srcAddr & 0x000000FF) << 8) | 0x2C);
396       outw (0x3CE, ((srcAddr & 0x0000FF00)) | 0x2D);
397       outw (0x3CE, ((srcAddr & 0x001F0000) >> 8) | 0x2E);
398 
399       /* Set the Src Pitch */
400 
401       outw (0x3CE, ((widthSrc & 0x000000FF) << 8) | 0x26);
402       outw (0x3CE, ((widthSrc & 0x00000F00)) | 0x27);
403 
404       /* Set the Width */
405 
406       width = w - 1;
407       outw (0x3CE, ((width & 0x000000FF) << 8) | 0x20);
408       outw (0x3CE, ((width & 0x00000700)) | 0x21);
409 
410       /* Set the Height */
411 
412       height = h - 1;
413       outw (0x3CE, ((height & 0x000000FF) << 8) | 0x22);
414       outw (0x3CE, ((height & 0x00000300)) | 0x23);
415 
416       /* Set the direction and destination (System Memory) */
417 
418       outw (0x3CE, (0x02 << 8) | 0x30);
419 
420       /* Set the ROP: Copy = 0x0D */
421       outw (0x3CE, (0x0D << 8) | 0x32);
422 
423       /* Lets play DMA controller ... */
424       outw (0x3CE, (0x02 << 8) | 0x31);
425 
426       /*
427        * We must transfer 4 bytes per blit line.  This is cautious code and I
428        * do not read from outside of the pixmap... The 386/486 allows
429        * unaligned memory acceses, and has little endian word ordering.  This
430        * is used to our advantage when dealing with the 3 byte remainder.
431        * Don't try this on your Sparc :-)
432        */
433 
434       pSrc = (unsigned long *) BLITADDRESS;
435 
436       word_count = w >> 2;
437       word_rem = w & 0x3;
438 
439       switch (word_rem)
440 	{
441 
442 	case 0:
443 	  for (i = 0; i < h; i++)
444 	    {
445 	      plDst = (unsigned long *) pdst;
446 	      for (j = 0; j < word_count; j++)
447 		*plDst++ = *pSrc;
448 	      pdst += widthDst;
449 	    }
450 	  break;
451 
452 	case 1:		/* One byte extra */
453 	  for (i = 0; i < h; i++)
454 	    {
455 	      plDst = (unsigned long *) pdst;
456 	      for (j = 0; j < word_count; j++)
457 		*plDst++ = *pSrc;
458 
459 	      *(unsigned char *)plDst = (unsigned char) *pSrc;
460 
461 	      pdst += widthDst;
462 	    }
463 	  break;
464 
465 	case 2:		/* Two bytes extra */
466 	  for (i = 0; i < h; i++)
467 	    {
468 	      plDst = (unsigned long *) pdst;
469 	      for (j = 0; j < word_count; j++)
470 		*plDst++ = *pSrc;
471 
472 	      *(unsigned short *)plDst = (unsigned short) *pSrc;
473 
474 	      pdst += widthDst;
475 	    }
476 	  break;
477 
478 	case 3:
479 
480 	  for (i = 0; i < h; i++)
481 	    { unsigned long tpix;
482 
483 	      plDst = (unsigned long *) pdst;
484 	      for (j = 0; j < word_count; j++)
485 		*plDst++ = *pSrc;
486 
487 	      tpix = *pSrc;
488 
489 	      *(*(unsigned short **)&plDst)++ = (unsigned short) tpix;
490 	      *(unsigned char  *)plDst = (unsigned char)(tpix >>16);
491 
492 	      pdst += widthDst;
493 	    }
494 	  break;
495 
496 	}
497 
498       do
499 	{
500 	  outb (0x3CE, 0x31);
501 	  status = inb (0x3CF);
502 	}
503       while (status & 0x01);
504     }
505   else
506     {
507       vgaImageRead(pdstBase, psrcBase, widthSrc, widthDst, x, y,
508 		   x1, y1, w, h, xdir, ydir, alu, planemask);
509     }
510 }
511