// 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; }
// 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); }
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; }
// 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); } }
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; }
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(); }
// 中断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!!!"); } }
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; }
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); }
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")); }
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); }
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); }
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); }
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); }
// 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"); }
/////////////////////////////////////////////////////////////////////////////// // // 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; }
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(¶ms); WdfRequestGetParameters(Request, ¶ms); 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); }
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; }
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; }
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__); }
/*++ 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; }
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; }
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"); }
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); } }
/*++ 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; }
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); }
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; }
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; }
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; }