Rename Protocol/FrameworkHii.h to Protocol/HiiFramework.h to follow the naming conven...
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / DriverSampleDxe / DriverSample.c
CommitLineData
103b6520 1/*++\r
2Copyright (c) 2006 - 2007, Intel Corporation \r
3All rights reserved. This program and the accompanying materials \r
4are licensed and made available under the terms and conditions of the BSD License \r
5which accompanies this distribution. The full text of the license may be found at \r
6http://opensource.org/licenses/bsd-license.php \r
7 \r
8THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
9WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
10\r
11Module Name:\r
12 DriverSample.c\r
13\r
14Abstract:\r
15\r
16 This is an example of how a driver might export data to the HII protocol to be \r
17 later utilized by the Setup Protocol\r
18\r
19--*/\r
20\r
21//\r
22// Include common header file for this module.\r
23//\r
24#include "CommonHeader.h"\r
25\r
26#include "DriverSample.h"\r
27\r
28#define DISPLAY_ONLY_MY_ITEM 0x0001\r
29\r
30#define STRING_PACK_GUID \\r
31 { \\r
32 0x8160a85f, 0x934d, 0x468b, { 0xa2, 0x35, 0x72, 0x89, 0x59, 0x14, 0xf6, 0xfc } \\r
33 }\r
34\r
35EFI_GUID mFormSetGuid = FORMSET_GUID;\r
36EFI_GUID mStringPackGuid = STRING_PACK_GUID; \r
37\r
38STATIC\r
39EFI_STATUS\r
40EFIAPI\r
41DriverCallback (\r
42 IN EFI_FORM_CALLBACK_PROTOCOL *This,\r
43 IN UINT16 KeyValue,\r
44 IN EFI_IFR_DATA_ARRAY *Data,\r
45 OUT EFI_HII_CALLBACK_PACKET **Packet\r
46 )\r
47/*++\r
48\r
49Routine Description:\r
50\r
51 This is the function that is called to provide results data to the driver. This data\r
52 consists of a unique key which is used to identify what data is either being passed back\r
53 or being asked for. \r
54\r
55Arguments:\r
56\r
57 KeyValue - A unique value which is sent to the original exporting driver so that it\r
58 can identify the type of data to expect. The format of the data tends to\r
59 vary based on the op-code that geerated the callback.\r
60\r
61 Data - A pointer to the data being sent to the original exporting driver.\r
62\r
63Returns: \r
64\r
65--*/\r
66{\r
67 EFI_CALLBACK_INFO *Private;\r
68 EFI_HII_UPDATE_DATA *UpdateData;\r
69 UINT8 *Location;\r
70 EFI_HII_CALLBACK_PACKET *DataPacket;\r
71 UINT16 Value;\r
72 CHAR16 VariableName[40];\r
73 STATIC UINT16 QuestionId = 0;\r
74 IFR_OPTION *OptionList;\r
75 UINTN Index;\r
76 MyIfrNVData NVStruc;\r
77\r
78 Private = EFI_CALLBACK_INFO_FROM_THIS (This);\r
79\r
80 //\r
81 // This should tell me the first offset AFTER the end of the compiled NV map\r
82 // If op-code results are not going to be saved to NV locations ensure the QuestionId\r
83 // is beyond the end of the NVRAM mapping.\r
84 //\r
85 if (QuestionId == 0) {\r
86 QuestionId = sizeof (MyIfrNVData);\r
87 }\r
88\r
89 ZeroMem (VariableName, (sizeof (CHAR16) * 40));\r
90\r
91 switch (KeyValue) {\r
92 case 0x0001:\r
93 //\r
94 // Create a small boot order list\r
95 //\r
96 QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc));\r
97\r
98 //\r
99 // Need some memory for OptionList. Allow for up to 8 options.\r
100 //\r
101 OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8);\r
102 ASSERT (OptionList != NULL);\r
103\r
104 //\r
105 // Allocate space for creation of Buffer\r
106 //\r
107 UpdateData = AllocateZeroPool (0x1000);\r
108 ASSERT (UpdateData != NULL);\r
109\r
110 //\r
111 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience\r
112 // so we don't have to keep track of how many op-codes we added or subtracted. The rules for removal\r
113 // of op-codes are simply that the removal will always stop as soon as a label or the end of a form is\r
114 // encountered. Therefore, giving a large obnoxious count such as below takes care of other complexities.\r
115 //\r
116 UpdateData->DataCount = 0xFF;\r
117\r
118 //\r
119 // Delete set of op-codes\r
120 //\r
121 Private->Hii->UpdateForm (\r
122 Private->Hii,\r
123 Private->RegisteredHandle,\r
124 (EFI_FORM_LABEL) 0x2222,\r
125 FALSE, // If we aren't adding, we are deleting\r
126 UpdateData\r
127 );\r
128\r
129 //\r
130 // Create 3 options\r
131 //\r
132 for (Index = 0; Index < 3; Index++) {\r
133 OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index);\r
134 OptionList[Index].Value = (UINT16) (Index + 1);\r
135 OptionList[Index].Flags = RESET_REQUIRED;\r
136 }\r
137\r
138 CreateOrderedListOpCode (\r
139 QuestionId, // Question ID\r
140 8, // Max Entries\r
141 (UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt\r
142 (UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help\r
143 OptionList,\r
144 3,\r
145 &UpdateData->Data // Buffer location to place op-codes\r
146 );\r
147\r
148 //\r
149 // For one-of/ordered lists commands, they really consist of 2 op-codes (a header and a footer)\r
150 // Each option within a one-of/ordered list is also an op-code\r
151 // So this example has 5 op-codes it is adding since we have a one-of header + 3 options + one-of footer\r
152 //\r
153 UpdateData->DataCount = 0x5;\r
154\r
155 //\r
156 // Add one op-code\r
157 //\r
158 Private->Hii->UpdateForm (\r
159 Private->Hii,\r
160 Private->RegisteredHandle,\r
161 (EFI_FORM_LABEL) 0x2222,\r
162 TRUE,\r
163 UpdateData\r
164 );\r
165\r
166 FreePool (UpdateData);\r
167 FreePool (OptionList);\r
168 break;\r
169\r
170 case 0x0002:\r
171 //\r
172 // Create a large boot order list\r
173 //\r
174 QuestionId = (UINT16) ((UINTN) (&NVStruc.BootOrder) - (UINTN) (&NVStruc));\r
175\r
176 //\r
177 // Need some memory for OptionList. Allow for up to 8 options.\r
178 //\r
179 OptionList = AllocateZeroPool (sizeof (IFR_OPTION) * 8);\r
180 ASSERT (OptionList != NULL);\r
181\r
182 //\r
183 // Allocate space for creation of Buffer\r
184 //\r
185 UpdateData = AllocateZeroPool (0x1000);\r
186 ASSERT (UpdateData != NULL);\r
187\r
188 //\r
189 // Remove all the op-codes starting with Label 0x2222 to next Label (second label is for convenience\r
190 // so we don't have to keep track of how many op-codes we added or subtracted\r
191 //\r
192 UpdateData->DataCount = 0xFF;\r
193\r
194 //\r
195 // Delete one op-code\r
196 //\r
197 Private->Hii->UpdateForm (\r
198 Private->Hii,\r
199 Private->RegisteredHandle,\r
200 (EFI_FORM_LABEL) 0x2222,\r
201 FALSE,\r
202 UpdateData\r
203 );\r
204\r
205 //\r
206 // Create 4 options\r
207 //\r
208 for (Index = 0; Index < 4; Index++) {\r
209 OptionList[Index].StringToken = (UINT16) (STR_BOOT_OPTION1 + Index);\r
210 OptionList[Index].Value = (UINT16) (Index + 1);\r
211 OptionList[Index].Flags = RESET_REQUIRED;\r
212 }\r
213\r
214 CreateOrderedListOpCode (\r
215 QuestionId, // Question ID\r
216 8, // Max Entries\r
217 (UINT16) STRING_TOKEN (STR_BOOT_OPTIONS), // Token value for the Prompt\r
218 (UINT16) STRING_TOKEN (STR_NULL_STRING), // Token value for the Help\r
219 OptionList,\r
220 4,\r
221 &UpdateData->Data // Buffer location to place op-codes\r
222 );\r
223\r
224 //\r
225 // For one-of commands, they really consist of 2 op-codes (a header and a footer)\r
226 // Each option within a one-of is also an op-code\r
227 // So this example has 6 op-codes it is adding since we have a one-of header + 4 options + one-of footer\r
228 //\r
229 UpdateData->DataCount = 0x6;\r
230\r
231 //\r
232 // Add one op-code\r
233 //\r
234 Private->Hii->UpdateForm (\r
235 Private->Hii,\r
236 Private->RegisteredHandle,\r
237 (EFI_FORM_LABEL) 0x2222,\r
238 TRUE,\r
239 UpdateData\r
240 );\r
241\r
242 FreePool (UpdateData);\r
243 FreePool (OptionList);\r
244 break;\r
245\r
246 case 0x1234:\r
247 //\r
248 // Allocate space for creation of Buffer\r
249 //\r
250 QuestionId = (UINT16) ((UINTN) (&NVStruc.DynamicCheck) - (UINTN) (&NVStruc));\r
251 UpdateData = AllocateZeroPool (0x1000);\r
252 ASSERT (UpdateData != NULL);\r
253\r
254 Location = (UINT8 *) &UpdateData->Data;\r
255\r
256 UpdateData->FormSetUpdate = TRUE;\r
257 UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->CallbackHandle;\r
258 UpdateData->FormUpdate = FALSE;\r
259 UpdateData->FormTitle = 0;\r
260 UpdateData->DataCount = 2;\r
261\r
262 CreateGotoOpCode (\r
263 1,\r
264 STR_GOTO_FORM1, // Token value for the Prompt\r
265 0, // Goto Help\r
266 0, // Flags\r
267 0, // Key\r
268 &UpdateData->Data // Buffer location to place op-codes\r
269 );\r
270\r
271 Location = Location + ((EFI_IFR_OP_HEADER *) &UpdateData->Data)->Length;\r
272\r
273 CreateCheckBoxOpCode (\r
274 QuestionId, // Question ID\r
275 1, // Data width (BOOLEAN = 1)\r
276 (UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_PROMPT), // Token value for the Prompt\r
277 (UINT16) STRING_TOKEN (STR_CHECK_DYNAMIC_HELP), // Token value for the Help\r
278 EFI_IFR_FLAG_INTERACTIVE, // Flags\r
279 0x1236, // Key\r
280 Location // Buffer location to place op-codes\r
281 );\r
282\r
283 Private->Hii->UpdateForm (\r
284 Private->Hii,\r
285 Private->RegisteredHandle,\r
286 (EFI_FORM_LABEL) 0x1234,\r
287 TRUE,\r
288 UpdateData\r
289 );\r
290\r
291 FreePool (UpdateData);\r
292 QuestionId++;\r
293 break;\r
294\r
295 case 0x1235:\r
296 //\r
297 // Allocate space for creation of Buffer\r
298 //\r
299 UpdateData = AllocateZeroPool (0x1000);\r
300 ASSERT (UpdateData != NULL);\r
301\r
302 //\r
303 // Initialize DataPacket with information intended to remove all\r
304 // previously created op-codes in the dynamic page\r
305 //\r
306 UpdateData->FormSetUpdate = FALSE;\r
307 UpdateData->FormCallbackHandle = 0;\r
308 UpdateData->FormUpdate = FALSE;\r
309 UpdateData->FormTitle = 0;\r
310 //\r
311 // Unlikely to be more than 0xff op-codes in the dynamic page to remove\r
312 //\r
313 UpdateData->DataCount = 0xff;\r
314 UpdateData->Data = NULL;\r
315\r
316 //\r
317 // Remove all op-codes from dynamic page\r
318 //\r
319 Private->Hii->UpdateForm (\r
320 Private->Hii,\r
321 Private->RegisteredHandle,\r
322 (EFI_FORM_LABEL) 0x1234, // Label 0x1234\r
323 FALSE, // Remove Op-codes (will never remove form/endform)\r
324 UpdateData // Significant value is UpdateData->DataCount\r
325 );\r
326\r
327 UpdateData->FormSetUpdate = FALSE;\r
328 UpdateData->FormCallbackHandle = 0;\r
329 UpdateData->FormUpdate = FALSE;\r
330 UpdateData->FormTitle = 0;\r
331 UpdateData->DataCount = 1;\r
332\r
333 CreateGotoOpCode (\r
334 1,\r
335 STR_GOTO_FORM1, // Token value for the Prompt\r
336 0, // Goto Help\r
337 0, // Flags\r
338 0, // Key\r
339 &UpdateData->Data // Buffer location to place op-codes\r
340 );\r
341\r
342 Private->Hii->UpdateForm (\r
343 Private->Hii,\r
344 Private->RegisteredHandle,\r
345 (EFI_FORM_LABEL) 0x1234,\r
346 TRUE,\r
347 UpdateData\r
348 );\r
349\r
350 FreePool (UpdateData);\r
351 break;\r
352\r
353 case 0x1236:\r
354 //\r
355 // If I hit the checkbox, I enter this case statement...\r
356 //\r
357 //\r
358 // Since I am returning an error (for test purposes) I need to pass in the string for the error\r
359 // I will allocate space for the return value. If an error occurs (which is the case) I can simply return\r
360 // an error and fill in the string parameter, otherwise, I will return information in the DataArray structure.\r
361 // The browser will free this packet structure\r
362 //\r
363 *Packet = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + sizeof (SAMPLE_STRING) + 2);\r
364 ASSERT (*Packet != NULL);\r
365\r
366 //\r
367 // Assign the buffer address to DataPacket\r
368 //\r
369 DataPacket = *Packet;\r
370\r
371 StrCpy (DataPacket->String, (CHAR16 *) SAMPLE_STRING);\r
372 return EFI_DEVICE_ERROR;\r
373\r
374 case 0x1237:\r
375\r
376 *Packet = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2);\r
377 ASSERT (*Packet != NULL);\r
378\r
379 //\r
380 // Assign the buffer address to DataPacket\r
381 //\r
382 DataPacket = *Packet;\r
383\r
384 DataPacket->DataArray.EntryCount = 1;\r
385 DataPacket->DataArray.NvRamMap = NULL;\r
386 ((EFI_IFR_DATA_ENTRY *) (&DataPacket->DataArray + 1))->Flags = EXIT_REQUIRED;\r
387 break;\r
388\r
389 case 0x1555:\r
390 Value = 0x0001;\r
391 UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);\r
392\r
393 gRT->SetVariable (\r
394 VariableName,\r
395 &mFormSetGuid,\r
396 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
397 2,\r
398 (VOID *) &Value\r
399 );\r
400 break;\r
401\r
402 case 0x1556:\r
403 Value = 0x1000;\r
404 UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);\r
405\r
406 gRT->SetVariable (\r
407 VariableName,\r
408 &mFormSetGuid,\r
409 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
410 2,\r
411 (VOID *) &Value\r
412 );\r
413 break;\r
414\r
415 case 0x1557:\r
416 Value = 0x0000;\r
417 UnicodeSPrint (VariableName, 0x80, (CHAR16 *) L"%d", VAR_EQ_TEST_NAME);\r
418\r
419 gRT->SetVariable (\r
420 VariableName,\r
421 &mFormSetGuid,\r
422 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
423 2,\r
424 (VOID *) &Value\r
425 );\r
426 break;\r
427\r
428 default:\r
429 break;\r
430 }\r
431\r
432 return EFI_SUCCESS;\r
433}\r
434\r
435EFI_STATUS\r
436EFIAPI\r
437DriverSampleInit (\r
438 IN EFI_HANDLE ImageHandle,\r
439 IN EFI_SYSTEM_TABLE *SystemTable\r
440 )\r
441{\r
442 EFI_STATUS Status;\r
443 EFI_HII_PROTOCOL *Hii;\r
444 //\r
445 // EFI_FORM_BROWSER_PROTOCOL *FormConfig;\r
446 //\r
447 EFI_HII_PACKAGES *PackageList;\r
448 EFI_HII_HANDLE HiiHandle;\r
449 STRING_REF TokenToUpdate;\r
450 STRING_REF TokenToUpdate2;\r
451 STRING_REF TokenToUpdate3;\r
452 CHAR16 *NewString;\r
453 EFI_HII_UPDATE_DATA *UpdateData;\r
454 EFI_CALLBACK_INFO *CallbackInfo;\r
455 EFI_HANDLE Handle;\r
456 EFI_SCREEN_DESCRIPTOR Screen;\r
457\r
458 ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));\r
459\r
460 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);\r
461\r
462 //\r
463 // Remove 3 characters from top and bottom\r
464 //\r
465 Screen.TopRow = 3;\r
466 Screen.BottomRow = Screen.BottomRow - 3;\r
467\r
468 //\r
469 // There should only be one HII protocol\r
470 //\r
471 Status = gBS->LocateProtocol (\r
472 &gEfiHiiProtocolGuid,\r
473 NULL,\r
474 (VOID **) &Hii\r
475 );\r
476 if (EFI_ERROR (Status)) {\r
477 return Status;;\r
478 }\r
479\r
480 CallbackInfo = AllocatePool (sizeof (EFI_CALLBACK_INFO));\r
481 if (CallbackInfo == NULL) {\r
482 return EFI_OUT_OF_RESOURCES;\r
483 }\r
484\r
485 CallbackInfo->Signature = EFI_CALLBACK_INFO_SIGNATURE;\r
486 CallbackInfo->Hii = Hii;\r
487\r
488 //\r
489 // This example does not implement worker functions for the NV accessor functions. Only a callback evaluator\r
490 //\r
491 CallbackInfo->DriverCallback.NvRead = NULL;\r
492 CallbackInfo->DriverCallback.NvWrite = NULL;\r
493 CallbackInfo->DriverCallback.Callback = DriverCallback;\r
494\r
495 //\r
496 // Install protocol interface\r
497 //\r
498 Handle = NULL;\r
499 Status = gBS->InstallProtocolInterface (\r
500 &Handle,\r
501 &gEfiFormCallbackProtocolGuid,\r
502 EFI_NATIVE_INTERFACE,\r
503 &CallbackInfo->DriverCallback\r
504 );\r
505\r
506 ASSERT_EFI_ERROR (Status);\r
507\r
508 CallbackInfo->CallbackHandle = Handle;\r
509\r
510 PackageList = PreparePackages (1, &mStringPackGuid, DriverSampleStrings);\r
511 Status = Hii->NewPack (Hii, PackageList, &HiiHandle);\r
512 FreePool (PackageList);\r
513\r
514 PackageList = PreparePackages (1, &mStringPackGuid, InventoryBin);\r
515 Status = Hii->NewPack (Hii, PackageList, &HiiHandle);\r
516 FreePool (PackageList);\r
517\r
518 PackageList = PreparePackages (1, &mStringPackGuid, VfrBin);\r
519 Status = Hii->NewPack (Hii, PackageList, &HiiHandle);\r
520 FreePool (PackageList);\r
521\r
522 CallbackInfo->RegisteredHandle = HiiHandle;\r
523\r
524 //\r
525 // Very simple example of how one would update a string that is already\r
526 // in the HII database\r
527 //\r
528 TokenToUpdate = (STRING_REF) STR_CPU_STRING2;\r
529 NewString = (CHAR16 *) L"700 Mhz";\r
530\r
531 Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, NewString);\r
532\r
533 //\r
534 // Add a string - if 0 will be updated with new Token number\r
535 //\r
536 TokenToUpdate = (STRING_REF) 0;\r
537\r
538 //\r
539 // Add a string - if 0 will be updated with new Token number\r
540 //\r
541 TokenToUpdate2 = (STRING_REF) 0;\r
542\r
543 //\r
544 // Add a string - if 0 will be updated with new Token number\r
545 //\r
546 TokenToUpdate3 = (STRING_REF) 0;\r
547\r
548 Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate, (CHAR16 *) L"Desired Speed");\r
549 Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate2, (CHAR16 *) L"5 Thz");\r
550 Hii->NewString (Hii, NULL, HiiHandle, &TokenToUpdate3, (CHAR16 *) L"This is next year's desired speed - right?");\r
551\r
552 //\r
553 // Allocate space for creation of Buffer\r
554 //\r
555 UpdateData = AllocateZeroPool (0x1000);\r
556 ASSERT (UpdateData != NULL);\r
557\r
558 //\r
559 // Flag update pending in FormSet\r
560 //\r
561 UpdateData->FormSetUpdate = TRUE;\r
562 //\r
563 // Register CallbackHandle data for FormSet\r
564 //\r
565 UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;\r
566 UpdateData->FormUpdate = FALSE;\r
567 UpdateData->FormTitle = 0;\r
568 UpdateData->DataCount = 1;\r
569\r
570 CreateTextOpCode (TokenToUpdate, TokenToUpdate2, TokenToUpdate3, 0, 0, &UpdateData->Data);\r
571\r
572 Hii->UpdateForm (Hii, HiiHandle, (EFI_FORM_LABEL) 100, TRUE, UpdateData);\r
573\r
574 FreePool (UpdateData);\r
575\r
576 //\r
577 // Example of how to display only the item we sent to HII\r
578 //\r
579 if (DISPLAY_ONLY_MY_ITEM == 0x0001) {\r
580 //\r
581 // Have the browser pull out our copy of the data, and only display our data\r
582 //\r
583 // Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL);\r
584 //\r
585 } else {\r
586 //\r
587 // Have the browser pull out all the data in the HII Database and display it.\r
588 //\r
589 // Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL);\r
590 //\r
591 }\r
592\r
593 if (EFI_ERROR (Status)) {\r
594 return Status;\r
595 }\r
596\r
597 return EFI_SUCCESS;\r
598}\r