]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Add support for HII
authorMichael Brown <mcb30@ipxe.org>
Thu, 7 Apr 2011 22:03:05 +0000 (23:03 +0100)
committerMichael Brown <mcb30@ipxe.org>
Thu, 7 Apr 2011 22:15:07 +0000 (23:15 +0100)
Some EFI platforms expect us to provide an HII interface to display
information about the driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h [new file with mode: 0644]
src/include/ipxe/efi/Guid/MdeModuleHii.h [new file with mode: 0644]
src/include/ipxe/efi/Protocol/FormBrowser2.h [new file with mode: 0644]
src/include/ipxe/efi/Protocol/HiiConfigAccess.h [new file with mode: 0644]
src/include/ipxe/efi/Protocol/HiiDatabase.h [new file with mode: 0644]
src/include/ipxe/efi/efi_hii.h [new file with mode: 0644]
src/interface/efi/efi_snp.c

diff --git a/src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h b/src/include/ipxe/efi/Guid/HiiPlatformSetupFormset.h
new file mode 100644 (file)
index 0000000..fa81736
--- /dev/null
@@ -0,0 +1,37 @@
+/** @file
+  GUID indicates that the form set contains forms designed to be used
+  for platform configuration and this form set will be displayed.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+  @par Revision Reference:
+  GUID defined in UEFI 2.1.
+
+**/
+
+#ifndef __HII_PLATFORM_SETUP_FORMSET_GUID_H__
+#define __HII_PLATFORM_SETUP_FORMSET_GUID_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \
+  { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } }
+
+#define EFI_HII_DRIVER_HEALTH_FORMSET_GUID \
+  { 0xf22fc20c, 0x8cf4, 0x45eb, { 0x8e, 0x6, 0xad, 0x4e, 0x50, 0xb9, 0x5d, 0xd3 } }
+
+#define EFI_HII_USER_CREDENTIAL_FORMSET_GUID \
+  { 0x337f4407, 0x5aee, 0x4b83, { 0xb2, 0xa7, 0x4e, 0xad, 0xca, 0x30, 0x88, 0xcd } }
+
+extern EFI_GUID gEfiHiiPlatformSetupFormsetGuid;
+extern EFI_GUID gEfiHiiDriverHealthFormsetGuid;
+extern EFI_GUID gEfiHiiUserCredentialFormsetGuid;
+
+#endif
diff --git a/src/include/ipxe/efi/Guid/MdeModuleHii.h b/src/include/ipxe/efi/Guid/MdeModuleHii.h
new file mode 100644 (file)
index 0000000..76890b7
--- /dev/null
@@ -0,0 +1,222 @@
+/** @file
+  EDKII extented HII IFR guid opcodes.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __MDEMODULE_HII_H__
+#define __MDEMODULE_HII_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define NARROW_CHAR         0xFFF0
+#define WIDE_CHAR           0xFFF1
+#define NON_BREAKING_CHAR   0xFFF2
+
+///
+/// State defined for password statemachine .
+///
+#define BROWSER_STATE_VALIDATE_PASSWORD  0
+#define BROWSER_STATE_SET_PASSWORD       1
+
+///
+/// GUIDed opcodes defined for EDKII implementation.
+///
+#define EFI_IFR_TIANO_GUID \
+  { 0xf0b1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce} }
+
+#pragma pack(1)
+
+///
+/// EDKII implementation extension opcodes, new extension can be added here later.
+///
+#define EFI_IFR_EXTEND_OP_LABEL       0x0
+#define EFI_IFR_EXTEND_OP_BANNER      0x1
+#define EFI_IFR_EXTEND_OP_TIMEOUT     0x2
+#define EFI_IFR_EXTEND_OP_CLASS       0x3
+#define EFI_IFR_EXTEND_OP_SUBCLASS    0x4
+
+///
+/// Label opcode.
+///
+typedef struct _EFI_IFR_GUID_LABEL {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_LABEL.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// Label Number.
+  ///
+  UINT16              Number;
+} EFI_IFR_GUID_LABEL;
+
+#define EFI_IFR_BANNER_ALIGN_LEFT     0
+#define EFI_IFR_BANNER_ALIGN_CENTER   1
+#define EFI_IFR_BANNER_ALIGN_RIGHT    2
+
+///
+/// Banner opcode.
+///
+typedef struct _EFI_IFR_GUID_BANNER {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_BANNER
+  ///
+  UINT8               ExtendOpCode;
+  EFI_STRING_ID       Title;        ///< The string token for the banner title.
+  UINT16              LineNumber;   ///< 1-based line number.
+  UINT8               Alignment;    ///< left, center, or right-aligned.
+} EFI_IFR_GUID_BANNER;
+
+///
+/// Timeout opcode.
+///
+typedef struct _EFI_IFR_GUID_TIMEOUT {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_TIMEOUT.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              TimeOut;       ///< TimeOut Value.
+} EFI_IFR_GUID_TIMEOUT;
+
+#define EFI_NON_DEVICE_CLASS              0x00
+#define EFI_DISK_DEVICE_CLASS             0x01
+#define EFI_VIDEO_DEVICE_CLASS            0x02
+#define EFI_NETWORK_DEVICE_CLASS          0x04
+#define EFI_INPUT_DEVICE_CLASS            0x08
+#define EFI_ON_BOARD_DEVICE_CLASS         0x10
+#define EFI_OTHER_DEVICE_CLASS            0x20
+
+///
+/// Device Class opcode.
+///
+typedef struct _EFI_IFR_GUID_CLASS {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_CLASS.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              Class;           ///< Device Class from the above.
+} EFI_IFR_GUID_CLASS;
+
+#define EFI_SETUP_APPLICATION_SUBCLASS    0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS  0x01
+#define EFI_FRONT_PAGE_SUBCLASS           0x02
+#define EFI_SINGLE_USE_SUBCLASS           0x03
+
+///
+/// SubClass opcode
+///
+typedef struct _EFI_IFR_GUID_SUBCLASS {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_TIANO_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_SUBCLASS.
+  ///
+  UINT8               ExtendOpCode;
+  UINT16              SubClass;      ///< Sub Class type from the above.
+} EFI_IFR_GUID_SUBCLASS;
+
+///
+/// GUIDed opcodes support for framework vfr.
+///
+#define EFI_IFR_FRAMEWORK_GUID \
+  { 0x31ca5d1a, 0xd511, 0x4931, { 0xb7, 0x82, 0xae, 0x6b, 0x2b, 0x17, 0x8c, 0xd7 } }
+
+///
+/// Two extended opcodes are added, and new extensions can be added here later.
+/// One is for framework OneOf question Option Key value;
+/// another is for framework vareqval.
+///
+#define EFI_IFR_EXTEND_OP_OPTIONKEY   0x0
+#define EFI_IFR_EXTEND_OP_VAREQNAME   0x1
+
+///
+/// Store the framework vfr option key value.
+///
+typedef struct _EFI_IFR_GUID_OPTIONKEY {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_FRAMEWORK_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_OPTIONKEY.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// OneOf Questiond ID binded by OneOf Option.
+  ///
+  EFI_QUESTION_ID     QuestionId;
+  ///
+  /// The OneOf Option Value.
+  ///
+  EFI_IFR_TYPE_VALUE  OptionValue;
+  ///
+  /// The Framework OneOf Option Key Value.
+  ///
+  UINT16              KeyValue;
+} EFI_IFR_GUID_OPTIONKEY;
+
+///
+/// Store the framework vfr vareqval name number.
+///
+typedef struct _EFI_IFR_GUID_VAREQNAME {
+  EFI_IFR_OP_HEADER   Header;
+  ///
+  /// EFI_IFR_FRAMEWORK_GUID.
+  ///
+  EFI_GUID            Guid;
+  ///
+  /// EFI_IFR_EXTEND_OP_VAREQNAME.
+  ///
+  UINT8               ExtendOpCode;
+  ///
+  /// Question ID of the Numeric Opcode created.
+  ///
+  EFI_QUESTION_ID     QuestionId;
+  ///
+  /// For vareqval (0x100), NameId is 0x100.
+  /// This value will convert to a Unicode String following this rule;
+  ///            sprintf(StringBuffer, "%d", NameId) .
+  /// The the Unicode String will be used as a EFI Variable Name.
+  ///
+  UINT16              NameId;
+} EFI_IFR_GUID_VAREQNAME;
+
+#pragma pack()
+
+extern EFI_GUID gEfiIfrTianoGuid;
+extern EFI_GUID gEfiIfrFrameworkGuid;
+
+#endif
+
diff --git a/src/include/ipxe/efi/Protocol/FormBrowser2.h b/src/include/ipxe/efi/Protocol/FormBrowser2.h
new file mode 100644 (file)
index 0000000..6befec6
--- /dev/null
@@ -0,0 +1,177 @@
+/** @file
+  This protocol is defined in UEFI spec.
+
+  The EFI_FORM_BROWSER2_PROTOCOL is the interface to call for drivers to
+  leverage the EFI configuration driver interface.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_FORM_BROWSER2_H__
+#define __EFI_FORM_BROWSER2_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Guid/HiiPlatformSetupFormset.h>
+
+#define EFI_FORM_BROWSER2_PROTOCOL_GUID \
+  {0xb9d4c360, 0xbcfb, 0x4f9b, {0x92, 0x98, 0x53, 0xc1, 0x36, 0x98, 0x22, 0x58 }}
+
+
+typedef struct _EFI_FORM_BROWSER2_PROTOCOL   EFI_FORM_BROWSER2_PROTOCOL;
+
+
+
+/**
+
+  @param LeftColumn   The value that designates the text column
+                      where the browser window will begin from
+                      the left-hand side of the screen
+
+  @param RightColumn  The value that designates the text
+                      column where the browser window will end
+                      on the right-hand side of the screen.
+
+  @param TopRow       The value that designates the text row from the
+                      top of the screen where the browser window
+                      will start.
+
+  @param BottomRow    The value that designates the text row from the
+                      bottom of the screen where the browser
+                      window will end.
+**/
+typedef struct {
+  UINTN   LeftColumn;
+  UINTN   RightColumn;
+  UINTN   TopRow;
+  UINTN   BottomRow;
+} EFI_SCREEN_DESCRIPTOR;
+
+typedef UINTN EFI_BROWSER_ACTION_REQUEST;
+
+#define EFI_BROWSER_ACTION_REQUEST_NONE   0
+#define EFI_BROWSER_ACTION_REQUEST_RESET  1
+#define EFI_BROWSER_ACTION_REQUEST_SUBMIT 2
+#define EFI_BROWSER_ACTION_REQUEST_EXIT   3
+
+
+/**
+  Initialize the browser to display the specified configuration forms.
+
+  This function is the primary interface to the internal forms-based browser.
+  The forms browser will display forms associated with the specified Handles.
+  The browser will select all forms in packages which have the specified Type
+  and (for EFI_HII_PACKAGE_TYPE_GUID) the specified PackageGuid.
+
+  @param This            A pointer to the EFI_FORM_BROWSER2_PROTOCOL instance
+
+  @param Handles         A pointer to an array of Handles. This value should correspond
+                         to the value of the HII form package that is required to be displayed.
+
+  @param HandleCount     The number of Handles specified in Handle.
+
+  @param FormSetGuid     This field points to the EFI_GUID which must match the Guid field or one of the
+                         elements of the ClassId field  in the EFI_IFR_FORM_SET op-code.  If
+                         FormsetGuid is NULL, then this function will display the the form set class
+                         EFI_HII_PLATFORM_SETUP_FORMSET_GUID.
+
+  @param FormId          This field specifies the identifier of the form within the form set to render as the first
+                         displayable page. If this field has a value of 0x0000, then the Forms Browser will
+                         render the first enabled form in the form set.
+
+  @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in
+                          characters.
+
+  @param ActionRequest   Points to the action recommended by the form.
+
+  @retval EFI_SUCCESS           The function completed successfully
+
+  @retval EFI_NOT_FOUND         The variable was not found.
+
+  @retval EFI_INVALID_PARAMETER One of the parameters has an
+                                invalid value.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SEND_FORM2)(
+  IN CONST  EFI_FORM_BROWSER2_PROTOCOL  *This,
+  IN        EFI_HII_HANDLE              *Handle,
+  IN        UINTN                      HandleCount,
+  IN        EFI_GUID                   *FormSetGuid, OPTIONAL
+  IN        EFI_FORM_ID                FormId, OPTIONAL
+  IN CONST  EFI_SCREEN_DESCRIPTOR      *ScreenDimensions, OPTIONAL
+  OUT       EFI_BROWSER_ACTION_REQUEST *ActionRequest  OPTIONAL
+);
+
+
+/**
+  This function is called by a callback handler to retrieve uncommitted state data from the browser.
+
+  This routine is called by a routine which was called by the
+  browser. This routine called this service in the browser to
+  retrieve or set certain uncommitted state information.
+
+  @param This           A pointer to the EFI_FORM_BROWSER2_PROTOCOL instance.
+
+  @param ResultsDataSize  A pointer to the size of the buffer
+                          associated with ResultsData. On input, the size in
+                          bytes of ResultsData. On output, the size of data
+                          returned in ResultsData.
+
+  @param ResultsData    A string returned from an IFR browser or
+                        equivalent. The results string will have
+                        no routing information in them.
+
+  @param RetrieveData   A BOOLEAN field which allows an agent to
+                        retrieve (if RetrieveData = TRUE) data
+                        from the uncommitted browser state
+                        information or set (if RetrieveData =
+                        FALSE) data in the uncommitted browser
+                        state information.
+
+  @param VariableGuid   An optional field to indicate the target
+                        variable GUID name to use.
+
+  @param VariableName   An optional field to indicate the target
+                        human-readable variable name.
+
+  @retval EFI_SUCCESS           The results have been distributed or are
+                                awaiting distribution.
+
+  @retval EFI_OUT_OF_RESOURCES  The ResultsDataSize specified
+                                was too small to contain the
+                                results data.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BROWSER_CALLBACK2)(
+  IN CONST  EFI_FORM_BROWSER2_PROTOCOL *This,
+  IN OUT    UINTN                     *ResultsDataSize,
+  IN OUT    EFI_STRING                ResultsData,
+  IN CONST  BOOLEAN                   RetrieveData,
+  IN CONST  EFI_GUID                  *VariableGuid, OPTIONAL
+  IN CONST  CHAR16                    *VariableName OPTIONAL
+);
+
+///
+/// This interface will allow the caller to direct the configuration
+/// driver to use either the HII database or use the passed-in packet of data.
+///
+struct _EFI_FORM_BROWSER2_PROTOCOL {
+  EFI_SEND_FORM2         SendForm;
+  EFI_BROWSER_CALLBACK2  BrowserCallback;
+} ;
+
+extern EFI_GUID gEfiFormBrowser2ProtocolGuid;
+
+#endif
+
diff --git a/src/include/ipxe/efi/Protocol/HiiConfigAccess.h b/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
new file mode 100644 (file)
index 0000000..2bef5cb
--- /dev/null
@@ -0,0 +1,221 @@
+/** @file
+
+  The EFI HII results processing protocol invokes this type of protocol
+  when it needs to forward results to a driver's configuration handler.
+  This protocol is published by drivers providing and requesting
+  configuration data from HII. It may only be invoked by HII.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __EFI_HII_CONFIG_ACCESS_H__
+#define __EFI_HII_CONFIG_ACCESS_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Protocol/FormBrowser2.h>
+
+#define EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID  \
+  { 0x330d4706, 0xf2a0, 0x4e4f, { 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85 } }
+
+typedef struct _EFI_HII_CONFIG_ACCESS_PROTOCOL  EFI_HII_CONFIG_ACCESS_PROTOCOL;
+
+typedef UINTN EFI_BROWSER_ACTION;
+
+#define EFI_BROWSER_ACTION_CHANGING   0
+#define EFI_BROWSER_ACTION_CHANGED    1
+#define EFI_BROWSER_ACTION_RETRIEVE   2
+#define EFI_BROWSER_ACTION_FORM_OPEN  3
+#define EFI_BROWSER_ACTION_FORM_CLOSE 4
+
+/**
+
+  This function allows the caller to request the current
+  configuration for one or more named elements. The resulting
+  string is in <ConfigAltResp> format. Any and all alternative
+  configuration strings shall also be appended to the end of the
+  current configuration string. If they are, they must appear
+  after the current configuration. They must contain the same
+  routing (GUID, NAME, PATH) as the current configuration string.
+  They must have an additional description indicating the type of
+  alternative configuration the string represents,
+  "ALTCFG=<StringToken>". That <StringToken> (when
+  converted from Hex UNICODE to binary) is a reference to a
+  string in the associated string pack.
+
+  @param This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+  @param Request    A null-terminated Unicode string in
+                    <ConfigRequest> format. Note that this
+                    includes the routing information as well as
+                    the configurable name / value pairs. It is
+                    invalid for this string to be in
+                    <MultiConfigRequest> format.
+                    If a NULL is passed in for the Request field,
+                    all of the settings being abstracted by this function
+                    will be returned in the Results field.  In addition,
+                    if a ConfigHdr is passed in with no request elements,
+                    all of the settings being abstracted for that particular
+                    ConfigHdr reference will be returned in the Results Field.
+
+  @param Progress   On return, points to a character in the
+                    Request string. Points to the string's null
+                    terminator if request was successful. Points
+                    to the most recent "&" before the first
+                    failing name / value pair (or the beginning
+                    of the string if the failure is in the first
+                    name / value pair) if the request was not
+                    successful.
+
+  @param Results    A null-terminated Unicode string in
+                    <MultiConfigAltResp> format which has all values
+                    filled in for the names in the Request string.
+                    String to be allocated by the called function.
+
+  @retval EFI_SUCCESS             The Results string is filled with the
+                                  values corresponding to all requested
+                                  names.
+
+  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
+                                  parts of the results that must be
+                                  stored awaiting possible future
+                                  protocols.
+
+  @retval EFI_NOT_FOUND           Routing data doesn't match any
+                                  known driver. Progress set to the
+                                  first character in the routing header.
+                                  Note: There is no requirement that the
+                                  driver validate the routing data. It
+                                  must skip the <ConfigHdr> in order to
+                                  process the names.
+
+  @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
+                                  to most recent "&" before the
+                                  error or the beginning of the
+                                  string.
+
+  @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
+                                  to the & before the name in
+                                  question.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_HII_ACCESS_EXTRACT_CONFIG)(
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Request,
+  OUT       EFI_STRING                      *Progress,
+  OUT       EFI_STRING                      *Results
+);
+
+
+/**
+
+  This function applies changes in a driver's configuration.
+  Input is a Configuration, which has the routing data for this
+  driver followed by name / value configuration pairs. The driver
+  must apply those pairs to its configurable storage. If the
+  driver's configuration is stored in a linear block of data
+  and the driver's name / value pairs are in <BlockConfig>
+  format, it may use the ConfigToBlock helper function (above) to
+  simplify the job.
+
+  @param This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+
+  @param Configuration  A null-terminated Unicode string in
+                        <ConfigString> format.
+
+  @param Progress       A pointer to a string filled in with the
+                        offset of the most recent '&' before the
+                        first failing name / value pair (or the
+                        beginn ing of the string if the failure
+                        is in the first name / value pair) or
+                        the terminating NULL if all was
+                        successful.
+
+  @retval EFI_SUCCESS             The results have been distributed or are
+                                  awaiting distribution.
+
+  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
+                                  parts of the results that must be
+                                  stored awaiting possible future
+                                  protocols.
+
+  @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
+                                  Results parameter would result
+                                  in this type of error.
+
+  @retval EFI_NOT_FOUND           Target for the specified routing data
+                                  was not found
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_HII_ACCESS_ROUTE_CONFIG)(
+  IN CONST  EFI_HII_CONFIG_ACCESS_PROTOCOL  *This,
+  IN CONST  EFI_STRING                      Configuration,
+  OUT       EFI_STRING                      *Progress
+);
+
+/**
+
+  This function is called to provide results data to the driver.
+  This data consists of a unique key that is used to identify
+  which data is either being passed back or being asked for.
+
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+  @param  Action                 Specifies the type of action taken by the browser.
+  @param  QuestionId             A unique value which is sent to the original
+                                 exporting driver so that it can identify the type
+                                 of data to expect. The format of the data tends to
+                                 vary based on the opcode that generated the callback.
+  @param  Type                   The type of value for the question.
+  @param  Value                  A pointer to the data being sent to the original
+                                 exporting driver.
+  @param  ActionRequest          On return, points to the action requested by the
+                                 callback function.
+
+  @retval EFI_SUCCESS            The callback successfully handled the action.
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
+                                 variable and its data.
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
+                                 callback.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_ACCESS_FORM_CALLBACK)(
+  IN     CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
+  IN     EFI_BROWSER_ACTION                     Action,
+  IN     EFI_QUESTION_ID                        QuestionId,
+  IN     UINT8                                  Type,
+  IN OUT EFI_IFR_TYPE_VALUE                     *Value,
+  OUT    EFI_BROWSER_ACTION_REQUEST             *ActionRequest
+  )
+  ;
+
+///
+/// This protocol provides a callable interface between the HII and
+/// drivers. Only drivers which provide IFR data to HII are required
+/// to publish this protocol.
+///
+struct _EFI_HII_CONFIG_ACCESS_PROTOCOL {
+  EFI_HII_ACCESS_EXTRACT_CONFIG     ExtractConfig;
+  EFI_HII_ACCESS_ROUTE_CONFIG       RouteConfig;
+  EFI_HII_ACCESS_FORM_CALLBACK      Callback;
+} ;
+
+extern EFI_GUID gEfiHiiConfigAccessProtocolGuid;
+
+#endif
+
+
diff --git a/src/include/ipxe/efi/Protocol/HiiDatabase.h b/src/include/ipxe/efi/Protocol/HiiDatabase.h
new file mode 100644 (file)
index 0000000..411ca2c
--- /dev/null
@@ -0,0 +1,519 @@
+/** @file
+  The file provides Database manager for HII-related data
+  structures.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __HII_DATABASE_H__
+#define __HII_DATABASE_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_HII_DATABASE_PROTOCOL_GUID \
+  { 0xef9fc172, 0xa1b2, 0x4693, { 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42 } }
+
+
+typedef struct _EFI_HII_DATABASE_PROTOCOL EFI_HII_DATABASE_PROTOCOL;
+
+
+///
+/// EFI_HII_DATABASE_NOTIFY_TYPE.
+///
+typedef UINTN   EFI_HII_DATABASE_NOTIFY_TYPE;
+
+#define EFI_HII_DATABASE_NOTIFY_NEW_PACK    0x00000001
+#define EFI_HII_DATABASE_NOTIFY_REMOVE_PACK 0x00000002
+#define EFI_HII_DATABASE_NOTIFY_EXPORT_PACK 0x00000004
+#define EFI_HII_DATABASE_NOTIFY_ADD_PACK    0x00000008
+/**
+
+  Functions which are registered to receive notification of
+  database events have this prototype. The actual event is encoded
+  in NotifyType. The following table describes how PackageType,
+  PackageGuid, Handle, and Package are used for each of the
+  notification types.
+
+  @param PackageType  Package type of the notification.
+
+  @param PackageGuid  If PackageType is
+                      EFI_HII_PACKAGE_TYPE_GUID, then this is
+                      the pointer to the GUID from the Guid
+                      field of EFI_HII_PACKAGE_GUID_HEADER.
+                      Otherwise, it must be NULL.
+
+  @param Package      Points to the package referred to by the notification.
+
+  @param Handle       The handle of the package
+                      list which contains the specified package.
+
+  @param NotifyType   The type of change concerning the
+                      database. See
+                      EFI_HII_DATABASE_NOTIFY_TYPE.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_NOTIFY)(
+  IN        UINT8                         PackageType,
+  IN CONST  EFI_GUID                      *PackageGuid,
+  IN CONST  EFI_HII_PACKAGE_HEADER        *Package,
+  IN        EFI_HII_HANDLE                 Handle,
+  IN        EFI_HII_DATABASE_NOTIFY_TYPE  NotifyType
+);
+
+/**
+
+  This function adds the packages in the package list to the
+  database and returns a handle. If there is a
+  EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then
+  this function will create a package of type
+  EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list. For
+  each package in the package list, registered functions with the
+  notification type NEW_PACK and having the same package type will
+  be called. For each call to NewPackageList(), there should be a
+  corresponding call to
+  EFI_HII_DATABASE_PROTOCOL.RemovePackageList().
+
+  @param This           A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageList    A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure.
+
+  @param DriverHandle   Associate the package list with this EFI handle.
+                        If a NULL is specified, this data will not be associate
+                        with any drivers and cannot have a callback induced.
+
+  @param Handle         A pointer to the EFI_HII_HANDLE instance.
+
+  @retval EFI_SUCCESS           The package list associated with the
+                                Handle was added to the HII database.
+
+  @retval EFI_OUT_OF_RESOURCES  Unable to allocate necessary
+                                resources for the new database
+                                contents.
+
+  @retval EFI_INVALID_PARAMETER PackageList is NULL, or Handle is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_NEW_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL   *This,
+  IN CONST  EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+  IN        EFI_HANDLE                  DriverHandle, OPTIONAL
+  OUT       EFI_HII_HANDLE               *Handle
+);
+
+
+/**
+
+  This function removes the package list that is associated with a
+  handle Handle from the HII database. Before removing the
+  package, any registered functions with the notification type
+  REMOVE_PACK and the same package type will be called. For each
+  call to EFI_HII_DATABASE_PROTOCOL.NewPackageList(), there should
+  be a corresponding call to RemovePackageList.
+
+  @param This             A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param Handle           The handle that was registered to the data
+                          that is requested for removal.
+
+  @retval EFI_SUCCESS     The data associated with the Handle was
+                          removed from the HII database.
+  @retval EFI_NOT_FOUND   The specified Handle is not in database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_REMOVE_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HII_HANDLE             Handle
+);
+
+
+/**
+
+  This function updates the existing package list (which has the
+  specified Handle) in the HII databases, using the new package
+  list specified by PackageList. The update process has the
+  following steps: Collect all the package types in the package
+  list specified by PackageList. A package type consists of the
+  Type field of EFI_HII_PACKAGE_HEADER and, if the Type is
+  EFI_HII_PACKAGE_TYPE_GUID, the Guid field, as defined in
+  EFI_HII_PACKAGE_GUID_HEADER. Iterate through the packages within
+  the existing package list in the HII database specified by
+  Handle. If a package's type matches one of the collected types collected
+  in step 1, then perform the following steps:
+  - Call any functions registered with the notification type
+  REMOVE_PACK.
+  - Remove the package from the package list and the HII
+  database.
+  Add all of the packages within the new package list specified
+  by PackageList, using the following steps:
+  - Add the package to the package list and the HII database.
+  - Call any functions registered with the notification type
+  ADD_PACK.
+
+  @param This         A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param Handle       The handle that was registered to the data
+                      that is requested for removal.
+
+  @param PackageList  A pointer to an EFI_HII_PACKAGE_LIST
+                      package.
+
+  @retval EFI_SUCCESS            The HII database was successfully updated.
+
+  @retval EFI_OUT_OF_RESOURCES   Unable to allocate enough memory
+                                 for the updated database.
+
+  @retval EFI_INVALID_PARAMETER  PackageList was NULL.
+  @retval EFI_NOT_FOUND          The specified Handle is not in database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_UPDATE_PACK)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL   *This,
+  IN        EFI_HII_HANDLE               Handle,
+  IN CONST  EFI_HII_PACKAGE_LIST_HEADER *PackageList
+);
+
+
+/**
+
+  This function returns a list of the package handles of the
+  specified type that are currently active in the database. The
+  pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package
+  handles to be listed.
+
+  @param This                 A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageType          Specifies the package type of the packages
+                              to list or EFI_HII_PACKAGE_TYPE_ALL for
+                              all packages to be listed.
+
+  @param PackageGuid          If PackageType is
+                              EFI_HII_PACKAGE_TYPE_GUID, then this is
+                              the pointer to the GUID which must match
+                              the Guid field of
+                              EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
+                              must be NULL.
+
+  @param HandleBufferLength   On input, a pointer to the length
+                              of the handle buffer. On output,
+                              the length of the handle buffer
+                              that is required for the handles found.
+
+  @param Handle               An array of EFI_HII_HANDLE instances returned.
+
+  @retval EFI_SUCCESS           The matching handles are outputed successfully.
+                                HandleBufferLength is updated with the actual length.
+  @retval EFI_BUFFER_TOO_SMALL  The HandleBufferLength parameter
+                                indicates that Handle is too
+                                small to support the number of
+                                handles. HandleBufferLength is
+                                updated with a value that will
+                                enable the data to fit.
+  @retval EFI_NOT_FOUND         No matching handle could be found in database.
+  @retval EFI_INVALID_PARAMETER Handle or HandleBufferLength was NULL.
+  @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but
+                                PackageGuid is not NULL, PackageType is a EFI_HII_
+                                PACKAGE_TYPE_GUID but PackageGuid is NULL.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_LIST_PACKS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        UINT8                     PackageType,
+  IN CONST  EFI_GUID                  *PackageGuid,
+  IN OUT    UINTN                     *HandleBufferLength,
+  OUT       EFI_HII_HANDLE            *Handle
+);
+
+/**
+
+  This function will export one or all package lists in the
+  database to a buffer. For each package list exported, this
+  function will call functions registered with EXPORT_PACK and
+  then copy the package list to the buffer. The registered
+  functions may call EFI_HII_DATABASE_PROTOCOL.UpdatePackageList()
+  to modify the package list before it is copied to the buffer. If
+  the specified BufferSize is too small, then the status
+  EFI_OUT_OF_RESOURCES will be returned and the actual package
+  size will be returned in BufferSize.
+
+  @param This         A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+
+  @param Handle       An EFI_HII_HANDLE  that corresponds to the
+                      desired package list in the HII database to
+                      export or NULL to indicate all package lists
+                      should be exported.
+
+  @param BufferSize   On input, a pointer to the length of the
+                      buffer. On output, the length of the
+                      buffer that is required for the exported
+                      data.
+
+  @param Buffer       A pointer to a buffer that will contain the
+                      results of the export function.
+
+
+  @retval EFI_SUCCESS           Package exported.
+
+  @retval EFI_OUT_OF_RESOURCES  BufferSize is too small to hold the package.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_EXPORT_PACKS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL      *This,
+  IN        EFI_HII_HANDLE                 Handle,
+  IN OUT    UINTN                          *BufferSize,
+  OUT       EFI_HII_PACKAGE_LIST_HEADER    *Buffer
+);
+
+
+/**
+
+
+  This function registers a function which will be called when
+  specified actions related to packages of the specified type
+  occur in the HII database. By registering a function, other
+  HII-related drivers are notified when specific package types
+  are added, removed or updated in the HII database. Each driver
+  or application which registers a notification should use
+  EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before
+  exiting.
+
+
+  @param This             A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param PackageType      The package type. See
+                          EFI_HII_PACKAGE_TYPE_x in EFI_HII_PACKAGE_HEADER.
+
+  @param PackageGuid      If PackageType is
+                          EFI_HII_PACKAGE_TYPE_GUID, then this is
+                          the pointer to the GUID which must match
+                          the Guid field of
+                          EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
+                          must be NULL.
+
+  @param PackageNotifyFn  Points to the function to be called
+                          when the event specified by
+                          NotificationType occurs. See
+                          EFI_HII_DATABASE_NOTIFY.
+
+  @param NotifyType       Describes the types of notification which
+                          this function will be receiving. See
+                          EFI_HII_DATABASE_NOTIFY_TYPE for a
+                          list of types.
+
+  @param NotifyHandle     Points to the unique handle assigned to
+                          the registered notification. Can be used
+                          in EFI_HII_DATABASE_PROTOCOL.UnregisterPack
+                          to stop notifications.
+
+
+  @retval EFI_SUCCESS           Notification registered successfully.
+
+  @retval EFI_OUT_OF_RESOURCES  Unable to allocate necessary
+                                data structures.
+
+  @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when
+                                PackageType is not
+                                EFI_HII_PACKAGE_TYPE_GUID.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_REGISTER_NOTIFY)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL     *This,
+  IN        UINT8                         PackageType,
+  IN CONST  EFI_GUID                      *PackageGuid,
+  IN        EFI_HII_DATABASE_NOTIFY       PackageNotifyFn,
+  IN        EFI_HII_DATABASE_NOTIFY_TYPE  NotifyType,
+  OUT       EFI_HANDLE                    *NotifyHandle
+);
+
+
+/**
+
+  Removes the specified HII database package-related notification.
+
+  @param This                 A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
+
+  @param NotificationHandle   The handle of the notification
+                              function being unregistered.
+
+  @retval EFI_SUCCESS   Successsfully unregistered the notification.
+
+  @retval EFI_NOT_FOUND The incoming notification handle does not exist
+                        in the current hii database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_UNREGISTER_NOTIFY)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HANDLE                NotificationHandle
+);
+
+
+/**
+
+  This routine retrieves an array of GUID values for each keyboard
+  layout that was previously registered in the system.
+
+  @param This                 A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuidBufferLength  On input, a pointer to the length
+                              of the keyboard GUID buffer. On
+                              output, the length of the handle
+                              buffer that is required for the
+                              handles found.
+
+  @param KeyGuidBuffer        An array of keyboard layout GUID
+                              instances returned.
+
+  @retval EFI_SUCCESS           KeyGuidBuffer was updated successfully.
+
+  @retval EFI_BUFFER_TOO_SMALL  The KeyGuidBufferLength
+                                parameter indicates that
+                                KeyGuidBuffer is too small to
+                                support the number of GUIDs.
+                                KeyGuidBufferLength is updated
+                                with a value that will enable
+                                the data to fit.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_FIND_KEYBOARD_LAYOUTS)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN OUT    UINT16                    *KeyGuidBufferLength,
+  OUT       EFI_GUID                  *KeyGuidBuffer
+);
+
+
+/**
+
+  This routine retrieves the requested keyboard layout. The layout
+  is a physical description of the keys on a keyboard, and the
+  character(s) that are associated with a particular set of key
+  strokes.
+
+  @param This                   A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuid                A pointer to the unique ID associated with a
+                                given keyboard layout. If KeyGuid is NULL then
+                                the current layout will be retrieved.
+
+  @param KeyboardLayoutLength   On input, a pointer to the length of the
+                                KeyboardLayout buffer.  On output, the length of
+                                the data placed into KeyboardLayout.
+
+  @param KeyboardLayout         A pointer to a buffer containing the
+                                retrieved keyboard layout.
+
+  @retval EFI_SUCCESS   The keyboard layout was retrieved
+                        successfully.
+
+  @retval EFI_NOT_FOUND The requested keyboard layout was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_GET_KEYBOARD_LAYOUT)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN CONST  EFI_GUID                  *KeyGuid,
+  IN OUT UINT16                       *KeyboardLayoutLength,
+  OUT       EFI_HII_KEYBOARD_LAYOUT   *KeyboardLayout
+);
+
+/**
+
+  This routine sets the default keyboard layout to the one
+  referenced by KeyGuid. When this routine is called, an event
+  will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+  group type. This is so that agents which are sensitive to the
+  current keyboard layout being changed can be notified of this
+  change.
+
+  @param This      A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param KeyGuid   A pointer to the unique ID associated with a
+                   given keyboard layout.
+
+  @retval EFI_SUCCESS    The current keyboard layout was successfully set.
+
+  @retval EFI_NOT_FOUND  The referenced keyboard layout was not
+                         found, so action was taken.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_SET_KEYBOARD_LAYOUT)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN CONST  EFI_GUID                  *KeyGuid
+);
+
+/**
+
+  Return the EFI handle associated with a package list.
+
+  @param This               A pointer to the EFI_HII_PROTOCOL instance.
+
+  @param PackageListHandle  An EFI_HII_HANDLE  that corresponds
+                            to the desired package list in the
+                            HIIdatabase.
+
+  @param DriverHandle       On return, contains the EFI_HANDLE which
+                            was registered with the package list in
+                            NewPackageList().
+
+  @retval EFI_SUCCESS            The DriverHandle was returned successfully.
+
+  @retval EFI_INVALID_PARAMETER  The PackageListHandle was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HII_DATABASE_GET_PACK_HANDLE)(
+  IN CONST  EFI_HII_DATABASE_PROTOCOL *This,
+  IN        EFI_HII_HANDLE             PackageListHandle,
+  OUT       EFI_HANDLE                *DriverHandle
+);
+
+///
+/// Database manager for HII-related data structures.
+///
+struct _EFI_HII_DATABASE_PROTOCOL {
+  EFI_HII_DATABASE_NEW_PACK           NewPackageList;
+  EFI_HII_DATABASE_REMOVE_PACK        RemovePackageList;
+  EFI_HII_DATABASE_UPDATE_PACK        UpdatePackageList;
+  EFI_HII_DATABASE_LIST_PACKS         ListPackageLists;
+  EFI_HII_DATABASE_EXPORT_PACKS       ExportPackageLists;
+  EFI_HII_DATABASE_REGISTER_NOTIFY    RegisterPackageNotify;
+  EFI_HII_DATABASE_UNREGISTER_NOTIFY  UnregisterPackageNotify;
+  EFI_HII_FIND_KEYBOARD_LAYOUTS       FindKeyboardLayouts;
+  EFI_HII_GET_KEYBOARD_LAYOUT         GetKeyboardLayout;
+  EFI_HII_SET_KEYBOARD_LAYOUT         SetKeyboardLayout;
+  EFI_HII_DATABASE_GET_PACK_HANDLE    GetPackageListHandle;
+};
+
+extern EFI_GUID gEfiHiiDatabaseProtocolGuid;
+
+#endif
+
+
diff --git a/src/include/ipxe/efi/efi_hii.h b/src/include/ipxe/efi/efi_hii.h
new file mode 100644 (file)
index 0000000..1a98750
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef _IPXE_EFI_HII_H
+#define _IPXE_EFI_HII_H
+
+/** @file
+ *
+ * EFI human interface infrastructure
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/efi/Uefi/UefiInternalFormRepresentation.h>
+#include <ipxe/efi/Guid/MdeModuleHii.h>
+
+/**
+ * Define an EFI IFR form set type
+ *
+ * @v num_class_guids  Number of class GUIDs
+ * @ret type           Form set type
+ */
+#define EFI_IFR_FORM_SET_TYPE( num_class_guids )                          \
+       struct {                                                           \
+               EFI_IFR_FORM_SET FormSet;                                  \
+               EFI_GUID ClassGuid[num_class_guids];                       \
+       } __attribute__ (( packed ))
+
+/**
+ * Define an EFI IFR form set
+ *
+ * @v guid             GUID
+ * @v title            Title string
+ * @v help             Help string
+ * @v type             Form set type (as returned by EFI_IFR_FORM_SET_TYPE())
+ * @ret ifr            Form set
+ *
+ * This definition opens a new scope, which must be closed by an
+ * EFI_IFR_END().
+ */
+#define EFI_IFR_FORM_SET( guid, title, help, type, ... ) {                \
+       .FormSet = {                                                       \
+               .Header = {                                                \
+                       .OpCode = EFI_IFR_FORM_SET_OP,                     \
+                       .Length = sizeof ( type ),                         \
+                       .Scope = 1,                                        \
+               },                                                         \
+               .Guid = guid,                                              \
+               .FormSetTitle = title,                                     \
+               .Help = help,                                              \
+               .Flags = ( sizeof ( ( ( type * ) NULL )->ClassGuid ) /     \
+                          sizeof ( ( ( type * ) NULL )->ClassGuid[0] ) ), \
+       },                                                                 \
+       .ClassGuid = {                                                     \
+               __VA_ARGS__                                                \
+       },                                                                 \
+       }
+
+/**
+ * Define an EFI IFR GUID class
+ *
+ * @v class            Class
+ * @ret ifr            GUID class
+ */
+#define EFI_IFR_GUID_CLASS( class ) {                                     \
+       .Header = {                                                        \
+               .OpCode = EFI_IFR_GUID_OP,                                 \
+               .Length = sizeof ( EFI_IFR_GUID_CLASS ),                   \
+       },                                                                 \
+       .Guid = EFI_IFR_TIANO_GUID,                                        \
+       .ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS,                           \
+       .Class = class,                                                    \
+       }
+
+/**
+ * Define an EFI IFR GUID subclass
+ *
+ * @v subclass         Subclass
+ * @ret ifr            GUID subclass
+ */
+#define EFI_IFR_GUID_SUBCLASS( subclass ) {                               \
+       .Header = {                                                        \
+               .OpCode = EFI_IFR_GUID_OP,                                 \
+               .Length = sizeof ( EFI_IFR_GUID_SUBCLASS ),                \
+       },                                                                 \
+       .Guid = EFI_IFR_TIANO_GUID,                                        \
+       .ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS,                        \
+       .SubClass = subclass,                                              \
+       }
+
+/**
+ * Define an EFI IFR form
+ *
+ * @v formid           Form ID
+ * @v title            Title string
+ * @ret ifr            Form
+ *
+ * This definition opens a new scope, which must be closed by an
+ * EFI_IFR_END().
+ */
+#define EFI_IFR_FORM( formid, title ) {                                           \
+       .Header = {                                                        \
+               .OpCode = EFI_IFR_FORM_OP,                                 \
+               .Length = sizeof ( EFI_IFR_FORM ),                         \
+               .Scope = 1,                                                \
+       },                                                                 \
+       .FormId = formid,                                                  \
+       .FormTitle = title,                                                \
+       }
+
+/**
+ * Define an EFI IFR text widget
+ *
+ * @v prompt           Prompt string
+ * @v help             Help string
+ * @v text             Text string
+ * @ret ifr            Text widget
+ */
+#define EFI_IFR_TEXT( prompt, help, text ) {                              \
+       .Header = {                                                        \
+               .OpCode = EFI_IFR_TEXT_OP,                                 \
+               .Length = sizeof ( EFI_IFR_TEXT ),                         \
+       },                                                                 \
+       .Statement = {                                                     \
+               .Prompt = prompt,                                          \
+               .Help = help,                                              \
+       },                                                                 \
+       .TextTwo = text,                                                   \
+       }
+
+/**
+ * Define an EFI IFR end marker
+ *
+ * @ret ifr            End marker
+ */
+#define EFI_IFR_END() {                                                           \
+       .Header = {                                                        \
+               .OpCode = EFI_IFR_END_OP,                                  \
+               .Length = sizeof ( EFI_IFR_END ),                          \
+       },                                                                 \
+       }
+
+#endif /* _IPXE_EFI_HII_H */
index 608aaf50bbf26bac3130b60f695cba8fc605007e..f40bfff94bdf1172662197bb373b4e869e851848 100644 (file)
@@ -31,9 +31,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/efi/efi_pci.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_hii.h>
 #include <ipxe/efi/Protocol/SimpleNetwork.h>
 #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
 #include <ipxe/efi/Protocol/DevicePath.h>
