sis: ifdef out unused variable.
[mesa.git] / src / mesa / drivers / dos / vesa.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 4.1
4 *
5 * Copyright (C) 1999 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * DOS/DJGPP device driver for Mesa
27 *
28 * Author: Daniel Borca
29 * Email : dborca@users.sourceforge.net
30 * Web : http://www.geocities.com/dborca
31 */
32
33
34 #include <dpmi.h>
35 #include <pc.h>
36 #include <stdlib.h>
37 #include <stubinfo.h>
38 #include <sys/exceptn.h>
39 #include <sys/segments.h>
40 #include <sys/farptr.h>
41 #include <sys/movedata.h>
42
43 #include "video.h"
44 #include "vesa.h"
45
46
47 static vl_mode modes[128];
48
49 static word16 vesa_ver;
50 static int banked_selector, linear_selector;
51 static int oldmode = -1;
52
53 static int vesa_color_precision = 6;
54
55 static word16 *vesa_pmcode;
56 unsigned int vesa_gran_mask, vesa_gran_shift;
57
58
59 /*
60 * VESA info
61 */
62 #define V_SIGN 0
63 #define V_MINOR 4
64 #define V_MAJOR 5
65 #define V_OEM_OFS 6
66 #define V_OEM_SEG 8
67 #define V_MODE_OFS 14
68 #define V_MODE_SEG 16
69 #define V_MEMORY 18
70
71 /*
72 * mode info
73 */
74 #define M_ATTR 0
75 #define M_GRAN 4
76 #define M_SCANLEN 16
77 #define M_XRES 18
78 #define M_YRES 20
79 #define M_BPP 25
80 #define M_RED 31
81 #define M_GREEN 33
82 #define M_BLUE 35
83 #define M_PHYS_PTR 40
84
85 /*
86 * VESA 3.0 CRTC timings structure
87 */
88 typedef struct CRTCInfoBlock {
89 unsigned short HorizontalTotal;
90 unsigned short HorizontalSyncStart;
91 unsigned short HorizontalSyncEnd;
92 unsigned short VerticalTotal;
93 unsigned short VerticalSyncStart;
94 unsigned short VerticalSyncEnd;
95 unsigned char Flags;
96 unsigned long PixelClock; /* units of Hz */
97 unsigned short RefreshRate; /* units of 0.01 Hz */
98 unsigned char reserved[40];
99 } __PACKED__ CRTCInfoBlock;
100
101 #define HNEG (1 << 2)
102 #define VNEG (1 << 3)
103 #define DOUBLESCAN (1 << 0)
104
105
106 /* Desc: Attempts to detect VESA, check video modes and create selectors.
107 *
108 * In : -
109 * Out : mode array
110 *
111 * Note: -
112 */
113 static vl_mode *
114 vesa_init (void)
115 {
116 __dpmi_regs r;
117 word16 *p;
118 vl_mode *q;
119 char vesa_info[512], tmp[512];
120 int maxsize = 0;
121 word32 linearfb = 0;
122
123 if (vesa_ver) {
124 return modes;
125 }
126
127 _farpokel(_stubinfo->ds_selector, 0, 0x32454256);
128 r.x.ax = 0x4f00;
129 r.x.di = 0;
130 r.x.es = _stubinfo->ds_segment;
131 __dpmi_int(0x10, &r);
132 movedata(_stubinfo->ds_selector, 0, _my_ds(), (unsigned)vesa_info, 512);
133 if ((r.x.ax != 0x004f) || ((_32_ vesa_info[V_SIGN]) != 0x41534556)) {
134 return NULL;
135 }
136
137 p = (word16 *)(((_16_ vesa_info[V_MODE_SEG]) << 4) + (_16_ vesa_info[V_MODE_OFS]));
138 q = modes;
139 do {
140 if ((q->mode = _farpeekw(__djgpp_dos_sel, (unsigned long)(p++))) == 0xffff) {
141 break;
142 }
143
144 r.x.ax = 0x4f01;
145 r.x.cx = q->mode;
146 r.x.di = 512;
147 r.x.es = _stubinfo->ds_segment;
148 __dpmi_int(0x10, &r);
149 movedata(_stubinfo->ds_selector, 512, _my_ds(), (unsigned)tmp, 256);
150 switch (tmp[M_BPP]) {
151 case 16:
152 q->bpp = tmp[M_RED] + tmp[M_GREEN] + tmp[M_BLUE];
153 break;
154 case 8:
155 case 15:
156 case 24:
157 case 32:
158 q->bpp = tmp[M_BPP];
159 break;
160 default:
161 q->bpp = 0;
162 }
163 if ((r.x.ax == 0x004f) && ((tmp[M_ATTR] & 0x11) == 0x11) && q->bpp) {
164 q->xres = _16_ tmp[M_XRES];
165 q->yres = _16_ tmp[M_YRES];
166 q->scanlen = _16_ tmp[M_SCANLEN];
167 q->gran = (_16_ tmp[M_GRAN]) << 10;
168 if (tmp[M_ATTR] & 0x80) {
169 vl_mode *q1 = q + 1;
170 *q1 = *q++;
171 linearfb = _32_ tmp[M_PHYS_PTR];
172 q->mode |= 0x4000;
173 }
174 if (maxsize < (q->scanlen * q->yres)) {
175 maxsize = q->scanlen * q->yres;
176 }
177 q++;
178 }
179 } while (TRUE);
180
181 if (q == modes) {
182 return NULL;
183 }
184 if (_create_selector(&banked_selector, 0xa0000, modes[0].gran)) {
185 return NULL;
186 }
187 if (linearfb) {
188 maxsize = ((maxsize + 0xfffUL) & ~0xfffUL);
189 if (_create_selector(&linear_selector, linearfb, maxsize)) {
190 linear_selector = banked_selector;
191 }
192 }
193
194 for (q = modes; q->mode != 0xffff; q++) {
195 q->sel = banked_selector;
196 if (q->mode & 0x4000) {
197 if (linear_selector != banked_selector) {
198 q->sel = linear_selector;
199 } else {
200 q->mode &= ~0x4000;
201 }
202 }
203 }
204
205 if (vesa_info[V_MAJOR] >= 2) {
206 r.x.ax = 0x4f0a;
207 r.x.bx = 0;
208 __dpmi_int(0x10, &r);
209 if (r.x.ax == 0x004f) {
210 vesa_pmcode = (word16 *)malloc(r.x.cx);
211 if (vesa_pmcode != NULL) {
212 movedata(__djgpp_dos_sel, (r.x.es << 4) + r.x.di, _my_ds(), (unsigned)vesa_pmcode, r.x.cx);
213 if (vesa_pmcode[3]) {
214 p = (word16 *)((long)vesa_pmcode + vesa_pmcode[3]);
215 while (*p++ != 0xffff) {
216 }
217 } else {
218 p = NULL;
219 }
220 if (p && (*p != 0xffff)) {
221 free(vesa_pmcode);
222 vesa_pmcode = NULL;
223 } else {
224 vesa_swbank = (void *)((long)vesa_pmcode + vesa_pmcode[0]);
225 }
226 }
227 }
228 }
229
230 vesa_ver = _16_ vesa_info[V_MINOR];
231 return modes;
232 }
233
234
235 /* Desc: Frees all resources allocated by VESA init code.
236 *
237 * In : -
238 * Out : -
239 *
240 * Note: -
241 */
242 static void
243 vesa_fini (void)
244 {
245 if (vesa_ver) {
246 _remove_selector(&linear_selector);
247 _remove_selector(&banked_selector);
248 if (vesa_pmcode != NULL) {
249 free(vesa_pmcode);
250 vesa_pmcode = NULL;
251 }
252 }
253 }
254
255
256 /* Desc: Uses VESA 3.0 function 0x4F0B to find the closest pixel clock to the requested value.
257 *
258 * In : mode, clock
259 * Out : desired clock
260 *
261 * Note: -
262 */
263 static unsigned long
264 _closest_pixclk (int mode_no, unsigned long vclk)
265 {
266 __dpmi_regs r;
267
268 r.x.ax = 0x4F0B;
269 r.h.bl = 0;
270 r.d.ecx = vclk;
271 r.x.dx = mode_no;
272 __dpmi_int(0x10, &r);
273
274 return (r.x.ax == 0x004f) ? r.d.ecx : 0;
275 }
276
277
278 /* Desc: Calculates CRTC mode timings.
279 *
280 * In : crtc block, geometry, adjust
281 * Out :
282 *
283 * Note:
284 */
285 static void
286 _crtc_timing (CRTCInfoBlock *crtc, int xres, int yres, int xadjust, int yadjust)
287 {
288 int HTotal, VTotal;
289 int HDisp, VDisp;
290 int HSS, VSS;
291 int HSE, VSE;
292 int HSWidth, VSWidth;
293 int SS, SE;
294 int doublescan = FALSE;
295
296 if (yres < 400) {
297 doublescan = TRUE;
298 yres *= 2;
299 }
300
301 HDisp = xres;
302 HTotal = (int)(HDisp * 1.27) & ~0x7;
303 HSWidth = (int)((HTotal - HDisp) / 5) & ~0x7;
304 HSS = HDisp + 16;
305 HSE = HSS + HSWidth;
306 VDisp = yres;
307 VTotal = VDisp * 1.07;
308 VSWidth = (VTotal / 100) + 1;
309 VSS = VDisp + ((int)(VTotal - VDisp) / 5) + 1;
310 VSE = VSS + VSWidth;
311
312 SS = HSS + xadjust;
313 SE = HSE + xadjust;
314
315 if (xadjust < 0) {
316 if (SS < (HDisp + 8)) {
317 SS = HDisp + 8;
318 SE = SS + HSWidth;
319 }
320 } else {
321 if ((HTotal - 24) < SE) {
322 SE = HTotal - 24;
323 SS = SE - HSWidth;
324 }
325 }
326
327 HSS = SS;
328 HSE = SE;
329
330 SS = VSS + yadjust;
331 SE = VSE + yadjust;
332
333 if (yadjust < 0) {
334 if (SS < (VDisp + 3)) {
335 SS = VDisp + 3;
336 SE = SS + VSWidth;
337 }
338 } else {
339 if ((VTotal - 4) < SE) {
340 SE = VTotal - 4;
341 SS = SE - VSWidth;
342 }
343 }
344
345 VSS = SS;
346 VSE = SE;
347
348 crtc->HorizontalTotal = HTotal;
349 crtc->HorizontalSyncStart = HSS;
350 crtc->HorizontalSyncEnd = HSE;
351 crtc->VerticalTotal = VTotal;
352 crtc->VerticalSyncStart = VSS;
353 crtc->VerticalSyncEnd = VSE;
354 crtc->Flags = HNEG | VNEG;
355
356 if (doublescan) {
357 crtc->Flags |= DOUBLESCAN;
358 }
359 }
360
361
362 /* Desc: Attempts to choose a suitable blitter.
363 *
364 * In : ptr to mode structure, software framebuffer bits
365 * Out : blitter funciton, or NULL
366 *
367 * Note: -
368 */
369 static BLTFUNC
370 _choose_blitter (vl_mode *p, int fbbits)
371 {
372 BLTFUNC blitter;
373
374 if (p->mode & 0x4000) {
375 blitter = _can_mmx() ? vesa_l_dump_virtual_mmx : vesa_l_dump_virtual;
376 switch (p->bpp) {
377 case 8:
378 switch (fbbits) {
379 case 8:
380 break;
381 case 16:
382 blitter = vesa_l_dump_16_to_8;
383 break;
384 case 24:
385 blitter = vesa_l_dump_24_to_8;
386 break;
387 case 32:
388 blitter = vesa_l_dump_32_to_8;
389 break;
390 case 15:
391 default:
392 return NULL;
393 }
394 break;
395 case 15:
396 switch (fbbits) {
397 case 16:
398 blitter = vesa_l_dump_16_to_15;
399 break;
400 case 32:
401 blitter = vesa_l_dump_32_to_15;
402 break;
403 case 8:
404 case 15:
405 case 24:
406 default:
407 return NULL;
408 }
409 break;
410 case 16:
411 switch (fbbits) {
412 case 16:
413 break;
414 case 32:
415 blitter = vesa_l_dump_32_to_16;
416 break;
417 case 8:
418 case 15:
419 case 24:
420 default:
421 return NULL;
422 }
423 break;
424 case 24:
425 switch (fbbits) {
426 case 24:
427 break;
428 case 32:
429 blitter = vesa_l_dump_32_to_24;
430 break;
431 case 8:
432 case 15:
433 case 16:
434 default:
435 return NULL;
436 }
437 break;
438 case 32:
439 switch (fbbits) {
440 case 24:
441 blitter = vesa_l_dump_24_to_32;
442 break;
443 case 32:
444 break;
445 case 8:
446 case 15:
447 case 16:
448 default:
449 return NULL;
450 }
451 break;
452 }
453 } else {
454 blitter = vesa_b_dump_virtual;
455 switch (p->bpp) {
456 case 8:
457 switch (fbbits) {
458 case 8:
459 break;
460 case 16:
461 blitter = vesa_b_dump_16_to_8;
462 break;
463 case 24:
464 blitter = vesa_b_dump_24_to_8;
465 break;
466 case 32:
467 blitter = vesa_b_dump_32_to_8;
468 break;
469 case 15:
470 default:
471 return NULL;
472 }
473 break;
474 case 15:
475 switch (fbbits) {
476 case 16:
477 blitter = vesa_b_dump_16_to_15;
478 break;
479 case 32:
480 blitter = vesa_b_dump_32_to_15;
481 break;
482 case 8:
483 case 15:
484 case 24:
485 default:
486 return NULL;
487 }
488 break;
489 case 16:
490 switch (fbbits) {
491 case 16:
492 break;
493 case 32:
494 blitter = vesa_b_dump_32_to_16;
495 break;
496 case 8:
497 case 15:
498 case 24:
499 default:
500 return NULL;
501 }
502 break;
503 case 24:
504 switch (fbbits) {
505 case 24:
506 break;
507 case 32:
508 blitter = vesa_b_dump_32_to_24;
509 break;
510 case 8:
511 case 15:
512 case 16:
513 default:
514 return NULL;
515 }
516 break;
517 case 32:
518 switch (fbbits) {
519 case 24:
520 blitter = vesa_b_dump_24_to_32;
521 break;
522 case 32:
523 break;
524 case 8:
525 case 15:
526 case 16:
527 default:
528 return NULL;
529 }
530 break;
531 }
532 }
533
534 return blitter;
535 }
536
537
538 /* Desc: Attempts to enter specified video mode.
539 *
540 * In : ptr to mode structure, refresh rate
541 * Out : 0 if success
542 *
543 * Note: -
544 */
545 static int
546 vesa_entermode (vl_mode *p, int refresh, int fbbits)
547 {
548 __dpmi_regs r;
549
550 if (!(p->mode & 0x4000)) {
551 { int n; for (vesa_gran_shift = 0, n = p->gran; n; vesa_gran_shift++, n >>= 1); }
552 vesa_gran_mask = (1 << (--vesa_gran_shift)) - 1;
553 if ((unsigned)p->gran != (vesa_gran_mask + 1)) {
554 return !0;
555 }
556 }
557
558 VESA.blit = _choose_blitter(p, fbbits);
559 if (VESA.blit == NULL) {
560 return !0;
561 }
562
563 if (oldmode == -1) {
564 r.x.ax = 0x4f03;
565 __dpmi_int(0x10, &r);
566 oldmode = r.x.bx;
567 }
568
569 r.x.ax = 0x4f02;
570 r.x.bx = p->mode;
571
572 if (refresh && ((vesa_ver >> 8) >= 3)) {
573 /* VESA 3.0 stuff for controlling the refresh rate */
574 CRTCInfoBlock crtc;
575 unsigned long vclk;
576 double f0;
577
578 _crtc_timing(&crtc, p->xres, p->yres, 0, 0);
579
580 vclk = (double)crtc.HorizontalTotal * crtc.VerticalTotal * refresh;
581 vclk = _closest_pixclk(p->mode, vclk);
582
583 if (vclk != 0) {
584 f0 = (double)vclk / (crtc.HorizontalTotal * crtc.VerticalTotal);
585 /*_current_refresh_rate = (int)(f0 + 0.5);*/
586
587 crtc.PixelClock = vclk;
588 crtc.RefreshRate = refresh * 100;
589
590 movedata(_my_ds(), (unsigned)&crtc, _stubinfo->ds_selector, 0, sizeof(crtc));
591
592 r.x.di = 0;
593 r.x.es = _stubinfo->ds_segment;
594 r.x.bx |= 0x0800;
595 }
596 }
597
598 __dpmi_int(0x10, &r);
599 if (r.x.ax != 0x004f) {
600 return !0;
601 }
602
603 if (p->bpp == 8) {
604 r.x.ax = 0x4f08;
605 r.x.bx = 0x0800;
606 __dpmi_int(0x10, &r);
607 if (r.x.ax == 0x004f) {
608 r.x.ax = 0x4f08;
609 r.h.bl = 0x01;
610 __dpmi_int(0x10, &r);
611 vesa_color_precision = r.h.bh;
612 }
613 }
614
615 return 0;
616 }
617
618
619 /* Desc: Restores to the mode prior to first call to vesa_entermode.
620 *
621 * In : -
622 * Out : -
623 *
624 * Note: -
625 */
626 static void
627 vesa_restore (void)
628 {
629 __dpmi_regs r;
630
631 if (oldmode != -1) {
632 if (oldmode < 0x100) {
633 __asm("int $0x10"::"a"(oldmode));
634 } else {
635 r.x.ax = 0x4f02;
636 r.x.bx = oldmode;
637 __dpmi_int(0x10, &r);
638 }
639 oldmode = -1;
640 }
641 }
642
643
644 /* Desc: set one palette entry
645 *
646 * In : color index, R, G, B
647 * Out : -
648 *
649 * Note: uses integer values
650 */
651 static void
652 vesa_setCI_i (int index, int red, int green, int blue)
653 {
654 #if 0
655 __asm("\n\
656 movw $0x1010, %%ax \n\
657 movb %1, %%dh \n\
658 movb %2, %%ch \n\
659 int $0x10 \n\
660 "::"b"(index), "m"(red), "m"(green), "c"(blue):"%eax", "%edx");
661 #else
662 outportb(0x03C8, index);
663 outportb(0x03C9, red);
664 outportb(0x03C9, green);
665 outportb(0x03C9, blue);
666 #endif
667 }
668
669
670 /* Desc: set one palette entry
671 *
672 * In : color index, R, G, B
673 * Out : -
674 *
675 * Note: uses normalized values
676 */
677 static void
678 vesa_setCI_f (int index, float red, float green, float blue)
679 {
680 float max = (1 << vesa_color_precision) - 1;
681
682 vesa_setCI_i(index, (int)(red * max), (int)(green * max), (int)(blue * max));
683 }
684
685
686 /* Desc: state retrieval
687 *
688 * In : parameter name, ptr to storage
689 * Out : 0 if request successfully processed
690 *
691 * Note: -
692 */
693 static int
694 vesa_get (int pname, int *params)
695 {
696 switch (pname) {
697 case VL_GET_CI_PREC:
698 params[0] = vesa_color_precision;
699 break;
700 default:
701 return -1;
702 }
703 return 0;
704 }
705
706
707 /*
708 * the driver
709 */
710 vl_driver VESA = {
711 vesa_init,
712 vesa_entermode,
713 NULL,
714 vesa_setCI_f,
715 vesa_setCI_i,
716 vesa_get,
717 vesa_restore,
718 vesa_fini
719 };