NTSTATUS Bus_EjectDevice( WDFDEVICE Device, ULONG SerialNo ) /*++ Routine Description: The user application has told us to eject the device from the bus. In a real situation the driver gets notified by an interrupt when the user presses the Eject button on the device. Arguments: Returns: STATUS_SUCCESS upon successful removal from the list STATUS_INVALID_PARAMETER if the removal was unsuccessful --*/ { PPDO_DEVICE_DATA pdoData; BOOLEAN ejectAll; WDFDEVICE hChild; NTSTATUS status = STATUS_INVALID_PARAMETER; PAGED_CODE (); // // Scan the list to find matching PDOs // ejectAll = (0 == SerialNo) ? TRUE : FALSE; hChild = NULL; WdfFdoLockStaticChildListForIteration(Device); while ((hChild = WdfFdoRetrieveNextStaticChild(Device, hChild, WdfRetrieveAddedChildren)) != NULL) { pdoData = PdoGetData(hChild); if (ejectAll || SerialNo == pdoData->SerialNo) { status = STATUS_SUCCESS; WdfPdoRequestEject(hChild); if (!ejectAll) { break; } } } WdfFdoUnlockStaticChildListFromIteration(Device); return status; }
VOID KbFilter_EvtIoDeviceControlForRawPdo( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This routine is the dispatch routine for device control requests. 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; WDFDEVICE parent = WdfIoQueueGetDevice(Queue); PRPDO_DEVICE_DATA pdoData; WDF_REQUEST_FORWARD_OPTIONS forwardOptions; pdoData = PdoGetData(parent); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); DebugPrint(("Entered KbFilter_EvtIoDeviceControlForRawPdo\n")); // // Process the ioctl and complete it when you are done. // Since the queue is configured for serial dispatch, you will // not receive another ioctl request until you complete this one. // switch (IoControlCode) { case IOCTL_KBFILTR_GET_KEYBOARD_ATTRIBUTES: WDF_REQUEST_FORWARD_OPTIONS_INIT(&forwardOptions); status = WdfRequestForwardToParentDeviceIoQueue(Request, pdoData->ParentQueue, &forwardOptions); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); } break; case IOCTL_KBFILTR_ON: case IOCTL_KBFILTR_OFF: case IOCTL_KBFILTR_GET_STATE: case IOCTL_KBFILTR_GET_CHAR: WDF_REQUEST_FORWARD_OPTIONS_INIT(&forwardOptions); status = WdfRequestForwardToParentDeviceIoQueue(Request, pdoData->ParentQueue, &forwardOptions); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); } break; default: WdfRequestComplete(Request, status); break; } return; }
NTSTATUS KbFiltr_CreateRawPdo( WDFDEVICE Device, ULONG InstanceNo ) /*++ Routine Description: This routine creates and initialize a PDO. Arguments: Return Value: NT Status code. --*/ { NTSTATUS status; PWDFDEVICE_INIT pDeviceInit = NULL; PRPDO_DEVICE_DATA pdoData = NULL; WDFDEVICE hChild = NULL; WDF_OBJECT_ATTRIBUTES pdoAttributes; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDFQUEUE queue; WDF_DEVICE_STATE deviceState; PDEVICE_EXTENSION devExt; DECLARE_CONST_UNICODE_STRING(deviceId,KBFILTR_DEVICE_ID ); DECLARE_CONST_UNICODE_STRING(hardwareId,KBFILTR_DEVICE_ID ); DECLARE_CONST_UNICODE_STRING(deviceLocation,L"Keyboard Filter\0" ); DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); DebugPrint(("Entered KbFiltr_CreateRawPdo\n")); // // Allocate a WDFDEVICE_INIT structure and set the properties // so that we can create a device object for the child. // pDeviceInit = WdfPdoInitAllocate(Device); if (pDeviceInit == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } // // Mark the device RAW so that the child device can be started // and accessed without requiring a function driver. Since we are // creating a RAW PDO, we must provide a class guid. // status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVCLASS_KEYBOARD); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Since keyboard is secure device, we must protect ourselves from random // users sending ioctls and creating trouble. // status = WdfDeviceInitAssignSDDLString(pDeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID // status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); if (!NT_SUCCESS(status)) { goto Cleanup; } // // For RAW PDO, there is no need to provide BusQueryHardwareIDs // and BusQueryCompatibleIDs IDs unless we are running on // Windows 2000. // if (!RtlIsNtDdiVersionAvailable(NTDDI_WINXP)) { // // On Win2K, we must provide a HWID for the device to get enumerated. // Since we are providing a HWID, we will have to provide a NULL inf // to avoid the "found new device" popup and get the device installed // silently. // status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); if (!NT_SUCCESS(status)) { goto Cleanup; } } // // We could be enumerating more than one children if the filter attaches // to multiple instances of keyboard, so we must provide a // BusQueryInstanceID. If we don't, system will throw CA bugcheck. // status = RtlUnicodeStringPrintf(&buffer, L"%02d", InstanceNo); if (!NT_SUCCESS(status)) { goto Cleanup; } status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Provide a description about the device. This text is usually read from // the device. In the case of USB device, this text comes from the string // descriptor. This text is displayed momentarily by the PnP manager while // it's looking for a matching INF. If it finds one, it uses the Device // Description from the INF file to display in the device manager. // Since our device is raw device and we don't provide any hardware ID // to match with an INF, this text will be displayed in the device manager. // status = RtlUnicodeStringPrintf(&buffer,L"Keyboard_Filter_%02d", InstanceNo ); if (!NT_SUCCESS(status)) { goto Cleanup; } // // You can call WdfPdoInitAddDeviceText multiple times, adding device // text for multiple locales. When the system displays the text, it // chooses the text that matches the current locale, if available. // Otherwise it will use the string for the default locale. // The driver can specify the driver's default locale by calling // WdfPdoInitSetDefaultLocale. // status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409 ); if (!NT_SUCCESS(status)) { goto Cleanup; } WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); // // Initialize the attributes to specify the size of PDO device extension. // All the state information private to the PDO will be tracked here. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); // // Set up our queue to allow forwarding of requests to the parent // This is done so that the cached Keyboard Attributes can be retrieved // WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Get the device context. // pdoData = PdoGetData(hChild); pdoData->InstanceNo = InstanceNo; // // Get the parent queue we will be forwarding to // devExt = FilterGetData(Device); pdoData->ParentQueue = devExt->rawPdoQueue; // // Configure the default queue associated with the control device object // to be Serial so that request passed to EvtIoDeviceControl are serialized. // A default queue gets all the requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlForRawPdo; status = WdfIoQueueCreate(hChild, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // pointer to default queue ); if (!NT_SUCCESS(status)) { DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); goto Cleanup; } // // Set some properties for the child device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.Removable = WdfTrue; pnpCaps.SurpriseRemovalOK = WdfTrue; pnpCaps.NoDisplayInUI = WdfTrue; pnpCaps.Address = InstanceNo; pnpCaps.UINumber = InstanceNo; WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); // // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we // have to do the following to hide the device. Following call // tells the framework to report the device state in // IRP_MN_QUERY_DEVICE_STATE request. // WDF_DEVICE_STATE_INIT(&deviceState); deviceState.DontDisplayInUI = WdfTrue; WdfDeviceSetDeviceState(hChild, &deviceState); // // Tell the Framework that this device will need an interface so that // application can find our device and talk to it. // status = WdfDeviceCreateDeviceInterface( hChild, &GUID_DEVINTERFACE_KBFILTER, NULL ); if (!NT_SUCCESS (status)) { DebugPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); goto Cleanup; } // // Add this device to the FDO's collection of children. // After the child device is added to the static collection successfully, // driver must call WdfPdoMarkMissing to get the device deleted. It // shouldn't delete the child device directly by calling WdfObjectDelete. // status = WdfFdoAddStaticChild(Device, hChild); if (!NT_SUCCESS(status)) { goto Cleanup; } // // pDeviceInit will be freed by WDF. // return STATUS_SUCCESS; Cleanup: DebugPrint(("KbFiltr_CreatePdo failed %x\n", status)); // // Call WdfDeviceInitFree if you encounter an error while initializing // a new framework device object. If you call WdfDeviceInitFree, // do not call WdfDeviceCreate. // if (pDeviceInit != NULL) { WdfDeviceInitFree(pDeviceInit); } if(hChild) { WdfObjectDelete(hChild); } return status; }
// handles operations that must be performed when an application requests access to a device. VOID vJoy_EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject ) { WDFFILEOBJECT FileObj; PCUNICODE_STRING pName; UNICODE_STRING TmpUstr; NTSTATUS status = STATUS_SUCCESS; int id=0; WCHAR RefStr[100]; PFILEOBJECT_EXTENSION pExtension=NULL; PDEVICE_EXTENSION pDevContext = NULL; PRPDO_DEVICE_DATA pPdoData=NULL; size_t len; DWORD_PTR ProcessId; PAGED_CODE (); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtDeviceFileCreate\n"); // Get file object then get its filename FileObj = WdfRequestGetFileObject(Request); if (!FileObj) goto going_out; pName = WdfFileObjectGetFileName(FileObj); if (!pName) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: File name=%wZ\n", pName); // Extract id from interface number status = RtlStringCchLengthW(VJOY_INTERFACE, 100, &len); if (!NT_SUCCESS(status)) goto going_out; status = RtlStringCchCopyNW(RefStr, 100, pName->Buffer+len+1,4); // Copy the numeric part of the string (000) if (!NT_SUCCESS(status)) goto going_out; RtlInitUnicodeString(&TmpUstr, RefStr); // Convert "000" to UNICODE_STRING status = RtlUnicodeStringToInteger(&TmpUstr, 10, &id); // Convert "000" to integer (0) if (!NT_SUCCESS(status)) goto going_out; if (id>0) { // Verify that this interface has a corresponding device TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: ID=%d\n", id); pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; if (!pDevContext->positions[id - 1]) goto going_out; // Get the file object context space // Test that this interface is not in use // and store there the parent (Raw PDO) context pExtension = GetFileObjectContext(FileObject); if (!pExtension) goto going_out; pExtension->pParentRawDeviceContext = pPdoData; if (pPdoData->UsedInterfacesMask & (1 << (id - 1))) { WdfRequestComplete(Request, STATUS_ACCESS_DENIED); ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Access Denied)\n", ProcessId); return; } ///// This is a successful file creation - Now record the file details // vJoy Device ID else pPdoData->UsedInterfacesMask |= 1 << (id - 1); // Put id in file object context space pExtension->id = id; // Update // Get the id of the calling process ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); pExtension->CallingProcessId = (DWORD)(ProcessId & 0xFFFFFFFF); TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d\n", pExtension->CallingProcessId); // Put the file object in the FDO extension pDevContext->DeviceFileObject[id - 1] = FileObject; // Activate FFB Queues FfbActiveSet(TRUE, id, pDevContext); WdfRequestComplete(Request, status); return; } // if (id>0) // Case of General purpose and non device-specific Interface else // if (id<1) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): ID=%d\n", id); #if 0 pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): Completing Request\n"); #endif // 0 WdfRequestComplete(Request, status); return; }; // if (id<1) going_out: ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Invalid Handle)\n", ProcessId); WdfRequestComplete(Request, STATUS_INVALID_HANDLE); }
NTSTATUS vJoy_CreateRawPdo( WDFDEVICE Device, ULONG InstanceNo ) /*++ Routine Description: This routine creates and initialize a PDO. Arguments: Return Value: NT Status code. --*/ { NTSTATUS status; PWDFDEVICE_INIT pDeviceInit = NULL; PRPDO_DEVICE_DATA pdoData = NULL; WDFDEVICE hChild = NULL; WDF_OBJECT_ATTRIBUTES pdoAttributes; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDFQUEUE queue; WDF_DEVICE_STATE deviceState; PDEVICE_EXTENSION devExt; DECLARE_CONST_UNICODE_STRING(deviceId,VJOY_RAW_DEVICE_ID ); //DECLARE_CONST_UNICODE_STRING(hardwareId,VJOY_HARDWARE_ID ); DECLARE_CONST_UNICODE_STRING(deviceLocation,L"vJoy Raw Device\0" ); DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); PDEVICE_OBJECT ChildDeviceObject; PDEVICE_OBJECT ParentDeviceObject; DECLARE_CONST_UNICODE_STRING( SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R_RES_R, L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)(A;;GR;;;RC)" ); DECLARE_CONST_UNICODE_STRING( SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_R, L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GR;;;RC)" ); int iInterface; WCHAR RefStr[20]; UNICODE_STRING RefStr2; WDF_FILEOBJECT_CONFIG FileObjInit; WDF_OBJECT_ATTRIBUTES FileObjAttributes; WDF_OBJECT_ATTRIBUTES LockAttributes; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_CreateRawPdo\n"); // // Allocate a WDFDEVICE_INIT structure and set the properties // so that we can create a device object for the child. // pDeviceInit = WdfPdoInitAllocate(Device); if (pDeviceInit == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAllocate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Mark the device RAW so that the child device can be started // and accessed without requiring a function driver. Since we are // creating a RAW PDO, we must provide a class guid. // status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVINTERFACE_VJOY); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignRawDevice", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // TODO: Assign correct SDDL //// status = WdfDeviceInitAssignSDDLString(pDeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_R); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceInitAssignSDDLString", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID // status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignDeviceID", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // We could be enumerating more than one children if the filter attaches // to multiple instances of keyboard, so we must provide a // BusQueryInstanceID. If we don't, system will throw CA bugcheck. // status = RtlUnicodeStringPrintf(&buffer, VJOY_DEVICE_INSTANCE, InstanceNo); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (1)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignInstanceID", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Provide a description about the device. This text is usually read from // the device. This text is displayed momentarily by the PnP manager while // it's looking for a matching INF. If it finds one, it uses the Device // Description from the INF file to display in the device manager. // Since our device is raw device and we don't provide any hardware ID // to match with an INF, this text will be displayed in the device manager. // status = RtlUnicodeStringPrintf(&buffer,VJOY_DEVICE_TEXT_409 ); // English - United States if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (2)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // You can call WdfPdoInitAddDeviceText multiple times, adding device // text for multiple locales. When the system displays the text, it // chooses the text that matches the current locale, if available. // Otherwise it will use the string for the default locale. // The driver can specify the driver's default locale by calling // WdfPdoInitSetDefaultLocale. // status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409 // English - United States ); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAddDeviceText (1)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } #if 0 // Hebrew (No real ned - just for fun) status = RtlUnicodeStringPrintf(&buffer,VJOY_DEVICE_TEXT_40D, InstanceNo ); // Hebrew if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (3)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x40D // Hebrew ); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAddDeviceText (2)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } #endif // 0 WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); // English - United States WdfDeviceInitSetExclusive(pDeviceInit, FALSE); // Create a WDFFILEOBJECT WDF_OBJECT_ATTRIBUTES_INIT(&FileObjAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&FileObjAttributes, FILEOBJECT_EXTENSION); WDF_FILEOBJECT_CONFIG_INIT(&FileObjInit, vJoy_EvtDeviceFileCreate, WDF_NO_EVENT_CALLBACK, vJoy_EvtFileCleanup); WdfDeviceInitSetFileObjectConfig(pDeviceInit, &FileObjInit, &FileObjAttributes); // // Initialize the attributes to specify the size of PDO device extension. // All the state information private to the PDO will be tracked here. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); pdoAttributes.EvtCleanupCallback = rawEvtCleanupCallback; // // Set up our queue to allow forwarding of requests to the parent // This is done so that the cached data can be retrieved // //WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); // TODO: Replace the above because it is needed for WdfRequestForwardToParentDeviceIoQueue() status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Get the device context. // pdoData = PdoGetData(hChild); pdoData->InstanceNo = InstanceNo; pdoData->hParentDevice = Device; // // Save the I/O target handle and adjust the I/O stack size: // devExt = GetDeviceContext(Device); pdoData->IoTargetToParent = devExt->IoTargetToSelf; ChildDeviceObject = WdfDeviceWdmGetDeviceObject(hChild); ParentDeviceObject = WdfDeviceWdmGetDeviceObject(Device); ChildDeviceObject->StackSize = ParentDeviceObject->StackSize+1; // Create a wait-lock object that will be used to synch access to positions[i] // The lock is created when the raw device is created so the raw device is set to be its parent WDF_OBJECT_ATTRIBUTES_INIT(&LockAttributes); LockAttributes.ParentObject = hChild; status = WdfWaitLockCreate(&LockAttributes, &(devExt->positionLock)); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfWaitLockCreate failed 0x%x\n", status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfWaitLockCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Configure the default queue associated with the control device object // to be Serial so that request passed to EvtIoDeviceControl are serialized. // A default queue gets all the requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDeviceControl = vJoy_EvtIoDeviceControlForRawPdo; status = WdfIoQueueCreate(hChild, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // pointer to default queue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed 0x%x\n", status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfIoQueueCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Set some properties for the child device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.Removable = WdfTrue; // Remove Icon from " Devices and Printers" pnpCaps.SurpriseRemovalOK = WdfTrue; pnpCaps.NoDisplayInUI = WdfTrue; // pnpCaps.Address = InstanceNo; pnpCaps.UINumber = 0; WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); // // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we // have to do the following to hide the device. Following call // tells the framework to report the device state in // IRP_MN_QUERY_DEVICE_STATE request. // WDF_DEVICE_STATE_INIT(&deviceState); deviceState.DontDisplayInUI = WdfTrue; // Remove Icon from Device manager WdfDeviceSetDeviceState(hChild, &deviceState); // // Create 16 interfaces // for (iInterface=1 ; iInterface <= MAX_N_DEVICES; iInterface++) { RtlStringCchPrintfW((NTSTRSAFE_PWSTR)RefStr, 20, VJOY_INTERFACE L"%03d", iInterface); RtlInitUnicodeString(&RefStr2, (PCWSTR)RefStr); status = WdfDeviceCreateDeviceInterface(hChild,&GUID_DEVINTERFACE_VJOY,&RefStr2); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateDeviceInterface number %d failed 0x%x\n", iInterface, status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceCreateDeviceInterface", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } }; // Mark all interfaces as unused pdoData->UsedInterfacesMask=0; // // Add this device to the FDO's collection of children. // After the child device is added to the static collection successfully, // driver must call WdfPdoMarkMissing to get the device deleted. It // shouldn't delete the child device directly by calling WdfObjectDelete. // status = WdfFdoAddStaticChild(Device, hChild); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfFdoAddStaticChild", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } return STATUS_SUCCESS; Cleanup: TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "KbFiltr_CreatePdo failed %x\n", status); // // Call WdfDeviceInitFree if you encounter an error while initializing // a new framework device object. If you call WdfDeviceInitFree, // do not call WdfDeviceCreate. // if (pDeviceInit != NULL) { WdfDeviceInitFree(pDeviceInit); } if(hChild) { WdfObjectDelete(hChild); } return status; }
VOID vJoy_EvtIoDeviceControlForRawPdo( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This routine is the dispatch routine for device control requests. 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; WDFDEVICE parent; WDF_REQUEST_FORWARD_OPTIONS forwardOptions; PDEVICE_EXTENSION pDevContext = NULL; WDFMEMORY inMemory, outMemory; PVOID buffer; size_t bufSize; WDFDEVICE hRawDevice = WdfIoQueueGetDevice(Queue); PRPDO_DEVICE_DATA pdoData = PdoGetData(hRawDevice); WDF_REQUEST_SEND_OPTIONS RequestOptions; WDFIOTARGET TargetOnParent; JOYSTICK_POSITION_V2 * iReport; WDFFILEOBJECT FileObj; USHORT id=0; PFILEOBJECT_EXTENSION pExtension=NULL; WDFREQUEST requestForceFeedback; PHID_XFER_PACKET transferPacket = NULL; PVOID ForceFeedbackBuffer = NULL; PVOID GenBuffer = NULL; size_t bytesReturned = 0; WDF_REQUEST_PARAMETERS Params; BOOLEAN FfbStat = FALSE; ULONG bytesToCopy = 0; BYTE Byte_tmp; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtIoDeviceControlForRawPdo\n"); // // Process the ioctl and complete it when you are done. // Since the queue is configured for serial dispatch, you will // not receive another ioctl request until you complete this one. // switch (IoControlCode) { case 1234: // TODO: Remove for production //RequestOptions.Flags = WDF_REQUEST_SEND_OPTION_TIMEOUT; //RequestOptions.Size = sizeof(WDF_REQUEST_SEND_OPTIONS); //WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&RequestOptions, WDF_REL_TIMEOUT_IN_SEC(1)); //status = WdfIoTargetSendInternalIoctlSynchronously(pdoData->IoTargetToParent, Request, IoControlCode , NULL, NULL, &RequestOptions, NULL); break; // Testing case GET_DEV_STAT: // Get information for a device by device ID TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DEV_STAT\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy<5) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesToCopy=%d\n", bytesToCopy); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the buffer status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<5) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesReturned=%d\n", bytesReturned); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the id number from input buffer status = WdfRequestRetrieveInputBuffer(Request, sizeof(BYTE), &buffer, &bufSize); if (!NT_SUCCESS(status) || (bufSize!=1)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed to retrieve input buffer\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get target ID id = *(BYTE *)buffer; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: id=%d\n", id); // Put data into output buffer // Byte 1: // Bit 0: Implemented? // Bit 1: FFB Device Enabled? // Bit 2: File Object associated with this device? pDevContext = GetDeviceContext(pdoData->hParentDevice); Byte_tmp = 0; // Implemented mask if (pDevContext->DeviceImplemented[id - 1]) Byte_tmp |= 1; else Byte_tmp &= 0xFE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Implemented=%x\n", pDevContext->DeviceImplemented[id - 1]); // FFB mask TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Enabled=%x\n", pDevContext->FfbEnable[id - 1]); if (pDevContext->FfbEnable[id - 1]) Byte_tmp |= 2; else Byte_tmp &= 0xFD; // File Object if (pDevContext->DeviceFileObject[id - 1]) Byte_tmp |= 4; else Byte_tmp &= 0xFB; ((BYTE *)GenBuffer)[0] = Byte_tmp; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Buffer[0]=%x\n", ((BYTE *)GenBuffer)[0]); // Byte2-5: Process ID // Get the context FileObj = pDevContext->DeviceFileObject[id - 1]; if (FileObj) *(DWORD *)(&((BYTE *)GenBuffer)[1]) = GetFileObjectContext(FileObj)->CallingProcessId; else *(DWORD *)(&((BYTE *)GenBuffer)[1]) = 0; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: ProcessID=%x\n", *(DWORD *)(&((BYTE *)GenBuffer)[1])); // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case GET_DRV_INFO: // Get information for this driver TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO]\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); // Number of bytes to copy must be at least one byte bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy <1 ) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesToCopy <1\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Output buffer must be at least one byte status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesReturned <1\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; pDevContext = GetDeviceContext(pdoData->hParentDevice); // Return the data in the output buffer // BYTE 0 ////////////////////////////// // Bit 0 : Supports FFB? // Bit 1 : Reserved // Bit 2 : Mode: Multi-device // Bit 3 : Mode: FFB // BYTE 1 ////////////////////////////// // Bits 0-7 : Maximum number of possible devices (16 ==> 255) not regarding to mode // BYTE 2 ////////////////////////////// // Bits 0-7 : Number of existing devices // BYTE 3 ////////////////////////////// // Bits 0-7 : Number of devices that can still be implemented (This is the number of possible devices for the current mode minus the number of already existing devices). ////////////////////////////////// // Byte 0 Byte_tmp = 0; Byte_tmp |= 0x01; // FFB Supported Byte_tmp |= 0x00; // Default Mode (TODO: Change to real mode when Implemented) Multi-Device=0x04; FFB=0x80 ((BYTE *)GenBuffer)[0] = Byte_tmp; // Byte 1 if (bytesToCopy >= 2 && bytesReturned >= 2) { ((BYTE *)GenBuffer)[1] = MAX_N_DEVICES; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[1]=%02x\n", ((BYTE *)GenBuffer)[1]); } // Byte 2 if (bytesToCopy >= 3 && bytesReturned >= 3) { ((BYTE *)GenBuffer)[2] = (BYTE)(pDevContext->nDevices); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[2]=%02x\n", ((BYTE *)GenBuffer)[2]); } // Byte 3 - TODO: Change according to mode if (bytesToCopy >= 4 && bytesReturned >= 4) { ((BYTE *)GenBuffer)[3] = MAX_N_DEVICES - (BYTE)(pDevContext->nDevices); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[3]=%02x\n", ((BYTE *)GenBuffer)[3]); } ////////////////////////////////// // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case GET_DEV_INFO: // Get information for this device (and for the driver) // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy<6) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<6) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Copy the state to the buffer pDevContext = GetDeviceContext(pdoData->hParentDevice); ((BYTE *)GenBuffer)[0] = (BYTE)id; ((BYTE *)GenBuffer)[1] = (BYTE)(pDevContext->nDevices); ((BYTE *)GenBuffer)[2] = pDevContext->DeviceImplemented ? 1:0; ((BYTE *)GenBuffer)[3] = MAX_N_DEVICES; ((BYTE *)GenBuffer)[4] = 1; // Driver does support FFB ((BYTE *)GenBuffer)[5] = pDevContext->FfbEnable[id - 1]; // Device support FFB // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case 0x910: // Backward compatibility value of LOAD_POSITIONS case LOAD_POSITIONS: // KdBreakPoint(); Break When loading position status = WdfRequestRetrieveInputBuffer( Request, sizeof(JOYSTICK_POSITION), &buffer, &bufSize); if(!NT_SUCCESS(status)) break; // Get interface that this IRP came from, // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id==0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the incoming report and compare the id in the report // to the implicated id of the top-level collection // They should match iReport = buffer; if (iReport->bDevice != id) { WdfRequestComplete(Request, STATUS_CANCELLED); return; }; pDevContext = GetDeviceContext(pdoData->hParentDevice); LoadPositions(iReport, pDevContext, bufSize); status = vJoyCompleteReadReport(pdoData->hParentDevice, (BYTE)id); break; case GET_FFB_STAT: /* Get the status of the FFB mechanism */ // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (!bytesReturned) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Copy the state to the buffer pDevContext = GetDeviceContext(pdoData->hParentDevice); ((BYTE *)GenBuffer)[0] = pDevContext->FfbEnable[id-1]; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case SET_FFB_STAT: /*Set the status of the FFB mechanism - Obsolete*/ // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); // Get interface that this IRP came from, // then get the implicated id of the top-level collection // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the data, process the data and complete the transaction //pDevContext = GetDeviceContext(pdoData->hParentDevice); - Obsolete //FfbActiveSet(*(BOOLEAN *)Params.Parameters.DeviceIoControl.Type3InputBuffer, id, pDevContext); - Obsolete WdfRequestComplete(Request, status); return; case GET_FFB_DATA: // Get interface that this IRP came from, // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); // If FFB is not active then just reject this request pDevContext = GetDeviceContext(pdoData->hParentDevice); if (id == 0xFFFF || !pDevContext->FfbEnable[id - 1]) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // If FFB is active then forward this request to the ReadQ and return status = WdfRequestForwardToIoQueue(Request, pDevContext->FfbReadQ[id - 1]); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfRequestForwardToIoQueue (FfbWriteQ[%d]) failed with status: 0x%x\n", id - 1, status); WdfRequestComplete(Request, status); } return; case GET_DRV_DEV_EN: // Get the number of devices that are currently enabled TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_EN\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; if (!pdoData) break; pDevContext = GetDeviceContext(pdoData->hParentDevice); if (!pDevContext) break; // The number of the max supported devices ((BYTE *)GenBuffer)[0] = (BYTE)(pDevContext->nDevices); // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case GET_DRV_DEV_MAX: // Get the max possible number of devices that this driver supports TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_MAX\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // The number of the max supported devices ((BYTE *)GenBuffer)[0] = MAX_N_DEVICES; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case IS_DRV_FFB_CAP: // Test is this version of vJoy driver supports FFB TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case IS_DRV_FFB_CAP\n"); // Get the data from the request (Bytes to copy) WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d (Failed)\n", bytesToCopy); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the buffer from the request status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d (Failed)\n", bytesReturned); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Yes, this driver supports FFB ((BYTE *)GenBuffer)[0] = 1; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case RESET_DEV: /* Resets device(s) to predefined values */ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case RESET_DEV\n"); // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: ID=%d\n", id); // Sanity check if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context of vJoy device pDevContext = GetDeviceContext(pdoData->hParentDevice); // Reset device(s) status = ResetDevice(id, pDevContext); WdfRequestCompleteWithInformation(Request, status, 0); return; default: break; } WdfRequestComplete(Request, status); return; }
NTSTATUS Bus_UnPlugDevice( WDFDEVICE Device, ULONG SerialNo ) /*++ Routine Description: The application has told us a device has departed from the bus. We therefore need to flag the PDO as no longer present and then tell Plug and Play about it. Arguments: Returns: STATUS_SUCCESS upon successful removal from the list STATUS_INVALID_PARAMETER if the removal was unsuccessful --*/ { PPDO_DEVICE_DATA pdoData; BOOLEAN found = FALSE; BOOLEAN plugOutAll; WDFDEVICE hChild; NTSTATUS status = STATUS_INVALID_PARAMETER; PAGED_CODE (); plugOutAll = (0 == SerialNo) ? TRUE : FALSE; hChild = NULL; WdfFdoLockStaticChildListForIteration(Device); while ((hChild = WdfFdoRetrieveNextStaticChild(Device, hChild, WdfRetrieveAddedChildren)) != NULL) { if (plugOutAll) { status = WdfPdoMarkMissing(hChild); if(!NT_SUCCESS(status)) { KdPrint(("WdfPdoMarkMissing failed 0x%x\n", status)); break; } found = TRUE; } else { pdoData = PdoGetData(hChild); if (SerialNo == pdoData->SerialNo) { status = WdfPdoMarkMissing(hChild); if(!NT_SUCCESS(status)) { KdPrint(("WdfPdoMarkMissing failed 0x%x\n", status)); break; } found = TRUE; break; } } } WdfFdoUnlockStaticChildListFromIteration(Device); if (found) { status = STATUS_SUCCESS; } return status; }
NTSTATUS Bus_PlugInDevice( _In_ WDFDEVICE Device, _In_ PWCHAR HardwareIds, _In_ ULONG SerialNo ) /*++ Routine Description: The user application has told us that a new device on the bus has arrived. We therefore need to create a new PDO, initialize it, add it to the list of PDOs for this FDO bus, and then tell Plug and Play that all of this happened so that it will start sending prodding IRPs. --*/ { NTSTATUS status = STATUS_SUCCESS; BOOLEAN unique = TRUE; WDFDEVICE hChild; PPDO_DEVICE_DATA pdoData; PFDO_DEVICE_DATA deviceData; PAGED_CODE (); // // First make sure that we don't already have another device with the // same serial number. // Framework creates a collection of all the child devices we have // created so far. So acquire the handle to the collection and lock // it before walking the item. // deviceData = FdoGetData(Device); hChild = NULL; // // We need an additional lock to synchronize addition because // WdfFdoLockStaticChildListForIteration locks against anyone immediately // updating the static child list (the changes are put on a queue until the // list has been unlocked). This type of lock does not enforce our concept // of unique IDs on the bus (ie SerialNo). // // Without our additional lock, 2 threads could execute this function, both // find that the requested SerialNo is not in the list and attempt to add // it. If that were to occur, 2 PDOs would have the same unique SerialNo, // which is incorrect. // // We must use a passive level lock because you can only call WdfDeviceCreate // at PASSIVE_LEVEL. // WdfWaitLockAcquire(deviceData->ChildLock, NULL); WdfFdoLockStaticChildListForIteration(Device); while ((hChild = WdfFdoRetrieveNextStaticChild(Device, hChild, WdfRetrieveAddedChildren)) != NULL) { // // WdfFdoRetrieveNextStaticChild returns reported and to be reported // children (ie children who have been added but not yet reported to PNP). // // A surprise removed child will not be returned in this list. // pdoData = PdoGetData(hChild); // // It's okay to plug in another device with the same serial number // as long as the previous one is in a surprise-removed state. The // previous one would be in that state after the device has been // physically removed, if somebody has an handle open to it. // if (SerialNo == pdoData->SerialNo) { unique = FALSE; status = STATUS_INVALID_PARAMETER; break; } } if (unique) { // // Create a new child device. It is OK to create and add a child while // the list locked for enumeration. The enumeration lock applies only // to enumeration, not addition or removal. // status = Bus_CreatePdo(Device, HardwareIds, SerialNo); } WdfFdoUnlockStaticChildListFromIteration(Device); WdfWaitLockRelease(deviceData->ChildLock); return status; }