Пример #1
0
// Fill in the given struct _HID_DEVICE_ATTRIBUTES
//
NTSTATUS HidFx2GetDeviceAttributes(_In_ WDFREQUEST hRequest)
{
    NTSTATUS                 status = STATUS_SUCCESS;
    PHID_DEVICE_ATTRIBUTES   pDeviceAttributes = NULL;
    PUSB_DEVICE_DESCRIPTOR   pUsbDeviceDescriptor = NULL;
    PDEVICE_EXTENSION        pDeviceInfo = NULL;

    TraceVerbose(DBG_IOCTL, "(%!FUNC!) Entry\n");

    pDeviceInfo = GetDeviceContext(WdfIoQueueGetDevice(WdfRequestGetIoQueue(hRequest)));
    status = WdfRequestRetrieveOutputBuffer(hRequest, sizeof (HID_DEVICE_ATTRIBUTES), &pDeviceAttributes, NULL);
    if (NT_SUCCESS(status))
    {
        // Retrieve USB device descriptor saved in device context
        pUsbDeviceDescriptor = WdfMemoryGetBuffer(pDeviceInfo->hDeviceDescriptor, NULL);
        pDeviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
        pDeviceAttributes->VendorID = pUsbDeviceDescriptor->idVendor;
        pDeviceAttributes->ProductID = pUsbDeviceDescriptor->idProduct;
        pDeviceAttributes->VersionNumber = pUsbDeviceDescriptor->bcdDevice;
        // Report how many bytes were copied
        WdfRequestSetInformation(hRequest, sizeof (HID_DEVICE_ATTRIBUTES));
    }
    else // WdfRequestRetrieveOutputBuffer failed
    {
        TraceErr(DBG_IOCTL, "(%!FUNC!) WdfRequestRetrieveOutputBuffer failed %!STATUS!\n", status);
    }

    TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit = %!STATUS!\n", status);
    return status;
}
Пример #2
0
// Bulk管道读操作的完成函数
//
VOID BulkReadComplete(IN WDFREQUEST  Request, IN WDFIOTARGET  Target,
					   IN PWDF_REQUEST_COMPLETION_PARAMS  Params, 
					   IN WDFCONTEXT  Context)
{
	PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams;
	NTSTATUS ntStatus;
	ULONG_PTR ulLen;
	LONG* lpBuf;

	UNREFERENCED_PARAMETER(Context);
	UNREFERENCED_PARAMETER(Target);

	KDBG(DPFLTR_INFO_LEVEL, "[BulkReadComplete]");

	usbCompletionParams = Params->Parameters.Usb.Completion;
	ntStatus = Params->IoStatus.Status;
	ulLen = usbCompletionParams->Parameters.PipeRead.Length;
	lpBuf = WdfMemoryGetBuffer(usbCompletionParams->Parameters.PipeRead.Buffer, NULL);

	if(NT_SUCCESS(ntStatus))
		KDBG(DPFLTR_INFO_LEVEL, "%d bytes readen from USB device successfully.", ulLen);
	else
		KDBG(DPFLTR_INFO_LEVEL, "Failed to read: 0x%08x!!!", ntStatus);

	// 完成操作
	// 应用程序将收到通知。
	WdfRequestCompleteWithInformation(Request, ntStatus, ulLen);
}
Пример #3
0
NTSTATUS
DeviceGetPdoName(
    _In_  PDEVICE_CONTEXT   DeviceContext
    )
{
    NTSTATUS                status;
    WDFDEVICE               device = DeviceContext->Device;
    WDF_OBJECT_ATTRIBUTES   attributes;
    WDFMEMORY               memory;

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = device;

    status = WdfDeviceAllocAndQueryProperty(
                            device,
                            DevicePropertyPhysicalDeviceObjectName,
                            NonPagedPool,
                            &attributes,
                            &memory);
    if (!NT_SUCCESS(status)) {
        Trace(TRACE_LEVEL_ERROR,
            "Error: Failed to query PDO name");
        goto Exit;
    }

    DeviceContext->PdoName = (PWCHAR) WdfMemoryGetBuffer(memory, NULL);
    Trace(TRACE_LEVEL_ERROR,
            "PDO Name is %ws", DeviceContext->PdoName);

Exit:
    return status;
}
Пример #4
0
// Bulk管道写操作
//
VOID BulkWrite(IN WDFQUEUE  Queue, IN WDFREQUEST  Request, IN size_t  Length)
{
	NTSTATUS status = STATUS_SUCCESS;
	WDFMEMORY hMem = NULL;
	WDFDEVICE hDevice = NULL;
	WDFUSBPIPE BulkOutputPipe = NULL;
	UCHAR* lpBuf;

	UNREFERENCED_PARAMETER(Length);

	KDBG(DPFLTR_INFO_LEVEL, "[BulkWrite] size: %d", Length);

	// 获取管道句柄
	hDevice = WdfIoQueueGetDevice(Queue);
	BulkOutputPipe = GetBulkPipe(FALSE, hDevice);

	if(NULL == BulkOutputPipe)
	{
		KDBG(DPFLTR_ERROR_LEVEL, "BulkOutputPipe = NULL");
		WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
		return;
	}

	status = WdfRequestRetrieveInputMemory(Request, &hMem);
	if(!NT_SUCCESS(status))
	{
		KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestRetrieveInputMemory failed(status = 0x%0.8x)!!!", status);
		WdfRequestComplete(Request, status);
		return;
	}

	// 打印出offset值。
	// 在写缓冲的前两个字节中存有write offset的值
	lpBuf = (UCHAR*)WdfMemoryGetBuffer(hMem, 0);
	KDBG(DPFLTR_TRACE_LEVEL, "write offset: %hd", *(WORD*)lpBuf);

	// 把当前的Request对象进行重利用,发送给USB总线。
	// 格式化Request对象,设置Pipe句柄、完成函数等。
	status = WdfUsbTargetPipeFormatRequestForWrite(BulkOutputPipe, Request, hMem, NULL);
	if(!NT_SUCCESS(status))
	{
		KDBG(DPFLTR_ERROR_LEVEL, "WdfUsbTargetPipeFormatRequestForWrite(status 0x%0.8x)!!!", status);
		WdfRequestComplete(Request, status);
		return;
	}

	WdfRequestSetCompletionRoutine(Request, BulkWriteComplete, BulkOutputPipe); 
	if(FALSE == WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(BulkOutputPipe), NULL))
	{
		status = WdfRequestGetStatus(Request);
		KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestSend failed with status 0x%0.8x\n", status);		
		WdfRequestComplete(Request, status);
	}
}
Пример #5
0
VOID
OsrFxEvtUsbInterruptPipeReadComplete(
    WDFUSBPIPE  Pipe,
    WDFMEMORY   Buffer,
    size_t      NumBytesTransferred,
    WDFCONTEXT  Context
    )
/*++

Routine Description:

    This the completion routine of the continour reader. This can
    called concurrently on multiprocessor system if there are
    more than one readers configured. So make sure to protect
    access to global resources.

Arguments:

    Buffer - This buffer is freed when this call returns.
             If the driver wants to delay processing of the buffer, it
             can take an additional referrence.

    Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro

Return Value:

    NT status value

--*/
{
    PUCHAR          switchState = NULL;
    WDFDEVICE       device;
    PDEVICE_CONTEXT pDeviceContext = Context;

    UNREFERENCED_PARAMETER(NumBytesTransferred);
    UNREFERENCED_PARAMETER(Pipe);

    device = WdfObjectContextGetObject(pDeviceContext);

    ASSERT(NumBytesTransferred == sizeof(UCHAR));

    switchState = WdfMemoryGetBuffer(Buffer, NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n",
                *switchState);

    pDeviceContext->CurrentSwitchState = *switchState;

}
Пример #6
0
VOID  
kmdf1394_AsyncReadCompletion (    
                              IN WDFREQUEST  Request,    
                              IN WDFIOTARGET  Target,    
                              IN PWDF_REQUEST_COMPLETION_PARAMS  Params,    
                              IN WDFCONTEXT  Context)
/*++

Routine Description:

    Async Read completion routine.

Arguments:

Arguments:

    Request - UNUSED

    Target - UNUSED

    Params - UNUSED
    
    Context - Pointer to a WDFMemory Object

Return Value:

    VOID
--*/
{
    PIRB pIrb = NULL;

    UNREFERENCED_PARAMETER (Request);
    UNREFERENCED_PARAMETER (Target);
    UNREFERENCED_PARAMETER (Params);

    Enter();

    ASSERT (Context);

    pIrb = (PIRB) WdfMemoryGetBuffer ((WDFMEMORY)Context, NULL);

    //
    // Just basic clean up here.
    //
    IoFreeMdl (pIrb->u.AsyncRead.Mdl);
    ExFreePoolWithTag (pIrb, POOLTAG_KMDF_VDEV);
    WdfObjectDelete ((WDFMEMORY) Context);

    Exit();
}
Пример #7
0
// 中断Pipe回调函数。这样一旦设备产生了中断信息,驱动就能够读取到。
//
VOID InterruptRead(WDFUSBPIPE Pipe, WDFMEMORY Buffer, size_t NumBytesTransferred, WDFCONTEXT Context)
{
	NTSTATUS status;
	size_t size = 0;
	PDEVICE_CONTEXT pContext = (PDEVICE_CONTEXT)Context;
	WDFREQUEST Request = NULL;
	CHAR *pchBuf = NULL;

	KDBG(DPFLTR_INFO_LEVEL, "[InterruptRead]");
	UNREFERENCED_PARAMETER(Pipe);

	// Read数据缓冲区。注意到,缓冲区长度总是管道最大包长度的倍数。
	// 我们这里只用缓冲区的第一个有效字节。
	pchBuf = (CHAR*)WdfMemoryGetBuffer(Buffer, &size);
	if(pchBuf == NULL || size == 0)
		return;

	// 第一个字节为确认字节,一定是0xD4
	//if(pchBuf[0] != 0xD4)return;

	// 从队列中提取一个未完成请求
	status = WdfIoQueueRetrieveNextRequest(pContext->InterruptManualQueue, &Request);

	if(NT_SUCCESS(status))
	{
		CHAR* pOutputBuffer = NULL;
		status = WdfRequestRetrieveOutputBuffer(Request, 1, &pOutputBuffer, NULL);

		if(NT_SUCCESS(status))
		{
			// 把结果返回给应用程序
			pOutputBuffer[0] = pchBuf[1];
			WdfRequestCompleteWithInformation(Request, status, 1);
		}
		else
		{
			// 返回错误
			WdfRequestComplete(Request, status);
		}

		KDBG(DPFLTR_INFO_LEVEL, "Get and finish an interrupt read request.");
	}else{
		// 队列空,将放弃从设备获取的数据。
		KDBG(DPFLTR_INFO_LEVEL, "Manual interrupt queue is empty!!!");
	}
}
Пример #8
0
NTSTATUS CyGetAndParseUSB30DeviceConfiguration(__in PDEVICE_CONTEXT pDevContext)
 {
	 NTSTATUS NtStatus = STATUS_SUCCESS;
	 WDFMEMORY pUsb30DeviceConfig =NULL;
	 PVOID pUsb30DeviceConfigBuf =NULL;
	 size_t szUsb30DeviceConfigBufSize =0;
	 // Get Device configuration.
	 NtStatus = CyGetUSB30DeviceConfiguration(pDevContext,&pUsb30DeviceConfig);
	 if (NT_SUCCESS(NtStatus) && pUsb30DeviceConfig) 
	 {
		 pUsb30DeviceConfigBuf = WdfMemoryGetBuffer(pUsb30DeviceConfig,&szUsb30DeviceConfigBufSize);
		 //Parse and store the Enpoint companion descriptor
		 CyParseAndStoreUSB30DeviceConfiguration(pDevContext,pUsb30DeviceConfigBuf,szUsb30DeviceConfigBufSize);

		 // Delete the device configuration memory object as it's no longer needed
	     WdfObjectDelete(pUsb30DeviceConfig);
	 }
	 
	 return NtStatus;
 }
