summaryrefslogtreecommitdiff
path: root/usb/UcmTcpciCxClientSample/Alert.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/Alert.cpp
parentce06de38a6daee9815dbf7eb8ddd8f335612ccc0 (diff)
Adding UcmTcpciCxClientSample
Diffstat (limited to 'usb/UcmTcpciCxClientSample/Alert.cpp')
-rw-r--r--usb/UcmTcpciCxClientSample/Alert.cpp329
1 files changed, 329 insertions, 0 deletions
diff --git a/usb/UcmTcpciCxClientSample/Alert.cpp b/usb/UcmTcpciCxClientSample/Alert.cpp
new file mode 100644
index 00000000..b63692db
--- /dev/null
+++ b/usb/UcmTcpciCxClientSample/Alert.cpp
@@ -0,0 +1,329 @@
+/*++
+
+Module Name:
+
+ Alert.c
+
+Abstract:
+
+ This file contains functions that handle alerts from the port controller hardware.
+
+Environment:
+
+ Kernel-mode Driver Framework
+
+--*/
+
+#include "Driver.h"
+#include "alert.tmh"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, OnInterruptPassiveIsr)
+#endif
+
+BOOLEAN
+OnInterruptPassiveIsr(
+ _In_ WDFINTERRUPT PortControllerInterrupt,
+ _In_ ULONG MessageID
+)
+/*++
+
+Routine Description:
+
+ Per the TCPCI spec, the port controller hardware will drive the Alert pin high
+ when a hardware event occurs. This routine services such a hardware interrupt at PASSIVE_LEVEL.
+ The routine determines if an interrupt is an alert from the port controller hardware;
+ if so, it completes processing of the alert.
+
+Arguments:
+
+ Interrupt: A handle to a framework interrupt object.
+
+ MessageID: If the device is using message-signaled interrupts (MSIs), this parameter
+ is the message number that identifies the device's hardware interrupt message.
+ Otherwise, this value is 0.
+
+Return Value:
+
+ TRUE if the function services the hardware interrupt.
+ Otherwise, this function must return FALSE.
+
+--*/
+{
+ TRACE_FUNC_ENTRY(TRACE_ALERT);
+
+ UNREFERENCED_PARAMETER(MessageID);
+ PAGED_CODE();
+
+ NTSTATUS status;
+ PDEVICE_CONTEXT deviceContext;
+ ALERT_REGISTER alertRegister;
+ BOOLEAN interruptRecognized = FALSE;
+ int numAlertsProcessed = 0;
+ deviceContext = DeviceGetContext(WdfInterruptGetDevice(PortControllerInterrupt));
+
+ // Process the alerts as long as there are bits set in the alert register.
+ // Set a maximum number of alerts to process in this loop. If the hardware is messed up and we're unable
+ // to quiesce the interrupt by writing to the alert register, then we don't want to be stuck in an
+ // infinite loop.
+ while (numAlertsProcessed <= MAX_ALERTS_TO_PROCESS)
+ {
+ status = I2CReadSynchronously(deviceContext,
+ I2CRequestSourceAlertIsr,
+ ALERT,
+ &alertRegister,
+ sizeof(alertRegister));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ // If there are no bits set in the alert register, we should not service this interrupt.
+ if (alertRegister.AsUInt16 == 0)
+ {
+ goto Exit;
+ }
+
+ // Since there are bits set in the alert register, we can safely assume that the
+ // interrupt is ours to process.
+ interruptRecognized = TRUE;
+
+ ProcessAndSendAlerts(&alertRegister, deviceContext);
+ ++numAlertsProcessed;
+ }
+
+Exit:
+ TRACE_FUNC_EXIT(TRACE_ALERT);
+ return interruptRecognized;
+}
+
+void
+ProcessAndSendAlerts(
+ _In_ PALERT_REGISTER AlertRegister,
+ _In_ PDEVICE_CONTEXT DeviceContext
+)
+/*++
+
+Routine Description:
+
+ Processes the set of hardware alerts that were reported and notifies UcmTcpciCx of the alerts
+ along with the contents of relevant registers.
+
+Arguments:
+
+ AlertRegister: Pointer to alert register contents.
+
+ DeviceContext: Device's context space.
+
+--*/
+{
+ TRACE_FUNC_ENTRY(TRACE_ALERT);
+ PAGED_CODE();
+
+ NTSTATUS status;
+ size_t numAlerts = 0;
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA alertData;
+ UCMTCPCI_PORT_CONTROLLER_CC_STATUS ccStatus;
+ UCMTCPCI_PORT_CONTROLLER_POWER_STATUS powerStatus;
+ UCMTCPCI_PORT_CONTROLLER_FAULT_STATUS faultStatus;
+ UCMTCPCI_PORT_CONTROLLER_RECEIVE_BUFFER receiveBuffer;
+
+ // UcmTcpciCx expects the information on all of the alerts firing presently.
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA hardwareAlerts[MAX_ALERTS];
+
+ status = STATUS_SUCCESS;
+
+ if (AlertRegister->CCStatus == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertCCStatus;
+
+ // We must read the CC status register and send the contents to
+ // UcmTcpciCx along with the CC status alert.
+ status = I2CReadSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ CC_STATUS,
+ &ccStatus,
+ sizeof(ccStatus));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ alertData.CCStatus = ccStatus;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->PowerStatus == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertPowerStatus;
+
+ // We must read the power status register and send the contents to
+ // UcmTcpciCx along with the power status alert.
+ status = I2CReadSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ POWER_STATUS,
+ &powerStatus,
+ sizeof(powerStatus));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ alertData.PowerStatus = powerStatus;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->Fault == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertFault;
+
+ // We must read the fault status register and send the contents to
+ // UcmTcpciCx along with the fault alert.
+ status = I2CReadSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ FAULT_STATUS,
+ &faultStatus,
+ sizeof(faultStatus));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ alertData.FaultStatus = faultStatus;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+
+ // Clear FAULT_STATUS Register.
+
+ // Mask reserved bit 7 in TCPCI Rev 1.0 Ver 1.0 only, see spec section 4.4.6.3
+ faultStatus.AsUInt8 &= 0x7F;
+
+ status = I2CWriteSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ FAULT_STATUS,
+ &faultStatus,
+ sizeof(faultStatus));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ if (AlertRegister->ReceiveSOPMessageStatus == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertReceiveSOPMessageStatus;
+
+ // We must read the receive buffer register and send the contents to
+ // UcmTcpciCx along with the receive SOP alert.
+ status = I2CReadSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ RECEIVE_BUFFER,
+ &receiveBuffer,
+ sizeof(receiveBuffer));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ alertData.ReceiveBuffer = &receiveBuffer;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ // The remainder of the alert types do not require us to provide any extra
+ // information to UcmTcpciCx.
+ if (AlertRegister->ReceivedHardReset == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertReceivedHardReset;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->RxBufferOverflow == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertRxBufferOverflow;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->TransmitSOPMessageDiscarded == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertTransmitSOPMessageDiscarded;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->TransmitSOPMessageFailed == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertTransmitSOPMessageFailed;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->TransmitSOPMessageSuccessful == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertTransmitSOPMessageSuccessful;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->VbusSinkDisconnectDetected == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertVbusSinkDisconnectDetected;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->VbusVoltageAlarmHi == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertVbusVoltageAlarmHi;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ if (AlertRegister->VbusVoltageAlarmLo == 1)
+ {
+ UCMTCPCI_PORT_CONTROLLER_ALERT_DATA_INIT(&alertData);
+ alertData.AlertType = UcmTcpciPortControllerAlertVbusVoltageAlarmLo;
+ hardwareAlerts[numAlerts] = alertData;
+ ++numAlerts;
+ }
+
+ // Only write back non-reserved bits see spec section 4.4.2
+ // TCPCI Rev 1.0 Ver 1.0: 0x0FFF
+ // TCPCI Rev 1.0 Ver 1.1: 0x8FFF
+ AlertRegister->AsUInt16 &= 0x0FFF;
+
+ // Quiesce the interrupt by writing back the alert register.
+ // Per TCPCI spec 4.4.2, the alert is cleared by writing a 1 back to the bit position it is to clear.
+ status = I2CWriteSynchronously(DeviceContext,
+ I2CRequestSourceAlertIsr,
+ ALERT,
+ AlertRegister,
+ sizeof(*AlertRegister));
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+ if (NT_SUCCESS(status))
+ {
+ // Send the list of hardware alerts to UcmTcpciCx.
+ UcmTcpciPortControllerAlert(DeviceContext->PortController, hardwareAlerts, numAlerts);
+ }
+
+ TRACE_FUNC_EXIT(TRACE_ALERT);
+} \ No newline at end of file