+#include <ipxe/efi/Protocol/HiiConfigAccess.h>
+#include <ipxe/efi/Protocol/HiiDatabase.h>
+#include <config/general.h>
 
 /** @file
  *
@@ -71,6 +75,12 @@ struct efi_snp_device {
        unsigned int rx_count_events;
        /** The network interface identifier */
        EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
+       /** HII configuration access protocol */
+       EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
+       /** HII package list */
+       EFI_HII_PACKAGE_LIST_HEADER *package_list;
+       /** HII handle */
+       EFI_HII_HANDLE hii_handle;
        /** Device name */
        wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
        /** The device path
@@ -744,6 +754,339 @@ static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
        .Receive        = efi_snp_receive,
 };
 
+/******************************************************************************
+ *
+ * Human Interface Infrastructure
+ *
+ ******************************************************************************
+ */
+
+/** EFI configuration access protocol GUID */
+static EFI_GUID efi_hii_config_access_protocol_guid
+       = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
+
+/** EFI HII database protocol */
+static EFI_HII_DATABASE_PROTOCOL *efihii;
+EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
+
+/** Local GUID used for our EFI SNP formset */
+#define EFI_SNP_FORMSET_GUID                                           \
+       { 0xc4f84019, 0x6dfd, 0x4a27,                                   \
+         { 0x9b, 0x94, 0xb7, 0x2e, 0x1f, 0xbc, 0xad, 0xca } }
+
+/** Form identifiers used for our EFI SNP HII */
+enum efi_snp_hii_form_id {
+       EFI_SNP_FORM = 0x0001,          /**< The only form */
+};
+
+/** String identifiers used for our EFI SNP HII */
+enum efi_snp_hii_string_id {
+       /* Language name */
+       EFI_SNP_LANGUAGE_NAME = 0x0001,
+       /* Formset */
+       EFI_SNP_FORMSET_TITLE, EFI_SNP_FORMSET_HELP,
+       /* Product name */
+       EFI_SNP_PRODUCT_PROMPT, EFI_SNP_PRODUCT_HELP, EFI_SNP_PRODUCT_TEXT,
+       /* Version */
+       EFI_SNP_VERSION_PROMPT, EFI_SNP_VERSION_HELP, EFI_SNP_VERSION_TEXT,
+       /* Driver */
+       EFI_SNP_DRIVER_PROMPT, EFI_SNP_DRIVER_HELP, EFI_SNP_DRIVER_TEXT,
+       /* Device */
+       EFI_SNP_DEVICE_PROMPT, EFI_SNP_DEVICE_HELP, EFI_SNP_DEVICE_TEXT,
+       /* End of list */
+       EFI_SNP_MAX_STRING_ID
+};
+
+/** EFI SNP formset */
+struct efi_snp_formset {
+       EFI_HII_PACKAGE_HEADER Header;
+       EFI_IFR_FORM_SET_TYPE(1) FormSet;
+       EFI_IFR_GUID_CLASS Class;
+       EFI_IFR_GUID_SUBCLASS SubClass;
+       EFI_IFR_FORM Form;
+       EFI_IFR_TEXT ProductText;
+       EFI_IFR_TEXT VersionText;
+       EFI_IFR_TEXT DriverText;
+       EFI_IFR_TEXT DeviceText;
+       EFI_IFR_END EndForm;
+       EFI_IFR_END EndFormSet;
+} __attribute__ (( packed )) efi_snp_formset = {
+       .Header = {
+               .Length = sizeof ( efi_snp_formset ),
+               .Type = EFI_HII_PACKAGE_FORMS,
+       },
+       .FormSet = EFI_IFR_FORM_SET ( EFI_SNP_FORMSET_GUID,
+                                     EFI_SNP_FORMSET_TITLE,
+                                     EFI_SNP_FORMSET_HELP,
+                                     typeof ( efi_snp_formset.FormSet ),
+                                     EFI_HII_PLATFORM_SETUP_FORMSET_GUID ),
+       .Class = EFI_IFR_GUID_CLASS ( EFI_NETWORK_DEVICE_CLASS ),
+       .SubClass = EFI_IFR_GUID_SUBCLASS ( 0x03 ),
+       .Form = EFI_IFR_FORM ( EFI_SNP_FORM, EFI_SNP_FORMSET_TITLE ),
+       .ProductText = EFI_IFR_TEXT ( EFI_SNP_PRODUCT_PROMPT,
+                                     EFI_SNP_PRODUCT_HELP,
+                                     EFI_SNP_PRODUCT_TEXT ),
+       .VersionText = EFI_IFR_TEXT ( EFI_SNP_VERSION_PROMPT,
+                                     EFI_SNP_VERSION_HELP,
+                                     EFI_SNP_VERSION_TEXT ),
+       .DriverText = EFI_IFR_TEXT ( EFI_SNP_DRIVER_PROMPT,
+                                    EFI_SNP_DRIVER_HELP,
+                                    EFI_SNP_DRIVER_TEXT ),
+       .DeviceText = EFI_IFR_TEXT ( EFI_SNP_DEVICE_PROMPT,
+                                    EFI_SNP_DEVICE_HELP,
+                                    EFI_SNP_DEVICE_TEXT ),
+       .EndForm = EFI_IFR_END(),
+       .EndFormSet = EFI_IFR_END(),
+};
+
+/**
+ * Generate EFI SNP string
+ *
+ * @v wbuf             Buffer
+ * @v swlen            Size of buffer (in wide characters)
+ * @v snpdev           SNP device
+ * @ret wlen           Length of string (in wide characters)
+ */
+static int efi_snp_string ( wchar_t *wbuf, ssize_t swlen,
+                           enum efi_snp_hii_string_id id,
+                           struct efi_snp_device *snpdev ) {
+       struct net_device *netdev = snpdev->netdev;
+       struct device *dev = netdev->dev;
+
+       switch ( id ) {
+       case EFI_SNP_LANGUAGE_NAME:
+               return efi_ssnprintf ( wbuf, swlen, "English" );
+       case EFI_SNP_FORMSET_TITLE:
+               return efi_ssnprintf ( wbuf, swlen, "%s (%s)",
+                                      ( PRODUCT_NAME[0] ?
+                                        PRODUCT_NAME : PRODUCT_SHORT_NAME ),
+                                      netdev_addr ( netdev ) );
+       case EFI_SNP_FORMSET_HELP:
+               return efi_ssnprintf ( wbuf, swlen,
+                                      "Configure " PRODUCT_SHORT_NAME );
+       case EFI_SNP_PRODUCT_PROMPT:
+               return efi_ssnprintf ( wbuf, swlen, "Name" );
+       case EFI_SNP_PRODUCT_HELP:
+               return efi_ssnprintf ( wbuf, swlen, "Firmware product name" );
+       case EFI_SNP_PRODUCT_TEXT:
+               return efi_ssnprintf ( wbuf, swlen, "%s",
+                                      ( PRODUCT_NAME[0] ?
+                                        PRODUCT_NAME : PRODUCT_SHORT_NAME ) );
+       case EFI_SNP_VERSION_PROMPT:
+               return efi_ssnprintf ( wbuf, swlen, "Version" );
+       case EFI_SNP_VERSION_HELP:
+               return efi_ssnprintf ( wbuf, swlen, "Firmware version" );
+       case EFI_SNP_VERSION_TEXT:
+               return efi_ssnprintf ( wbuf, swlen, VERSION );
+       case EFI_SNP_DRIVER_PROMPT:
+               return efi_ssnprintf ( wbuf, swlen, "Driver" );
+       case EFI_SNP_DRIVER_HELP:
+               return efi_ssnprintf ( wbuf, swlen, "Firmware driver" );
+       case EFI_SNP_DRIVER_TEXT:
+               return efi_ssnprintf ( wbuf, swlen, "%s", dev->driver_name );
+       case EFI_SNP_DEVICE_PROMPT:
+               return efi_ssnprintf ( wbuf, swlen, "Device" );
+       case EFI_SNP_DEVICE_HELP:
+               return efi_ssnprintf ( wbuf, swlen, "Hardware device" );
+       case EFI_SNP_DEVICE_TEXT:
+               return efi_ssnprintf ( wbuf, swlen, "%s", dev->name );
+       default:
+               assert ( 0 );
+               return 0;
+       }
+}
+
+/**
+ * Generate EFI SNP string package
+ *
+ * @v strings          String package header buffer
+ * @v max_len          Buffer length
+ * @v snpdev           SNP device
+ * @ret len            Length of string package
+ */
+static int efi_snp_strings ( EFI_HII_STRING_PACKAGE_HDR *strings,
+                            size_t max_len, struct efi_snp_device *snpdev ) {
+       static const char language[] = "en-us";
+       void *buf = strings;
+       ssize_t remaining = max_len;
+       size_t hdrsize;
+       EFI_HII_SIBT_STRING_UCS2_BLOCK *string;
+       ssize_t wremaining;
+       size_t string_wlen;
+       unsigned int id;
+       EFI_HII_STRING_BLOCK *end;
+       size_t len;
+
+       /* Calculate header size */
+       hdrsize = ( offsetof ( typeof ( *strings ), Language ) +
+                   sizeof ( language ) );
+       buf += hdrsize;
+       remaining -= hdrsize;
+
+       /* Fill in strings */
+       for ( id = 1 ; id < EFI_SNP_MAX_STRING_ID ; id++ ) {
+               string = buf;
+               if ( remaining >= ( ( ssize_t ) sizeof ( string->Header ) ) )
+                       string->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
+               buf += offsetof ( typeof ( *string ), StringText );
+               remaining -= offsetof ( typeof ( *string ), StringText );
+               wremaining = ( remaining /
+                              ( ( ssize_t ) sizeof ( string->StringText[0] )));
+               assert ( ! ( ( remaining <= 0 ) && ( wremaining > 0 ) ) );
+               string_wlen = efi_snp_string ( string->StringText, wremaining,
+                                              id, snpdev );
+               buf += ( ( string_wlen + 1 /* wNUL */ ) *
+                        sizeof ( string->StringText[0] ) );
+               remaining -= ( ( string_wlen + 1 /* wNUL */ ) *
+                              sizeof ( string->StringText[0] ) );
+       }
+
+       /* Fill in end marker */
+       end = buf;
+       if ( remaining >= ( ( ssize_t ) sizeof ( *end ) ) )
+               end->BlockType = EFI_HII_SIBT_END;
+       buf += sizeof ( *end );
+       remaining -= sizeof ( *end );
+
+       /* Calculate overall length */
+       len = ( max_len - remaining );
+
+       /* Fill in string package header */
+       if ( strings ) {
+               memset ( strings, 0, sizeof ( *strings ) );
+               strings->Header.Length = len;
+               strings->Header.Type = EFI_HII_PACKAGE_STRINGS;
+               strings->HdrSize = hdrsize;
+               strings->StringInfoOffset = hdrsize;
+               strings->LanguageName = EFI_SNP_LANGUAGE_NAME;
+               memcpy ( strings->Language, language, sizeof ( language ) );
+       }
+
+       return len;
+}
+
+/**
+ * Generate EFI SNP package list
+ *
+ * @v snpdev           SNP device
+ * @ret package_list   Package list, or NULL on error
+ *
+ * The package list is allocated using malloc(), and must eventually
+ * be freed by the caller.
+ */
+static EFI_HII_PACKAGE_LIST_HEADER *
+efi_snp_package_list ( struct efi_snp_device *snpdev ) {
+       size_t strings_len = efi_snp_strings ( NULL, 0, snpdev );
+       struct {
+               EFI_HII_PACKAGE_LIST_HEADER header;
+               struct efi_snp_formset formset;
+               union {
+                       EFI_HII_STRING_PACKAGE_HDR strings;
+                       uint8_t pad[strings_len];
+               } __attribute__ (( packed )) strings;
+               EFI_HII_PACKAGE_HEADER end;
+       } __attribute__ (( packed )) *package_list;
+
+       /* Allocate package list */
+       package_list = zalloc ( sizeof ( *package_list ) );
+       if ( ! package_list )
+               return NULL;
+
+       /* Populate package list */
+       memcpy ( &package_list->header.PackageListGuid,
+                &efi_snp_formset.FormSet.FormSet.Guid,
+                sizeof ( package_list->header.PackageListGuid ) );
+       package_list->header.PackageLength = sizeof ( *package_list );
+       memcpy ( &package_list->formset, &efi_snp_formset,
+                sizeof ( package_list->formset ) );
+       efi_snp_strings ( &package_list->strings.strings,
+                         sizeof ( package_list->strings ), snpdev );
+       package_list->end.Length = sizeof ( package_list->end );
+       package_list->end.Type = EFI_HII_PACKAGE_END;
+
+       return &package_list->header;
+}
+
+/**
+ * Fetch configuration
+ *
+ * @v hii              HII configuration access protocol
+ * @v request          Configuration to fetch
+ * @ret progress       Progress made through configuration to fetch
+ * @ret results                Query results
+ * @ret efirc          EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+                            EFI_STRING request, EFI_STRING *progress,
+                            EFI_STRING *results __unused ) {
+       struct efi_snp_device *snpdev =
+               container_of ( hii, struct efi_snp_device, hii );
+
+       DBGC ( snpdev, "SNPDEV %p ExtractConfig\n", snpdev );
+
+       *progress = request;
+       return EFI_INVALID_PARAMETER;
+}
+
+/**
+ * Store configuration
+ *
+ * @v hii              HII configuration access protocol
+ * @v config           Configuration to store
+ * @ret progress       Progress made through configuration to store
+ * @ret efirc          EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+                          EFI_STRING config, EFI_STRING *progress ) {
+       struct efi_snp_device *snpdev =
+               container_of ( hii, struct efi_snp_device, hii );
+
+       DBGC ( snpdev, "SNPDEV %p RouteConfig\n", snpdev );
+
+       *progress = config;
+       return EFI_INVALID_PARAMETER;
+}
+
+/**
+ * Handle form actions
+ *
+ * @v hii              HII configuration access protocol
+ * @v action           Form browser action
+ * @v question_id      Question ID
+ * @v type             Type of value
+ * @v value            Value
+ * @ret action_request Action requested by driver
+ * @ret efirc          EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+                      EFI_BROWSER_ACTION action __unused,
+                      EFI_QUESTION_ID question_id __unused,
+                      UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
+                      EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
+       struct efi_snp_device *snpdev =
+               container_of ( hii, struct efi_snp_device, hii );
+
+       DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
+       return EFI_UNSUPPORTED;
+}
+
+/** HII configuration access protocol */
+static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
+       .ExtractConfig  = efi_snp_hii_extract_config,
+       .RouteConfig    = efi_snp_hii_route_config,
+       .Callback       = efi_snp_hii_callback,
+};
+
+/******************************************************************************
+ *
+ * iPXE network driver
+ *
+ ******************************************************************************
+ */
+
 /**
  * Locate SNP device corresponding to network device
  *
@@ -830,6 +1173,9 @@ static int efi_snp_probe ( struct net_device *netdev ) {
        strncpy ( snpdev->nii.StringId, "iPXE",
                  sizeof ( snpdev->nii.StringId ) );
 
+       /* Populate the HII configuration access structure */
+       memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
+
        /* Populate the device name */
        efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
                                       sizeof ( snpdev->name[0] ) ),
