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