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