/*****************************************************************************

INTEL CONFIDENTIAL
Copyright 2007,2008,2009 Intel Corporation All Rights Reserved.

The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its
suppliers and licensors. The Material may contain trade secrets and proprietary
and confidential information of Intel Corporation and its suppliers and
licensors, and is protected by worldwide copyright and trade secret laws and
treaty provisions. No part of the Material may be used, copied, reproduced,
modified, published, uploaded, posted, transmitted, distributed, or disclosed
in any way without Intels prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.

Include any supplier copyright notices as supplier requires Intel to use.
Include supplier trademarks or logos as supplier requires Intel to use,
preceded by an asterisk.
An asterisked footnote can be added as follows: 
  *Third Party trademarks are the property of their respective owners.

Unless otherwise agreed by Intel in writing, you may not remove or alter this
notice or any other notice embedded in Materials by Intel or Intels suppliers
or licensors in any way.

 version: Embedded.X.1.0.3-127

  Contact Information:

  Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226 

*****************************************************************************/
/*****************************************************************************
 * @ingroup OEM_PHY_GENERAL
 *
 * @file phyfw.c
 *
 * @description
 *   This file contains example Windows driver code for phy extensiblity
 *   support for Gigabit Ethernet for Intel(R) EP80579 Integrated Processor
 *   Line Product
 *****************************************************************************/
#include "phyEx.h"
#include "..\public\public.h"
#include "phyoem.h"

/******************************************************************************
 * @description
 *   The main entry point used by windows to load the driver
 *
 * @param driverObj - pointer to the DRIVER_OBJECT created for this driver
 * @param regPath - unicode string for the Registry path for this driver
 *
 * @return - NTSTATUS
 *
 * @notes - runs at IRQL == IRQL_PASSIVE_LEVEL
 *****************************************************************************/
NTSTATUS
DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
{
    NTSTATUS code;
    WDF_DRIVER_CONFIG driverConfig;

    DBGPRINT(("PHYEX: Entering %s\n", "DriverEntry"));
    DBGPRINT(("Build Date: "__DATE__" Time: "__TIME__"\n"));

    /*
     * initialize the driver config and set the Add Device entry point
     */
    WDF_DRIVER_CONFIG_INIT(&driverConfig, EvtDriverDeviceAdd);

    /*
     * create the WDFDRIVER object
     */
    code = WdfDriverCreate(driverObj,
                           regPath,
                           WDF_NO_OBJECT_ATTRIBUTES,
                           &driverConfig,
                           WDF_NO_HANDLE);

    if (!NT_SUCCESS(code)) {
        DBGPRINT(("PHYEX: WdfDriverCreate failed with status 0x%0x\n", code));
    }

    return code;
}


/******************************************************************************
 * @description
 *   The callback used by windows to add another device object to the driver
 *
 * @param driver - IN windows driver object for the GCU driver
 * @param deviceInit - IN device object initialization data
 *
 * @return - NTSTATUS
 *
 * @notes - runs at IRQL == IRQL_PASSIVE_LEVEL
 *****************************************************************************/
NTSTATUS
EvtDriverDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT devInit)
{
    NTSTATUS                        code;
    WDFDEVICE                       device;
    WDF_OBJECT_ATTRIBUTES           objAttr;
    WDF_IO_QUEUE_CONFIG             defaultQueueConfig;
    WDF_QUERY_INTERFACE_CONFIG      queryConfig;
    WDF_PNPPOWER_EVENT_CALLBACKS    pnpCallbacks;
    PPHY_DEVICE_CONTEXT             devContext;
    PHYDEV_INTERFACE_V1             devInterface;

    UNREFERENCED_PARAMETER(driver);

    /*
     * init the PnpPowerCallbacks structure with default data
     */
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks);
    WdfDeviceInitSetPnpPowerEventCallbacks(devInit, &pnpCallbacks);

    WDF_OBJECT_ATTRIBUTES_INIT(&objAttr);
    WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttr,
                                           PHY_DEVICE_CONTEXT);

    /* 
     * Override the SynchronizationScope member of the objAttr. We want
     * to serialize access, by using the queue scope, the callbacks 
     * specified within the queue can not be called in parallel.
     */
    objAttr.SynchronizationScope = WdfSynchronizationScopeQueue;

    code = WdfDeviceCreate(&devInit,     /* device init structure */
                           &objAttr,     /* attributes for WDF device */
                           &device);     /* returns pointer to new WDF dev */
    if (!NT_SUCCESS(code)) {
        DBGPRINT(("PHYEX: WdfDeviceCreate failed 0x%0x\n", code));
        return code;
    }

    /* get the device context for initialization */
    devContext = GetDeviceContext(device);

    /* read registry parameters */
    ReadRegistry(device);

    /*
     * Configure our one and only queue...
     * Note: WdfIoQueueDispatchSequential() forces serialization on IRP
     *       requests.
     */
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&defaultQueueConfig,
                                           WdfIoQueueDispatchSequential
                                           );

    /*
     * there are several callbacks available in the defaultQueue struct,
     * and we only need the EvtIoInternalDeviceControl so we can send ioctls
     * as the inter-driver interface. No other interfaces are exported...
     */
    defaultQueueConfig.EvtIoInternalDeviceControl =
                                               EvtIoInternalDeviceControl;

    code = WdfIoQueueCreate(device,
                            &defaultQueueConfig,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &devContext->defaultQueue);
    if (!NT_SUCCESS(code)) {
        DBGPRINT(("PHYEX: WdfIoQueueCreate for default queue failed 0x%0x\n",
                 code));
        return code;
    }

    /*
     * Get a device interface for gbe or others to identify
     */
    code = WdfDeviceCreateDeviceInterface(
                device,
                (LPGUID) &GUID_PHYDEV_IF,
                NULL /* No Reference String */
                );

    if (!NT_SUCCESS (code)) {
        DBGPRINT(("PHYEX: WdfDeviceCreateDeviceInterface failed 0x%x\n", code));
        return code;
    }

    RtlZeroMemory(&devInterface, sizeof(PHYDEV_INTERFACE_V1));

    /*
     * create custom interface so that GbE driver can call phy device driver
     */
    devInterface.hdr.Context = (PVOID) device;
    devInterface.hdr.Size = sizeof(PHYDEV_INTERFACE_V1);
    devInterface.hdr.Version = 1;

    /*
     * Let the framework handle reference counting.
     */
    devInterface.hdr.InterfaceReference =
        WdfDeviceInterfaceReferenceNoOp;
    devInterface.hdr.InterfaceDereference =
        WdfDeviceInterfaceDereferenceNoOp;

    OemRegisterCallback( &devInterface );

    WDF_QUERY_INTERFACE_CONFIG_INIT(&queryConfig,
                                    (PINTERFACE) &devInterface,
                                    &GUID_PHYDEV_QUERY_IF,
                                    NULL);
    code = WdfDeviceAddQueryInterface(device, &queryConfig);

    if (!NT_SUCCESS(code)) {
        DBGPRINT(("PHYEX: WdfIoQueueCreate for default queue failed 0x%0x\n",
                  code));
        return code;
    }

    return STATUS_SUCCESS;
}