Пример #9
0
VOID
CyEvtInterruptINepReaderComplete(
    WDFUSBPIPE  Pipe,
    WDFMEMORY   Buffer,
    size_t      szNumBytesTransferred,
    WDFCONTEXT  Context
    )
{
	PUCHAR          pucIntData = NULL;    
    PDEVICE_CONTEXT pDeviceContext = Context;
	WDFDEVICE WdfDevice;

    UNREFERENCED_PARAMETER(Pipe); 

	WdfDevice = WdfObjectContextGetObject(pDeviceContext);

    if (szNumBytesTransferred == 0) {
        CyTraceEvents(TRACE_LEVEL_WARNING, DBG_INIT,
                    "CyEvtInterruptINepReaderComplete Zero length read "
                    "occured on the Interrupt Pipe's Continuous Reader\n"
                    );
        return;
    }


    ASSERT(szNumBytesTransferred == sizeof(UCHAR));

    pucIntData = WdfMemoryGetBuffer(Buffer, NULL);

    CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                "CyEvtInterruptINepReaderComplete Data %x\n",
                *pucIntData);

    pDeviceContext->ucIntInData = *pucIntData;
    
    CyCompleteIoctlRequest(WdfDevice);
}
Пример #10
0
VOID
EvtIoWrite(
    IN WDFQUEUE         Queue,
    IN WDFREQUEST       Request,
    IN size_t           Length
    )
{
	WDFMEMORY					memory;
	NTSTATUS					status;
	PMY_SERIAL_DEVICE_EXTENSION	pContext;
	PUCHAR						buffer;
	size_t						buf_size;
	size_t						i = 0;

	KdPrint((DRIVER_NAME "-->EvtIoWrite\n"));
	pContext = MySerialGetDeviceExtension(WdfIoQueueGetDevice(Queue));
	status = WdfRequestRetrieveInputMemory(Request, &memory);
	if(!NT_SUCCESS(status))
	{
        KdPrint((DRIVER_NAME "EvtIoWrite Could not get request memory buffer 0x%x\n",
                 status));
        WdfRequestComplete(Request, status);
		KdPrint((DRIVER_NAME "<-- EvtDeviceIoWrite\n"));
        return;
    }
	buffer = WdfMemoryGetBuffer(memory, &buf_size);
	KdPrint((DRIVER_NAME "Sending a buffer of %d bytes\n", buf_size));
	while (i < buf_size)
	{
		while (UartGetBit(pContext, LSR, LSR_ETHR) == 0 ) {}
		UartWriteByte(pContext, buffer[i]);
		i++;
	}
	WdfRequestCompleteWithInformation(Request, status, i);
	KdPrint((DRIVER_NAME "<--EvtIoWrite\n"));
}
Пример #11
0
VOID
CyCompleteIoctlRequest(
    __in WDFDEVICE WdfDevice
    )
{
	NTSTATUS            NtStatus;
    WDFREQUEST          request;
    PDEVICE_CONTEXT     pDevContext;
    size_t              szBytesReturned = 0;
    PUCHAR              pucData;
	PREQUEST_CONTEXT    pReqContext;

    pDevContext = CyGetDeviceContext(WdfDevice);

    do 
	{
       //check for pending request
        NtStatus = WdfIoQueueRetrieveNextRequest(pDevContext->IntInMsgQ, &request);
        if (NT_SUCCESS(NtStatus))
		{
			pReqContext = CyGetRequestContext(request);
			if(pReqContext->IsNeitherIO)
			{
				pucData = WdfMemoryGetBuffer(pReqContext->OutputMemoryBufferWrite,NULL);
				*pucData = pDevContext->ucIntInData;
				szBytesReturned = sizeof(UCHAR);
			}
			else
			{
				NtStatus = WdfRequestRetrieveOutputBuffer(request,
														sizeof(UCHAR),
														&pucData,
														NULL);// BufferLength

				if (!NT_SUCCESS(NtStatus)) 
				{

					CyTraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
						"User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n");
					szBytesReturned = sizeof(UCHAR);

				}
				else
				{
				   *pucData = pDevContext->ucIntInData;
					szBytesReturned = sizeof(UCHAR);
				}
			}

            WdfRequestCompleteWithInformation(request, NtStatus, szBytesReturned);
            NtStatus = STATUS_SUCCESS;

        }
		else if (NtStatus != STATUS_NO_MORE_ENTRIES)
		{
            CyTraceEvents(TRACE_LEVEL_ERROR,DBG_IOCTL,"WdfIoQueueRetrieveNextRequest status %08x\n", NtStatus);
        }
        request = NULL;
    } while (NtStatus == STATUS_SUCCESS);

}
Пример #12
0
VOID
OsrFxEvtUsbInterruptPipeReadComplete(
    WDFUSBPIPE  Pipe,
    WDFMEMORY   Buffer,
    size_t      NumBytesTransferred,
    WDFCONTEXT  Context
    )
