Esempio n. 1
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
	}
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
/////////////////////////////////////////////////////////////////////////
//
//  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);
}
Esempio n. 9
0
//
// 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);
}
Esempio n. 10
0
//
// 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);
}
Esempio n. 11
0
//
// 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);
}
Esempio n. 12
0
//
// 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);
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
/////////////////////////////////////////////////////////////////////////
//
//  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);
}
Esempio n. 18
0
/////////////////////////////////////////////////////////////////////////
//
//  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;
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
//
// 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);
}
Esempio n. 21
0
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;
}
Esempio n. 22
0
//
// 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);
}
Esempio n. 23
0
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);
}
Esempio n. 24
0
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;
}