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