/*++

Routine Description:

    This the completion routine of the continour reader. This can
    called concurrently on multiprocessor system if there are
    more than one readers configured. So make sure to protect
    access to global resources.

Arguments:

    Buffer - This buffer is freed when this call returns.
             If the driver wants to delay processing of the buffer, it
             can take an additional referrence.

    Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro

Return Value:

    NT status value

--*/
{
    PMOUSE_STATE    mouseState = NULL;
    WDFDEVICE       device;
    PDEVICE_CONTEXT pDeviceContext = Context;

    UNREFERENCED_PARAMETER(Pipe);

    device = WdfObjectContextGetObject(pDeviceContext);

    //
    // Make sure that there is data in the read packet.  Depending on the device
    // specification, it is possible for it to return a 0 length read in
    // certain conditions.
    //

    if (NumBytesTransferred == 0) {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT,
                    "OsrFxEvtUsbInterruptPipeReadComplete Zero length read "
                    "occured on the Interrupt Pipe's Continuous Reader\n"
                    );
        return;
    }


    ASSERT(NumBytesTransferred == sizeof(UCHAR));

    mouseState = WdfMemoryGetBuffer(Buffer, NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n",
                *mouseState);

    pDeviceContext->CurrentMouseState = *mouseState;

    //
    // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device
    // will generate an interrupt message when the the device resumes from a low
    // power state. So if the Interrupt Message IOCTL was sent after the device
    // has gone to a low power state, the pending Interrupt Message IOCTL will
    // get completed in the function call below, before the user twiddles the
    // dip switches on the OSR USB device. If this is not the desired behavior
    // for your driver, then you could handle this condition by maintaining a
    // state variable on D0Entry to track interrupt messages caused by power up.
    //
    OsrUsbIoctlGetInterruptMessage(device);

}
Пример #13
0
VOID
FileEvtIoDeviceControl(
    IN WDFQUEUE         Queue,
    IN WDFREQUEST       Request,
    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:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - 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

--*/
{
    NTSTATUS            status = STATUS_SUCCESS;// Assume success
    PCHAR               inBuf = NULL, outBuf = NULL; // pointer to Input and output buffer
    PCHAR               data = "this String is from Device Driver !!!";
    ULONG               datalen = (ULONG) strlen(data)+1;//Length of data including null
    PCHAR               buffer = NULL;
    PREQUEST_CONTEXT    reqContext = NULL;
    size_t               bufSize;

    UNREFERENCED_PARAMETER( Queue );

    PAGED_CODE();

    if(!OutputBufferLength || !InputBufferLength)
    {
        WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
        return;
    }

    //
    // Determine which I/O control code was specified.
    //

    switch (IoControlCode)
    {
    case IOCTL_NONPNP_METHOD_BUFFERED:


        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_BUFFERED\n");

        //
        // For bufffered ioctls WdfRequestRetrieveInputBuffer &
        // WdfRequestRetrieveOutputBuffer return the same buffer
        // pointer (Irp->AssociatedIrp.SystemBuffer), so read the
        // content of the buffer before writing to it.
        //
        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);
        if(!NT_SUCCESS(status)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        ASSERT(bufSize == InputBufferLength);

        //
        // Read the input buffer content.
        // We are using the following function to print characters instead
        // TraceEvents with %s format because the string we get may or
        // may not be null terminated. The buffer may contain non-printable
        // characters also.
        //
        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data from User : %!HEXDUMP!\n",
                        log_xstr(inBuf, (USHORT)InputBufferLength)));
        PrintChars(inBuf, InputBufferLength  );


        status = WdfRequestRetrieveOutputBuffer(Request, 0, &outBuf, &bufSize);
        if(!NT_SUCCESS(status)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        ASSERT(bufSize == OutputBufferLength);

        //
        // Writing to the buffer over-writes the input buffer content
        //

        RtlCopyMemory(outBuf, data, OutputBufferLength);

        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data to User : %!HEXDUMP!\n",
                        log_xstr(outBuf, (USHORT)datalen)));
        PrintChars(outBuf, datalen  );

        //
        // Assign the length of the data copied to IoStatus.Information
        // of the request and complete the request.
        //
        WdfRequestSetInformation(Request,
                OutputBufferLength < datalen? OutputBufferLength:datalen);

        //
        // When the request is completed the content of the SystemBuffer
        // is copied to the User output buffer and the SystemBuffer is
        // is freed.
        //

       break;


    case IOCTL_NONPNP_METHOD_IN_DIRECT:


        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_IN_DIRECT\n");

        //
        // Get the Input buffer. WdfRequestRetrieveInputBuffer returns
        // Irp->AssociatedIrp.SystemBuffer.
        //
        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);
        if(!NT_SUCCESS(status)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        ASSERT(bufSize == InputBufferLength);

        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data from User : %!HEXDUMP!\n",
                        log_xstr(inBuf, (USHORT)InputBufferLength)));
        PrintChars(inBuf, InputBufferLength);

        //
        // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe
        // on the Irp->MdlAddress and returns the system address.
        // Oddity: For this method, this buffer is intended for transfering data
        // from the application to the driver.
        //

        status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize);
        if(!NT_SUCCESS(status)) {
            break;
        }

        ASSERT(bufSize == OutputBufferLength);

        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data from User in OutputBuffer: %!HEXDUMP!\n",
                        log_xstr(buffer, (USHORT)OutputBufferLength)));
        PrintChars(buffer, OutputBufferLength);

        //
        // Return total bytes read from the output buffer.
        // Note OutputBufferLength = MmGetMdlByteCount(Irp->MdlAddress)
        //

        WdfRequestSetInformation(Request, OutputBufferLength);

        //
        // NOTE: Changes made to the  SystemBuffer are not copied
        // to the user input buffer by the I/O manager
        //

      break;

    case IOCTL_NONPNP_METHOD_OUT_DIRECT:


        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_OUT_DIRECT\n");

        //
        // Get the Input buffer. WdfRequestRetrieveInputBuffer returns
        // Irp->AssociatedIrp.SystemBuffer.
        //
        status = WdfRequestRetrieveInputBuffer(Request, 0, &inBuf, &bufSize);
        if(!NT_SUCCESS(status)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        ASSERT(bufSize == InputBufferLength);

        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data from User : %!HEXDUMP!\n",
                        log_xstr(inBuf, (USHORT)InputBufferLength)));
        PrintChars(inBuf, InputBufferLength);

        //
        // Get the output buffer. Framework calls MmGetSystemAddressForMdlSafe
        // on the Irp->MdlAddress and returns the system address.
        // For this method, this buffer is intended for transfering data from the
        // driver to the application.
        //
        status = WdfRequestRetrieveOutputBuffer(Request, 0, &buffer, &bufSize);
        if(!NT_SUCCESS(status)) {
            break;
        }

        ASSERT(bufSize == OutputBufferLength);

        //
        // Write data to be sent to the user in this buffer
        //
        RtlCopyMemory(buffer, data, OutputBufferLength);

        Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data to User : %!HEXDUMP!\n",
                        log_xstr(buffer, (USHORT)datalen)));
        PrintChars(buffer, datalen);

        WdfRequestSetInformation(Request,
                    OutputBufferLength < datalen? OutputBufferLength: datalen);

        //
        // NOTE: Changes made to the  SystemBuffer are not copied
        // to the user input buffer by the I/O manager
        //

        break;

    case IOCTL_NONPNP_METHOD_NEITHER:
        {
            size_t inBufLength, outBufLength;

            //
            // The NonPnpEvtDeviceIoInCallerContext has already probe and locked the
            // pages and mapped the user buffer into system address space and
            // stored memory buffer pointers in the request context. We can get the
            // buffer pointer by calling WdfMemoryGetBuffer.
            //
            TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Called IOCTL_NONPNP_METHOD_NEITHER\n");

            reqContext = GetRequestContext(Request);

            inBuf = WdfMemoryGetBuffer(reqContext->InputMemoryBuffer, &inBufLength);
            outBuf = WdfMemoryGetBuffer(reqContext->OutputMemoryBuffer, &outBufLength);

            if(inBuf == NULL || outBuf == NULL) {
                status = STATUS_INVALID_PARAMETER;
            }

            ASSERT(inBufLength == InputBufferLength);
            ASSERT(outBufLength == OutputBufferLength);

            //
            // Now you can safely read the data from the buffer in any arbitrary
            // context.
            //
            Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data from User : %!HEXDUMP!\n",
                            log_xstr(inBuf, (USHORT)inBufLength)));
            PrintChars(inBuf, inBufLength);

            //
            // Write to the buffer in any arbitrary context.
            //
            RtlCopyMemory(outBuf, data, outBufLength);

            Hexdump((TRACE_LEVEL_VERBOSE,  DBG_IOCTL, "Data to User : %!HEXDUMP!\n",
                            log_xstr(outBuf, (USHORT)datalen)));
            PrintChars(outBuf, datalen);

            //
            // Assign the length of the data copied to IoStatus.Information
            // of the Irp and complete the Irp.
            //
            WdfRequestSetInformation(Request,
                    outBufLength < datalen? outBufLength:datalen);

            break;
        }
    default:

        //
        // The specified I/O control code is unrecognized by this driver.
        //
        status = STATUS_INVALID_DEVICE_REQUEST;
        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ERROR: unrecognized IOCTL %x\n", IoControlCode);
        break;
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "Completing Request %p with status %X",
                   Request, status );

    WdfRequestComplete( Request, status);

}
Пример #14
0
VOID  
kmdf1394_AllocateAddressRangeCompletion (    
    IN WDFREQUEST  Request,    
    IN WDFIOTARGET  Target,    
    IN PWDF_REQUEST_COMPLETION_PARAMS  Params,    
    IN WDFCONTEXT  Context)
