/** @file

  Implements get/set firmware volume attributes.

  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 which 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.

**/

#include "FwVolDriver.h"

/**
  Retrieves attributes, insures positive polarity of attribute bits, returns
  resulting attributes in output parameter.

  @param  This             Calling context
  @param  Attributes       output buffer which contains attributes

  @retval EFI_SUCCESS      Successfully got volume attributes

**/
EFI_STATUS
EFIAPI
FvGetVolumeAttributes (
  IN  CONST EFI_FIRMWARE_VOLUME2_PROTOCOL  *This,
  OUT EFI_FV_ATTRIBUTES             *Attributes
  )
{
  EFI_STATUS                          Status;
  FV_DEVICE                           *FvDevice;
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
  EFI_FVB_ATTRIBUTES_2                FvbAttributes;

  FvDevice  = FV_DEVICE_FROM_THIS (This);
  Fvb       = FvDevice->Fvb;

  //
  // First get the Firmware Volume Block Attributes
  //
  Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
  FvbAttributes &= 0xfffff0ff;

  *Attributes = FvbAttributes;
  *Attributes |= EFI_FV2_WRITE_POLICY_RELIABLE;
  return Status;
}

/**
  Sets current attributes for volume.

  @param  This          Calling context
  @param  Attributes    On input, FvAttributes is a pointer to
                        an EFI_FV_ATTRIBUTES containing the
                        desired firmware volume settings. On
                        successful return, it contains the new
                        settings of the firmware volume. On
                        unsuccessful return, FvAttributes is not
                        modified and the firmware volume
                        settings are not changed.
  
  @retval EFI_SUCCESS             The requested firmware volume attributes
                                  were set and the resulting
                                  EFI_FV_ATTRIBUTES is returned in
                                  FvAttributes.
  @retval EFI_ACCESS_DENIED       Atrribute is locked down.
  @retval EFI_INVALID_PARAMETER   Atrribute is not valid.

**/
EFI_STATUS
EFIAPI
FvSetVolumeAttributes (
  IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL   *This,
  IN OUT EFI_FV_ATTRIBUTES          *Attributes
  )
{
  EFI_STATUS                          Status;
  FV_DEVICE                           *FvDevice;
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
  EFI_FVB_ATTRIBUTES_2                OldFvbAttributes;
  EFI_FVB_ATTRIBUTES_2                NewFvbAttributes;
  UINT64                              NewStatus;
  UINT32                              Capabilities;

  FvDevice  = FV_DEVICE_FROM_THIS (This);
  Fvb       = FvDevice->Fvb;

  //
  // First get the current Volume Attributes
  //
  Status = Fvb->GetAttributes (
                  Fvb,
                  &OldFvbAttributes
                  );

  if ((OldFvbAttributes & EFI_FVB2_LOCK_STATUS) != 0) {
    return EFI_ACCESS_DENIED;
  }
  //
  // Only status attributes can be updated.
  //
  Capabilities  = OldFvbAttributes & EFI_FVB2_CAPABILITIES;
  NewStatus     = (*Attributes) & EFI_FVB2_STATUS;

  //
  // Test read disable
  //
  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test read enable
  //
  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test write disable
  //
  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test write enable
  //
  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test lock
  //
  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {
      return EFI_INVALID_PARAMETER;
    }
  }

  NewFvbAttributes = OldFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
  NewFvbAttributes |= NewStatus;
  Status = Fvb->SetAttributes (
                  Fvb,
                  &NewFvbAttributes
                  );

  if (EFI_ERROR (Status)) {
    return Status;
  }

  *Attributes = 0;

  This->GetVolumeAttributes (
          This,
          Attributes
          );

  return EFI_SUCCESS;
}

/**
  Return information of type InformationType for the requested firmware
  volume.

  @param This             Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
  @param InformationType  InformationType for requested.
  @param BufferSize       On input, size of Buffer.On output, the amount of
                          data returned in Buffer.
  @param Buffer           A poniter to the data buffer to return.

  @return EFI_UNSUPPORTED Could not get.

**/
EFI_STATUS
EFIAPI
FvGetVolumeInfo (
  IN  CONST EFI_FIRMWARE_VOLUME2_PROTOCOL       *This,
  IN  CONST EFI_GUID                            *InformationType,
  IN OUT UINTN                                  *BufferSize,
  OUT VOID                                      *Buffer
  )
{
  return EFI_UNSUPPORTED;
}

/**
  Set information with InformationType into the requested firmware volume.

  @param  This             Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
  @param  InformationType  InformationType for requested.
  @param  BufferSize       Size of Buffer data.
  @param  Buffer           A poniter to the data buffer to be set.

  @retval EFI_UNSUPPORTED  Could not set.

**/
EFI_STATUS
EFIAPI
FvSetVolumeInfo (
  IN  CONST EFI_FIRMWARE_VOLUME2_PROTOCOL       *This,
  IN  CONST EFI_GUID                            *InformationType,
  IN  UINTN                                     BufferSize,
  IN CONST  VOID                                *Buffer
  )
{
  return EFI_UNSUPPORTED;
}