/******************************************************************************
 * @description
 *   Generic function can be used to read any REG_DWORD registry value stored
 *   under Device Parameter.
 *
 *  @param Name - Registry key name
 *  @param Value - Value returned
 *
 * @return - 
 *   TRUE if successful
 *   FALSE if not present/error in reading registry
 */
BOOLEAN
GetRegistryKeyValue(IN PWCHAR Name, OUT PULONG Value)
{
    WDFKEY      hKey = NULL;
    NTSTATUS    status;
    BOOLEAN     retValue = FALSE;
    UNICODE_STRING valueName;

    PAGED_CODE();

    *Value = 0;

    status = WdfDriverOpenParametersRegistryKey(
                                  WdfGetDriver(),
                                  STANDARD_RIGHTS_ALL,
                                  WDF_NO_OBJECT_ATTRIBUTES,
                                  &hKey);

    if (NT_SUCCESS (status)) {

        RtlInitUnicodeString(&valueName,Name);

        status = WdfRegistryQueryULong (hKey,
                                  &valueName,
                                  Value);

        if (NT_SUCCESS (status)) {
            retValue = TRUE;
        }

        WdfRegistryClose(hKey);
    }

    return retValue;
}

/******************************************************************************
 * @description
 *   Read configurable parameters from registry parameters
 *
 * @param device - WDF device handle
 *
 * @return - VOID
 *
 */
VOID
ReadRegistry(IN WDFDEVICE  device)
{
    PPHY_DEVICE_CONTEXT             devContext;
    ULONG i;

    /* get the device context for initialization */
    devContext = GetDeviceContext(device);

    /* Example: */
    /* GetRegistryKeyValue(L"phyaddr0", &devCtx->sampleKey); */

    return;
}


/******************************************************************************
 *
 * @description
 *    The callback used by windows for internal device control
 *
 * @param queue - WDF queue
 * @param request - WDF request
 * @param outBufSize - Output buffer size
 * @param inBufSize - Input buffer size
 *
 * @return - NTSTATUS (via WdfRequestCompleteWithInformation()
 *
 * @notes - runs at IRQL == IRQL_PASSIVE_LEVEL
 *****************************************************************************/
VOID
EvtIoInternalDeviceControl(WDFQUEUE queue,
                              WDFREQUEST request,
                              size_t outBufSize,
                              size_t inBufSize,
                              ULONG ioCtrlCode)
{
    NTSTATUS            retCode = STATUS_SUCCESS;
    WDFDEVICE           dev = WdfIoQueueGetDevice(queue);
    PPHY_DEVICE_CONTEXT devContext;
    ULONG               uBytesOfInfo=0;

    if ( WdfDeviceGetDevicePowerState(dev) != WdfDevStatePowerD0 )
    {
        WdfRequestCompleteWithInformation(request, STATUS_DEVICE_POWER_FAILURE, uBytesOfInfo);
        return;
    }

    /* need to get the I/O mapped base address to access the GCU */
    devContext = GetDeviceContext(dev);

    switch(ioCtrlCode)
    {
      /*case IOCTL_XXX:*/
      default:
          retCode = STATUS_INVALID_PARAMETER;
          break;
    }

    WdfRequestCompleteWithInformation(request, retCode, uBytesOfInfo);

    return;
}