/*++

Routine Description:

    Allocate Address Range completion routine.

Arguments:

    Request - UNUSED

    Target - UNUSED

    Params - Completion param struct filled out by the completing driver
    
    Context - Pointer to a context structure

Return Value:

    VOID
--*/
{
    PASYNC_ADDRESS_DATA   AsyncAddrData = NULL;
    PALLOCATE_ADDRESS_RANGE  AllocateAddrRange = NULL;
    PDEVICE_EXTENSION  DeviceExtension = NULL;
    WDFMEMORY Memory; 
    PIRB pIrb = NULL;

    PCONTEXT_BUNDLE ContextBundle = NULL;

    //
    // We can get the request completion status from here
    //
    NTSTATUS ntStatus = Params->IoStatus.Status;

    UNREFERENCED_PARAMETER (Target);
    UNREFERENCED_PARAMETER (Request);

    if (NULL == Context)
    {
        TRACE (TL_ERROR, ("Context is NULL!\n"));
        return;
    }

    ContextBundle = (PCONTEXT_BUNDLE) Context;


    AllocateAddrRange = (PALLOCATE_ADDRESS_RANGE) ContextBundle->Context0;
    AsyncAddrData = (PASYNC_ADDRESS_DATA) ContextBundle->Context1;
    Memory = (WDFMEMORY) ContextBundle->Context2;
    DeviceExtension = ContextBundle->Context3;

    //
    // By using the WdfMemoryCreatePreallocated, we can pull the pointer to our
    // IRB from the WDFMemory Object.
    //
    pIrb = (PIRB) WdfMemoryGetBuffer (Memory, NULL);


    if (NT_SUCCESS (ntStatus)) 
    {
        AsyncAddrData->nAddressesReturned = \
            pIrb->u.AllocateAddressRange.AddressesReturned;
        AsyncAddrData->hAddressRange = \
            pIrb->u.AllocateAddressRange.hAddressRange;

        WdfSpinLockAcquire (DeviceExtension->AsyncSpinLock);

        InsertHeadList(
            &DeviceExtension->AsyncAddressData, 
            &AsyncAddrData->AsyncAddressList);

        WdfSpinLockRelease(DeviceExtension->AsyncSpinLock);

        AsyncAddrData->hAddressRange = \
            pIrb->u.AllocateAddressRange.hAddressRange;

        //
        // This goes back in to our original packet from user mode
        //
        AllocateAddrRange->hAddressRange = \
            pIrb->u.AllocateAddressRange.hAddressRange;

        AllocateAddrRange->Required1394Offset.Off_High = \
            pIrb->u.AllocateAddressRange.p1394AddressRange[0].AR_Off_High;

        AllocateAddrRange->Required1394Offset.Off_Low = \
            pIrb->u.AllocateAddressRange.p1394AddressRange[0].AR_Off_Low;
    }
    else 
    {
        TRACE(TL_ERROR, ("AllocateAddressRange failed = 0x%x\n", ntStatus));

        if (pIrb->u.AllocateAddressRange.Mdl)
        {
            IoFreeMdl (pIrb->u.AllocateAddressRange.Mdl);
        }

        if (AsyncAddrData->Buffer)
        {
            ExFreePoolWithTag (AsyncAddrData->Buffer, POOLTAG_KMDF_VDEV);
        }

        if (AsyncAddrData->AddressRange)
        {
            ExFreePoolWithTag (AsyncAddrData->AddressRange, POOLTAG_KMDF_VDEV);
        }

        ExFreePoolWithTag (AsyncAddrData, POOLTAG_KMDF_VDEV);
    }

    ExFreePoolWithTag (pIrb, POOLTAG_KMDF_VDEV);

    WdfObjectDelete (Memory);
}
Пример #15
0
// This the completion routine of the continuous reader. This can called concurrently on multiprocessor system if there are
// more than one readers configured. So make sure to protect access to global resources.
//
void HidFx2EvtUsbInterruptPipeReadComplete(
    WDFUSBPIPE  hPipe,
    WDFMEMORY   hBuffer,
    size_t      cNumBytesTransferred,
    WDFCONTEXT  pContext
   )
{
    PDEVICE_EXTENSION   pDevContext = pContext;
    BOOLEAN             fInTimerQueue;
    unsigned char       *pbSwitchState = NULL;
    unsigned char       bCurrentSwitchState = 0;
    unsigned char       bPrevSwitchState = 0;
    unsigned char       bToggledSwitch = 0;

    UNREFERENCED_PARAMETER(cNumBytesTransferred);
    UNREFERENCED_PARAMETER(hPipe);

    TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n");

    // Interrupt endpoints sends switch state when first started  or when resuming from suspend.
    // We need to ignore that data since user did not change the switch state.
    if (pDevContext->fIsPowerUpSwitchState)
    {
        pDevContext->fIsPowerUpSwitchState = FALSE;
        TraceInfo(DBG_INIT, "(%!FUNC!) Dropping interrupt message since received during powerup/resume\n");
        return;
    }


    // Make sure that there is data in the read packet. 
    // Depending on the device specification, it is possible for it to return a 0 length read in certain conditions.
    if (cNumBytesTransferred == 0)
    {
        TraceWarning(DBG_INIT, "(%!FUNC!) Zero length read occured on the Interrupt Pipe's Continuous Reader\n");
        return;
    }

    pbSwitchState = WdfMemoryGetBuffer(hBuffer, NULL);
    bCurrentSwitchState = ~(*pbSwitchState);                // switchs are inverted on hardware boards
    bCurrentSwitchState &= RADIO_SWITCH_BUTTONS_BIT_MASK;   //Mask off everything except the actual radio switch bit
    bPrevSwitchState = pDevContext->bCurrentSwitchState;

    if (bPrevSwitchState ^ bCurrentSwitchState) // make sure we toggled the radio switch
    {
        switch(pDevContext->driverMode)
        {
        // If it's a slider switch we want  0->1 and 1->0 transitions.
        case DM_SLIDER_SWITCH:
        case DM_SLIDER_SWITCH_AND_LED:
            bToggledSwitch = bCurrentSwitchState;
            // A timer is started for 10 ms everytime there is a switch toggled
            fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME));
            TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue);
            break;
        //If it's a button so we only report 0->1 transitions
        case DM_BUTTON:
        case DM_BUTTON_AND_LED:
            bToggledSwitch = (bPrevSwitchState ^ bCurrentSwitchState) & bCurrentSwitchState;
            if (bToggledSwitch != 0)
            {
                // A timer is started for 10 ms everytime there is a switch toggled on
                fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME));
                TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue);
            }
            break;
        // Ignore button presses if LED only
        case DM_LED_ONLY:
        default:
            break;
        }

        // Store switch state in device context
        pDevContext->bCurrentSwitchState = bCurrentSwitchState;
        pDevContext->bLatestToggledSwitch = bToggledSwitch;
    }
    else
    {
        TraceInfo(DBG_INIT, "(%!FUNC!) Not a radio switch toggle\n");
    }
    TraceInfo(DBG_INIT, "(%!FUNC!) Switch 0x%x, prevSwitch:0x%x, X0R:0x%x\n", bCurrentSwitchState, bPrevSwitchState, bToggledSwitch);

    TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n");
}
Пример #16
0
///////////////////////////////////////////////////////////////////////////////
//
//  BasicUsbInterruptPipeReadComplete
//
//    This is the callback we supplied for the continuous reader
//    on the interrupt IN pipe. It is called whenever the user
//    changes the state of the switches on the switch pack
//
//  INPUTS:
//
//      Pipe    - Our interrupt IN pipe
//
//      Buffer  - The WDFMEMORY object associated with the
//                 transfer. The buffer of thie memory contains
//                 the state of the switch pack
//
//      NumBytesTransferred - Self explanatory
//
//      Context - One of our per device context structures
//                (passed as a parameter to
//                 WDF_USB_CONTINUOUS_READER_CONFIG_INIT)
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      STATUS_SUCCESS, otherwise an error indicating why the driver could not
//                      load.
//
//  IRQL:
//
//      This routine is called at IRQL <= DISPATCH_LEVEL.
//
//  NOTES:
//
//      Even though we've applied a PASSIVE_LEVEL execution
//      level constraint on our device, this callback falls
//      outstide of the callbacks that the constraint is
//      enforced on.
//
///////////////////////////////////////////////////////////////////////////////
VOID
BasicUsbInterruptPipeReadComplete(
    IN WDFUSBPIPE Pipe,
    IN WDFMEMORY Buffer,
    IN size_t NumBytesTransferred,
    IN WDFCONTEXT Context
    ) {

    PUCHAR                   dataBuffer;
    WDFREQUEST               stateChangeRequest;
    PBASICUSB_DEVICE_CONTEXT devContext;
    PUCHAR                   userBuffer;
    NTSTATUS                 status;

    UNREFERENCED_PARAMETER(Pipe);
    UNREFERENCED_PARAMETER(NumBytesTransferred);
    UNREFERENCED_PARAMETER(Context);

    //
    // Someone toggled the switch pack. Complete a pending user
    // request if there is one.
    //

    devContext = (PBASICUSB_DEVICE_CONTEXT)Context;

    dataBuffer = (PUCHAR)WdfMemoryGetBuffer(Buffer, NULL);

#if DBG
    DbgPrint("Interrupt read complete. Bytes transferred = 0x%x, Data = 0x%x\n",
             (ULONG)NumBytesTransferred, *dataBuffer);
#endif

    //
    // See if there is anyone waiting to be notified of the state
    // change.
    //
    status = WdfIoQueueRetrieveNextRequest(
                                        devContext->SwitchPackStateChangeQueue,
                                        &stateChangeRequest);

    if (NT_SUCCESS(status)) {

#if DBG
        DbgPrint("State change request 0x%p pending\n", 
                 stateChangeRequest);
#endif
        //
        // Yup, someone waiting. Complete their request with the switch
        // pack state.
        //
        status = WdfRequestRetrieveOutputBuffer(stateChangeRequest, 
                                                sizeof(UCHAR),
                                                (PVOID *)&userBuffer,
                                                NULL);

        if (NT_SUCCESS(status)) {

            //
            // Stuff the value into the buffer...
            //
            *userBuffer = *dataBuffer;

            //
            // And complete the request, indicating the proper number of
            // bytes transferred.
            //
            WdfRequestCompleteWithInformation(stateChangeRequest,
                                              STATUS_SUCCESS,
                                              sizeof(UCHAR));
        } else {
#if DBG
            DbgPrint("Failed to get user buffer ofState change request 0x%x\n",
                     status);
#endif
            WdfRequestComplete(stateChangeRequest, status);

        }

    } else {
#if DBG
        DbgPrint("No state change requests pending? (0x%x)\n", 
                 status);
#endif

    }

    return;
}
Пример #17
0
VOID
tgwinkEvtIoRead(
    WDFQUEUE Queue,
    WDFREQUEST Request,
    size_t Length
    )
{
    NTSTATUS status;
    WDFMEMORY mem;
    WDF_REQUEST_PARAMETERS params;
    ULONG offset;
    ULONG result;
    PDEVICE_CONTEXT context;
    WDFDEVICE device;
    
    device = WdfIoQueueGetDevice(Queue);
    context = DeviceGetContext(device);

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(Request, &params);

    offset = (ULONG)params.Parameters.Read.DeviceOffset;

    status = WdfRequestRetrieveOutputMemory(Request, &mem);
    if (!NT_SUCCESS(status)) {
        KdPrint("tgwinkEvtIoRead could not get request memory buffer, status 0x%x\n", status);
        WdfVerifierDbgBreakPoint();
        WdfRequestCompleteWithInformation(Request, status, 0);
        return;
    }

    result = context->busInterface.GetBusData(context->busInterface.Context, PCI_WHICHSPACE_CONFIG, WdfMemoryGetBuffer(mem, NULL), offset, (ULONG)Length);

    WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)result);
}
Пример #18
0
NTSTATUS
BthEchoConnectionObjectFormatRequestForL2CaTransfer(
    _In_ PBTHECHO_CONNECTION Connection,
    _In_ WDFREQUEST Request,
    _Inout_ struct _BRB_L2CA_ACL_TRANSFER ** Brb,
    _In_ WDFMEMORY Memory,
    _In_ ULONG TransferFlags //flags include direction of transfer
    )
