text: /* Copyright (c) Microsoft Corporation. All rights reserved.
     Licensed under the MIT License.
  
  Module Name:
  
      device.c - Device handling events for example driver.
  
  Abstract:
  
     This file contains the device entry points and callbacks.
  
  Environment:
  
      User-mode Driver Framework 2
  
  */
  
  #include "driver.h"
  #include "Codec.h"
  #include "device.tmh"
  
  NTSTATUS
  Wm8731LCodecCreateDevice(
      _Inout_ PWDFDEVICE_INIT DeviceInit
      )
  /*++
  
  Routine Description:
  
      Worker routine called to create a device and its software resources.
  
  Arguments:
  
      DeviceInit - Pointer to an opaque init structure. Memory for this
                      structure will be freed by the framework when the WdfDeviceCreate
                      succeeds. So don't access the structure after that point.
  
  Return Value:
  
      NTSTATUS
  
  --*/
  {
      WDF_OBJECT_ATTRIBUTES   deviceAttributes;
      PDEVICE_CONTEXT deviceContext;
      WDFDEVICE device;
      NTSTATUS status;
      WDF_OBJECT_ATTRIBUTES targetAttributes;
      
      WDF_PNPPOWER_EVENT_CALLBACKS callbacks;
      WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&callbacks);
      callbacks.EvtDevicePrepareHardware = EvtWm8731LDevicePrepareHardware;
      WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &callbacks);
  
      WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
  
      status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
  
      if (NT_SUCCESS(status)) {
          //
          // Get a pointer to the device context structure that we just associated
          // with the device object. We define this structure in the device.h
          // header file. DeviceGetContext is an inline function generated by
          // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h.
          // This function will do the type checking and return the device context.
          // If you pass a wrong object handle it will return NULL and assert if
          // run under framework verifier mode.
          //
          deviceContext = DeviceGetContext(device);
  
          //
          // Initialize the context.
          //        
          deviceContext->I2cConnectionId.QuadPart = 0;
  
          WDF_OBJECT_ATTRIBUTES_INIT(&targetAttributes);
          targetAttributes.ParentObject = device;
          status = WdfIoTargetCreate(device, &targetAttributes, &deviceContext->I2cTarget);
  
          //
          // Create a device interface so that applications can find and talk
          // to us.
          //
  
          if (NT_SUCCESS(status)) {
              status = WdfDeviceCreateDeviceInterface(
                  device,
                  &GUID_DEVINTERFACE_Wm8731LCodec,
                  NULL // ReferenceString
              );
  
              if (NT_SUCCESS(status)) {
                  //
                  // Initialize the I/O Package and any Queues
                  //
                  status = Wm8731LCodecQueueInitialize(device);
              }
          }
      }
  
      return status;
  }
  
  NTSTATUS
  EvtWm8731LDevicePrepareHardware(
     _In_ WDFDEVICE    Device,
     _In_ WDFCMRESLIST ResourcesRaw,
     _In_ WDFCMRESLIST ResourcesTranslated
     )
  {
     BOOLEAN fConnectionIdFound = FALSE;
     ULONG resourceCount;
     NTSTATUS status = STATUS_UNSUCCESSFUL;
     PDEVICE_CONTEXT deviceContext;
     WDF_IO_TARGET_OPEN_PARAMS openParams;
  
     UNREFERENCED_PARAMETER(ResourcesRaw);
     DECLARE_UNICODE_STRING_SIZE(strDeviceName, RESOURCE_HUB_PATH_SIZE);
  
     deviceContext = DeviceGetContext(Device);
     resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
  
     // Loop through the resources and save the relevant ones.
     for (ULONG ix = 0; ix < resourceCount; ix++)
     {
        PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
  
        pDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, ix);
  
        if (pDescriptor == NULL)
        {
           status = E_POINTER;
           break;
        }
  
        // Determine the resource type.
        switch (pDescriptor->Type)
        {
        case CmResourceTypeConnection:
           {
              // Check against the expected connection types.
  
              UCHAR Class = pDescriptor->u.Connection.Class;
              UCHAR Type = pDescriptor->u.Connection.Type;
  
              if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL)
              {
                 if (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C)
                 {
                    if (fConnectionIdFound == FALSE)
                    {
                       // Save the SPB connection ID.
  
                       deviceContext->I2cConnectionId.LowPart = pDescriptor->u.Connection.IdLowPart;
                       deviceContext->I2cConnectionId.HighPart = pDescriptor->u.Connection.IdHighPart;
                       fConnectionIdFound = TRUE;
                       status = RESOURCE_HUB_CREATE_PATH_FROM_ID(&strDeviceName,
                                                                 deviceContext->I2cConnectionId.LowPart,
                                                                 deviceContext->I2cConnectionId.HighPart);
  
                       if (NT_SUCCESS(status))
                       {
  
                          WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&openParams, &strDeviceName,
                                                                      (GENERIC_READ | GENERIC_WRITE));
  
                          openParams.ShareAccess = 0;
                          openParams.CreateDisposition = FILE_OPEN;
                          openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  
                          status = WdfIoTargetOpen(deviceContext->I2cTarget, &openParams);
  
                          if (NT_SUCCESS(status))
                          {
                             status = CodecInitializeHeadphoneOutJack(deviceContext);
                          }
                       }
                    }
                 }
              }
           }
           break;
  
        default:
           // Don't care about other resource descriptors.
           break;
        }
     }
  
     return status;
  }
  
  