]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
f083c6c3 A |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14c7c974 A |
14 | * |
15 | * The Original Code and all software distributed under the License are | |
f083c6c3 | 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
f083c6c3 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
14c7c974 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * Copyright 1993 NeXT, Inc. | |
27 | * All rights reserved. | |
28 | */ | |
75b89a82 | 29 | |
14c7c974 | 30 | #include "libsaio.h" |
14c7c974 | 31 | #include "vbe.h" |
14c7c974 A |
32 | |
33 | /* | |
34 | * Various inline routines for video I/O | |
35 | */ | |
36 | static inline void | |
37 | outi (int port, int index, int val) | |
38 | { | |
39 | outw (port, (val << 8) | index); | |
40 | } | |
41 | ||
42 | static inline void | |
43 | outib (int port, int index, int val) | |
44 | { | |
45 | outb (port, index); | |
46 | outb (port + 1, val); | |
47 | } | |
48 | ||
49 | static inline int | |
50 | ini (int port, int index) | |
51 | { | |
52 | outb (port, index); | |
53 | return inb (port + 1); | |
54 | } | |
55 | ||
56 | static inline void | |
57 | rmwi (int port, int index, int clear, int set) | |
58 | { | |
59 | outb (port, index); | |
60 | outb (port + 1, (inb (port + 1) & ~clear) | set); | |
61 | } | |
62 | ||
14c7c974 A |
63 | /* |
64 | * Globals | |
65 | */ | |
66 | static biosBuf_t bb; | |
67 | ||
75b89a82 | 68 | int getVBEInfo( void * infoBlock ) |
14c7c974 | 69 | { |
75b89a82 | 70 | bb.intno = 0x10; |
14c7c974 | 71 | bb.eax.rr = funcGetControllerInfo; |
75b89a82 A |
72 | bb.es = SEG( infoBlock ); |
73 | bb.edi.rr = OFF( infoBlock ); | |
74 | bios( &bb ); | |
14c7c974 A |
75 | return(bb.eax.r.h); |
76 | } | |
77 | ||
75b89a82 | 78 | int getVBEModeInfo( int mode, void * minfo_p ) |
14c7c974 | 79 | { |
75b89a82 | 80 | bb.intno = 0x10; |
14c7c974 A |
81 | bb.eax.rr = funcGetModeInfo; |
82 | bb.ecx.rr = mode; | |
75b89a82 | 83 | bb.es = SEG(minfo_p); |
14c7c974 A |
84 | bb.edi.rr = OFF(minfo_p); |
85 | bios(&bb); | |
86 | return(bb.eax.r.h); | |
87 | } | |
88 | ||
89 | int getVBEDACFormat(unsigned char *format) | |
90 | { | |
91 | bb.intno = 0x10; | |
92 | bb.eax.rr = funcGetSetPaletteFormat; | |
93 | bb.ebx.r.l = subfuncGet; | |
94 | bios(&bb); | |
95 | *format = bb.ebx.r.h; | |
96 | return(bb.eax.r.h); | |
97 | } | |
98 | ||
99 | int setVBEDACFormat(unsigned char format) | |
100 | { | |
101 | bb.intno = 0x10; | |
102 | bb.eax.rr = funcGetSetPaletteFormat; | |
103 | bb.ebx.r.l = subfuncSet; | |
104 | bb.ebx.r.h = format; | |
105 | bios(&bb); | |
106 | return(bb.eax.r.h); | |
107 | } | |
108 | ||
f083c6c3 A |
109 | /* |
110 | * Default GTF parameter values. | |
111 | */ | |
112 | #define kCellGranularity 8.0 // character cell granularity | |
113 | #define kMinVSyncPlusBP 550.0 // min VSync + BP interval (us) | |
114 | #define kMinFrontPorch 1.0 // minimum front porch in lines(V)/cells(H) | |
115 | #define kVSyncLines 3.0 // width of VSync in lines | |
116 | #define kHSyncWidth 8.0 // HSync as a percent of total line width | |
117 | #define kC 30.0 // C = (C'-J) * (K/256) + J | |
118 | #define kM 300.0 // M = K/256 * M' | |
119 | ||
120 | static inline double Round( double f ) | |
14c7c974 | 121 | { |
f083c6c3 A |
122 | asm volatile ("frndint" : "=t" (f) : "0" (f)); |
123 | return f; | |
124 | } | |
125 | ||
126 | static inline double Sqrt( double f ) | |
127 | { | |
128 | asm volatile ("fsqrt" : "=t" (f) : "0" (f)); | |
129 | return f; | |
130 | } | |
131 | ||
132 | int generateCRTCTiming( unsigned short width, | |
133 | unsigned short height, | |
134 | unsigned long paramValue, | |
135 | int paramType, | |
136 | VBECRTCInfoBlock * timing ) | |
137 | { | |
138 | double h_period_est, h_freq, h_period, h_total_pixels, h_sync_pixels; | |
139 | double h_active_pixels, h_ideal_duty_cycle, h_blank_pixels, pixel_freq = 0; | |
140 | double v_sync_plus_bp = 0, v_total_lines = 0, v_field_rate_est, v_frame_rate = 0; | |
141 | const double h_pixels = (double) width; | |
142 | const double v_lines = (double) height; | |
143 | ||
144 | enum { | |
145 | left_margin_pixels = 0, | |
146 | right_margin_pixels = 0, | |
147 | top_margin_lines = 0, | |
148 | bot_margin_lines = 0, | |
149 | interlace = 0 | |
150 | }; | |
151 | ||
152 | // Total number of active pixels in image and both margins | |
153 | h_active_pixels = h_pixels + left_margin_pixels + right_margin_pixels; | |
154 | ||
155 | if (paramType == kCRTCParamPixelClock) | |
156 | { | |
157 | // Pixel clock provided in MHz | |
158 | pixel_freq = (double) paramValue / 1000000; | |
159 | ||
160 | // Ideal horizontal period from the blanking duty cycle equation | |
161 | h_period = ((kC - 100) + (Sqrt(((100 - kC) * (100 - kC)) + (0.4 * kM * | |
162 | (h_active_pixels + right_margin_pixels + left_margin_pixels) / | |
163 | pixel_freq)))) / 2.0 / kM * 1000; | |
164 | } | |
165 | else /* kCRTCParamRefreshRate */ | |
166 | { | |
167 | double v_field_rate_in = (double) paramValue; | |
168 | ||
169 | // Estimate the horizontal period | |
170 | h_period_est = ((1 / v_field_rate_in) - kMinVSyncPlusBP / 1000000) / | |
171 | (v_lines + (2 * top_margin_lines) + kMinFrontPorch + interlace) * | |
172 | 1000000; | |
173 | ||
174 | // Number of lines in Vsync + back porch | |
175 | v_sync_plus_bp = Round(kMinVSyncPlusBP / h_period_est); | |
176 | ||
177 | // Total number of lines in Vetical field period | |
178 | v_total_lines = v_lines + top_margin_lines + bot_margin_lines + | |
179 | v_sync_plus_bp + interlace + kMinFrontPorch; | |
180 | ||
181 | // Estimate the vertical field frequency | |
182 | v_field_rate_est = 1 / h_period_est / v_total_lines * 1000000; | |
183 | ||
184 | // Find the actual horizontal period | |
185 | h_period = h_period_est / (v_field_rate_in / v_field_rate_est); | |
186 | ||
187 | // Find the vertical frame rate (no interlace) | |
188 | v_frame_rate = 1 / h_period / v_total_lines * 1000000; | |
189 | } | |
190 | ||
191 | // Ideal blanking duty cycle from the blanking duty cycle equation | |
192 | h_ideal_duty_cycle = kC - (kM * h_period / 1000); | |
193 | ||
194 | // Number of pixels in the blanking time to the nearest double character cell | |
195 | h_blank_pixels = Round(h_active_pixels * h_ideal_duty_cycle / | |
196 | (100 - h_ideal_duty_cycle) / (2 * kCellGranularity)) * | |
197 | (2 * kCellGranularity); | |
198 | ||
199 | // Total number of horizontal pixels | |
200 | h_total_pixels = h_active_pixels + h_blank_pixels; | |
201 | ||
202 | if (paramType == kCRTCParamPixelClock) | |
203 | { | |
204 | // Horizontal frequency | |
205 | h_freq = pixel_freq / h_total_pixels * 1000; | |
206 | ||
207 | // Number of lines in V sync + back porch | |
208 | v_sync_plus_bp = Round(kMinVSyncPlusBP * h_freq / 1000); | |
209 | ||
210 | // Total number of lines in vertical field period | |
211 | v_total_lines = v_lines + top_margin_lines + bot_margin_lines + | |
212 | interlace + v_sync_plus_bp + kMinFrontPorch; | |
213 | ||
214 | // Vertical frame frequency | |
215 | v_frame_rate = Round(h_freq / v_total_lines * 1000); | |
216 | } | |
217 | else | |
218 | { | |
219 | // Find pixel clock frequency | |
220 | pixel_freq = Round(h_total_pixels / h_period); | |
221 | } | |
222 | ||
223 | h_sync_pixels = Round(h_total_pixels * kHSyncWidth / 100 / kCellGranularity) * | |
224 | kCellGranularity; | |
225 | ||
226 | timing->HTotal = h_total_pixels; | |
227 | timing->HSyncStart = h_active_pixels + (h_blank_pixels / 2) - h_sync_pixels; | |
228 | timing->HSyncEnd = timing->HSyncStart + h_sync_pixels; | |
229 | timing->VTotal = v_total_lines; | |
230 | timing->VSyncStart = v_total_lines - v_sync_plus_bp; | |
231 | timing->VSyncEnd = timing->VSyncStart + kVSyncLines; | |
232 | timing->Flags = kCRTCNegativeHorizontalSync; | |
233 | timing->PixelClock = pixel_freq * 1000000; | |
234 | timing->RefreshRate = v_frame_rate * 100; | |
235 | ||
236 | return 0; | |
237 | } | |
238 | ||
239 | int setVBEMode(unsigned short mode, const VBECRTCInfoBlock * timing) | |
240 | { | |
241 | bb.intno = 0x10; | |
14c7c974 A |
242 | bb.eax.rr = funcSetMode; |
243 | bb.ebx.rr = mode; | |
f083c6c3 A |
244 | if (timing) { |
245 | bb.es = SEG(timing); | |
246 | bb.edi.rr = OFF(timing); | |
247 | } | |
14c7c974 A |
248 | bios(&bb); |
249 | return(bb.eax.r.h); | |
250 | } | |
251 | ||
252 | int setVBEPalette(void *palette) | |
253 | { | |
254 | bb.intno = 0x10; | |
255 | bb.eax.rr = funcGetSetPaletteData; | |
256 | bb.ebx.r.l = subfuncSet; | |
257 | bb.ecx.rr = 256; | |
258 | bb.edx.rr = 0; | |
259 | bb.es = SEG(palette); | |
260 | bb.edi.rr = OFF(palette); | |
261 | bios(&bb); | |
262 | return(bb.eax.r.h); | |
263 | } | |
264 | ||
265 | int getVBEPalette(void *palette) | |
266 | { | |
267 | bb.intno = 0x10; | |
268 | bb.eax.rr = funcGetSetPaletteData; | |
269 | bb.ebx.r.l = subfuncGet; | |
270 | bb.ecx.rr = 256; | |
271 | bb.edx.rr = 0; | |
272 | bb.es = SEG(palette); | |
273 | bb.edi.rr = OFF(palette); | |
274 | bios(&bb); | |
275 | return(bb.eax.r.h); | |
276 | } | |
277 | ||
278 | int getVBECurrentMode(unsigned short *mode) | |
279 | { | |
280 | bb.intno = 0x10; | |
281 | bb.eax.rr = funcGetCurrentMode; | |
282 | bios(&bb); | |
283 | *mode = bb.ebx.rr; | |
284 | return(bb.eax.r.h); | |
285 | } | |
f083c6c3 A |
286 | |
287 | int getVBEPixelClock(unsigned short mode, unsigned long * pixelClock) | |
288 | { | |
289 | bb.intno = 0x10; | |
290 | bb.eax.rr = funcGetSetPixelClock; | |
291 | bb.ebx.r.l = 0; | |
292 | bb.ecx.rx = *pixelClock; | |
293 | bb.edx.rr = mode; | |
294 | bios(&bb); | |
295 | *pixelClock = bb.ecx.rx; | |
296 | return(bb.eax.r.h); | |
297 | } |