2 Copyright © 2007-2018, The AROS Development Team. All rights reserved.
5 Desc: Real-mode code to set VBE mode.
9 #define _IMPLEMENTATION_
14 #define ABS(x) (((x) >= 0) ? (x) : -(x))
16 asm (".long getControllerInfo");
17 asm (".long getModeInfo");
18 asm (".long findMode");
19 asm (".long setVbeMode");
20 asm (".long paletteWidth");
21 asm (".long controllerinfo");
22 asm (".long modeinfo");
23 asm (".long timings");
25 short getControllerInfo(void)
29 controllerinfo
.signature
[0] = 'V';
30 controllerinfo
.signature
[1] = 'B';
31 controllerinfo
.signature
[2] = 'E';
32 controllerinfo
.signature
[3] = '2';
33 asm volatile("call go16 \n\t.code16 \n\t"
34 "movw $0x4f00, %%ax\n\t"
37 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"D"(&controllerinfo
):"eax","ecx","cc");
41 /* In VBE 1.1 information about standard modes was optional,
42 so we use a hardcoded table here (we rely on this information) */
43 struct vesa11Info vesa11Modes
[] = {
54 short getModeInfo(long mode
)
58 char *ptr
= (char *)&modeinfo
;
59 for (i
= 0; i
< sizeof(modeinfo
); i
++)
61 asm volatile("call go16 \n\t.code16 \n\t"
62 "movw $0x4f01, %%ax\n\t"
65 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"c"(mode
),"D"(&modeinfo
):"eax","cc");
66 if ((controllerinfo
.version
< 0x0102) && (mode
> 0x0FF) && (mode
< 0x108)) {
68 modeinfo
.x_resolution
= vesa11Modes
[i
].x_resolution
;
69 modeinfo
.y_resolution
= vesa11Modes
[i
].y_resolution
;
70 modeinfo
.bits_per_pixel
= vesa11Modes
[i
].bits_per_pixel
;
71 modeinfo
.memory_model
= vesa11Modes
[i
].memory_model
;
76 short setVbeMode(long mode
, BOOL set_refresh
)
80 /* Enable custom timings if possible */
81 if (set_refresh
&& controllerinfo
.version
>= 0x0300)
86 asm volatile("call go16 \n\t.code16 \n\t"
87 "movw $0x4f02, %%ax\n\t"
90 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"0"(mode
),"D"(&timings
):"eax","ecx","cc");
94 short paletteWidth(long req
, unsigned char* width
)
97 unsigned char reswidth
;
99 asm volatile("call go16\n\t.code16\n\t"
100 "movw $0x4f08, %%ax\n\t"
104 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
),"=c"(reswidth
):"0"(req
):"eax","cc");
109 /* Definitions used in CVT formula */
114 #define DUTY_CYCLE(period) \
115 (((C - J) / 2 + J) * 1000 - (M / 2 * (period) / 1000))
116 #define MIN_DUTY_CYCLE 20 /* % */
117 #define MIN_V_PORCH 3 /* lines */
118 #define MIN_V_PORCH_TIME 550 /* us */
119 #define CLOCK_STEP 250000 /* Hz */
121 /* Partial implementation of CVT formula */
122 void calcTimings(int vfreq
)
124 ULONG x
, y
, h_period
, h_freq
, h_total
, h_blank
, h_front
, h_sync
, h_back
,
125 v_freq
, v_total
, v_front
, v_sync
, v_back
, duty_cycle
, pixel_freq
;
127 x
= modeinfo
.x_resolution
;
128 y
= modeinfo
.y_resolution
;
130 /* Get horizontal period in microseconds */
131 h_period
= (1000000000 / vfreq
- MIN_V_PORCH_TIME
* 1000)
134 /* Vertical front porch is fixed */
135 v_front
= MIN_V_PORCH
;
137 /* Use aspect ratio to determine V-sync lines */
140 else if (x
== y
* 16 / 9)
142 else if (x
== y
* 16 / 10)
144 else if (x
== y
* 5 / 4)
146 else if (x
== y
* 15 / 9)
151 /* Get vertical back porch */
152 v_back
= MIN_V_PORCH_TIME
* 1000 / h_period
+ 1;
153 if (v_back
< MIN_V_PORCH
)
154 v_back
= MIN_V_PORCH
;
157 /* Get total lines per frame */
158 v_total
= y
+ v_front
+ v_sync
+ v_back
;
160 /* Get horizontal blanking pixels */
161 duty_cycle
= DUTY_CYCLE(h_period
);
162 if (duty_cycle
< MIN_DUTY_CYCLE
)
163 duty_cycle
= MIN_DUTY_CYCLE
;
165 h_blank
= 10 * x
* duty_cycle
/ (100000 - duty_cycle
);
166 h_blank
/= 2 * 8 * 10;
167 h_blank
= h_blank
* (2 * 8);
169 /* Get total pixels in a line */
170 h_total
= x
+ h_blank
;
172 /* Calculate frequencies for each pixel, line and field */
173 h_freq
= 1000000000 / h_period
;
174 pixel_freq
= h_freq
* h_total
/ CLOCK_STEP
* CLOCK_STEP
;
175 h_freq
= pixel_freq
/ h_total
;
176 v_freq
= 100 * h_freq
/ v_total
;
178 /* Back porch is half of H-blank */
179 h_back
= h_blank
/ 2;
181 /* H-sync is a fixed percentage of H-total */
182 h_sync
= h_total
/ 100 * 8;
184 /* Front porch is whatever's left */
185 h_front
= h_blank
- h_sync
- h_back
;
187 /* Fill in VBE timings structure */
188 timings
.h_total
= h_total
;
189 timings
.h_sync_start
= x
+ h_front
;
190 timings
.h_sync_end
= h_total
- h_back
;
191 timings
.v_total
= v_total
;
192 timings
.v_sync_start
= y
+ v_front
;
193 timings
.v_sync_end
= v_total
- v_back
;
195 timings
.pixel_clock
= pixel_freq
;
196 timings
.refresh_rate
= v_freq
;
199 short findMode(int x
, int y
, int d
, int vfreq
, BOOL prioritise_depth
)
201 unsigned long match
, bestmatch
= 0, matchd
, bestmatchd
= 0;
202 unsigned short bestmode
= 0xffff, mode_attrs
;
205 if (getControllerInfo() == 0x4f)
207 unsigned short *modes
= (unsigned short *)
208 (((controllerinfo
.video_mode
& 0xffff0000) >> 12) + (controllerinfo
.video_mode
& 0xffff));
212 if (controllerinfo
.version
< 0x0200)
217 for (i
=0; modes
[i
] != 0xffff; ++i
)
219 /* Check we can get info on the mode */
220 if (getModeInfo(modes
[i
])!= 0x4f)
223 /* Check for our manatory attributes */
224 if ((modeinfo
.mode_attributes
& mode_attrs
) != mode_attrs
)
227 /* We only support direct colour and paletted modes */
228 if ((modeinfo
.memory_model
!= 6) && (modeinfo
.memory_model
!= 4))
231 /* Don't use a paletted mode that isn't VGA compatible: the VESA
232 * driver uses VGA palette registers */
233 if ((modeinfo
.memory_model
== 4) && (modeinfo
.mode_attributes
& 0x20))
236 /* Return immediately if an exactly matching mode is found
237 * (otherwise we could potentially return a mode with the right
238 * area but different dimensions) */
239 if (modeinfo
.x_resolution
== x
&&
240 modeinfo
.y_resolution
== y
&&
241 modeinfo
.bits_per_pixel
== d
)
247 match
= ABS(modeinfo
.x_resolution
*modeinfo
.y_resolution
- x
*y
);
248 matchd
= modeinfo
.bits_per_pixel
>= d
? modeinfo
.bits_per_pixel
-d
: (d
-modeinfo
.bits_per_pixel
)*2;
250 if (prioritise_depth
)
252 /* Check if current mode is the best so far at the desired
253 * depth, or has a higher depth than previously found */
254 if (bestmode
== 0xffff || (match
< bestmatch
255 && modeinfo
.bits_per_pixel
== bestd
)
256 || (bestd
< d
&& modeinfo
.bits_per_pixel
> bestd
257 && modeinfo
.bits_per_pixel
<= d
))
261 bestd
= modeinfo
.bits_per_pixel
;
266 /* Check if current mode either has the closest resolution
267 * so far to that requested, or is equally close as the
268 * previous best but has closer colour depth */
269 if (bestmode
== 0xffff || match
< bestmatch
270 || (match
== bestmatch
&& matchd
< bestmatchd
))
280 /* Set up timings to achieve the desired refresh rate */
281 if (controllerinfo
.version
>= 0x0300 && getModeInfo(bestmode
) == 0x4f)
288 " .code16\n\t.globl go32\n\t.type go32,@function\n"
289 "go32: DATA32 ADDR32 lgdt GDT_reg\n"
295 "1: movw $0x10, %ax\n"
301 " movl (%esp), %ecx\n"
302 " movl stack32, %eax\n"
304 " movl %ecx, (%esp)\n"
310 " .code32\n\t.globl go16\n\t.type go16,@function\n"
311 "go16: lgdt GDT_reg\n"
314 " movl %esp, stack32\n"
315 " movl (%esp), %eax\n"
316 " movl %eax, scratch + 63\n"
317 " movl $scratch + 63, %esp\n"
324 " ljmp $0x18, $1f\n\t.code16\n"
329 " DATA32 ljmp $0x00, $1f\n"
340 const unsigned long long GDT_Table
[] = {
341 0x0000000000000000ULL
,
342 0x00cf9a000000ffffULL
, /* Code32 */
343 0x00cf92000000ffffULL
, /* Data32 */
344 0x00009e000000ffffULL
, /* Code16 */
345 0x000092000000ffffULL
/* Data16 */
350 unsigned short l1
__attribute__((packed
));
351 const void *l3
__attribute__((packed
));
353 GDT_reg
= {sizeof(GDT_Table
)-1, GDT_Table
},
354 IDT_reg16
= {0x400, 0},
357 unsigned long stack32
;
358 unsigned long scratch
[64];
359 struct vbe_controller controllerinfo
;
360 struct vbe_mode modeinfo
;
361 struct CRTCInfoBlock timings
;