@@ -858,6 +1204,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
                        &efi_device_path_protocol_guid, &snpdev->path,
                        &efi_nii_protocol_guid, &snpdev->nii,
                        &efi_nii31_protocol_guid, &snpdev->nii,
+                       &efi_hii_config_access_protocol_guid, &snpdev->hii,
                        NULL ) ) != 0 ) {
                DBGC ( snpdev, "SNPDEV %p could not install protocols: "
                       "%s\n", snpdev, efi_strerror ( efirc ) );
@@ -874,6 +1221,25 @@ static int efi_snp_probe ( struct net_device *netdev ) {
                goto err_efipci_child_add;
        }
 
+       /* Create HII package list */
+       snpdev->package_list = efi_snp_package_list ( snpdev );
+       if ( ! snpdev->package_list ) {
+               DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
+                      snpdev );
+               rc = -ENOMEM;
+               goto err_create_hii;
+       }
+
+       /* Add HII packages */
+       if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
+                                               snpdev->handle,
+                                               &snpdev->hii_handle ) ) != 0 ) {
+               DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
+                      snpdev, efi_strerror ( efirc ) );
+               rc = EFIRC_TO_RC ( efirc );
+               goto err_register_hii;
+       }
+
        /* Add to list of SNP devices */
        list_add ( &snpdev->list, &efi_snp_devices );
 
