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