]> code.delx.au - refind/blobdiff - libeg/screen.c
Tweaks to graphics mode-setting code; added --root option to install.sh
[refind] / libeg / screen.c
index 90988cf26cf71cb04d2d07a0a7a5259a7d73bfdb..02b9f676414bfec579cb7ac0befaade357303643 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+/*
+ * Modifications copyright (c) 2012 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
 
 #include "libegint.h"
 #include "../refind/screen.h"
 #define LibLocateProtocol EfiLibLocateProtocol
 #endif
 
-// Scan for at least this many text-mode and graphics-mode display modes, even
-// if the first modes are invalid. The number of text modes scanned must be at
-// least 3 on some computers to properly list all the available modes when the
-// user specifies an invalid value, since mode 1 (numbered from 0) is often
-// invalid, but mode 2 (the third one) is usually valid. AFAIK, gaps never
-// occur in graphics modes, although I've heard of one case that makes me think
-// some exceptions may occur.
-#define MIN_SCAN_TEXT_MODES 3
-#define MIN_SCAN_GRAPHICS_MODES 1
-
 // Console defines and variables
 
 static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
@@ -75,24 +73,10 @@ static UINTN egScreenHeight = 600;
 // Screen handling
 //
 
-VOID egInitScreen(VOID)
-{
+static VOID egDetermineScreenSize(VOID) {
     EFI_STATUS Status = EFI_SUCCESS;
     UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate;
 
-    // get protocols
-    Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl);
-    if (EFI_ERROR(Status))
-        ConsoleControl = NULL;
-
-    Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw);
-    if (EFI_ERROR(Status))
-        UgaDraw = NULL;
-
-    Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
-    if (EFI_ERROR(Status))
-        GraphicsOutput = NULL;
-
     // get screen size
     egHasGraphics = FALSE;
     if (GraphicsOutput != NULL) {
@@ -111,6 +95,43 @@ VOID egInitScreen(VOID)
     }
 }
 
+VOID egInitScreen(VOID)
+{
+    EFI_STATUS Status = EFI_SUCCESS;
+
+    // get protocols
+    Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl);
+    if (EFI_ERROR(Status))
+        ConsoleControl = NULL;
+
+    Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw);
+    if (EFI_ERROR(Status))
+        UgaDraw = NULL;
+
+    Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+    if (EFI_ERROR(Status))
+        GraphicsOutput = NULL;
+
+    egDetermineScreenSize();
+}
+
+// Convert a graphics mode (in *ModeWidth) to a width and height (returned in
+// *ModeWidth and *Height, respectively).
+// Returns TRUE if successful, FALSE if not (invalid mode)
+BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) {
+   UINTN                                 Size;
+   EFI_STATUS                            Status;
+   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info = NULL;
+
+   Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info);
+   if ((Status == EFI_SUCCESS) && (Info != NULL)) {
+      *ModeWidth = Info->HorizontalResolution;
+      *Height = Info->VerticalResolution;
+      return TRUE;
+   }
+   return FALSE;
+} // BOOLEAN egGetResFromMode()
+
 // Sets the screen resolution to the specified value, if possible. If *ScreenHeight
 // is 0 and GOP mode is detected, assume that *ScreenWidth contains a GOP mode
 // number rather than a horizontal resolution. If the specified resolution is not
@@ -131,35 +152,45 @@ BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) {
    if (GraphicsOutput != NULL) { // GOP mode (UEFI)
       if (*ScreenHeight == 0) { // User specified a mode number (stored in *ScreenWidth); use it directly
          ModeNum = (UINT32) *ScreenWidth;
-         Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
-         if (Status == EFI_SUCCESS) {
-            Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum);
-            if (Status == EFI_SUCCESS) {
-               ModeSet = TRUE;
-               *ScreenWidth = Info->HorizontalResolution;
-               *ScreenHeight = Info->VerticalResolution;
-            }
+         if (egGetResFromMode(ScreenWidth, ScreenHeight) && (
+             refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum) == EFI_SUCCESS)) {
+            ModeSet = TRUE;
          }
-      } else { // User specified width & height; must find mode
-         // Do a loop through the modes to see if the specified one is available;
-         // and if so, switch to it....
-         do {
+//          if ((*ScreenWidth == GraphicsOutput->Mode->Mode)) { // user requested current mode; do nothing
+//             ModeSet = TRUE;
+//             *ScreenWidth = Info->HorizontalResolution;
+//             *ScreenHeight = Info->VerticalResolution;
+//          } else {
+/*            ModeNum = (UINT32) *ScreenWidth;
             Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
-            if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info)) &&
-                (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) {
+            if (Status == EFI_SUCCESS) {
                Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum);
-               ModeSet = (Status == EFI_SUCCESS);
-            } // if
-         } while (((++ModeNum < MIN_SCAN_GRAPHICS_MODES) || (Status == EFI_SUCCESS)) && !ModeSet);
-//          while ((Status == EFI_SUCCESS) && (!ModeSet)) {
-//             Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
-//             if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info)) &&
-//                 (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) {
-//                Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum);
-//                ModeSet = (Status == EFI_SUCCESS);
-//             } // if
-//             ModeNum++;
-//          } // while()
+               if (Status == EFI_SUCCESS) {
+                  ModeSet = TRUE;
+                  *ScreenWidth = Info->HorizontalResolution;
+                  *ScreenHeight = Info->VerticalResolution;
+               } // if set mode OK
+            } // if queried mode OK */
+//         } // if/else
+
+      // User specified width & height; must find mode -- but only if change is required....
+      } else {
+         Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, GraphicsOutput->Mode->Mode, &Size, &Info);
+//          if ((Status == EFI_SUCCESS) && (Info->HorizontalResolution == *ScreenWidth) &&
+//              (Info->VerticalResolution == *ScreenHeight) && !AlwaysSet) {
+//             ModeSet = TRUE; // user requested current mode; do nothing
+//          } else {
+            // Do a loop through the modes to see if the specified one is available;
+            // and if so, switch to it....
+            do {
+               Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
+               if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info)) &&
+                   (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) {
+                  Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum);
+                  ModeSet = (Status == EFI_SUCCESS);
+               } // if
+            } while ((++ModeNum < GraphicsOutput->Mode->MaxMode) && !ModeSet);
+//         } // if/else
       } // if/else
 
       if (ModeSet) {
@@ -174,15 +205,7 @@ BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) {
             if ((Status == EFI_SUCCESS) && (Info != NULL)) {
                Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution);
             } // else