@@ -881,6 +1247,10 @@ static int efi_snp_probe ( struct net_device *netdev ) {
               snpdev, netdev->name, snpdev->handle );
        return 0;
 
+       efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+ err_register_hii:
+       free ( snpdev->package_list );
+ err_create_hii:
        efipci_child_del ( efipci, snpdev->handle );
  err_efipci_child_add:
        bs->UninstallMultipleProtocolInterfaces (
@@ -889,6 +1259,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
                        &efi_device_path_protocol_guid, &snpdev->path,
                        &efi_nii_protocol_guid, &snpdev->nii,
                        &efi_nii31_protocol_guid, &snpdev->nii,
+                       &efi_hii_config_access_protocol_guid, &snpdev->hii,
                        NULL );
  err_install_protocol_interface:
        bs->CloseEvent ( snpdev->snp.WaitForPacket );
@@ -927,6 +1298,8 @@ static void efi_snp_remove ( struct net_device *netdev ) {
        }
 
        /* Uninstall the SNP */
+       efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+       free ( snpdev->package_list );
        efipci_child_del ( snpdev->efipci, snpdev->handle );
        list_del ( &snpdev->list );
        bs->UninstallMultipleProtocolInterfaces (
@@ -935,6 +1308,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
                        &efi_device_path_protocol_guid, &snpdev->path,
                        &efi_nii_protocol_guid, &snpdev->nii,
                        &efi_nii31_protocol_guid, &snpdev->nii,
+                       &efi_hii_config_access_protocol_guid, &snpdev->hii,
                        NULL );
        bs->CloseEvent ( snpdev->snp.WaitForPacket );
        netdev_put ( snpdev->netdev );