summaryrefslogtreecommitdiff
path: root/usb/UcmTcpciCxClientSample/Device.cpp
diff options
context:
space:
mode:
authorPhilip Froese <[email protected]>2016-10-19 13:25:24 -0700
committerPhilip Froese <[email protected]>2016-10-19 13:25:24 -0700
commit7995677b7883bad51cbadd6bd1d1674dbd689c38 (patch)
treebbde63ce3535c264de5202e337a86fb0606819b7 /usb/UcmTcpciCxClientSample/Device.cpp
parentce06de38a6daee9815dbf7eb8ddd8f335612ccc0 (diff)
Adding UcmTcpciCxClientSample
Diffstat (limited to 'usb/UcmTcpciCxClientSample/Device.cpp')
-rw-r--r--usb/UcmTcpciCxClientSample/Device.cpp335
1 files changed, 335 insertions, 0 deletions
diff --git a/usb/UcmTcpciCxClientSample/Device.cpp b/usb/UcmTcpciCxClientSample/Device.cpp
new file mode 100644
index 00000000..fc2330ad
--- /dev/null
+++ b/usb/UcmTcpciCxClientSample/Device.cpp
@@ -0,0 +1,335 @@
+/*++
+
+Module Name:
+
+ Device.c - Device handling events.
+
+Abstract:
+
+ This file contains the device definitions.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "Driver.h"
+#include "device.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, EvtCreateDevice)
+#pragma alloc_text (PAGE, EvtPrepareHardware)
+#pragma alloc_text (PAGE, EvtDeviceD0Entry)
+#pragma alloc_text (PAGE, EvtReleaseHardware)
+#endif
+
+NTSTATUS
+EvtCreateDevice(
+ _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. Don't access the structure after that point.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ TRACE_FUNC_ENTRY(TRACE_DEVICE);
+
+ PAGED_CODE();
+
+ NTSTATUS status;
+ WDFDEVICE device;
+ PDEVICE_CONTEXT deviceContext;
+ UCMTCPCI_DEVICE_CONFIG config;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_OBJECT_ATTRIBUTES attributes;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDevicePrepareHardware = EvtPrepareHardware;
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = EvtReleaseHardware;
+ pnpPowerCallbacks.EvtDeviceD0Entry = EvtDeviceD0Entry;
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ status = UcmTcpciDeviceInitInitialize(DeviceInit);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "[PWDFDEVICE_INIT: 0x%p] UcmTcpciDeviceInitInitialize failed - %!STATUS!",
+ DeviceInit, status);
+ goto Exit;
+ }
+
+ status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "[PWDFDEVICE_INIT: 0x%p] WdfDeviceCreate failed - %!STATUS!", DeviceInit, status);
+ goto Exit;
+ }
+
+ deviceContext = DeviceGetContext(device);
+
+ // Save the device in the context so we can access it later.
+ deviceContext->Device = device;
+
+ // Initialize platform-level device reset.
+ deviceContext->ResetAttempts = 0;
+
+ RtlZeroMemory(&deviceContext->ResetInterface, sizeof(deviceContext->ResetInterface));
+ deviceContext->ResetInterface.Size = sizeof(deviceContext->ResetInterface);
+ deviceContext->ResetInterface.Version = 1;
+
+ status = WdfFdoQueryForInterface(
+ deviceContext->Device,
+ &GUID_DEVICE_RESET_INTERFACE_STANDARD,
+ (PINTERFACE)&deviceContext->ResetInterface,
+ sizeof(deviceContext->ResetInterface),
+ 1,
+ NULL);
+
+ // The reset interface may not exist on certain environments.
+ // In this case, we will fall back to using a different reset method.
+ // Zero the reset interface and ignore the error.
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "[WDFDEVICE: 0x%p] WdfFdoQueryForInterface for GUID_DEVICE_RESET_INTERFACE_STANDARD failed. Status: %!STATUS!",
+ device, status);
+ RtlZeroMemory(&deviceContext->ResetInterface, sizeof(deviceContext->ResetInterface));
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "[WDFDEVICE: 0x%p] Successfully initialized platform-level device reset.", deviceContext->Device);
+ }
+
+ // Register our device with UcmTcpciCx.
+ UCMTCPCI_DEVICE_CONFIG_INIT(&config);
+ status = UcmTcpciDeviceInitialize(device, &config);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
+ "[WDFDEVICE: 0x%p] UcmTcpciDeviceInitialize failed - %!STATUS!",
+ device, status);
+ goto Exit;
+ }
+
+Exit:
+ TRACE_FUNC_EXIT(TRACE_DEVICE);
+ return status;
+}
+
+NTSTATUS
+EvtPrepareHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourcesRaw,
+ _In_ WDFCMRESLIST ResourcesTranslated
+)
+/*++
+
+Routine Description:
+
+ A driver's EvtDevicePrepareHardware event callback function performs any operations
+ that are needed to make a device accessible to the driver.
+
+Arguments:
+
+ Device - A handle to a framework device object.
+
+ ResourcesRaw - A handle to a framework resource-list object that identifies the raw hardware
+ resources that the Plug and Play manager has assigned to the device.
+
+ ResourcesTranslated - A handle to a framework resource-list object that identifies the
+ translated hardware resources that the Plug and Play manager has assigned to the device.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ TRACE_FUNC_ENTRY(TRACE_DEVICE);
+
+ PAGED_CODE();
+
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+
+ deviceContext = DeviceGetContext(Device);
+
+ //// Initialize the I2C communication channel to read from/write to the hardware.
+ status = I2CInitialize(deviceContext, ResourcesRaw, ResourcesTranslated);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = I2COpen(deviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+ return status;
+}
+
+NTSTATUS EvtDeviceD0Entry(
+ _In_ WDFDEVICE Device,
+ _In_ WDF_POWER_DEVICE_STATE PreviousState
+)
+{
+ TRACE_FUNC_ENTRY(TRACE_DEVICE);
+
+ UNREFERENCED_PARAMETER(PreviousState);
+
+ PAGED_CODE();
+
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+ UCMTCPCIPORTCONTROLLER portController = WDF_NO_HANDLE;
+ UCMTCPCI_PORT_CONTROLLER_CONFIG config;
+ UCMTCPCI_PORT_CONTROLLER_IDENTIFICATION ident;
+ UCMTCPCI_PORT_CONTROLLER_CAPABILITIES capabilities;
+
+ deviceContext = DeviceGetContext(Device);
+
+ UCMTCPCI_PORT_CONTROLLER_IDENTIFICATION_INIT(&ident);
+ UCMTCPCI_PORT_CONTROLLER_CAPABILITIES_INIT(&capabilities);
+
+ // Read device identification and capabilities from the registers.
+ REGISTER_ITEM items[] = {
+ GEN_REGISTER_ITEM(VENDOR_ID, ident.VendorId),
+ GEN_REGISTER_ITEM(PRODUCT_ID, ident.ProductId),
+ GEN_REGISTER_ITEM(DEVICE_ID, ident.DeviceId),
+ GEN_REGISTER_ITEM(USBTYPEC_REV, ident.TypeCRevisionInBcd),
+ GEN_REGISTER_ITEM(USBPD_REV_VER, ident.PDRevisionAndVersionInBcd),
+ GEN_REGISTER_ITEM(PD_INTERFACE_REV, ident.PDInterfaceRevisionAndVersionInBcd),
+ GEN_REGISTER_ITEM(DEVICE_CAPABILITIES_1, capabilities.DeviceCapabilities1),
+ GEN_REGISTER_ITEM(DEVICE_CAPABILITIES_2, capabilities.DeviceCapabilities2),
+ GEN_REGISTER_ITEM(STANDARD_INPUT_CAPABILITIES, capabilities.StandardInputCapabilities),
+ GEN_REGISTER_ITEM(STANDARD_OUTPUT_CAPABILITIES, capabilities.StandardOutputCapabilities),
+ };
+
+ status = I2CReadSynchronouslyMultiple(deviceContext,
+ I2CRequestSourceClient,
+ items,
+ _countof(items));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+
+ capabilities.IsPowerDeliveryCapable = TRUE;
+
+ UCMTCPCI_PORT_CONTROLLER_CONFIG_INIT(&config, &ident, &capabilities);
+
+ // Create a UCMTCPCIPORTCONTROLLER framework object.
+ status = UcmTcpciPortControllerCreate(Device, &config, WDF_NO_OBJECT_ATTRIBUTES, &portController);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "[WDFDEVICE: 0x%p] UcmTcpciPortControllerCreate "
+ "failed - %!STATUS!", Device, status);
+ goto Exit;
+ }
+
+ // Save the UCMTCPCIPORTCONTROLLER in our device context.
+ deviceContext = DeviceGetContext(Device);
+ deviceContext->PortController = portController;
+
+ // Set the hardware request queue for our device.
+ status = HardwareRequestQueueInitialize(Device);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ // Direct UcmTcpciCx to start the port controller.
+ // At this point, UcmTcpciCx will assume control of USB Type-C and Power Delivery.
+ // After the port controller is started, UcmTcpciCx may start putting requests into the
+ // hardware request queue.
+ status = UcmTcpciPortControllerStart(portController);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "[UCMTCPCIPORTCONTROLLER: 0x%p]"
+ "UcmTcpciPortControllerStart failed - %!STATUS!", portController, status);
+ goto Exit;
+ }
+
+Exit:
+ if (!NT_SUCCESS(status) && (portController != WDF_NO_HANDLE))
+ {
+ WdfObjectDelete(portController);
+ deviceContext->PortController = WDF_NO_HANDLE;
+ }
+
+ TRACE_FUNC_EXIT(TRACE_DEVICE);
+ return status;
+}
+
+NTSTATUS
+EvtReleaseHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourcesTranslated
+)
+/*++
+
+Routine Description:
+
+ A driver's EvtDeviceReleaseHardware event callback function performs operations
+ that are needed when a device is no longer accessible.
+
+Arguments:
+
+ Device - A handle to a framework device object.
+
+ ResourcesTranslated - A handle to a resource list object that identifies the translated
+ hardware resources that the Plug and Play manager has assigned to the device.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ TRACE_FUNC_ENTRY(TRACE_DEVICE);
+
+ UNREFERENCED_PARAMETER(ResourcesTranslated);
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+ PDEVICE_CONTEXT deviceContext;
+
+ deviceContext = DeviceGetContext(Device);
+
+ if (deviceContext->PortController != WDF_NO_HANDLE)
+ {
+ // Direct UcmTcpciCx to stop the port controller and then delete the backing object.
+ UcmTcpciPortControllerStop(deviceContext->PortController);
+ WdfObjectDelete(deviceContext->PortController);
+ deviceContext->PortController = WDF_NO_HANDLE;
+ }
+
+ // Close the I2C controller.
+ I2CClose(deviceContext);
+
+ TRACE_FUNC_EXIT(TRACE_DEVICE);
+ return status;
+}