// Exstact the device id of the current device from the request // Return id // Returns 0xFFFF if error or id out of range USHORT GetIdFromRawPdoRequest( WDFREQUEST Request, PVOID pExt ) { WDFFILEOBJECT FileObj = NULL; PFILEOBJECT_EXTENSION pExtension = (PFILEOBJECT_EXTENSION)pExt; USHORT id = 0xFFFF; // Get the context, id and the status FileObj = WdfRequestGetFileObject(Request); if (FileObj) { pExtension = GetFileObjectContext(FileObj); if (pExtension) id = (UCHAR)pExtension->id; //else // id = 0; } //else // id = 0; //if (id > MAX_N_DEVICES) // id = 0; return id; }
VOID NdisProtEvtFileClose( IN WDFFILEOBJECT FileObject ) /*++ Routine Description: EvtFileClose is called when all the handles represented by the FileObject is closed and all the references to FileObject is removed. This callback may get called in an arbitrary thread context instead of the thread that called CloseHandle. If you want to delete any per FileObject context that must be done in the context of the user thread that made the Create call, you should do that in the EvtDeviceCleanp callback. Arguments: FileObject - Pointer to fileobject that represents the open handle. Return Value: VOID --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; PFILE_OBJECT_CONTEXT fileContext; fileContext = GetFileObjectContext(FileObject); pOpenContext = fileContext->OpenContext; DEBUGP(DL_INFO, ("Close: FileObject %p\n", FileObject)); if (pOpenContext != NULL) { NPROT_STRUCT_ASSERT(pOpenContext, oc); // // Deref the endpoint // NPROT_DEREF_OPEN(pOpenContext); // Close } fileContext->OpenContext = NULL; return; }
VOID NdisProtEvtDeviceFileCreate( IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject ) /*++ Routine Description: The framework calls a driver's EvtDeviceFileCreate callback when the framework receives an IRP_MJ_CREATE request. The system sends this request when a user application opens the device to perform an I/O operation, such as reading or writing a file. This callback is called synchronously, in the context of the thread that created the IRP_MJ_CREATE request. Arguments: Device - Handle to a framework device object. FileObject - Pointer to fileobject that represents the open handle. CreateParams - Parameters of IO_STACK_LOCATION for create Return Value: NT status code --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; PFILE_OBJECT_CONTEXT fileContext; UNREFERENCED_PARAMETER(Device); DEBUGP(DL_INFO, ("Open: FileObject %p\n", FileObject)); fileContext = GetFileObjectContext(FileObject); fileContext->OpenContext = NULL; WdfRequestComplete(Request, NtStatus); return; }
VOID vJoy_EvtFileCleanup( __in WDFFILEOBJECT FileObject ) { PFILEOBJECT_EXTENSION pExtension=NULL; PRPDO_DEVICE_DATA pParentRawDeviceContext=NULL; PDEVICE_EXTENSION pDevContext = NULL; PAGED_CODE() pExtension = GetFileObjectContext(FileObject); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtFileCleanup: DevID=%d PID=%d\n", pExtension->id, pExtension->CallingProcessId); // Remove id in file object context space if (pExtension && pExtension->id) pExtension->pParentRawDeviceContext->UsedInterfacesMask &= ~(1<< (pExtension->id-1)); // Reset the ID of the calling process if (pExtension) pExtension->CallingProcessId = 0; // Get the parent device context pParentRawDeviceContext = pExtension->pParentRawDeviceContext; if (!pParentRawDeviceContext) return; pDevContext = GetDeviceContext(pParentRawDeviceContext->hParentDevice); if (!pDevContext) return; if ( pExtension->id) { // set FFB to false FfbActiveSet(FALSE, pExtension->id, pDevContext); // Remove record of this file object pDevContext->DeviceFileObject[pExtension->id - 1] = NULL; }; }
VOID NdisProtEvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) /*++ Routine Description: Dispatch routine to handle Request_MJ_WRITE. Arguments: Queue - Default queue handle Request - Handle to the read/write request Lenght - Length of the data buffer associated with the request. 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 --*/ { ULONG DataLength; NTSTATUS NtStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; PNET_BUFFER_LIST pNetBufferList; NDISPROT_ETH_HEADER UNALIGNED *pEthHeader; PVOID CancelId; ULONG SendFlags = 0; PMDL pMdl = NULL; WDFFILEOBJECT fileObject; PREQUEST_CONTEXT reqContext; WDF_OBJECT_ATTRIBUTES attributes; UNREFERENCED_PARAMETER(Queue); fileObject = WdfRequestGetFileObject(Request); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; do { // // Create a context to track the length of transfer and NDIS packet // associated with this request. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); NtStatus = WdfObjectAllocateContext(Request, &attributes, &reqContext); if(!NT_SUCCESS(NtStatus)){ DEBUGP(DL_WARN, ("Write: WdfObjectAllocateContext failed: %x\n", NtStatus)); NtStatus = STATUS_INVALID_HANDLE; break; } reqContext->Length = (ULONG) Length; if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n", fileObject)); NtStatus = STATUS_INVALID_HANDLE; break; } NPROT_STRUCT_ASSERT(pOpenContext, oc); NtStatus = WdfRequestRetrieveInputWdmMdl(Request, &pMdl); if (!NT_SUCCESS(NtStatus)) { DEBUGP(DL_FATAL, ("Write: WdfRequestRetrieveInputWdmMdl failed %x\n", NtStatus)); break; } // // Try to get a virtual address for the MDL. // pEthHeader = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority | MdlMappingNoExecute); if (pEthHeader == NULL) { DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for" " Request %p, MDL %p\n", Request, pMdl)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Sanity-check the length. // DataLength = MmGetMdlByteCount(pMdl); if (DataLength < sizeof(NDISPROT_ETH_HEADER)) { DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n", DataLength)); NtStatus = STATUS_BUFFER_TOO_SMALL; break; } if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER))) { DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)" " larger than max frame size (%d)\n", pOpenContext, DataLength, pOpenContext->MaxFrameSize)); NtStatus = STATUS_INVALID_BUFFER_SIZE; break; } // // To prevent applications from sending packets with spoofed // mac address, we will do the following check to make sure the source // address in the packet is same as the current MAC address of the NIC. // if ((WdfRequestGetRequestorMode(Request) == UserMode) && !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN)) { DEBUGP(DL_WARN, ("Write: Failing with invalid Source address")); NtStatus = STATUS_INVALID_PARAMETER; break; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: Open %p is not bound" " or in low power state\n", pOpenContext)); NtStatus = STATUS_INVALID_HANDLE; break; } if ((pOpenContext->State == NdisprotPaused) || (pOpenContext->State == NdisprotPausing)) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_INFO, ("Device is paused.\n")); NtStatus = STATUS_UNSUCCESSFUL; break; } NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL); pNetBufferList = NdisAllocateNetBufferAndNetBufferList( pOpenContext->SendNetBufferListPool, sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta 0, // back fill size pMdl, 0, // Data offset DataLength); if (pNetBufferList == NULL) { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n", pOpenContext)); NtStatus = STATUS_INSUFFICIENT_RESOURCES; break; } pOpenContext->PendedSendCount++; NPROT_REF_OPEN(pOpenContext); // pended send // // Initialize the NetBufferList ref count. This NetBufferList will be freed // when this count goes to zero. // NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1; // // We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), // and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use // NdisCancelSendNetBufferLists() to cancel the NetBufferList. // // Note that this sample code does not implement the cancellation logic. An actual // driver may find value in implementing this. // CancelId = NPROT_GET_NEXT_CANCEL_ID(); NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId); reqContext->NetBufferList = (PVOID)pNetBufferList; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Set a back pointer from the packet to the IRP. // NPROT_REQUEST_FROM_SEND_NBL(pNetBufferList) = Request; NtStatus = STATUS_PENDING; pNetBufferList->SourceHandle = pOpenContext->BindingHandle; NPROT_ASSERT (pMdl->Next == NULL); SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK; NdisSendNetBufferLists( pOpenContext->BindingHandle, pNetBufferList, NDIS_DEFAULT_PORT_NUMBER, SendFlags); } while (FALSE); if (NtStatus != STATUS_PENDING) { WdfRequestComplete(Request, NtStatus); } return; }
// 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); }
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; }
VOID NdisProtEvtIoDeviceControl( 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 NtStatus; NDIS_STATUS Status; PNDISPROT_OPEN_CONTEXT pOpenContext; ULONG BytesReturned; PVOID sysBuffer; WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); size_t bufSize; UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); DEBUGP(DL_LOUD, ("IoControl: Irp %p\n", Request)); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; BytesReturned = 0; switch (IoControlCode) { case IOCTL_NDISPROT_BIND_WAIT: // // Block until we have seen a NetEventBindsComplete event, // meaning that we have finished binding to all running // adapters that we are supposed to bind to. // // If we don't get this event in 5 seconds, time out. // NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (NPROT_WAIT_EVENT(&Globals.BindsComplete, 5000)) { NtStatus = STATUS_SUCCESS; } else { NtStatus = STATUS_TIMEOUT; } DEBUGP(DL_INFO, ("IoControl: BindWait returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_QUERY_BINDING: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_BINDING), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } Status = ndisprotQueryBinding( sysBuffer, (ULONG) bufSize, (ULONG) bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_OPEN_DEVICE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NPROT_STRUCT_ASSERT(pOpenContext, oc); DEBUGP(DL_WARN, ("IoControl: OPEN_DEVICE: FileObj %p already" " associated with open %p\n", fileObject, pOpenContext)); NtStatus = STATUS_DEVICE_BUSY; break; } NtStatus = WdfRequestRetrieveInputBuffer(Request, 0, &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } NtStatus = ndisprotOpenDevice( sysBuffer, (ULONG)bufSize, fileObject, &pOpenContext ); if (NT_SUCCESS(NtStatus)) { DEBUGP(DL_VERY_LOUD, ("IoControl OPEN_DEVICE: Open %p <-> FileObject %p\n", pOpenContext, fileObject)); } break; case IOCTL_NDISPROT_QUERY_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotQueryOidValue( pOpenContext, sysBuffer, (ULONG)bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_SET_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveInputBuffer(Request, sizeof(NDISPROT_SET_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotSetOidValue( pOpenContext, sysBuffer, (ULONG)bufSize ); BytesReturned = 0; NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_INDICATE_STATUS: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NtStatus = WdfRequestForwardToIoQueue(Request, pOpenContext->StatusIndicationQueue ); if(NT_SUCCESS(NtStatus)) { NtStatus = STATUS_PENDING; } } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; default: NtStatus = STATUS_NOT_SUPPORTED; break; } if (NtStatus != STATUS_PENDING) { WdfRequestCompleteWithInformation(Request, NtStatus, BytesReturned); } return; }
VOID NdisProtEvtFileCleanup( IN WDFFILEOBJECT FileObject ) /*++ Routine Description: EvtFileCleanup is called when the handle represented by the FileObject is closed. This callback is invoked in the context of the thread that closed the handle. Arguments: FileObject - Pointer to fileobject that represents the open handle. Return Value: VOID --*/ { NTSTATUS NtStatus; NDIS_STATUS NdisStatus; PNDISPROT_OPEN_CONTEXT pOpenContext; ULONG PacketFilter; ULONG BytesProcessed; PFILE_OBJECT_CONTEXT fileContext; fileContext = GetFileObjectContext(FileObject); pOpenContext = fileContext->OpenContext; DEBUGP(DL_VERY_LOUD, ("Cleanup: FileObject %p, Open %p\n", FileObject, pOpenContext)); if (pOpenContext != NULL) { NPROT_STRUCT_ASSERT(pOpenContext, oc); // // Mark this endpoint. // NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_IDLE); pOpenContext->pFileObject = NULL; NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Set the packet filter to 0, telling NDIS that we aren't // interested in any more receives. // PacketFilter = 0; NdisStatus = ndisprotValidateOpenAndDoRequest( pOpenContext, NdisRequestSetInformation, OID_GEN_CURRENT_PACKET_FILTER, &PacketFilter, sizeof(PacketFilter), &BytesProcessed, FALSE // Don't wait for device to be powered on ); if (NdisStatus != NDIS_STATUS_SUCCESS) { DEBUGP(DL_INFO, ("Cleanup: Open %p, set packet filter (%x) failed: %x\n", pOpenContext, PacketFilter, NdisStatus)); // // Ignore the result. If this failed, we may continue // to get indicated receives, which will be handled // appropriately. // NdisStatus = NDIS_STATUS_SUCCESS; } NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE); if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)){ NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); // // Cancel any pending reads. // WdfIoQueuePurgeSynchronously(pOpenContext->ReadQueue); // // Cancel pending control request for status indication. // WdfIoQueuePurgeSynchronously(pOpenContext->StatusIndicationQueue); } else { NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE); } // // Clean up the receive packet queue // ndisprotFlushReceiveQueue(pOpenContext); } NtStatus = STATUS_SUCCESS; DEBUGP(DL_INFO, ("Cleanup: OpenContext %p\n", pOpenContext)); return; }
Return Value: Status is returned. --*/ { PNDISPROT_OPEN_CONTEXT pOpenContext; NTSTATUS NtStatus; ULONG PacketFilter; NDIS_STATUS NdisStatus; ULONG BytesProcessed; PNDISPROT_OPEN_CONTEXT pCurrentOpenContext = NULL; PFILE_OBJECT_CONTEXT fileContext; pOpenContext = NULL; fileContext = GetFileObjectContext(FileObject); do { pOpenContext = ndisprotLookupDevice( pDeviceName, DeviceNameLength ); if (pOpenContext == NULL) { DEBUGP(DL_WARN, ("ndisprotOpenDevice: couldn't find device\n")); NtStatus = STATUS_OBJECT_NAME_NOT_FOUND; break; }