/*++

Description:

    Formats a request for L2Ca transfer

Arguments:

    Connection - Connection on which L2Ca transfer will be made
    Request - Request to be formatted
    Brb - If a Brb is passed in, it will be used, otherwise
          this routine will allocate the Brb and return in this parameter
    Memory - Memory object which has the buffer for transfer
    TransferFlags - Transfer flags which include direction of the transfer

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    struct _BRB_L2CA_ACL_TRANSFER *brb = NULL;
    size_t bufferSize;
    BOOLEAN brbAllocatedLocally = FALSE; //whether this function allocated the BRB

    WdfSpinLockAcquire(Connection->ConnectionLock);

    if(Connection->ConnectionState != ConnectionStateConnected)
    {
        status = STATUS_CONNECTION_DISCONNECTED;
        WdfSpinLockRelease(Connection->ConnectionLock);
        goto exit;
    }

    WdfSpinLockRelease(Connection->ConnectionLock);

    if (NULL == *Brb)
    {
        brb= (struct _BRB_L2CA_ACL_TRANSFER *)
            Connection->DevCtxHdr->ProfileDrvInterface.BthAllocateBrb(
                BRB_L2CA_ACL_TRANSFER, 
                POOLTAG_BTHECHOSAMPLE
                );
        if(!brb)
        {
            status = STATUS_INSUFFICIENT_RESOURCES;

            TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, 
                "Failed to allocate BRB_L2CA_ACL_TRANSFER, returning status code %!STATUS!\n", status);

            goto exit;
        }
        else
        {
            brbAllocatedLocally = TRUE;
        }
    }
    else
    {
        brb = *Brb;
        Connection->DevCtxHdr->ProfileDrvInterface.BthReuseBrb(
            (PBRB)brb, BRB_L2CA_ACL_TRANSFER
            );
    }

    brb->BtAddress = Connection->RemoteAddress;
    brb->BufferMDL = NULL;
    brb->Buffer = WdfMemoryGetBuffer(Memory, &bufferSize);

    __analysis_assume(bufferSize <= (ULONG)(-1));
    if (bufferSize > (ULONG)(-1))
    {
        status = STATUS_BUFFER_OVERFLOW;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, 
            "Buffer passed in longer than max ULONG, returning status code %!STATUS!\n", status);

        goto exit;        
    }
    
    brb->BufferSize = (ULONG) bufferSize;
    brb->ChannelHandle = Connection->ChannelHandle;
    brb->TransferFlags = TransferFlags;

    status = FormatRequestWithBrb(
        Connection->DevCtxHdr->IoTarget,
        Request,
        (PBRB) brb,
        sizeof(*brb)
        );
    
    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    if (NULL == *Brb)
    {
        *Brb = brb;
    }
exit:
    if (!NT_SUCCESS(status) && brb && brbAllocatedLocally)
    {
        Connection->DevCtxHdr->ProfileDrvInterface.BthFreeBrb((PBRB)brb);
    }
    
    return status;
}
Пример #19
0
NTSTATUS
FmCreateDosDevicesSymbolicLink(
                              WDFDEVICE       Device,
                              PFM_DEVICE_DATA FmDeviceData
                              )
{
    NTSTATUS        status;
    UNICODE_STRING  comPort;
    UNICODE_STRING  pdoName;
    UNICODE_STRING  symbolicLink;
    WDFKEY          hKey = NULL;
    DECLARE_CONST_UNICODE_STRING(valueName, L"PortName");
    WDFSTRING       string = NULL;
    WDFMEMORY       memory;
    WDF_OBJECT_ATTRIBUTES  memoryAttributes;
    size_t          bufferLength;


    PAGED_CODE();

    symbolicLink.Buffer = NULL;

    //
    // Open the device registry and read the "PortName" value written by the
    // class installer.
    //
    status = WdfDeviceOpenRegistryKey(Device,
                                      PLUGPLAY_REGKEY_DEVICE,
                                      STANDARD_RIGHTS_ALL,
                                      NULL, // PWDF_OBJECT_ATTRIBUTES
                                      &hKey);

    if (!NT_SUCCESS (status)) {
        goto Error;
    }
    status = WdfStringCreate(
                            NULL,
                            WDF_NO_OBJECT_ATTRIBUTES ,
                            &string
                            );

    if (!NT_SUCCESS(status)) {
        goto Error;
    }

    //
    // Retrieve the value of ValueName from registry
    //
    status = WdfRegistryQueryString(
                                   hKey,
                                   &valueName,
                                   string
                                   );


    if (!NT_SUCCESS (status)) {
        goto Error;
    }

    //
    // Retrieve the UNICODE_STRING from string object
    //
    WdfStringGetUnicodeString(
                             string,
                             &comPort
                             );

    WdfRegistryClose(hKey);
    hKey = NULL;

    symbolicLink.Length=0;
    symbolicLink.MaximumLength = sizeof(OBJECT_DIRECTORY) + comPort.MaximumLength;

    symbolicLink.Buffer = ExAllocatePoolWithTag(PagedPool,
                                                symbolicLink.MaximumLength + sizeof(WCHAR),
                                                'wkaF');

    if (symbolicLink.Buffer == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Error;
    }
    RtlZeroMemory(symbolicLink.Buffer, symbolicLink.MaximumLength);
    RtlAppendUnicodeToString(&symbolicLink, OBJECT_DIRECTORY);
    RtlAppendUnicodeStringToString(&symbolicLink, &comPort);
    //
    // This DDI will get the underlying PDO name and create a symbolic to that
    // because our FDO doesn't have a name.
    //
    status = WdfDeviceCreateSymbolicLink(Device,
                                         &symbolicLink);

    if (!NT_SUCCESS(status)) {
        goto Error;
    }

    WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
    memoryAttributes.ParentObject = Device;

    status = WdfDeviceAllocAndQueryProperty(Device,
                                            DevicePropertyPhysicalDeviceObjectName,
                                            PagedPool,
                                            &memoryAttributes,
                                            &memory);
    if (!NT_SUCCESS(status)) {
        //
        // We expect a zero length buffer. Anything else is fatal.
        //
        goto Error;
    }

    pdoName.Buffer = WdfMemoryGetBuffer(memory, &bufferLength);

    if (pdoName.Buffer == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto Error;

    }
    pdoName.MaximumLength = (USHORT) bufferLength;
    pdoName.Length = (USHORT) bufferLength - sizeof(UNICODE_NULL);

    status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
                                   L"SERIALCOMM",
                                   pdoName.Buffer,
                                   REG_SZ,
                                   comPort.Buffer,
                                   comPort.Length);

    if (!NT_SUCCESS(status)) {
        goto Error;
    }
    FmDeviceData->Flags |= REG_VALUE_CREATED_FLAG;
    //
    // Store it so it can be deleted later.
    //

    FmDeviceData->PdoName = pdoName;

    Error:

    if (symbolicLink.Buffer != NULL) {
        ExFreePool(symbolicLink.Buffer);
    }

    if (hKey != NULL) {
        WdfRegistryClose(hKey);
    }
    if (string != NULL) {
        WdfObjectDelete(string);
    }

    return status;
}
Пример #20
0
VOID VIOSerialPortWrite(IN WDFQUEUE Queue,
                        IN WDFREQUEST Request,
                        IN size_t Length)
{
    NTSTATUS status;
    PVOID InBuf;
    PVOID buffer;
    PVIOSERIAL_PORT Port;
    PWRITE_BUFFER_ENTRY entry;
    WDFDEVICE Device;
    PDRIVER_CONTEXT Context;
    WDFMEMORY EntryHandle;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
        "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length);

    PAGED_CODE();

    Device = WdfIoQueueGetDevice(Queue);
    Port = RawPdoSerialPortGetData(Device)->port;
    if (Port->Removed)
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_WRITE,
            "Write request on a removed port %d\n", Port->PortId);
        WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS);
        return;
    }

    status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to retrieve input buffer: %x\n", status);
        WdfRequestComplete(Request, status);
        return;
    }

    if (VIOSerialWillWriteBlock(Port))
    {
        WdfRequestComplete(Request, STATUS_CANT_WAIT);
        return;
    }

    buffer = ExAllocatePoolWithTag(NonPagedPool, Length,
        VIOSERIAL_DRIVER_MEMORY_TAG);

    if (buffer == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n");
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    Context = GetDriverContext(WdfDeviceGetDriver(Device));
    status = WdfMemoryCreateFromLookaside(Context->WriteBufferLookaside, &EntryHandle);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to allocate write buffer entry: %x.\n", status);
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    status = WdfRequestMarkCancelableEx(Request,
        VIOSerialPortWriteRequestCancel);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to mark request as cancelable: %x\n", status);
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfObjectDelete(EntryHandle);
        WdfRequestComplete(Request, status);
        return;
    }

    RtlCopyMemory(buffer, InBuf, Length);
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    entry = (PWRITE_BUFFER_ENTRY)WdfMemoryGetBuffer(EntryHandle, NULL);
    entry->EntryHandle = EntryHandle;
    entry->Buffer = buffer;
    entry->Request = Request;

    if (VIOSerialSendBuffers(Port, entry, Length) <= 0)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to send user's buffer.\n");

        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfObjectDelete(EntryHandle);

        if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request, Port->Removed ?
                STATUS_INVALID_DEVICE_STATE : STATUS_INSUFFICIENT_RESOURCES);
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__);
}
Пример #21
0
/*++
Routine Description:

This is the completion routine for reads/writes
If the irp completes with success, we check if we
need to recirculate this irp for another stage of
transfer.

Arguments:

Context - Driver supplied context
Device - Device handle
Request - Request handle
Params - request completion params

Return Value:
None
--*/
VOID ReadWriteCompletion(IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context)
{
    PMDL                    requestMdl;
    WDFUSBPIPE              pipe;
    ULONG                   stageLength;
    NTSTATUS                status;
    PREQUEST_CONTEXT        rwContext;
    PURB                    urb;
    PCHAR                   operation;
    ULONG                   bytesReadWritten;

    UNREFERENCED_PARAMETER(Context);
    rwContext = GetRequestContext(Request);

    PSDrv_DbgPrint(3, ("ReadWriteCompletion - begins\n"));

    if (rwContext->Read)
	{
        operation = "Read";
    }
	else
	{
        operation = "Write";
    }

    pipe = (WDFUSBPIPE)Target;
    status = CompletionParams->IoStatus.Status;

    if (!NT_SUCCESS(status))
	{
        goto End;
    }

    urb = (PURB)WdfMemoryGetBuffer(rwContext->UrbMemory, NULL);
    bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    rwContext->Numxfer += bytesReadWritten;

    // If there is anything left to transfer.
    if (rwContext->Length == 0)
	{
        // this is the last transfer
        WdfRequestSetInformation(Request, rwContext->Numxfer);
        goto End;
    }

    // Start another transfer
    PSDrv_DbgPrint(3, ("Stage next %s transfer...\n", operation));

    if (rwContext->Length > MAX_TRANSFER_SIZE)
	{
        stageLength = MAX_TRANSFER_SIZE;
    }
    else
	{
        stageLength = rwContext->Length;
    }

    // Following call is required to free any mapping made on the partial MDL and reset internal MDL state.
    MmPrepareMdlForReuse(rwContext->Mdl);

    if (rwContext->Read)
	{
        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
            PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed! (Status = %x)\n", status));
            goto End;
        }
    }
	else
	{
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if(!NT_SUCCESS(status))
		{
            PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed! (Status =  %x)\n", status));
            goto End;
        }
    }

    IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID)rwContext->VirtualAddress, stageLength);

    // Reinitialize the urb
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

    rwContext->VirtualAddress += stageLength;
    rwContext->Length -= stageLength;

    // Format the request to send a URB to a USB pipe.
    status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL);
    if (!NT_SUCCESS(status))
	{
        PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }

    WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL);

    // Send the request asynchronously.
    if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS))
	{
        PSDrv_DbgPrint(1, ("WdfRequestSend for %s failed!\n", operation));
        status = WdfRequestGetStatus(Request);
        goto End;
    }

    // Else when the request completes, this completion routine will be called again.
    PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 1\n"));

    return;

End:
    // Dump the request context, complete the request and return.
	PSDrv_DbgPrint(3, ("rwContext->UrbMemory      = %p\n", rwContext->UrbMemory));
	PSDrv_DbgPrint(3, ("rwContext->Mdl            = %p\n", rwContext->Mdl));
	PSDrv_DbgPrint(3, ("rwContext->Length         = %d\n", rwContext->Length));
	PSDrv_DbgPrint(3, ("rwContext->Numxfer        = %d\n", rwContext->Numxfer));
	PSDrv_DbgPrint(3, ("rwContext->VirtualAddress = %p\n", rwContext->VirtualAddress));

    IoFreeMdl(rwContext->Mdl);

    PSDrv_DbgPrint(3, ("Bulk or Interrupt %s request has finished. (Status = %x)\n", operation, status));

    WdfRequestComplete(Request, status);

    PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 2\n"));

    return;
}
Пример #22
0
NTSTATUS
FireFlyEvtDeviceAdd(
    WDFDRIVER Driver,
    PWDFDEVICE_INIT DeviceInit
    )
