2 Copyright © 2007-2010, 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 *(ULONG
*)controllerinfo
.signature
= *(ULONG
*)"VBE2";
30 asm volatile("call go16 \n\t.code16 \n\t"
31 "movw $0x4f00, %%ax\n\t"
34 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"D"(&controllerinfo
):"eax","ecx","cc");
38 /* In VBE 1.1 information about standard modes was optional,
39 so we use a hardcoded table here (we rely on this information) */
40 struct vesa11Info vesa11Modes
[] = {
51 short getModeInfo(long mode
)
55 char *ptr
= (char *)&modeinfo
;
56 for (i
= 0; i
< sizeof(modeinfo
); i
++)
58 asm volatile("call go16 \n\t.code16 \n\t"
59 "movw $0x4f01, %%ax\n\t"
62 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"c"(mode
),"D"(&modeinfo
):"eax","cc");
63 if ((controllerinfo
.version
< 0x0102) && (mode
> 0x0FF) && (mode
< 0x108)) {
65 modeinfo
.x_resolution
= vesa11Modes
[i
].x_resolution
;
66 modeinfo
.y_resolution
= vesa11Modes
[i
].y_resolution
;
67 modeinfo
.bits_per_pixel
= vesa11Modes
[i
].bits_per_pixel
;
68 modeinfo
.memory_model
= vesa11Modes
[i
].memory_model
;
73 short setVbeMode(long mode
, BOOL set_refresh
)
77 /* Enable custom timings if possible */
78 if (set_refresh
&& controllerinfo
.version
>= 0x0300)
83 asm volatile("call go16 \n\t.code16 \n\t"
84 "movw $0x4f02, %%ax\n\t"
87 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
):"0"(mode
),"D"(&timings
):"eax","ecx","cc");
91 short paletteWidth(long req
, unsigned char* width
)
94 unsigned char reswidth
;
96 asm volatile("call go16\n\t.code16\n\t"
97 "movw $0x4f08, %%ax\n\t"
101 "DATA32 call go32\n\t.code32\n\t":"=b"(retval
),"=c"(reswidth
):"0"(req
):"eax","cc");
106 /* Definitions used in CVT formula */
111 #define DUTY_CYCLE(period) \
112 (((C - J) / 2 + J) * 1000 - (M / 2 * (period) / 1000))
113 #define MIN_DUTY_CYCLE 20 /* % */
114 #define MIN_V_PORCH 3 /* lines */
115 #define MIN_V_PORCH_TIME 550 /* us */
116 #define CLOCK_STEP 250000 /* Hz */
118 /* Partial implementation of CVT formula */
119 void calcTimings(int vfreq
)
121 ULONG x
, y
, h_period
, h_freq
, h_total
, h_blank
, h_front
, h_sync
, h_back
,
122 v_freq
, v_total
, v_front
, v_sync
, v_back
, duty_cycle
, pixel_freq
;
124 x
= modeinfo
.x_resolution
;
125 y
= modeinfo
.y_resolution
;
127 /* Get horizontal period in microseconds */
128 h_period
= (1000000000 / vfreq
- MIN_V_PORCH_TIME
* 1000)
131 /* Vertical front porch is fixed */
132 v_front
= MIN_V_PORCH
;
134 /* Use aspect ratio to determine V-sync lines */
137 else if (x
== y
* 16 / 9)
139 else if (x
== y
* 16 / 10)
141 else if (x
== y
* 5 / 4)
143 else if (x
== y
* 15 / 9)
148 /* Get vertical back porch */
149 v_back
= MIN_V_PORCH_TIME
* 1000 / h_period
+ 1;
150 if (v_back
< MIN_V_PORCH
)
151 v_back
= MIN_V_PORCH
;
154 /* Get total lines per frame */
155 v_total
= y
+ v_front
+ v_sync
+ v_back
;
157 /* Get horizontal blanking pixels */
158 duty_cycle
= DUTY_CYCLE(h_period
);
159 if (duty_cycle
< MIN_DUTY_CYCLE
)
160 duty_cycle
= MIN_DUTY_CYCLE
;
162 h_blank
= 10 * x
* duty_cycle
/ (100000 - duty_cycle
);
163 h_blank
/= 2 * 8 * 10;
164 h_blank
= h_blank
* (2 * 8);
166 /* Get total pixels in a line */
167 h_total
= x
+ h_blank
;
169 /* Calculate frequencies for each pixel, line and field */
170 h_freq
= 1000000000 / h_period
;
171 pixel_freq
= h_freq
* h_total
/ CLOCK_STEP
* CLOCK_STEP
;
172 h_freq
= pixel_freq
/ h_total
;
173 v_freq
= 100 * h_freq
/ v_total
;
175 /* Back porch is half of H-blank */
176 h_back
= h_blank
/ 2;
178 /* H-sync is a fixed percentage of H-total */
179 h_sync
= h_total
/ 100 * 8;
181 /* Front porch is whatever's left */
182 h_front
= h_blank
- h_sync
- h_back
;
184 /* Fill in VBE timings structure */
185 timings
.h_total
= h_total
;
186 timings
.h_sync_start
= x
+ h_front
;
187 timings
.h_sync_end
= h_total
- h_back
;
188 timings
.v_total
= v_total
;
189 timings
.v_sync_start
= y
+ v_front
;
190 timings
.v_sync_end
= v_total
- v_back
;
192 timings
.pixel_clock
= pixel_freq
;
193 timings
.refresh_rate
= v_freq
;
196 short findMode(int x
, int y
, int d
, int vfreq
, BOOL prioritise_depth
)
198 unsigned long match
, bestmatch
, matchd
, bestmatchd
;
199 unsigned short bestmode
= 0xffff, mode_attrs
;
202 if (getControllerInfo() == 0x4f)
204 unsigned short *modes
= (unsigned short *)
205 (((controllerinfo
.video_mode
& 0xffff0000) >> 12) + (controllerinfo
.video_mode
& 0xffff));
209 if (controllerinfo
.version
< 0x0200)
214 for (i
=0; modes
[i
] != 0xffff; ++i
)
216 if (getModeInfo(modes
[i
])!= 0x4f) continue;
217 if ((modeinfo
.mode_attributes
& mode_attrs
) != mode_attrs
) continue;
218 if ((modeinfo
.memory_model
!= 6) && (modeinfo
.memory_model
!= 4))
220 if ((modeinfo
.memory_model
== 4) && (modeinfo
.mode_attributes
& 0x20))
223 /* Return immediately if an exactly matching mode is found
224 * (otherwise we could potentially return a mode with the right
225 * area but different dimensions) */
226 if (modeinfo
.x_resolution
== x
&&
227 modeinfo
.y_resolution
== y
&&
228 modeinfo
.bits_per_pixel
== d
)
234 match
= ABS(modeinfo
.x_resolution
*modeinfo
.y_resolution
- x
*y
);
235 matchd
= modeinfo
.bits_per_pixel
>= d
? modeinfo
.bits_per_pixel
-d
: (d
-modeinfo
.bits_per_pixel
)*2;
237 if (prioritise_depth
)
239 /* Check if current mode is the best so far at the desired
240 * depth, or has a higher depth than previously found */
241 if (bestmode
== 0xffff || (match
< bestmatch
242 && modeinfo
.bits_per_pixel
== bestd
)
243 || (bestd
< d
&& modeinfo
.bits_per_pixel
> bestd
244 && modeinfo
.bits_per_pixel
<= d
))
248 bestd
= modeinfo
.bits_per_pixel
;
253 /* Check if current mode either has the closest resolution
254 * so far to that requested, or is equally close as the
255 * previous best but has closer colour depth */
256 if (bestmode
== 0xffff || match
< bestmatch
257 || (match
== bestmatch
&& matchd
< bestmatchd
))
267 /* Set up timings to achieve the desired refresh rate */
268 if (controllerinfo
.version
>= 0x0300 && getModeInfo(bestmode
) == 0x4f)
275 " .code16\n\t.globl go32\n\t.type go32,@function\n"
276 "go32: DATA32 ADDR32 lgdt GDT_reg\n"
282 "1: movw $0x10, %ax\n"
288 " movl (%esp), %ecx\n"
289 " movl stack32, %eax\n"
291 " movl %ecx, (%esp)\n"
295 " .code32\n\t.globl go16\n\t.type go16,@function\n"
296 "go16: lgdt GDT_reg\n"
297 " movl %esp, stack32\n"
298 " movl (%esp), %eax\n"
299 " movl %eax, begin + 0xff8\n"
300 " movl $begin + 0xff8, %esp\n"
307 " ljmp $0x18, $1f\n\t.code16\n"
312 " DATA32 ljmp $0x00, $1f\n"
323 const unsigned long long GDT_Table
[] = {
324 0x0000000000000000ULL
,
325 0x00cf9a000000ffffULL
, /* Code32 */
326 0x00cf92000000ffffULL
, /* Data32 */
327 0x00009e000000ffffULL
, /* Code16 */
328 0x000092000000ffffULL
/* Data16 */
333 unsigned short l1
__attribute__((packed
));
334 const void *l3
__attribute__((packed
));
336 GDT_reg
= {sizeof(GDT_Table
)-1, GDT_Table
};
338 unsigned long stack32
;
339 struct vbe_controller controllerinfo
;
340 struct vbe_mode modeinfo
;
341 struct CRTCInfoBlock timings
;