-         } while ((++ModeNum < MIN_SCAN_GRAPHICS_MODES) || (Status == EFI_SUCCESS));
-//          Status = EFI_SUCCESS;
-//          while (Status == EFI_SUCCESS) {
-//             Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info);
-//             if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info))) {
-//                Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution);
-//             } // else
-//             ModeNum++;
-//          } // while()
+         } while (++ModeNum < GraphicsOutput->Mode->MaxMode);
          PauseForKey();
          SwitchToGraphics();
       } // if()
@@ -208,38 +231,43 @@ BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) {
 
 VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight)
 {
+    egDetermineScreenSize();
+
     if (ScreenWidth != NULL)
         *ScreenWidth = egScreenWidth;
     if (ScreenHeight != NULL)
         *ScreenHeight = egScreenHeight;
 }
 
-// Set a text mode
-// Returns the mode that was actually set.
-UINT32 egSetTextMode(UINT32 RequestedMode) {
+// Set a text mode.
+// Returns TRUE if the mode actually changed, FALSE otherwise.
+// Note that a FALSE return value can mean either an error or no change
+// necessary.
+BOOLEAN egSetTextMode(UINT32 RequestedMode) {
    UINTN         i = 0, Width, Height;
-   UINT32        UsedMode = ST->ConOut->Mode->Mode;
    EFI_STATUS    Status;
+   BOOLEAN       ChangedIt = FALSE;
 
    if (RequestedMode != ST->ConOut->Mode->Mode) {
+//      SwitchToGraphics();
       Status = refit_call2_wrapper(ST->ConOut->SetMode, ST->ConOut, RequestedMode);
       if (Status == EFI_SUCCESS) {
-         UsedMode = RequestedMode;
+         ChangedIt = TRUE;
       } else {
          SwitchToText(FALSE);
          Print(L"Error setting text mode %d; available modes are:\n", RequestedMode);
          do {
             Status = refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, i, &Width, &Height);
             if (Status == EFI_SUCCESS)
-               Print(L"Mode: %d: %d x %d\n", i, Width, Height);
-         } while ((++i < MIN_SCAN_TEXT_MODES) || (Status == EFI_SUCCESS));
+               Print(L"Mode %d: %d x %d\n", i, Width, Height);
+         } while (++i < ST->ConOut->Mode->MaxMode);
 
          PauseForKey();
          SwitchToGraphics();
       } // if/else successful change
    } // if need to change mode
-   return UsedMode;
-} // UINT32 egSetTextMode()
+   return ChangedIt;
+} // BOOLEAN egSetTextMode()
 
 CHAR16 * egScreenDescription(VOID)
 {