/*++
Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent to be part of the device stack as a filter.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/    
{
    WDF_OBJECT_ATTRIBUTES           attributes;
    NTSTATUS                        status;
    PDEVICE_CONTEXT                 pDeviceContext;
    WDFDEVICE                       device;
    WDFMEMORY                       memory;
    size_t                          bufferLength;

    UNREFERENCED_PARAMETER(Driver);

    PAGED_CODE();

    //
    // Configure the device as a filter driver
    //
    WdfFdoInitSetFilter(DeviceInit);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status)) {
        KdPrint(("FireFly: WdfDeviceCreate, Error %x\n", status));
        return status;
    }

    //
    // Driver Framework always zero initializes an objects context memory
    //
    pDeviceContext = WdfObjectGet_DEVICE_CONTEXT(device);

    //
    // Initialize our WMI support
    //
    status = WmiInitialize(device, pDeviceContext);
    if (!NT_SUCCESS(status)) {
        KdPrint(("FireFly: Error initializing WMI 0x%x\n", status));
        return status;
    }

    //
    // In order to send ioctls to our PDO, we have open to open it
    // by name so that we have a valid filehandle (fileobject).
    // When we send ioctls using the IoTarget, framework automatically 
    // sets the filobject in the stack location.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    //
    // By parenting it to device, we don't have to worry about
    // deleting explicitly. It will be deleted along witht the device.
    //
    attributes.ParentObject = device;

    status = WdfDeviceAllocAndQueryProperty(device,
                                    DevicePropertyPhysicalDeviceObjectName,
                                    NonPagedPoolNx,
                                    &attributes,
                                    &memory);

    if (!NT_SUCCESS(status)) {
        KdPrint(("FireFly: WdfDeviceAllocAndQueryProperty failed 0x%x\n", status));        
        return STATUS_UNSUCCESSFUL;
    }

    pDeviceContext->PdoName.Buffer = WdfMemoryGetBuffer(memory, &bufferLength);

    if (pDeviceContext->PdoName.Buffer == NULL) {
        return STATUS_UNSUCCESSFUL;
    }

    pDeviceContext->PdoName.MaximumLength = (USHORT) bufferLength;
    pDeviceContext->PdoName.Length = (USHORT) bufferLength-sizeof(UNICODE_NULL);

    return status;
}
Пример #23
0
Файл: usb.c Проект: uri247/wdk80
VOID
HidFx2EvtUsbInterruptPipeReadComplete(
    WDFUSBPIPE  Pipe,
    WDFMEMORY   Buffer,
    size_t      NumBytesTransferred,
    WDFCONTEXT  Context
    )
/*++

Routine Description:

    This the completion routine of the continuous reader. This can
    called concurrently on multiprocessor system if there are
    more than one readers configured. So make sure to protect
    access to global resources.

Arguments:

    Pipe - Handle to WDF USB pipe object

    Buffer - This buffer is freed when this call returns.
             If the driver wants to delay processing of the buffer, it
             can take an additional referrence.

    NumBytesTransferred - number of bytes of data that are in the read buffer.

    Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro

Return Value:

    NT status value

--*/
{
    PDEVICE_EXTENSION  devContext = Context;
    UCHAR              toggledSwitch = 0;
    PUCHAR             switchState = NULL;
    UCHAR              currentSwitchState = 0;
    UCHAR              previousSwitchState = 0;

    UNREFERENCED_PARAMETER(NumBytesTransferred);
    UNREFERENCED_PARAMETER(Pipe);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
        "HidFx2EvtUsbInterruptPipeReadComplete Enter\n");

    //
    // Interrupt endpoints sends switch state when first started
    // or when resuming from suspend. We need to ignore that data since
    // user did not change the switch state.
    //
    if (devContext->IsPowerUpSwitchState) {
        devContext->IsPowerUpSwitchState = FALSE;

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
            "Dropping interrupt message since received during powerup/resume\n");
        return;
    }


    //
    // Make sure that there is data in the read packet.  Depending on the device
    // specification, it is possible for it to return a 0 length read in
    // certain conditions.
    //

    if (NumBytesTransferred == 0) {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT,
                    "HidFx2EvtUsbInterruptPipeReadComplete Zero length read "
                    "occured on the Interrupt Pipe's Continuous Reader\n"
                    );
        return;
    }
    
    switchState = WdfMemoryGetBuffer(Buffer, NULL);

    currentSwitchState = *switchState;
    previousSwitchState = devContext->CurrentSwitchState;

    //
    // we want to know which switch got toggled from 0 to 1
    // Since the device returns the state of all the swicthes and not just the
    // one that got toggled, we need to store previous state and xor
    // it with current state to know whcih one swicth got toggled.
    // Further, the toggle is considered "on" only when it changes from 0 to 1
    // (and not when it changes from 1 to 0).
    //
    toggledSwitch = (previousSwitchState ^ currentSwitchState) & currentSwitchState;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                "HidFx2EvtUsbInterruptPipeReadComplete SwitchState %x, "
                "prevSwitch:0x%x, x0R:0x%x\n",
                currentSwitchState,
                previousSwitchState,
                toggledSwitch
                );

    //
    // Store switch state in device context
    //
    devContext->CurrentSwitchState = *switchState;
    //if (toggledSwitch != 0) {
        devContext->LatestToggledSwitch = toggledSwitch;
    //}

    //
    // Complete pending Read requests if there is at least one switch toggled
    // to on position.
    //
    if (toggledSwitch != 0) {
        BOOLEAN inTimerQueue;

        //
        // Debounce the switchpack. A simple logic is used for debouncing.
        // A timer is started for 10 ms everytime there is a switch toggled on.
        // If within 10 ms same or another switch gets toggled, the timer gets
        // reset for another 10 ms. The HID read request is completed in timer
        // function if there is still a switch in toggled-on state. Note that
        // debouncing happens at the whole switch pack level (not individual
        // switches) which means if two different switches are toggled-on within
        // 10 ms only one of them (later one in this case) will get accepted and
        // sent to hidclass driver
        //
        inTimerQueue = WdfTimerStart(
            devContext->DebounceTimer,
            WDF_REL_TIMEOUT_IN_MS(SWICTHPACK_DEBOUNCE_TIME_IN_MS)
            );

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
            "Debounce Timer started with timeout of %d ms"
            " (TimerReturnValue:%d)\n",
            SWICTHPACK_DEBOUNCE_TIME_IN_MS, inTimerQueue);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
        "HidFx2EvtUsbInterruptPipeReadComplete Exit\n");
}
Пример #24
0
VOID
tgwinkEvtIoDeviceControl(
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength,
    _In_ ULONG IoControlCode
    )
{
    WDFMEMORY mem;
    NTSTATUS status;
    WDFDEVICE dev;
    PDEVICE_CONTEXT context;
    void *uBase = NULL;
    LARGE_INTEGER offset;
    size_t size;

    dev = WdfIoQueueGetDevice(Queue);
    context = DeviceGetContext(dev);

    switch (IoControlCode) {
    case IOCTL_TGWINK_SAY_HELLO:
        
        if (OutputBufferLength != 4) {
            WdfRequestComplete(Request, STATUS_BAD_DATA);
            break;
        }

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfVerifierDbgBreakPoint();
            WdfRequestComplete(Request, status);
            break;
        }

        *((DWORD32 *)(WdfMemoryGetBuffer(mem, NULL))) = 0x5a5aa5a5;
        WdfRequestComplete(Request, STATUS_SUCCESS);
        break;

    case IOCTL_TGWINK_MAP_BAR_0:
        if (sizeof(void *) > OutputBufferLength) {
            KdPrint("tgwinkEvtIoDeviceControl needs a larger buffer (%d > %d)!\n", sizeof(void *), OutputBufferLength);
            WdfRequestComplete(Request, STATUS_BUFFER_TOO_SMALL);
            break;
        }

        offset = context->bar[0].phyAddr;
        size = context->bar[0].length;

        status = ZwMapViewOfSection(context->hMemory, ZwCurrentProcess(), &uBase, 0, 0, &offset, &size, ViewUnmap, 0, PAGE_READWRITE);
        if (!NT_SUCCESS(status)) {

            KdPrint("tgwinkEvtIoDeviceControl could not map view of section, status ");
            switch (status) {
            case STATUS_CONFLICTING_ADDRESSES: 
                KdPrint("STATUS_CONFLICTING_ADDRESSES\n"); 
                break;
            case STATUS_INVALID_PAGE_PROTECTION: 
                KdPrint("STATUS_INVALID_PAGE_PROTECTION\n"); 
                break;
            case STATUS_SECTION_PROTECTION: 
                KdPrint("STATUS_SECTION_PROTECTION\n"); 
                break;
            default: 
                KdPrint("0x % x\n", status); 
                break;
            }
            WdfRequestComplete(Request, status);
            break;
        }

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfVerifierDbgBreakPoint();
            WdfRequestComplete(Request, status);
            break;
        }

        *((void **)(WdfMemoryGetBuffer(mem, NULL))) = uBase;

        WdfRequestComplete(Request, STATUS_SUCCESS);
        break;

    case IOCTL_TGWINK_READ_PHYS:
    {
        PVOID buf;
        ULONG_PTR page, ofs, vtgt = 0;
        SIZE_T vsz = 0;

        if (InputBufferLength != sizeof(PVOID)) {
            KdPrint("tgwinkEvtIoDeviceControl requires a %d-byte buffer for this ioctl (got %d)\n", sizeof(PVOID), OutputBufferLength);
            WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
            break;
        }
        
        status = WdfRequestRetrieveInputBuffer(Request, sizeof(PVOID), &buf, NULL);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        ofs = *((ULONG_PTR *)buf);
        page = ofs & ~0xfff;
        vsz = OutputBufferLength + (page ^ ofs);
        buf = NULL;

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        status = ZwMapViewOfSection(context->hMemory, (HANDLE)-1, (PVOID *)&vtgt, 0, 0, (PLARGE_INTEGER)&page, &vsz, ViewUnmap, 0, PAGE_READONLY);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not map view of physical memory section, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        ofs -= page;
        status = WdfMemoryCopyFromBuffer(mem, 0, (PVOID)(vtgt + ofs), OutputBufferLength);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl failed to copy data from memory to buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        status = ZwUnmapViewOfSection((HANDLE)-1, (PVOID)vtgt);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl failed to unmap view of physical memory section, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }
    
        WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, OutputBufferLength);
    } break;

    case IOCTL_TGWINK_PEND_INTR:
    {
        WdfWaitLockAcquire(context->nnLock, NULL);
        if (context->notifyNext) {
            PINTERRUPT_CONTEXT pCtx = InterruptGetContext(context->hIrq);
            status = WdfRequestRetrieveOutputMemory(Request, &mem);
            if (!NT_SUCCESS(status)) {
                KdPrint("tgwinkEvtIoDeviceControl failed to retrieve output memory, status 0x%x\n", status);
                WdfRequestComplete(Request, status);
            }
            status = WdfMemoryCopyFromBuffer(mem, 0, &pCtx->serial, 8);
            if (!NT_SUCCESS(status)) {
                KdPrint("tgwinkEvtIoDeviceControl failed to copy interrupt number to buffer, status 0x%x\n", status);
                WdfRequestComplete(Request, status);
            }
            WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, 8);
            context->notifyNext = 0;
            KdPrint("tgwinkEvtIoDeviceControl satisfied interrupt notification request synchronously.\n");
            //WdfInterruptEnable(context->hIrq);
        } else {
            KdPrint("tgwinkEvtIoDeviceControl forwarding PEND_INTR request to notification queue\n");
            WdfRequestForwardToIoQueue(Request, context->NotificationQueue);
        }
        WdfWaitLockRelease(context->nnLock);
    } break;

    default:
        WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
    }
}
Пример #25
0
/*++
Routine Description:

This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
requests from the system.

Arguments:

Queue - Handle to the framework queue object that is associated
with the I/O request.
Request - 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
--*/
VOID PSDrv_EvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode)
{
    WDFDEVICE					 device;
    PVOID						 ioBuffer;
    size_t						 bufLength;
    NTSTATUS					 status;
    PDEVICE_CONTEXT				 pDevContext;
    PFILE_CONTEXT				 pFileContext;
    ULONG						 length = 0;
	PSUSBDRV_PIPE_PROPERTY*		 pPipeProp;
	PSUSBDRV_CONTROL_TRANSFER*	 pControlTransfer;
	PSUSBDRV_DRIVER_VERSION*	 pDriverVersion;
	PSUSBDRV_INTERFACE_PROPERTY* pInterfaceProperty;
	unsigned int*				 pnDeviceSpeed;
	WDFMEMORY					 WdfMem = NULL; 
	PUCHAR                       pControlBuffer;
	WDFMEMORY					 WdfMemOut = NULL;

	
	WDF_USB_INTERFACE_SELECT_SETTING_PARAMS  selectSettingParams;

    UNREFERENCED_PARAMETER(InputBufferLength);

    PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - begins\n"));

    PAGED_CODE();

    // initialize variables
    device = WdfIoQueueGetDevice(Queue);
    pDevContext = GetDeviceContext(device);

    switch(IoControlCode)
	{
		case IOCTL_PSDRV_RESET_PIPE:
			PSDrv_DbgPrint(3, ("IOControl: ResetPipe\n"));

			pFileContext = GetFileContext(WdfRequestGetFileObject(Request));

			if (pFileContext->Pipe == NULL)
			{
				PSDrv_DbgPrint(3, ("Invalid pipe!\n"));
				status = STATUS_INVALID_PARAMETER;
			}
			else
			{
				status = ResetPipe(pFileContext->Pipe);
			}

			break;

		case IOCTL_PSDRV_ABORT_PIPE:
			PSDrv_DbgPrint(3, ("IOControl: AbortPipe\n"));

			pFileContext = GetFileContext(WdfRequestGetFileObject(Request));

			if (pFileContext->Pipe == NULL)
			{
				PSDrv_DbgPrint(3, ("Invalid pipe!\n"));
				status = STATUS_INVALID_PARAMETER;
			}
			else
			{
				status = AbortPipe(pFileContext->Pipe);
			}

			break;

		case IOCTL_PSDRV_GET_CONFIG_DESCRIPTOR:
			PSDrv_DbgPrint(3, ("IOControl: GetConfigDescriptor\n"));

			if (pDevContext->UsbConfigurationDescriptor)
			{
				length = pDevContext->UsbConfigurationDescriptor->wTotalLength;

				status = WdfRequestRetrieveOutputBuffer(Request, length, &ioBuffer, &bufLength);
				if(!NT_SUCCESS(status))
				{
					PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status));
					status = STATUS_INVALID_PARAMETER;
					break;
				}

				RtlCopyMemory(ioBuffer, pDevContext->UsbConfigurationDescriptor, length);

				status = STATUS_SUCCESS;
			}
			else
			{
				PSDrv_DbgPrint(3, ("UsbConfigurationDescriptor is NULL!\n"));
				status = STATUS_INVALID_DEVICE_STATE;
			}

			break;

		case IOCTL_PSDRV_RESET_DEVICE:
			PSDrv_DbgPrint(3, ("IOControl: ResetDevice\n"));

			status = ResetDevice(device);

			break;

		case IOCTL_PSDRV_CONTROL_TRANSFER:
			PSDrv_DbgPrint(3, ("IOControl: ControlTransfer\n"));

			//Get a pointer to the input buffer
			status = WdfRequestRetrieveInputMemory(Request, &WdfMem);
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			if (WdfMem == NULL)
			{
				PSDrv_DbgPrint(1, ("WdfMem is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pControlTransfer = WdfMemoryGetBuffer(WdfMem, NULL);
			if (pControlTransfer == NULL)
			{
				PSDrv_DbgPrint(1, ("pControlTransfer is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			//Get a pointer to the output buffer
			if (OutputBufferLength != 0)
			{
				status = WdfRequestRetrieveOutputMemory(Request, &WdfMemOut);
				if(!NT_SUCCESS(status))
				{
					PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputMemory failed! (Status = %x)\n", status));
					status = STATUS_INVALID_PARAMETER;
					break;
				}

				if (WdfMemOut == NULL)
				{
					PSDrv_DbgPrint(1, ("WdfMemOut is NULL!\n"));
					status = STATUS_INVALID_PARAMETER;
					break;
				}

				pControlBuffer = WdfMemoryGetBuffer(WdfMemOut, NULL);
				if (pControlBuffer == NULL)
				{
					PSDrv_DbgPrint(1, ("pControlBuffer is NULL!\n"));
					status = STATUS_INVALID_PARAMETER;
					break;
				}
			}
			else
			{
				PSDrv_DbgPrint(1, ("This control request has no buffer...\n"));
				pControlBuffer = NULL;
			}

			// Call the control transfer function
			status = ControlTransfer(pDevContext, pControlTransfer, pControlBuffer, OutputBufferLength, &length);

			break;

		case IOCTL_PSDRV_SET_PIPE_PROPERTY:
			PSDrv_DbgPrint(3, ("IOControl: SetPipeProperty\n"));

			status = WdfRequestRetrieveInputMemory(Request, &WdfMem); 
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			if (WdfMem == NULL)
			{
				PSDrv_DbgPrint(1, ("WdfMem is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pPipeProp = WdfMemoryGetBuffer(WdfMem, NULL);
			if (pPipeProp == NULL)
			{
				PSDrv_DbgPrint(1, ("pPipeProp is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pFileContext = GetFileContext(WdfRequestGetFileObject(Request));
			if (pFileContext->Pipe == NULL)
			{
				PSDrv_DbgPrint(3, ("Invalid pipe!\n"));
				status = STATUS_INVALID_PARAMETER;
			}
			else
			{
				status = SetPipeProperty(pFileContext, pPipeProp);
			}

			break;

		case IOCTL_PSDRV_SET_INTERFACE:
			PSDrv_DbgPrint(3, ("IOControl: SetInterface\n"));

			status = WdfRequestRetrieveInputMemory(Request, &WdfMem); 
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			if (WdfMem == NULL)
			{
				PSDrv_DbgPrint(1, ("WdfMem is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pInterfaceProperty = WdfMemoryGetBuffer(WdfMem, NULL);
			if (pInterfaceProperty == NULL)
			{
				PSDrv_DbgPrint(1, ("pInterfaceProperty is NULL!\n"));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			PSDrv_DbgPrint(3, ("SetInterface: Going to change AltIF to %d...\n", pInterfaceProperty->nAltIF));

			WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams, pInterfaceProperty->nAltIF);

			status = WdfUsbInterfaceSelectSetting(pDevContext->UsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &selectSettingParams);

			if (status == STATUS_SUCCESS)
			{
				pDevContext->nCurrIf = 0;
				pDevContext->nCurrAltIf = pInterfaceProperty->nAltIF;

				PSDrv_DbgPrint(3, ("SetInterface: AltIF is now %d...\n", pInterfaceProperty->nAltIF));
			}

			break;

		case IOCTL_PSDRV_GET_INTERFACE:
			PSDrv_DbgPrint(3, ("IOControl: GetInterface\n"));

			length = sizeof(PSUSBDRV_INTERFACE_PROPERTY);

			status = WdfRequestRetrieveOutputBuffer(Request, length, &pInterfaceProperty, &bufLength);
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pInterfaceProperty->nIF = pDevContext->nCurrIf;
			pInterfaceProperty->nAltIF = pDevContext->nCurrAltIf;

			status = STATUS_SUCCESS;

			break;

		case IOCTL_PSDRV_GET_DRIVER_VERSION:
			PSDrv_DbgPrint(3, ("IOControl: GetDriverVersion\n"));

			length = sizeof(PSUSBDRV_DRIVER_VERSION);

			status = WdfRequestRetrieveOutputBuffer(Request, length, &pDriverVersion, &bufLength);
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			pDriverVersion->nMajor = PSUSBDRV_MAJOR_VERSION;
			pDriverVersion->nMinor = PSUSBDRV_MINOR_VERSION;
			pDriverVersion->nMaintenance = PSUSBDRV_MAINTENANCE_VERSION;
			pDriverVersion->nBuild = PSUSBDRV_BUILD_VERSION;
			
			status = STATUS_SUCCESS;

			break;

		case IOCTL_PSDRV_GET_DEVICE_SPEED:
			PSDrv_DbgPrint(3, ("IOControl: GetDeviceSpeed\n"));

			length = sizeof(unsigned int);

			status = WdfRequestRetrieveOutputBuffer(Request, length, &pnDeviceSpeed, &bufLength);
			if(!NT_SUCCESS(status))
			{
				PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status));
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			if (pDevContext->IsDeviceHighSpeed == TRUE)
			{
				*pnDeviceSpeed = PSUSBDRV_DEVICE_HIGH_SPEED;
			}
			else
			{
				*pnDeviceSpeed = PSUSBDRV_DEVICE_FULL_SPEED;
			}

			break;

		default:
			PSDrv_DbgPrint(3, ("Unknown IOControl! (ControlCode = %x)\n", IoControlCode));

			status = STATUS_INVALID_DEVICE_REQUEST;

			break;
    }

    WdfRequestCompleteWithInformation(Request, status, length);

	PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - ends\n"));

    return;
}
Пример #26
0
VOID
MonitorEvtDeviceControl (
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength,
    _In_ ULONG IoControlCode
    )
/*++

   Handles device IO control requests. This callback drives all communication
   between the usermode exe and this driver.

--*/
{
   NTSTATUS status = STATUS_SUCCESS;

   UNREFERENCED_PARAMETER(Queue);
   UNREFERENCED_PARAMETER(OutputBufferLength);

   DoTraceMessage(TRACE_DEVICE_CONTROL, "MonitorSample Dispatch Device Control: 0x%x", IoControlCode);

   switch (IoControlCode)
   {
      case MONITOR_IOCTL_ENABLE_MONITOR:
      {
         WDFMEMORY pMemory;
         void* pBuffer;

         if (InputBufferLength < sizeof(MONITOR_SETTINGS))
         {
            status = STATUS_INVALID_PARAMETER;
         }
         else
         {
            status = WdfRequestRetrieveInputMemory(Request, &pMemory);

            if (NT_SUCCESS(status))
            {
               pBuffer = WdfMemoryGetBuffer(pMemory, NULL);
               status = MonitorCoEnableMonitoring((MONITOR_SETTINGS*) pBuffer);
            }
         }
         break;
      }

      case MONITOR_IOCTL_DISABLE_MONITOR:
      {
         status = STATUS_SUCCESS;
         
         MonitorCoDisableMonitoring();

         break;
      }

      default:
      {
         status = STATUS_INVALID_PARAMETER;
      }
   }

   WdfRequestComplete(Request, status);
}
Пример #27
0
VOID
GetDeviceEventLoggingNames(
    _In_ WDFDEVICE Device
    )
/*++

Routine Description:

    Retrieve the friendly name and the location string into WDFMEMORY objects
    and store them in the device context.

Arguments:

Return Value:

    None

--*/
{
    PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device);

    WDF_OBJECT_ATTRIBUTES objectAttributes;

    WDFMEMORY deviceNameMemory = NULL;
    WDFMEMORY locationMemory = NULL;

    NTSTATUS status;

    PAGED_CODE();

    //
    // We want both memory objects to be children of the device so they will
    // be deleted automatically when the device is removed.
    //

    WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);
    objectAttributes.ParentObject = Device;

    //
    // First get the length of the string. If the FriendlyName
    // is not there then get the lenght of device description.
    //

    status = WdfDeviceAllocAndQueryProperty(Device,
                                            DevicePropertyFriendlyName,
                                            NonPagedPoolNx,
                                            &objectAttributes,
                                            &deviceNameMemory);

    if (!NT_SUCCESS(status))
    {
        status = WdfDeviceAllocAndQueryProperty(Device,
                                                DevicePropertyDeviceDescription,
                                                NonPagedPoolNx,
                                                &objectAttributes,
                                                &deviceNameMemory);
    }

    if (NT_SUCCESS(status))
    {
        pDevContext->DeviceNameMemory = deviceNameMemory;
        pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL);
    }
    else
    {
        pDevContext->DeviceNameMemory = NULL;
        pDevContext->DeviceName = L"(error retrieving name)";
    }

    //
    // Retrieve the device location string.
    //

    status = WdfDeviceAllocAndQueryProperty(Device,
                                            DevicePropertyLocationInformation,
                                            NonPagedPoolNx,
                                            WDF_NO_OBJECT_ATTRIBUTES,
                                            &locationMemory);

    if (NT_SUCCESS(status))
    {
        pDevContext->LocationMemory = locationMemory;
        pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL);
    }
    else
    {
        pDevContext->LocationMemory = NULL;
        pDevContext->Location = L"(error retrieving location)";
    }

    return;
}
Пример #28
0
VOID
UsbSamp_EvtReadWriteCompletion(
    _In_ WDFREQUEST                  Request,
    _In_ WDFIOTARGET                 Target,
    PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
    _In_ WDFCONTEXT                  Context
    )
/*++

Routine Description:

    This is the completion routine for reads/writes
    If the irp completes with success, we check if we
    need to recirculate this irp for another stage of
    transfer.

Arguments:

    Context - Driver supplied context
    Device - Device handle
    Request - Request handle
    Params - request completion params

Return Value:
    None

--*/
{
    PMDL                    requestMdl;
    WDFUSBPIPE              pipe;
    ULONG                   stageLength;
    NTSTATUS               status;
    PREQUEST_CONTEXT        rwContext;
    PURB                    urb;
    PCHAR                   operation;
    ULONG                   bytesReadWritten;
    ULONG                   maxTransferSize;
    PDEVICE_CONTEXT         deviceContext;

    rwContext = GetRequestContext(Request);
    deviceContext = Context;

    if (rwContext->Read) {
        operation = "Read";
    } 
    else {
        operation = "Write";
    }

    pipe = (WDFUSBPIPE) Target   ;
    status = CompletionParams->IoStatus.Status;

    if (!NT_SUCCESS(status)){
        //
        // Queue a workitem to reset the pipe because the completion could be
        // running at DISPATCH_LEVEL.
        //
        QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe);
        goto End;
    }

    urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL);
    bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    rwContext->Numxfer += bytesReadWritten;

    //
    // If there is anything left to transfer.
    //
    if (rwContext->Length == 0) {
        //
        // this is the last transfer
        //
        WdfRequestSetInformation(Request, rwContext->Numxfer);
        goto End;
    }

    //
    // Start another transfer
    //
    UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation));

    //
    // The transfer request is for totalLength. 
    // We can perform a max of maxTransfersize in each stage.
    //
    maxTransferSize = GetMaxTransferSize(pipe, deviceContext);

    if (rwContext->Length > maxTransferSize) {
        stageLength = maxTransferSize;
    }
    else {
        stageLength = rwContext->Length;
    }

    //
    // Following call is required to free any mapping made on the partial MDL
    // and reset internal MDL state.
    //
    MmPrepareMdlForReuse(rwContext->Mdl);

    if (rwContext->Read) {
        status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status));
            goto End;
        }
    } 
    else {
        status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl);
        if (!NT_SUCCESS(status)){
            UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed %x\n", status));
            goto End;
        }
    }

    IoBuildPartialMdl(requestMdl,
                      rwContext->Mdl,
                      (PVOID) rwContext->VirtualAddress,
                      stageLength);

    //
    // reinitialize the urb
    //
    urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

    rwContext->VirtualAddress += stageLength;
    rwContext->Length -= stageLength;

    //
    // Format the request to send a URB to a USB pipe.
    //
    status = WdfUsbTargetPipeFormatRequestForUrb(pipe,
                                Request,
                                rwContext->UrbMemory,
                                NULL);
    if (!NT_SUCCESS(status)) {
        UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto End;
    }

    WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext);

    //
    // Send the request asynchronously.
    //
    if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) {
        UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation));
        status = WdfRequestGetStatus(Request);
        goto End;
    }

    //
    // Else when the request completes, this completion routine will be
    // called again.
    //
    return;

