1 /** @file
2   Provides services to display completion progress of a firmware update on a
3   text console.
4 
5   Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
6   Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
7 
8   SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include <PiDxe.h>
13 #include <Library/DebugLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16 
17 //
18 // Control Style.  Set to 100 so it is reset on first call.
19 //
20 UINTN  mPreviousProgress = 100;
21 
22 //
23 // Text foreground color of progress bar
24 //
25 UINTN  mProgressBarForegroundColor;
26 
27 /**
28   Function indicates the current completion progress of a firmware update.
29   Platform may override with its own specific function.
30 
31   @param[in] Completion  A value between 0 and 100 indicating the current
32                          completion progress of a firmware update.  This
33                          value must the the same or higher than previous
34                          calls to this service.  The first call of 0 or a
35                          value of 0 after reaching a value of 100 resets
36                          the progress indicator to 0.
37   @param[in] Color       Color of the progress indicator.  Only used when
38                          Completion is 0 to set the color of the progress
39                          indicator.  If Color is NULL, then the default color
40                          is used.
41 
42   @retval EFI_SUCCESS            Progress displayed successfully.
43   @retval EFI_INVALID_PARAMETER  Completion is not in range 0..100.
44   @retval EFI_INVALID_PARAMETER  Completion is less than Completion value from
45                                  a previous call to this service.
46   @retval EFI_NOT_READY          The device used to indicate progress is not
47                                  available.
48 **/
49 EFI_STATUS
50 EFIAPI
DisplayUpdateProgress(IN UINTN Completion,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION * Color OPTIONAL)51 DisplayUpdateProgress (
52   IN UINTN                                Completion,
53   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  *Color       OPTIONAL
54   )
55 {
56   UINTN  Index;
57   UINTN  CurrentAttribute;
58 
59   //
60   // Check range
61   //
62   if (Completion > 100) {
63     return EFI_INVALID_PARAMETER;
64   }
65 
66   //
67   // Check to see if this Completion percentage has already been displayed
68   //
69   if (Completion == mPreviousProgress) {
70     return EFI_SUCCESS;
71   }
72 
73   //
74   // Do special init on first call of each progress session
75   //
76   if (mPreviousProgress == 100) {
77     Print (L"\n");
78 
79     //
80     // Convert pixel color to text foreground color
81     //
82     if (Color == NULL) {
83       mProgressBarForegroundColor = EFI_WHITE;
84     } else {
85       mProgressBarForegroundColor = EFI_BLACK;
86       if (Color->Pixel.Blue >= 0x40) {
87         mProgressBarForegroundColor |= EFI_BLUE;
88       }
89       if (Color->Pixel.Green >= 0x40) {
90         mProgressBarForegroundColor |= EFI_GREEN;
91       }
92       if (Color->Pixel.Red >= 0x40) {
93         mProgressBarForegroundColor |= EFI_RED;
94       }
95       if (Color->Pixel.Blue >= 0xC0 || Color->Pixel.Green >= 0xC0 || Color->Pixel.Red >= 0xC0) {
96         mProgressBarForegroundColor |= EFI_BRIGHT;
97       }
98       if (mProgressBarForegroundColor == EFI_BLACK) {
99         mProgressBarForegroundColor = EFI_WHITE;
100       }
101     }
102 
103     //
104     // Clear previous
105     //
106     mPreviousProgress = 0;
107   }
108 
109   //
110   // Can not update progress bar if Completion is less than previous
111   //
112   if (Completion < mPreviousProgress) {
113     DEBUG ((DEBUG_WARN, "WARNING: Completion (%d) should not be lesss than Previous (%d)!!!\n", Completion, mPreviousProgress));
114     return EFI_INVALID_PARAMETER;
115   }
116 
117   //
118   // Save current text color
119   //
120   CurrentAttribute = (UINTN)gST->ConOut->Mode->Attribute;
121 
122   //
123   // Print progress percentage
124   //
125   Print (L"\rUpdate Progress - %3d%% ", Completion);
126 
127   //
128   // Set progress bar color
129   //
130   gST->ConOut->SetAttribute (
131                  gST->ConOut,
132                  EFI_TEXT_ATTR (mProgressBarForegroundColor, EFI_BLACK)
133                  );
134 
135   //
136   // Print completed portion of progress bar
137   //
138   for (Index = 0; Index < Completion / 2; Index++) {
139     Print (L"%c", BLOCKELEMENT_FULL_BLOCK);
140   }
141 
142   //
143   // Restore text color
144   //
145   gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
146 
147   //
148   // Print remaining portion of progress bar
149   //
150   for (; Index < 50; Index++) {
151     Print (L"%c", BLOCKELEMENT_LIGHT_SHADE);
152   }
153 
154   mPreviousProgress = Completion;
155 
156   return EFI_SUCCESS;
157 }
158