]> git.saurik.com Git - apple/boot.git/blobdiff - i386/libsaio/vbe.c
boot-111.tar.gz
[apple/boot.git] / i386 / libsaio / vbe.c
index a195171ee4722208142fa9d4b7c53e7dbc13548d..f5e9f1d4f869dcc096fea37ede586778991ab2e4 100644 (file)
@@ -3,21 +3,22 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
- * Reserved.  This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.1 (the "License").  You may not use this file
- * except in compliance with the License.  Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
  * 
  * The Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
@@ -105,11 +106,145 @@ int setVBEDACFormat(unsigned char format)
     return(bb.eax.r.h);
 }
 
-int setVBEMode(unsigned short mode)
+/*
+ * Default GTF parameter values.
+ */
+#define kCellGranularity  8.0    // character cell granularity
+#define kMinVSyncPlusBP   550.0  // min VSync + BP interval (us)
+#define kMinFrontPorch    1.0    // minimum front porch in lines(V)/cells(H)
+#define kVSyncLines       3.0    // width of VSync in lines
+#define kHSyncWidth       8.0    // HSync as a percent of total line width
+#define kC                30.0   // C = (C'-J) * (K/256) + J
+#define kM                300.0  // M = K/256 * M'
+
+static inline double Round( double f )
 {
-    bb.intno = 0x10;
+    asm volatile ("frndint" : "=t" (f) : "0" (f));
+    return f;
+}
+
+static inline double Sqrt( double f )
+{
+    asm volatile ("fsqrt" : "=t" (f) : "0" (f));
+    return f;
+}
+
+int generateCRTCTiming( unsigned short     width,
+                        unsigned short     height,
+                        unsigned long      paramValue,  
+                        int                paramType,
+                        VBECRTCInfoBlock * timing )
+{
+    double h_period_est, h_freq, h_period, h_total_pixels, h_sync_pixels;
+    double h_active_pixels, h_ideal_duty_cycle, h_blank_pixels, pixel_freq = 0;
+    double v_sync_plus_bp = 0, v_total_lines = 0, v_field_rate_est, v_frame_rate = 0;
+    const double h_pixels = (double) width;
+    const double v_lines  = (double) height;
+
+    enum {
+        left_margin_pixels  = 0,
+        right_margin_pixels = 0,
+        top_margin_lines    = 0,
+        bot_margin_lines    = 0,
+        interlace           = 0
+    };
+
+    // Total number of active pixels in image and both margins
+    h_active_pixels = h_pixels + left_margin_pixels + right_margin_pixels;
+
+    if (paramType == kCRTCParamPixelClock)
+    {
+        // Pixel clock provided in MHz
+        pixel_freq = (double) paramValue / 1000000;
+
+        // Ideal horizontal period from the blanking duty cycle equation
+        h_period = ((kC - 100) + (Sqrt(((100 - kC) * (100 - kC)) + (0.4 * kM *
+                    (h_active_pixels + right_margin_pixels + left_margin_pixels) /
+                     pixel_freq)))) / 2.0 / kM * 1000;
+    }
+    else /* kCRTCParamRefreshRate */
+    {
+        double v_field_rate_in = (double) paramValue;
+
+        // Estimate the horizontal period
+        h_period_est = ((1 / v_field_rate_in) - kMinVSyncPlusBP / 1000000) /
+                        (v_lines + (2 * top_margin_lines) + kMinFrontPorch + interlace) * 
+                        1000000;
+
+        // Number of lines in Vsync + back porch
+        v_sync_plus_bp = Round(kMinVSyncPlusBP / h_period_est);
+
+        // Total number of lines in Vetical field period
+        v_total_lines = v_lines + top_margin_lines + bot_margin_lines +
+                        v_sync_plus_bp + interlace + kMinFrontPorch;
+
+        // Estimate the vertical field frequency
+        v_field_rate_est = 1 / h_period_est / v_total_lines * 1000000;
+
+        // Find the actual horizontal period
+        h_period = h_period_est / (v_field_rate_in / v_field_rate_est);
+
+        // Find the vertical frame rate (no interlace)
+        v_frame_rate = 1 / h_period / v_total_lines * 1000000;
+    }
+
+    // Ideal blanking duty cycle from the blanking duty cycle equation
+    h_ideal_duty_cycle = kC - (kM * h_period / 1000);
+
+    // Number of pixels in the blanking time to the nearest double character cell
+    h_blank_pixels = Round(h_active_pixels * h_ideal_duty_cycle /
+                           (100 - h_ideal_duty_cycle) / (2 * kCellGranularity)) *
+                     (2 * kCellGranularity);
+
+    // Total number of horizontal pixels
+    h_total_pixels = h_active_pixels + h_blank_pixels;
+
+    if (paramType == kCRTCParamPixelClock)
+    {
+        // Horizontal frequency
+        h_freq = pixel_freq / h_total_pixels * 1000;
+
+        // Number of lines in V sync + back porch
+        v_sync_plus_bp = Round(kMinVSyncPlusBP * h_freq / 1000);
+
+        // Total number of lines in vertical field period
+        v_total_lines = v_lines + top_margin_lines + bot_margin_lines +
+                        interlace + v_sync_plus_bp + kMinFrontPorch;
+
+        // Vertical frame frequency
+        v_frame_rate = Round(h_freq / v_total_lines * 1000);
+    }
+    else
+    {
+        // Find pixel clock frequency
+        pixel_freq = Round(h_total_pixels / h_period);
+    }
+
+    h_sync_pixels = Round(h_total_pixels * kHSyncWidth / 100 / kCellGranularity) *
+                    kCellGranularity;
+
+    timing->HTotal      = h_total_pixels;
+    timing->HSyncStart  = h_active_pixels + (h_blank_pixels / 2) - h_sync_pixels;
+    timing->HSyncEnd    = timing->HSyncStart + h_sync_pixels;
+    timing->VTotal      = v_total_lines;
+    timing->VSyncStart  = v_total_lines - v_sync_plus_bp;
+    timing->VSyncEnd    = timing->VSyncStart + kVSyncLines;
+    timing->Flags       = kCRTCNegativeHorizontalSync;
+    timing->PixelClock  = pixel_freq * 1000000;
+    timing->RefreshRate = v_frame_rate * 100;
+
+    return 0;
+}
+
+int setVBEMode(unsigned short mode, const VBECRTCInfoBlock * timing)
+{
+    bb.intno  = 0x10;
     bb.eax.rr = funcSetMode;
     bb.ebx.rr = mode;
+    if (timing) {
+        bb.es     = SEG(timing);
+        bb.edi.rr = OFF(timing);
+    }
     bios(&bb);
     return(bb.eax.r.h);
 }
@@ -148,3 +283,15 @@ int getVBECurrentMode(unsigned short *mode)
     *mode = bb.ebx.rr;
     return(bb.eax.r.h);
 }
+
+int getVBEPixelClock(unsigned short mode, unsigned long * pixelClock)
+{
+    bb.intno   = 0x10;
+    bb.eax.rr  = funcGetSetPixelClock;
+    bb.ebx.r.l = 0;
+    bb.ecx.rx  = *pixelClock;
+    bb.edx.rr  = mode;
+    bios(&bb);
+    *pixelClock = bb.ecx.rx;
+    return(bb.eax.r.h);
+}