End:
    //
    // We are here because the request failed or some other call failed.
    // Dump the request context, complete the request and return.
    //
    DbgPrintRWContext(rwContext);

    IoFreeMdl(rwContext->Mdl);

    UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n",
                                                    operation, status));

    WdfRequestComplete(Request, status);

    return;
}
Пример #29
0
VOID
EchoEvtIoRead(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request,
    IN size_t      Length
    )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_READ request.
    It will copy the content from the queue-context buffer to the request buffer.
    If the driver hasn't received any write request earlier, the read returns zero.

Arguments:

    Queue -  Handle to the framework queue object that is associated with the
             I/O request.

    Request - Handle to a framework request object.

    Length  - number of bytes to be read.
              The default property of the queue is to not dispatch
              zero lenght read & write requests to the driver and
              complete is with status success. So we will never get
              a zero length request.

Return Value:

    VOID

--*/
{
    NTSTATUS Status;
    PQUEUE_CONTEXT queueContext = QueueGetContext(Queue);
    WDFMEMORY memory;
    size_t writeMemoryLength;

    _Analysis_assume_(Length > 0);

    KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n",
             Queue,Request,Length));
    //
    // No data to read
    //
    if( (queueContext->WriteMemory == NULL)  ) {
        WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L);
        return;
    }

    //
    // Read what we have
    //
    WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength);
    _Analysis_assume_(writeMemoryLength > 0);

    if( writeMemoryLength < Length ) {
        Length = writeMemoryLength;
    }

    //
    // Get the request memory
    //
    Status = WdfRequestRetrieveOutputMemory(Request, &memory);
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status));
        WdfVerifierDbgBreakPoint();
        WdfRequestCompleteWithInformation(Request, Status, 0L);
        return;
    }

    // Copy the memory out
    Status = WdfMemoryCopyFromBuffer( memory, // destination
                             0,      // offset into the destination memory
                             WdfMemoryGetBuffer(queueContext->WriteMemory, NULL),
                             Length );
    if( !NT_SUCCESS(Status) ) {
        KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status));
        WdfRequestComplete(Request, Status);
        return;
    }

    // Set transfer information
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    // Mark the request is cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);


    // Defer the completion to another thread from the timer dpc
    queueContext->CurrentRequest = Request;
    queueContext->CurrentStatus  = Status;

    return;
}
NTSTATUS
NfcCxEvtNciReadNotification(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE    Device,
    _In_ WDFMEMORY    Memory
    )
/*++

Routine Description:

    This routine is called by the CX client to signal a
    read notification.  The implementation of this function forwards
    the content of the notification to the Tml layer which will complete
    a pended read request up to the NfcLib.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    Memory - A pointer to a WDFMEMORY object that contains the 
             content of the read notification

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    
    PUCHAR buffer = NULL;
    size_t bufferSize = 0;

    UNREFERENCED_PARAMETER(NfcCxGlobals);

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    buffer = (PUCHAR)WdfMemoryGetBuffer(Memory, &bufferSize);

    if (MAX_USHORT < bufferSize) {
        TRACE_LINE(LEVEL_ERROR, "Invalid read notification sent, ignoring!!!");
        NT_ASSERTMSG("ReadNotification too large", FALSE);
        goto Done;
    }

    //
    // Forward the read to the Tml interface
    //
    status = NfcCxTmlDispatchReadNotification((NfcCxFdoGetContext(Device))->TmlInterface,
                                              buffer,
                                              (USHORT)bufferSize);
    if (!NT_SUCCESS(status)) {
        TRACE_LINE(LEVEL_ERROR, "Failed to dispatch read notification, %!STATUS!", status);
        goto Done;
    }

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}