static void memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write) { uintptr racectx; if(!onstack((uintptr)addr)) { m->racecall = true; racectx = g->racectx; if(callpc) { if(callpc == (uintptr)runtime·lessstack) runtime·callers(3, &callpc, 1); runtime∕race·FuncEnter(racectx, (void*)callpc); } if(write) runtime∕race·Write(racectx, addr, (void*)pc); else runtime∕race·Read(racectx, addr, (void*)pc); if(callpc) runtime∕race·FuncExit(racectx); m->racecall = false; } }
ULONG ControllerGetInterruptStatus( _In_ PPBC_DEVICE pDevice, _In_ ULONG InterruptMask ) /*++ Routine Description: This routine gets the interrupt status of the specificed interrupt bits. Arguments: pDevice - a pointer to the PBC device context InterruptMask - interrupt bits to check Return Value: A bitmap indicating which interrupts are set. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); ULONG interruptStatus = 0; NT_ASSERT(pDevice != NULL); // TODO: Check if any of the interrupt mask // bits have triggered an interrupt. UNREFERENCED_PARAMETER(pDevice); UNREFERENCED_PARAMETER(InterruptMask); FuncExit(TRACE_FLAG_TRANSFER); return interruptStatus; }
NTSTATUS OnD0Entry( _In_ WDFDEVICE FxDevice, _In_ WDF_POWER_DEVICE_STATE FxPreviousState ) /*++ Routine Description: This routine allocates objects needed by the driver. Arguments: FxDevice - a handle to the framework device object FxPreviousState - previous power state Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); UNREFERENCED_PARAMETER(FxPreviousState); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); NTSTATUS status = STATUS_SUCCESS; WdfTimerStart(pDevice->Timer, WDF_REL_TIMEOUT_IN_MS(10)); pDevice->RegsSet = false; pDevice->ConnectInterrupt = true; FuncExit(TRACE_FLAG_WDFLOADING); return status; }
static void memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write) { int64 goid; if(!onstack((uintptr)addr)) { m->racecall = true; goid = g->goid-1; if(callpc) { if(callpc == (uintptr)runtime·lessstack || (callpc >= (uintptr)runtime·mheap.arena_start && callpc < (uintptr)runtime·mheap.arena_used)) runtime·callers(3, &callpc, 1); runtime∕race·FuncEnter(goid, (void*)callpc); } if(write) runtime∕race·Write(goid, addr, (void*)pc); else runtime∕race·Read(goid, addr, (void*)pc); if(callpc) runtime∕race·FuncExit(goid); m->racecall = false; } }
NTSTATUS OnD0Exit( _In_ WDFDEVICE FxDevice, _In_ WDF_POWER_DEVICE_STATE FxPreviousState ) /*++ Routine Description: This routine destroys objects needed by the driver. Arguments: FxDevice - a handle to the framework device object FxPreviousState - previous power state Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); UNREFERENCED_PARAMETER(FxPreviousState); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); WdfTimerStop(pDevice->Timer, TRUE); pDevice->ConnectInterrupt = false; FuncExit(TRACE_FLAG_WDFLOADING); return STATUS_SUCCESS; }
NTSTATUS OnReleaseHardware( _In_ WDFDEVICE FxDevice, _In_ WDFCMRESLIST FxResourcesTranslated ) /*++ Routine Description: Arguments: FxDevice - a handle to the framework device object FxResourcesTranslated - list of raw hardware resources that the PnP manager has assigned to the device Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(FxResourcesTranslated); SpbTargetDeinitialize(FxDevice, &pDevice->I2CContext); deviceLoaded = false; FuncExit(TRACE_FLAG_WDFLOADING); return status; }
///////////////////////////////////////////////////////////////////////// // // CMyDevice::OnD0Exit // // This method is called when a device leaves the system // // Parameters: // pWdfDevice - pointer to a device object // newState - new WDF power state // // Return Values: // status // ///////////////////////////////////////////////////////////////////////// HRESULT CMyDevice::OnD0Exit( _In_ IWDFDevice* pWdfDevice, _In_ WDF_POWER_DEVICE_STATE newState ) { FuncEntry(); UNREFERENCED_PARAMETER(pWdfDevice); UNREFERENCED_PARAMETER(newState); HRESULT hr = m_pSensorDdi->Stop(); if (FAILED(hr)) { Trace( TRACE_LEVEL_ERROR, "Failed to stop the sensor DDI, %!HRESULT!", hr); } FuncExit(); return hr; }
VOID ControllerCompleteTransfer( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest, _In_ BOOLEAN AbortSequence ) /*++ Routine Description: This routine completes a data transfer. Unless there are more transfers remaining in the sequence, the request is completed. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context AbortSequence - specifies whether the driver should abort the ongoing sequence or begin the next transfer Return Value: None. The request is completed asynchronously. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); NT_ASSERT(pDevice != NULL); NT_ASSERT(pRequest != NULL); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Transfer (index %lu) %s with %Iu bytes for address 0x%lx " "(SPBREQUEST %p)", pRequest->TransferIndex, NT_SUCCESS(pRequest->Status) ? "complete" : "error", pRequest->Information, pDevice->pCurrentTarget->Settings.Address, pRequest->SpbRequest); // // Update request context with information from this transfer. // pRequest->TotalInformation += pRequest->Information; pRequest->Information = 0; // // Check if there are more transfers // in the sequence. // if (!AbortSequence) { pRequest->TransferIndex++; if (pRequest->TransferIndex < pRequest->TransferCount) { // // Configure the request for the next transfer. // pRequest->Status = PbcRequestConfigureForIndex( pRequest, pRequest->TransferIndex); if (NT_SUCCESS(pRequest->Status)) { // // Configure controller and kick-off read. // Request will be completed asynchronously. // PbcRequestDoTransfer(pDevice,pRequest); goto exit; } } } // // If not already cancelled, unmark request cancellable. // if (pRequest->Status != STATUS_CANCELLED) { NTSTATUS cancelStatus; cancelStatus = WdfRequestUnmarkCancelable(pRequest->SpbRequest); if (!NT_SUCCESS(cancelStatus)) { // // WdfRequestUnmarkCancelable should only fail if the request // has already been or is about to be cancelled. If it does fail // the request must NOT be completed - the cancel callback will do // this. // NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if the request has already been or is about to be cancelled", cancelStatus == STATUS_CANCELLED); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Failed to unmark SPBREQUEST %p as cancelable - %!STATUS!", pRequest->SpbRequest, cancelStatus); goto exit; } } // // Done or error occurred. Set interrupt mask to 0. // Doing this keeps the DPC from re-enabling interrupts. // PbcDeviceSetInterruptMask(pDevice, 0); // // Clear the target's current request. This will prevent // the request context from being accessed once the request // is completed (and the context is invalid). // pDevice->pCurrentTarget->pCurrentRequest = NULL; // // Clear the controller's current target if any of // 1. request is type sequence // 2. request position is single // (did not come between lock/unlock) // Otherwise wait until unlock. // if ((pRequest->Type == SpbRequestTypeSequence) || (pRequest->SequencePosition == SpbRequestSequencePositionSingle)) { pDevice->pCurrentTarget = NULL; } // // Mark the IO complete. Request not // completed here. // pRequest->bIoComplete = TRUE; exit: FuncExit(TRACE_FLAG_TRANSFER); }
// // Internal Function: UartCtlSetBaudRate // VOID UartCtlSetBaudRate( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_BAUD_RATE pBaudRate = NULL; USHORT DivisorLatchRegs = 0; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveInputBuffer(Request, sizeof(SERIAL_BAUD_RATE), (PVOID*)(& pBaudRate), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve input buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { status = UartRegConvertAndValidateBaud( pBaudRate->BaudRate, &DivisorLatchRegs); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to convert and validate baudrate %lu - " "%!STATUS!", pBaudRate->BaudRate, status); } } if (NT_SUCCESS(status)) { // Acquires the interrupt lock and writes the Divisor Latch. WdfInterruptAcquireLock(pDevExt->WdfInterrupt); pDevExt->CurrentBaud = pBaudRate->BaudRate; WRITE_DIVISOR_LATCH(pDevExt, pDevExt->Controller, DivisorLatchRegs); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetLineControl // VOID UartCtlGetLineControl( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); UCHAR lineControlRegister = 0; PSERIAL_LINE_CONTROL pLineControl = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_LINE_CONTROL), (PVOID*)(& pLineControl), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // Acquires the interrupt lock and reads the LCR. WdfInterruptAcquireLock(pDevExt->WdfInterrupt); lineControlRegister = READ_LINE_CONTROL(pDevExt, pDevExt->Controller); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); status = UartRegLCRToStruct(lineControlRegister, pLineControl); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to calculate SERIAL_LINE_CONTROL from LCR %c - " "%!STATUS!", lineControlRegister, status); } } if (NT_SUCCESS(status)) { WdfRequestSetInformation(Request, sizeof(SERIAL_LINE_CONTROL)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlSetLineControl // VOID UartCtlSetLineControl( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); UCHAR lineControlRegister = 0; PSERIAL_LINE_CONTROL pLineControl = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveInputBuffer(Request, sizeof(SERIAL_LINE_CONTROL), (PVOID*)(& pLineControl), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve input buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { status = UartRegStructToLCR(pLineControl, &lineControlRegister); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to calculate LCR from SERIAL_LINE_CONTROL %p - " "%!STATUS!", pLineControl, status); } } if (NT_SUCCESS(status)) { WdfInterruptAcquireLock(pDevExt->WdfInterrupt); // Set line control, save break setting lineControlRegister = lineControlRegister | (READ_LINE_CONTROL(pDevExt, pDevExt->Controller) & SERIAL_LCR_BREAK); WRITE_LINE_CONTROL(pDevExt, pDevExt->Controller, lineControlRegister); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetProperties // VOID UartCtlGetProperties( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PSERIAL_COMMPROP pProps = NULL; ULONG bufferSize; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_COMMPROP), (PVOID*)(& pProps), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { RtlZeroMemory(pProps, sizeof(SERIAL_COMMPROP)); pProps->PacketLength = sizeof(SERIAL_COMMPROP); pProps->PacketVersion = 2; pProps->ServiceMask = SERIAL_SP_SERIALCOMM; pProps->MaxTxQueue = 0; pProps->MaxRxQueue = MAXLONG; pProps->MaxBaud = UartMaxBaudRate; pProps->SettableBaud = SERIAL_BAUD_USER; pProps->ProvSubType = SERIAL_SP_UNSPECIFIED; pProps->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; pProps->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; pProps->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; pProps->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; SerCxGetRingBufferUtilization(Device, NULL, &bufferSize); pProps->CurrentTxQueue = 0; pProps->CurrentRxQueue = bufferSize; WdfRequestSetInformation(Request, sizeof(SERIAL_COMMPROP)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
BOOLEAN UartRecordInterrupt( _In_ WDFDEVICE Device ) { BOOLEAN servicedAnInterrupt = FALSE; UCHAR regInterruptId = 0; UCHAR regLineStatus = 0; UCHAR regModemStatus = 0; UCHAR oldErrorBits = 0; PUART_DEVICE_EXTENSION pDevExt; FuncEntry(TRACE_FLAG_REGUTIL); pDevExt = UartGetDeviceExtension(Device); regInterruptId = READ_INTERRUPT_ID_REG(pDevExt, pDevExt->Controller); // If an interrupt actually happened, record the registers... // While the NO_INTERRUPT_PENDING bit is NOT set, while ((regInterruptId & SERIAL_IIR_NO_INTERRUPT_PENDING) == 0) { BYTE ier = 0x00; servicedAnInterrupt = TRUE; pDevExt->InterruptIdentifier = regInterruptId; // TODO: Fix // IIR indicates a single interrupt ordered by priority. // This switch statement ensures that interrupts are not // confused with one another. switch (regInterruptId & SERIAL_IIR_MASK) { case SERIAL_IIR_RLS: regLineStatus = READ_LINE_STATUS(pDevExt, pDevExt->Controller); oldErrorBits = pDevExt->LineStatus & SERIAL_LSR_ERROR; pDevExt->LineStatus = regLineStatus | oldErrorBits; break; case SERIAL_IIR_RDA: case SERIAL_IIR_CTI: // Issue flow control UartFlowReceiveFull(Device); // Clear the RDA interrupt for now. We will // read the data in the DPC. ier = READ_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller); ier &= (~SERIAL_IER_RDA); WRITE_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller, ier); break; case SERIAL_IIR_THR: pDevExt->HoldingEmpty = TRUE; // Clear the THR interrupt for now ier = READ_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller); ier &= ~(SERIAL_IER_THR); WRITE_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller, ier); break; case SERIAL_IIR_MS: regModemStatus = READ_MODEM_STATUS(pDevExt, pDevExt->Controller); pDevExt->ModemStatus = (pDevExt->ModemStatus & SERIAL_MSR_EVENTS) | regModemStatus; break; default: break; } regInterruptId = READ_INTERRUPT_ID_REG(pDevExt, pDevExt->Controller); } FuncExit(TRACE_FLAG_REGUTIL); return servicedAnInterrupt; }
///////////////////////////////////////////////////////////////////////// // // CMyDevice::Initialize // // This method initializes the device callback object and creates the // partner device object. // // Parameters: // pDriver - pointer to an IWDFDriver interface // pDeviceInit - pointer to an interface used to intialize the device // // Return Values: // status // ///////////////////////////////////////////////////////////////////////// HRESULT CMyDevice::Initialize( _In_ IWDFDriver* pDriver, _In_ IWDFDeviceInitialize* pDeviceInit ) { FuncEntry(); CComPtr<IUnknown> spCallback; CComPtr<IWDFDevice> spIWDFDevice; CComPtr<IWDFDevice3> spIWDFDevice3; HRESULT hr; // Prepare device parameters pDeviceInit->SetLockingConstraint(None); pDeviceInit->SetPowerPolicyOwnership(TRUE); hr = QueryInterface(IID_PPV_ARGS(&spCallback)); if (SUCCEEDED(hr)) { // Create the IWDFDevice object hr = pDriver->CreateDevice(pDeviceInit, spCallback, &spIWDFDevice); if (FAILED(hr)) { Trace( TRACE_LEVEL_ERROR, "Failed to create the IWDFDevice object, %!HRESULT!", hr); } if (SUCCEEDED(hr)) { // Assign context hr = spIWDFDevice->AssignContext(nullptr, (void*)this); if (FAILED(hr)) { Trace( TRACE_LEVEL_ERROR, "Failed to assign context, %!HRESULT!", hr); } } } if (SUCCEEDED(hr)) { WUDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; WUDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT( &idleSettings, IdleCannotWakeFromS0 ); // Set delay timeout value. This specifies the time // delay between WDF detecting the device is idle // and WDF requesting a Dx power transition on the // device's behalf. idleSettings.IdleTimeout = 100; // Opt-in to D3Cold to allow the platform to remove // power when the device is idle and enters D3. idleSettings.ExcludeD3Cold = WdfFalse; // Get a pointer to the IWDFDevice3 interface and // assign the idle settings. hr = spIWDFDevice->QueryInterface(IID_PPV_ARGS(&spIWDFDevice3)); if (SUCCEEDED(hr)) { hr = spIWDFDevice3->AssignS0IdleSettingsEx(&idleSettings); } } if (SUCCEEDED(hr)) { // Ensure device is disable-able spIWDFDevice->SetPnpState(WdfPnpStateNotDisableable, WdfFalse); spIWDFDevice->CommitPnpState(); // Store the IWDFDevice pointer m_spWdfDevice = spIWDFDevice; } FuncExit(); return hr; }
NTSTATUS ControllerTransferData( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest ) /*++ Routine Description: This routine transfers data to or from the device. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context Return Value: None. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); UNREFERENCED_PARAMETER(pDevice); size_t bytesToTransfer = 0; NTSTATUS status = STATUS_SUCCESS; // // Write // if (pRequest->Direction == SpbTransferDirectionToDevice) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Ready to write %Iu byte(s) for address 0x%lx", bytesToTransfer, pDevice->pCurrentTarget->Settings.Address); // TODO: Perform write. May need to use // PbcRequestGetByte() or some variation. } // // Read // else { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Ready to read %Iu byte(s) for address 0x%lx", bytesToTransfer, pDevice->pCurrentTarget->Settings.Address); // TODO: Perform read. May need to use // PbcRequestSetByte() or some variation. } // // Update request context with bytes transferred. // pRequest->Information += bytesToTransfer; FuncExit(TRACE_FLAG_TRANSFER); return status; }
VOID ControllerProcessInterrupts( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest, _In_ ULONG InterruptStatus ) /*++ Routine Description: This routine processes a hardware interrupt. Activities include checking for errors and transferring data. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context InterruptStatus - saved interrupt status bits from the ISR. These have already been acknowledged and disabled Return Value: None. The request is completed asynchronously. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); NTSTATUS status; NT_ASSERT(pDevice != NULL); NT_ASSERT(pRequest != NULL); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Ready to process interrupts with status 0x%lx for WDFDEVICE %p", InterruptStatus, pDevice->FxDevice); // // Check for address NACK. // if (TestAnyBits(InterruptStatus, SI2C_STATUS_ADDRESS_NACK /*update with nack flag*/)) { // // An address NACK indicates that a device is // not present at that address or is not responding. // Set the error status accordingly. // pRequest->Status = STATUS_NO_SUCH_DEVICE; pRequest->Information = 0; // TODO: Perform any additional action needed to handle NACK. Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_TRANSFER, "NACK on address 0x%lx (WDFDEVICE %p) - %!STATUS!", pDevice->pCurrentTarget->Settings.Address, pDevice->FxDevice, pRequest->Status); // // Complete the transfer and stop processing // interrupts. // ControllerCompleteTransfer(pDevice, pRequest, TRUE); goto exit; } // // Check for data NACK. // if (TestAnyBits(InterruptStatus, SI2C_STATUS_DATA_NACK /*update with nack flag*/)) { // // A data NACK is not necessarily an error. // Set the error status to STATUS_SUCCESS and // indicate the number of bytes successfully // transferred in the information field. The // client will determine success or failure of // the IO based on this length. // pRequest->Status = STATUS_SUCCESS; // TODO: Assuming this info is available, set // information to the actual number of // bytes successfully transferred. //pRequest->Information = 0; // TODO: Perform any additional action needed to handle NACK. Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_TRANSFER, "NACK after %Iu bytes transferred for address 0x%lx " "(WDFDEVICE %p)- %!STATUS!", pRequest->Information, pDevice->pCurrentTarget->Settings.Address, pDevice->FxDevice, pRequest->Status); // // Complete the transfer and stop processing // interrupts. // ControllerCompleteTransfer(pDevice, pRequest, TRUE); goto exit; } // TODO: Check for other errors. if (TestAnyBits(InterruptStatus, SI2C_STATUS_GENERIC_ERROR /*update with error flag*/)) { // TODO: Perform any action needed to handle error, // i.e. set status or bytes transferred accordingly. pRequest->Status = STATUS_UNSUCCESSFUL; pRequest->Information = 0; Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_TRANSFER, "Error after %Iu bytes transferred for address 0x%lx " "(WDFDEVICE %p)- %!STATUS!", pRequest->Information, pDevice->pCurrentTarget->Settings.Address, pDevice->FxDevice, pRequest->Status); // // Complete the transfer and stop processing // interrupts. // ControllerCompleteTransfer(pDevice, pRequest, TRUE); goto exit; } // // Check if controller is ready to transfer more data. // if (TestAnyBits(InterruptStatus, pRequest->DataReadyFlag)) { // // Transfer data. // status = ControllerTransferData(pDevice, pRequest); if (!NT_SUCCESS(status)) { pRequest->Status = status; Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_TRANSFER, "Unexpected error while transferring data for address 0x%lx, " "completing transfer and resetting controller - %!STATUS!", pDevice->pCurrentTarget->Settings.Address, pRequest->Status); // // Complete the transfer and stop processing // interrupts. // ControllerCompleteTransfer(pDevice, pRequest, TRUE); goto exit; } // // If finished transferring data, stop listening for // data ready interrupt. Do not complete transfer // until transfer complete interrupt occurs. // if (PbcRequestGetInfoRemaining(pRequest) == 0) { Trace( TRACE_LEVEL_VERBOSE, TRACE_FLAG_TRANSFER, "No bytes remaining in transfer for address 0x%lx, wait for " "transfer complete interrupt", pDevice->pCurrentTarget->Settings.Address); PbcDeviceAndInterruptMask(pDevice, ~pRequest->DataReadyFlag); } } // // Check if transfer is complete. // if (TestAnyBits(InterruptStatus, 0 /*update with transfer complete flag*/)) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Transfer complete for address 0x%lx with %Iu bytes remaining", pDevice->pCurrentTarget->Settings.Address, PbcRequestGetInfoRemaining(pRequest)); // // If transfer complete interrupt occured and there // are still bytes remaining, transfer data. This occurs // when the number of bytes remaining is less than // the FIFO transfer level to trigger a data ready interrupt. // if (PbcRequestGetInfoRemaining(pRequest) > 0) { status = ControllerTransferData(pDevice, pRequest); if (!NT_SUCCESS(status)) { pRequest->Status = status; Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_TRANSFER, "Unexpected error while transferring data for address 0x%lx, " "completing transfer and resetting controller " "(WDFDEVICE %p) - %!STATUS!", pDevice->pCurrentTarget->Settings.Address, pDevice->FxDevice, pRequest->Status); // // Complete the transfer and stop processing // interrupts. // ControllerCompleteTransfer(pDevice, pRequest, TRUE); goto exit; } } // // Complete the transfer. // ControllerCompleteTransfer(pDevice, pRequest, FALSE); } exit: FuncExit(TRACE_FLAG_TRANSFER); }
VOID ControllerConfigureForTransfer( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest ) /*++ Routine Description: This routine configures and starts the controller for a transfer. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context Return Value: None. The request is completed asynchronously. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); NT_ASSERT(pDevice != NULL); NT_ASSERT(pRequest != NULL); // // Initialize request context for transfer. // pRequest->Settings = g_TransferSettings[pRequest->SequencePosition]; pRequest->Status = STATUS_SUCCESS; // // Configure hardware for transfer. // // TODO: Initialize controller hardware for a general // transfer via the pDevice->pRegisters->* register // interface. Work may include setting up transfer, // configuring FIFOs, selecting address, etc. if (pRequest->Settings.IsStart) { // TODO: Perform any action to program a start bit. } else if (pRequest->Settings.IsEnd) { // TODO: Perform any action to program a stop bit. } if (pRequest->Direction == SpbTransferDirectionToDevice) { // TODO: Perform write-specific configuration, // i.e. pRequest->DataReadyFlag = ... } else if (pRequest->Direction == SpbTransferDirectionFromDevice) { // TODO: Perform read-specific configuration, // i.e. pRequest->DataReadyFlag = ... } // // Synchronize access to device context with ISR. // // TODO: Uncomment when using interrupts. //WdfInterruptAcquireLock(pDevice->InterruptObject); // // Set interrupt mask and clear current status. // // TODO: Save desired interrupt mask. // PbcDeviceSetInterruptMask(pDevice, mask) pDevice->InterruptStatus = 0; Trace( TRACE_LEVEL_VERBOSE, TRACE_FLAG_TRANSFER, "Controller configured for %s of %Iu bytes to address 0x%lx " "(SPBREQUEST %p, WDFDEVICE %p)", pRequest->Direction == SpbTransferDirectionFromDevice ? "read" : "write", pRequest->Length, pDevice->pCurrentTarget->Settings.Address, pRequest->SpbRequest, pDevice->FxDevice); // TODO: Perform necessary action to begin transfer. ControllerEnableInterrupts( pDevice, PbcDeviceGetInterruptMask(pDevice)); // TODO: Uncomment when using interrupts. //WdfInterruptReleaseLock(pDevice->InterruptObject); // TODO: For the purpose of this skeleton sample, // simply complete the request synchronously. ControllerCompleteTransfer(pDevice, pRequest, FALSE); FuncExit(TRACE_FLAG_TRANSFER); }
///////////////////////////////////////////////////////////////////////// // // CMyDevice::OnPrepareHardware // // Called by UMDF to prepare the hardware for use. In our case // we create the SensorDdi object and initialize the Sensor Class Extension // // Parameters: // pWdfDevice - pointer to an IWDFDevice object representing the // device // pWdfResourcesRaw - pointer the raw resource list // pWdfResourcesTranslated - pointer to the translated resource list // // Return Values: // status // ///////////////////////////////////////////////////////////////////////// HRESULT CMyDevice::OnPrepareHardware( _In_ IWDFDevice3 * pWdfDevice, _In_ IWDFCmResourceList * pWdfResourcesRaw, _In_ IWDFCmResourceList * pWdfResourcesTranslated ) { FuncEntry(); HRESULT hr = S_OK; // Create the SensorDDI hr = CComObject<CSensorDdi>::CreateInstance(&m_pSensorDdi); if (FAILED(hr)) { Trace( TRACE_LEVEL_ERROR, "Failed to create the sensor DDI, %!HRESULT!", hr); } if (SUCCEEDED(hr)) { // AddRef after CreateInstance m_pSensorDdi->AddRef(); // Initialize the DDI hr = m_pSensorDdi->Initialize( pWdfDevice, pWdfResourcesRaw, pWdfResourcesTranslated); CComPtr<IUnknown> spUnknown; if (SUCCEEDED(hr)) { hr = m_pSensorDdi->QueryInterface(IID_PPV_ARGS(&spUnknown)); } if (SUCCEEDED(hr)) { // Create and initialize the sensor class extension hr = CoCreateInstance( CLSID_SensorClassExtension, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_spClassExtension)); if (FAILED(hr)) { Trace( TRACE_LEVEL_ERROR, "Could not create the sensor class extension, " "%!HRESULT!", hr); } if (SUCCEEDED(hr)) { // Initialize the sensor class extension hr = m_spClassExtension->Initialize(pWdfDevice, spUnknown); } if (SUCCEEDED(hr)) { // Pass a pointer to the class extension to the DDI hr = m_pSensorDdi->SetSensorClassExtension(m_spClassExtension); } } } FuncExit(); return hr; }
NTSTATUS OnDeviceAdd( _In_ WDFDRIVER FxDriver, _Inout_ PWDFDEVICE_INIT FxDeviceInit ) /*++ Routine Description: This routine creates the device object for an SPB controller and the device's child objects. Arguments: FxDriver - the WDF driver object handle FxDeviceInit - information about the PDO that we are loading on Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); PDEVICE_CONTEXT pDevice; WDFDEVICE fxDevice; WDF_INTERRUPT_CONFIG interruptConfig; NTSTATUS status; UNREFERENCED_PARAMETER(FxDriver); // // Tell framework this is a filter driver. Filter drivers by default are // not power policy owners. This works well for this driver because // HIDclass driver is the power policy owner for HID minidrivers. // WdfFdoInitSetFilter(FxDeviceInit); // // Setup PNP/Power callbacks. // { WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDevicePrepareHardware = OnPrepareHardware; pnpCallbacks.EvtDeviceReleaseHardware = OnReleaseHardware; pnpCallbacks.EvtDeviceD0Entry = OnD0Entry; pnpCallbacks.EvtDeviceD0Exit = OnD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(FxDeviceInit, &pnpCallbacks); } // // Set request attributes. // { WDF_OBJECT_ATTRIBUTES attributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &attributes, REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(FxDeviceInit, &attributes); } // // Create the device. // { WDF_OBJECT_ATTRIBUTES deviceAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate( &FxDeviceInit, &deviceAttributes, &fxDevice); if (!NT_SUCCESS(status)) { CyapaPrint( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error creating WDFDEVICE - %!STATUS!", status); goto exit; } pDevice = GetDeviceContext(fxDevice); NT_ASSERT(pDevice != nullptr); pDevice->FxDevice = fxDevice; } // // Ensure device is disable-able // { WDF_DEVICE_STATE deviceState; WDF_DEVICE_STATE_INIT(&deviceState); deviceState.NotDisableable = WdfFalse; WdfDeviceSetDeviceState(pDevice->FxDevice, &deviceState); } // // Create queues to handle IO // { WDF_IO_QUEUE_CONFIG queueConfig; WDFQUEUE queue; // // Top-level queue // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDefault = OnTopLevelIoDefault; queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate( pDevice->FxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); if (!NT_SUCCESS(status)) { CyapaPrint( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error creating top-level IO queue - %!STATUS!", status); goto exit; } // // Sequential SPB queue // WDF_IO_QUEUE_CONFIG_INIT( &queueConfig, WdfIoQueueDispatchSequential); queueConfig.EvtIoInternalDeviceControl = OnIoDeviceControl; queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate( fxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->SpbQueue ); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto exit; } } WDF_IO_QUEUE_CONFIG queueConfig; WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); queueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate(pDevice->FxDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->ReportQueue ); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Queue 2!\n"); CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); return status; } // // Create an interrupt object for hardware notifications // WDF_INTERRUPT_CONFIG_INIT( &interruptConfig, OnInterruptIsr, NULL); interruptConfig.PassiveHandling = TRUE; status = WdfInterruptCreate( fxDevice, &interruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevice->Interrupt); if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Error creating WDF interrupt object - %!STATUS!", status); goto exit; } WDF_TIMER_CONFIG timerConfig; WDFTIMER hTimer; WDF_OBJECT_ATTRIBUTES attributes; WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, CyapaTimerFunc, 10); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = fxDevice; status = WdfTimerCreate(&timerConfig, &attributes, &hTimer); pDevice->Timer = hTimer; if (!NT_SUCCESS(status)) { CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "(%!FUNC!) WdfTimerCreate failed status:%!STATUS!\n", status); return status; } CyapaPrint(DEBUG_LEVEL_ERROR, DBG_PNP, "Success! 0x%x\n", status); pDevice->DeviceMode = DEVICE_MODE_MOUSE; exit: FuncExit(TRACE_FLAG_WDFLOADING); return status; }
// // Internal Function: UartCtlSetHandflow // VOID UartCtlSetHandflow( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_HANDFLOW pHandFlow = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveInputBuffer(Request, sizeof(SERIAL_HANDFLOW), (PVOID*)(& pHandFlow), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve input buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // // Make sure there are no invalid bits set in // the control and handshake // if ((pHandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) || (pHandFlow->FlowReplace & SERIAL_FLOW_INVALID)) { status = STATUS_INVALID_PARAMETER; TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Invalid bit in SERIAL_HANDFLOW %p - " "%!STATUS!", pHandFlow, status); } } if (NT_SUCCESS(status)) { // // Software flow control and in-band signaling // have not been implemented in this sample. // if ((pHandFlow->ControlHandShake & SERIAL_DSR_SENSITIVITY) || (pHandFlow->ControlHandShake & SERIAL_ERROR_ABORT) || (pHandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE) || (pHandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT) || (pHandFlow->FlowReplace & SERIAL_AUTO_RECEIVE) || (pHandFlow->FlowReplace & SERIAL_ERROR_CHAR) || (pHandFlow->FlowReplace & SERIAL_NULL_STRIPPING) || (pHandFlow->FlowReplace & SERIAL_BREAK_CHAR) || (pHandFlow->FlowReplace & SERIAL_XOFF_CONTINUE) || ((pHandFlow->FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { status = STATUS_NOT_IMPLEMENTED; TraceMessage( TRACE_LEVEL_WARNING, TRACE_FLAG_CONTROL, "Specified SERIAL_HANDFLOW %p has not been implemented - " "%!STATUS!", pHandFlow, status); } } if (NT_SUCCESS(status)) { // // Make sure the DTR mode is valid // if ((pHandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { status = STATUS_INVALID_PARAMETER; TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Cannot set handflow with invalid DTR mode %lu - " "%!STATUS!", pHandFlow->ControlHandShake, status); } } if (NT_SUCCESS(status)) { WdfSpinLockAcquire(pDevExt->ReceiveBufferSpinLock); WdfInterruptAcquireLock(pDevExt->WdfInterrupt); BOOLEAN newFlowControl; BOOLEAN prevFlowControl = UsingRXFlowControl(pDevExt); pDevExt->HandFlow = *pHandFlow; newFlowControl = UsingRXFlowControl(pDevExt); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); // Empty software FIFO before changing flow control if (newFlowControl != prevFlowControl) { if (!newFlowControl) { if (pDevExt->FIFOBufferBytes > 0) { // If switching from flow control to no flow control, // read bytes from the software FIFO to ring buffer before // asserting flow control lines. // Shouldn't have a cached buffer and bytes in the software FIFO NT_ASSERT(!HasCachedReceiveBuffer(pDevExt)); // Using a new status variable so the IOCTL doesn't fail if // the driver can't read the software FIFO to SerCx ring buffer, which // may happen after the file has closed. NTSTATUS fifoStatus = SerCxRetrieveReceiveBuffer(Device, SERIAL_SOFTWARE_FIFO_SIZE, &pDevExt->PIOReceiveBuffer); // Read bytes from software FIFO and return the buffer if (NT_SUCCESS(fifoStatus)) { // Read the software FIFO bytes into the ring buffer. // This function won't return the buffer. UartReceiveBytesFromSoftwareFIFO(pDevExt); // The software FIFO has been read out and should be empty now. NT_ASSERT(pDevExt->FIFOBufferBytes == 0); fifoStatus = SerCxProgressReceive( Device, pDevExt->ReceiveProgress, SerCxStatusSuccess); if (!NT_SUCCESS(fifoStatus)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "%!FUNC! Failed to return buffer - %!STATUS!", fifoStatus); NT_ASSERTMSG("SerCxProgressReceive shouldn't fail", NT_SUCCESS(fifoStatus)); } pDevExt->PerfStats.ReceivedCount += pDevExt->ReceiveProgress; pDevExt->ReceiveProgress = 0; pDevExt->PIOReceiveBuffer.Buffer = NULL; } else { TraceMessage( TRACE_LEVEL_WARNING, TRACE_FLAG_CONTROL, "SerCxRetrieveReceiveBuffer failed - %!STATUS!", fifoStatus); } } } else { // If switching from no flow control to flow control, // the software FIFO should already be empty. NT_ASSERT(pDevExt->FIFOBufferBytes == 0); } } WdfInterruptAcquireLock(pDevExt->WdfInterrupt); // If software FIFO empty, re-assert flow control // Automatic flow control MUST be re-enabled here if it's being used. if (pDevExt->FIFOBufferBytes == 0) { UartFlowReceiveAvailable(Device); } WdfInterruptReleaseLock(pDevExt->WdfInterrupt); WdfSpinLockRelease(pDevExt->ReceiveBufferSpinLock); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
NTSTATUS OnPrepareHardware( _In_ WDFDEVICE FxDevice, _In_ WDFCMRESLIST FxResourcesRaw, _In_ WDFCMRESLIST FxResourcesTranslated ) /*++ Routine Description: This routine caches the SPB resource connection ID. Arguments: FxDevice - a handle to the framework device object FxResourcesRaw - list of translated hardware resources that the PnP manager has assigned to the device FxResourcesTranslated - list of raw hardware resources that the PnP manager has assigned to the device Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); BOOLEAN fSpbResourceFound = FALSE; NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; UNREFERENCED_PARAMETER(FxResourcesRaw); // // Parse the peripheral's resources. // ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); for(ULONG i = 0; i < resourceCount; i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; UCHAR Class; UCHAR Type; pDescriptor = WdfCmResourceListGetDescriptor( FxResourcesTranslated, i); switch (pDescriptor->Type) { case CmResourceTypeConnection: // // Look for I2C or SPI resource and save connection ID. // Class = pDescriptor->u.Connection.Class; Type = pDescriptor->u.Connection.Type; if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) { if (fSpbResourceFound == FALSE) { status = STATUS_SUCCESS; pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; fSpbResourceFound = TRUE; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_WDFLOADING, "SPB resource found with ID=0x%llx", pDevice->I2CContext.I2cResHubId.QuadPart); } else { Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_WDFLOADING, "Duplicate SPB resource found with ID=0x%llx", pDevice->I2CContext.I2cResHubId.QuadPart); } } break; default: // // Ignoring all other resource types. // break; } } // // An SPB resource is required. // if (fSpbResourceFound == FALSE) { status = STATUS_NOT_FOUND; Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "SPB resource not found - %!STATUS!", status); } status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error in Spb initialization - %!STATUS!", status); return status; } FuncExit(TRACE_FLAG_WDFLOADING); return status; }
// // Internal Function: UartCtlGetCommstatus // VOID UartCtlGetCommstatus( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_STATUS pStat = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_STATUS), (PVOID*)(& pStat), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve output buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { WdfSpinLockAcquire(pDevExt->DpcSpinLock); pStat->Errors = pDevExt->ErrorWord; pDevExt->ErrorWord = 0; WdfSpinLockRelease(pDevExt->DpcSpinLock); // // Software flow control and in-band signaling // have not been implemented in this samples. Parameters // such as HoldReasons, AmountInIn/OutQueue, and // WaitForImmediate have not been populated. // WdfRequestSetInformation(Request, sizeof(SERIAL_STATUS)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
VOID OnIoDeviceControl( _In_ WDFQUEUE FxQueue, _In_ WDFREQUEST FxRequest, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: FxQueue - Handle to the framework queue object that is associated with the I/O request. FxRequest - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { FuncEntry(TRACE_FLAG_SPBAPI); WDFDEVICE device; PDEVICE_CONTEXT pDevice; BOOLEAN fSync = FALSE; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); device = WdfIoQueueGetDevice(FxQueue); pDevice = GetDeviceContext(device); CyapaPrint( DEBUG_LEVEL_INFO, DBG_IOCTL, "DeviceIoControl request %p received with IOCTL=%lu", FxRequest, IoControlCode); CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); // // Translate the test IOCTL into the appropriate // SPB API method. Open and close are completed // synchronously. // switch (IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: // // Retrieves the device's HID descriptor. // status = CyapaGetHidDescriptor(device, FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: // //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. // status = CyapaGetDeviceAttributes(FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: // //Obtains the report descriptor for the HID device. // status = CyapaGetReportDescriptor(device, FxRequest); fSync = TRUE; break; case IOCTL_HID_GET_STRING: // // Requests that the HID minidriver retrieve a human-readable string // for either the manufacturer ID, the product ID, or the serial number // from the string descriptor of the device. The minidriver must send // a Get String Descriptor request to the device, in order to retrieve // the string descriptor, then it must extract the string at the // appropriate index from the string descriptor and return it in the // output buffer indicated by the IRP. Before sending the Get String // Descriptor request, the minidriver must retrieve the appropriate // index for the manufacturer ID, the product ID or the serial number // from the device extension of a top level collection associated with // the device. // status = CyapaGetString(FxRequest); fSync = TRUE; break; case IOCTL_HID_WRITE_REPORT: case IOCTL_HID_SET_OUTPUT_REPORT: // //Transmits a class driver-supplied report to the device. // status = CyapaWriteReport(pDevice, FxRequest); fSync = TRUE; break; case IOCTL_HID_READ_REPORT: case IOCTL_HID_GET_INPUT_REPORT: // // Returns a report from the device into a class driver-supplied buffer. // status = CyapaReadReport(pDevice, FxRequest, &fSync); break; case IOCTL_HID_GET_FEATURE: // // returns a feature report associated with a top-level collection // status = CyapaGetFeature(pDevice, FxRequest, &fSync); break; case IOCTL_HID_ACTIVATE_DEVICE: // // Makes the device ready for I/O operations. // case IOCTL_HID_DEACTIVATE_DEVICE: // // Causes the device to cease operations and terminate all outstanding // I/O requests. // default: fSync = TRUE; status = STATUS_NOT_SUPPORTED; CyapaPrint( DEBUG_LEVEL_INFO, DBG_IOCTL, "Request %p received with unexpected IOCTL=%lu", FxRequest, IoControlCode); } // // Complete the request if necessary. // if (fSync) { CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s completed, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); WdfRequestComplete(FxRequest, status); } else { CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL, "%s deferred, Queue:0x%p, Request:0x%p\n", DbgHidInternalIoctlString(IoControlCode), FxQueue, FxRequest ); } FuncExit(TRACE_FLAG_SPBAPI); }
NTSTATUS BOOTTRACKPAD( _In_ PDEVICE_CONTEXT pDevice ) { if (deviceLoaded) return 0; NTSTATUS status = 0; FuncEntry(TRACE_FLAG_WDFLOADING); elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_RESET); uint8_t val[256]; SpbReadDataSynchronously(&pDevice->I2CContext, 0x00, &val, ETP_I2C_INF_LENGTH); SpbReadDataSynchronously16(&pDevice->I2CContext, ETP_I2C_DESC_CMD, &val, ETP_I2C_DESC_LENGTH); SpbReadDataSynchronously16(&pDevice->I2CContext, ETP_I2C_REPORT_DESC_CMD, &val, ETP_I2C_REPORT_DESC_LENGTH); elan_i2c_write_cmd(pDevice, ETP_I2C_SET_CMD, ETP_ENABLE_ABS); elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); uint8_t val2[3]; elan_i2c_read_cmd(pDevice, ETP_I2C_UNIQUEID_CMD, val2); uint8_t prodid = val2[0]; elan_i2c_read_cmd(pDevice, ETP_I2C_FW_VERSION_CMD, val2); uint8_t version = val2[0]; elan_i2c_read_cmd(pDevice, ETP_I2C_FW_CHECKSUM_CMD, val2); uint16_t csum = *((uint16_t *)val2); elan_i2c_read_cmd(pDevice, ETP_I2C_SM_VERSION_CMD, val2); uint8_t smvers = val2[0]; elan_i2c_read_cmd(pDevice, ETP_I2C_IAP_VERSION_CMD, val2); uint8_t iapversion = val2[0]; elan_i2c_read_cmd(pDevice, ETP_I2C_PRESSURE_CMD, val2); elan_i2c_read_cmd(pDevice, ETP_I2C_MAX_X_AXIS_CMD, val2); uint16_t max_x = (*((uint16_t *)val2)) & 0x0fff; elan_i2c_read_cmd(pDevice, ETP_I2C_MAX_Y_AXIS_CMD, val2); uint16_t max_y = (*((uint16_t *)val2)) & 0x0fff; elan_i2c_read_cmd(pDevice, ETP_I2C_XY_TRACENUM_CMD, val2); uint8_t x_traces = val2[0]; uint8_t y_traces = val2[1]; pDevice->max_y = max_y; csgesture_softc *sc = &pDevice->sc; sc->resx = max_x; sc->resy = max_y; sc->phyx = max_x / x_traces; sc->phyy = max_y / y_traces; ElanPrint(DEBUG_LEVEL_INFO, DBG_PNP, "[etp] ProdID: %d Vers: %d Csum: %d SmVers: %d IAPVers: %d Max X: %d Max Y: %d\n", prodid, version, csum, smvers, iapversion, max_x, max_y); elan_i2c_write_cmd(pDevice, ETP_I2C_SET_CMD, ETP_ENABLE_CALIBRATE | ETP_ENABLE_ABS); elan_i2c_write_cmd(pDevice, ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); elan_i2c_write_cmd(pDevice, ETP_I2C_CALIBRATE_CMD, 1); SpbReadDataSynchronously16(&pDevice->I2CContext, ETP_I2C_CALIBRATE_CMD, &val2, 1); elan_i2c_write_cmd(pDevice, ETP_I2C_SET_CMD, ETP_ENABLE_ABS); deviceLoaded = true; FuncExit(TRACE_FLAG_WDFLOADING); return status; }