newline added at end
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / PlatformBds / Generic / DeviceMngr / DeviceManager.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name: \r
13 \r
14   DeviceManager.c\r
15 \r
16 Abstract:\r
17 \r
18   The platform device manager reference implement\r
19 \r
20 --*/\r
21 #include "DeviceManager.h"\r
22 \r
23 STATIC UINT16                     mTokenCount;\r
24 EFI_FRONTPAGE_CALLBACK_INFO       FPCallbackInfo;\r
25 extern UINTN                      gCallbackKey;\r
26 extern EFI_FORM_BROWSER_PROTOCOL  *gBrowser;\r
27 extern EFI_GUID                   gBdsStringPackGuid;\r
28 extern BOOLEAN                    gConnectAllHappened;\r
29 \r
30 STRING_REF                        gStringTokenTable[] = {\r
31   STR_VIDEO_DEVICE,\r
32   STR_NETWORK_DEVICE,\r
33   STR_INPUT_DEVICE,\r
34   STR_ON_BOARD_DEVICE,\r
35   STR_OTHER_DEVICE,\r
36   STR_EMPTY_STRING,\r
37   0xFFFF\r
38 };\r
39 \r
40 EFI_STATUS\r
41 EFIAPI\r
42 DeviceManagerCallbackRoutine (\r
43   IN EFI_FORM_CALLBACK_PROTOCOL       *This,\r
44   IN UINT16                           KeyValue,\r
45   IN EFI_IFR_DATA_ARRAY               *DataArray,\r
46   OUT EFI_HII_CALLBACK_PACKET         **Packet\r
47   )\r
48 /*++\r
49 \r
50 Routine Description:\r
51 \r
52   This is the function that is called to provide results data to the driver.  This data\r
53   consists of a unique key which is used to identify what data is either being passed back\r
54   or being asked for. \r
55 \r
56 Arguments:\r
57 \r
58   KeyValue -        A unique value which is sent to the original exporting driver so that it\r
59                     can identify the type of data to expect.  The format of the data tends to\r
60                     vary based on the op-code that geerated the callback.\r
61 \r
62   Data -            A pointer to the data being sent to the original exporting driver.\r
63 \r
64 Returns: \r
65 \r
66 --*/\r
67 {\r
68   //\r
69   // The KeyValue corresponds in this case to the handle which was requested to be displayed\r
70   //\r
71   EFI_FRONTPAGE_CALLBACK_INFO *CallbackInfo;\r
72 \r
73   CallbackInfo = EFI_FP_CALLBACK_DATA_FROM_THIS (This);\r
74   switch (KeyValue) {\r
75   case 0x2000:\r
76     CallbackInfo->Data.VideoBIOS = (UINT8) (UINTN) (((EFI_IFR_DATA_ENTRY *)(DataArray + 1))->Data);\r
77     gRT->SetVariable (\r
78           L"VBIOS",\r
79           &gEfiGlobalVariableGuid,\r
80           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
81           sizeof (UINT8),\r
82           &CallbackInfo->Data.VideoBIOS\r
83           );\r
84     break;\r
85 \r
86   default:\r
87     break;\r
88   }\r
89 \r
90   gCallbackKey = KeyValue;\r
91   return EFI_SUCCESS;\r
92 }\r
93 \r
94 EFI_STATUS\r
95 InitializeDeviceManager (\r
96   VOID\r
97   )\r
98 /*++\r
99 \r
100 Routine Description:\r
101 \r
102   Initialize HII information for the FrontPage\r
103 \r
104 Arguments:\r
105   None\r
106             \r
107 Returns:\r
108 \r
109 --*/\r
110 {\r
111   EFI_STATUS          Status;\r
112   EFI_HII_PACKAGES    *PackageList;\r
113   EFI_HII_UPDATE_DATA *UpdateData;\r
114 \r
115   //\r
116   // Allocate space for creation of UpdateData Buffer\r
117   //\r
118   UpdateData = AllocateZeroPool (0x1000);\r
119   ASSERT (UpdateData != NULL);\r
120 \r
121   PackageList = PreparePackages (1, &gBdsStringPackGuid, DeviceManagerVfrBin);\r
122   Status      = Hii->NewPack (Hii, PackageList, &FPCallbackInfo.DevMgrHiiHandle);\r
123   gBS->FreePool (PackageList);\r
124 \r
125   //\r
126   // This example does not implement worker functions for the NV accessor functions.  Only a callback evaluator\r
127   //\r
128   FPCallbackInfo.Signature                = EFI_FP_CALLBACK_DATA_SIGNATURE;\r
129   FPCallbackInfo.DevMgrCallback.NvRead    = NULL;\r
130   FPCallbackInfo.DevMgrCallback.NvWrite   = NULL;\r
131   FPCallbackInfo.DevMgrCallback.Callback  = DeviceManagerCallbackRoutine;\r
132 \r
133   //\r
134   // Install protocol interface\r
135   //\r
136   FPCallbackInfo.CallbackHandle = NULL;\r
137 \r
138   Status = gBS->InstallProtocolInterface (\r
139                   &FPCallbackInfo.CallbackHandle,\r
140                   &gEfiFormCallbackProtocolGuid,\r
141                   EFI_NATIVE_INTERFACE,\r
142                   &FPCallbackInfo.DevMgrCallback\r
143                   );\r
144 \r
145   ASSERT_EFI_ERROR (Status);\r
146 \r
147   //\r
148   // Flag update pending in FormSet\r
149   //\r
150   UpdateData->FormSetUpdate = TRUE;\r
151   //\r
152   // Register CallbackHandle data for FormSet\r
153   //\r
154   UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) FPCallbackInfo.CallbackHandle;\r
155   //\r
156   // Simply registering the callback handle\r
157   //\r
158   Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
159 \r
160   gBS->FreePool (UpdateData);\r
161   return Status;\r
162 }\r
163 \r
164 EFI_STATUS\r
165 CallDeviceManager (\r
166   VOID\r
167   )\r
168 /*++\r
169 \r
170 Routine Description:\r
171   \r
172   Call the browser and display the device manager\r
173 \r
174 Arguments:\r
175   \r
176   None\r
177   \r
178 Returns:\r
179   EFI_SUCCESS            - Operation is successful.\r
180   EFI_INVALID_PARAMETER  - If the inputs to SendForm function is not valid.\r
181   \r
182 --*/\r
183 {\r
184   EFI_STATUS          Status;\r
185   UINTN               BufferSize;\r
186   UINTN               Count;\r
187   EFI_HII_HANDLE      Index;\r
188   UINT8               *Buffer;\r
189   EFI_IFR_FORM_SET    *FormSetData;\r
190   CHAR16              *String;\r
191   UINTN               StringLength;\r
192   EFI_HII_UPDATE_DATA *UpdateData;\r
193   STRING_REF          Token;\r
194   STRING_REF          TokenHelp;\r
195   IFR_OPTION          *IfrOptionList;\r
196   UINT8               *VideoOption;\r
197   UINTN               VideoOptionSize;\r
198   EFI_HII_HANDLE      *HiiHandles;\r
199   UINT16              HandleBufferLength;\r
200   BOOLEAN                 BootDeviceMngrMenuResetRequired;\r
201 \r
202   IfrOptionList       = NULL;\r
203   VideoOption         = NULL;\r
204   HiiHandles          = NULL;\r
205   HandleBufferLength  = 0;\r
206 \r
207   //\r
208   // Connect all prior to entering the platform setup menu.\r
209   //\r
210   if (!gConnectAllHappened) {\r
211     BdsLibConnectAllDriversToAllControllers ();\r
212     gConnectAllHappened = TRUE;\r
213   }\r
214   //\r
215   // Allocate space for creation of UpdateData Buffer\r
216   //\r
217   UpdateData = AllocateZeroPool (0x1000);\r
218   ASSERT (UpdateData != NULL);\r
219 \r
220   Status        = EFI_SUCCESS;\r
221   Buffer        = NULL;\r
222   FormSetData   = NULL;\r
223   gCallbackKey  = 0;\r
224   if (mTokenCount == 0) {\r
225     Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &mTokenCount, L" ");\r
226   }\r
227 \r
228   Token     = mTokenCount;\r
229   TokenHelp = (UINT16) (Token + 1);\r
230 \r
231   //\r
232   // Reset the menu\r
233   //\r
234   for (Index = 0, Count = 1; Count < 0x10000; Count <<= 1, Index++) {\r
235     //\r
236     // We will strip off all previous menu entries\r
237     //\r
238     UpdateData->DataCount = 0xFF;\r
239 \r
240     //\r
241     // Erase entries on this label\r
242     //\r
243     Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, FALSE, UpdateData);\r
244 \r
245     //\r
246     // Did we reach the end of the Token Table?\r
247     //\r
248     if (gStringTokenTable[Index] == 0xFFFF) {\r
249       break;\r
250     }\r
251 \r
252     CreateSubTitleOpCode (gStringTokenTable[Index], &UpdateData->Data);\r
253     //\r
254     // Add a single menu item - in this case a subtitle for the device type\r
255     //\r
256     UpdateData->DataCount = 1;\r
257 \r
258     //\r
259     // Add default title for this label\r
260     //\r
261     Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
262   }\r
263   //\r
264   // Add a space and an exit string.  Remember since we add things at the label and push other things beyond the\r
265   // label down, we add this in reverse order\r
266   //\r
267   CreateSubTitleOpCode (STRING_TOKEN (STR_EXIT_STRING), &UpdateData->Data);\r
268   Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
269   CreateSubTitleOpCode (STR_EMPTY_STRING, &UpdateData->Data);\r
270   Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) Count, TRUE, UpdateData);\r
271 \r
272   //\r
273   // Get all the Hii handles\r
274   //\r
275   Status = BdsLibGetHiiHandles (Hii, &HandleBufferLength, &HiiHandles);\r
276   ASSERT_EFI_ERROR (Status);\r
277 \r
278   for (Index = 1, BufferSize = 0; Index < HandleBufferLength; Index++) {\r
279     //\r
280     // Am not initializing Buffer since the first thing checked is the size\r
281     // this way I can get the real buffersize in the smallest code size\r
282     //\r
283     Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer);\r
284 \r
285     if (Status != EFI_NOT_FOUND) {\r
286       //\r
287       // BufferSize should have the real size of the forms now\r
288       //\r
289       Buffer = AllocateZeroPool (BufferSize);\r
290       ASSERT (Buffer != NULL);\r
291 \r
292       //\r
293       // Am not initializing Buffer since the first thing checked is the size\r
294       // this way I can get the real buffersize in the smallest code size\r
295       //\r
296       Status = Hii->GetForms (Hii, Index, 0, &BufferSize, Buffer);\r
297 \r
298       //\r
299       // Skip EFI_HII_PACK_HEADER, advance to EFI_IFR_FORM_SET data.\r
300       //\r
301       FormSetData = (EFI_IFR_FORM_SET *) (Buffer + sizeof (EFI_HII_PACK_HEADER));\r
302 \r
303       //\r
304       // If this formset belongs in the device manager, add it to the menu\r
305       //\r
306       if (FormSetData->Class != EFI_NON_DEVICE_CLASS) {\r
307 \r
308         StringLength  = 0x1000;\r
309         String        = AllocateZeroPool (StringLength);\r
310         ASSERT (String != NULL);\r
311 \r
312         Status  = Hii->GetString (Hii, Index, FormSetData->FormSetTitle, TRUE, NULL, &StringLength, String);\r
313         Status  = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String);\r
314 \r
315         //\r
316         // If token value exceeded real token value - we need to add a new token values\r
317         //\r
318         if (Status == EFI_INVALID_PARAMETER) {\r
319           Token     = 0;\r
320           TokenHelp = 0;\r
321           Status    = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &Token, String);\r
322         }\r
323 \r
324         StringLength = 0x1000;\r
325         if (FormSetData->Help == 0) {\r
326           TokenHelp = 0;\r
327         } else {\r
328           Status = Hii->GetString (Hii, Index, FormSetData->Help, TRUE, NULL, &StringLength, String);\r
329           if (StringLength == 0x02) {\r
330             TokenHelp = 0;\r
331           } else {\r
332             Status = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String);\r
333             if (Status == EFI_INVALID_PARAMETER) {\r
334               TokenHelp = 0;\r
335               Status    = Hii->NewString (Hii, NULL, FPCallbackInfo.DevMgrHiiHandle, &TokenHelp, String);\r
336             }\r
337           }\r
338         }\r
339 \r
340         gBS->FreePool (String);\r
341 \r
342         CreateGotoOpCode (\r
343           0x1000,     // Device Manager Page\r
344           Token,      // Description String Token\r
345           TokenHelp,  // Description Help String Token\r
346           EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS,  // Flag designating callback is active\r
347           (UINT16) Index,                                     // Callback key value\r
348           &UpdateData->Data                                   // Buffer to fill with op-code\r
349           );\r
350 \r
351         //\r
352         // In the off-chance that we have lots of extra tokens allocated to the DeviceManager\r
353         // this ensures we are fairly re-using the tokens instead of constantly growing the token\r
354         // storage for this one handle.  If we incremented the token value beyond what it normally\r
355         // would use, we will fall back into the error path which seeds the token value with a 0\r
356         // so that we can correctly add a token value.\r
357         //\r
358         if (TokenHelp == 0) {\r
359           //\r
360           // Since we didn't add help, only advance Token by 1\r
361           //\r
362           Token++;\r
363         } else {\r
364           Token     = (UINT16) (Token + 2);\r
365           TokenHelp = (UINT16) (TokenHelp + 2);\r
366         }\r
367         //\r
368         // This for loop basically will take the Class value which is a bitmask and\r
369         // update the form for every active bit.  There will be a label at each bit\r
370         // location.  So if someone had a device which a class of EFI_DISK_DEVICE_CLASS |\r
371         // EFI_ON_BOARD_DEVICE_CLASS, this routine will unwind that mask and drop the menu entry\r
372         // on each corresponding label.\r
373         //\r
374         for (Count = 1; Count < 0x10000; Count <<= 1) {\r
375           //\r
376           // This is an active bit, so update the form\r
377           //\r
378           if (FormSetData->Class & Count) {\r
379             Hii->UpdateForm (\r
380                   Hii,\r
381                   FPCallbackInfo.DevMgrHiiHandle,\r
382                   (EFI_FORM_LABEL) (FormSetData->Class & Count),\r
383                   TRUE,\r
384                   UpdateData\r
385                   );\r
386           }\r
387         }\r
388       }\r
389 \r
390       BufferSize = 0;\r
391       //\r
392       // Reset Buffer pointer to original location\r
393       //\r
394       gBS->FreePool (Buffer);\r
395     }\r
396   }\r
397   //\r
398   // Add oneof for video BIOS selection\r
399   //\r
400   VideoOption = BdsLibGetVariableAndSize (\r
401                   L"VBIOS",\r
402                   &gEfiGlobalVariableGuid,\r
403                   &VideoOptionSize\r
404                   );\r
405   if (NULL == VideoOption) {\r
406     FPCallbackInfo.Data.VideoBIOS = 0;\r
407   } else {\r
408     FPCallbackInfo.Data.VideoBIOS = VideoOption[0];\r
409     gBS->FreePool (VideoOption);\r
410   }\r
411 \r
412   ASSERT (FPCallbackInfo.Data.VideoBIOS <= 1);\r
413 \r
414   Status = gBS->AllocatePool (EfiBootServicesData, 2 * sizeof (IFR_OPTION), (VOID**) &IfrOptionList);\r
415   if (IfrOptionList != NULL) {\r
416     IfrOptionList[0].Flags        = EFI_IFR_FLAG_INTERACTIVE;\r
417     IfrOptionList[0].Key          = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000;\r
418     IfrOptionList[0].StringToken  = STRING_TOKEN (STR_ONE_OF_PCI);\r
419     IfrOptionList[0].Value        = 0;\r
420     IfrOptionList[0].OptionString = NULL;\r
421     IfrOptionList[1].Flags        = EFI_IFR_FLAG_INTERACTIVE;\r
422     IfrOptionList[1].Key          = SET_VIDEO_BIOS_TYPE_QUESTION_ID + 0x2000;\r
423     IfrOptionList[1].StringToken  = STRING_TOKEN (STR_ONE_OF_AGP);\r
424     IfrOptionList[1].Value        = 1;\r
425     IfrOptionList[1].OptionString = NULL;\r
426     IfrOptionList[FPCallbackInfo.Data.VideoBIOS].Flags |= EFI_IFR_FLAG_DEFAULT;\r
427 \r
428     CreateOneOfOpCode (\r
429       SET_VIDEO_BIOS_TYPE_QUESTION_ID,\r
430       (UINT8) 1,\r
431       STRING_TOKEN (STR_ONE_OF_VBIOS),\r
432       STRING_TOKEN (STR_ONE_OF_VBIOS_HELP),\r
433       IfrOptionList,\r
434       2,\r
435       &UpdateData->Data\r
436       );\r
437 \r
438     UpdateData->DataCount = 4;\r
439     Hii->UpdateForm (Hii, FPCallbackInfo.DevMgrHiiHandle, (EFI_FORM_LABEL) EFI_VBIOS_CLASS, TRUE, UpdateData);\r
440     gBS->FreePool (IfrOptionList);\r
441   }\r
442 \r
443   BootDeviceMngrMenuResetRequired = FALSE;\r
444   Status = gBrowser->SendForm (\r
445                       gBrowser,\r
446                       TRUE,                             // Use the database\r
447                       &FPCallbackInfo.DevMgrHiiHandle,  // The HII Handle\r
448                       1,\r
449                       NULL,\r
450                       FPCallbackInfo.CallbackHandle,\r
451                       (UINT8 *) &FPCallbackInfo.Data,\r
452                       NULL,\r
453                       &BootDeviceMngrMenuResetRequired\r
454                       );\r
455 \r
456   if (BootDeviceMngrMenuResetRequired) {\r
457     EnableResetRequired ();\r
458   }\r
459 \r
460   Hii->ResetStrings (Hii, FPCallbackInfo.DevMgrHiiHandle);\r
461 \r
462   //\r
463   // We will have returned from processing a callback - user either hit ESC to exit, or selected\r
464   // a target to display\r
465   //\r
466   if (gCallbackKey != 0 && gCallbackKey < 0x2000) {\r
467     BootDeviceMngrMenuResetRequired = FALSE;\r
468     Status = gBrowser->SendForm (\r
469                         gBrowser,\r
470                         TRUE,                             // Use the database\r
471                         (EFI_HII_HANDLE *) &gCallbackKey, // The HII Handle\r
472                         1,\r
473                         NULL,\r
474                         NULL,                             // This is the handle that the interface to the callback was installed on\r
475                         NULL,\r
476                         NULL,\r
477                         &BootDeviceMngrMenuResetRequired\r
478                         );\r
479 \r
480     if (BootDeviceMngrMenuResetRequired) {\r
481       EnableResetRequired ();\r
482     }\r
483     //\r
484     // Force return to Device Manager\r
485     //\r
486     gCallbackKey = 4;\r
487   }\r
488 \r
489   if (gCallbackKey >= 0x2000) {\r
490     gCallbackKey = 4;\r
491   }\r
492 \r
493   gBS->FreePool (UpdateData);\r
494   gBS->FreePool (HiiHandles);\r
495 \r
496   return Status;\r
497 }\r