KAFFINITY restrictCurrentThreadToSecondaryCores() throw () { // // Set thread affinity mask to restrict scheduling of the current thread // on any processor but CPU0. // KAFFINITY callerAffinity; NT_ASSERTMSG("IRQL unexpected", KeGetCurrentIrql() < DISPATCH_LEVEL); ULONG numCpus = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); ULONG noCpu0AffinityMask = (~(ULONG(~0x0) << numCpus) & ULONG(~0x1)); callerAffinity = KeSetSystemAffinityThreadEx(KAFFINITY(noCpu0AffinityMask)); NT_ASSERTMSG("Thread affinity not set as requested", KeGetCurrentProcessorNumberEx(NULL) != 0); return callerAffinity; }
__forceinline void PwmCreateRequestGetAccess( _In_ WDFREQUEST WdfRequest, _Out_ ACCESS_MASK* DesiredAccessPtr, _Out_ ULONG* ShareAccessPtr ) { NT_ASSERT(ARGUMENT_PRESENT(DesiredAccessPtr)); NT_ASSERT(ARGUMENT_PRESENT(ShareAccessPtr)); WDF_REQUEST_PARAMETERS wdfRequestParameters; WDF_REQUEST_PARAMETERS_INIT(&wdfRequestParameters); WdfRequestGetParameters(WdfRequest, &wdfRequestParameters); NT_ASSERTMSG( "Expected create request", wdfRequestParameters.Type == WdfRequestTypeCreate); *DesiredAccessPtr = wdfRequestParameters.Parameters.Create.SecurityContext->DesiredAccess; *ShareAccessPtr = wdfRequestParameters.Parameters.Create.ShareAccess; }
NTSTATUS WDFEXPORT(WdfDmaTransactionCreate)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDMAENABLER DmaEnabler, __in_opt WDF_OBJECT_ATTRIBUTES * Attributes, __out WDFDMATRANSACTION * DmaTransactionHandle ) { NTSTATUS status; FxDmaEnabler* pDmaEnabler; PFX_DRIVER_GLOBALS pFxDriverGlobals; FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), DmaEnabler, FX_TYPE_DMA_ENABLER, (PVOID *) &pDmaEnabler, &pFxDriverGlobals); FxPointerNotNull(pFxDriverGlobals, DmaTransactionHandle); *DmaTransactionHandle = NULL; status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes, FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED ); if (!NT_SUCCESS(status)) { return status; } switch (pDmaEnabler->GetProfile()) { case WdfDmaProfilePacket: case WdfDmaProfilePacket64: status = FxDmaPacketTransaction::_Create(pFxDriverGlobals, Attributes, pDmaEnabler, DmaTransactionHandle); break; case WdfDmaProfileScatterGather: case WdfDmaProfileScatterGather64: case WdfDmaProfileScatterGatherDuplex: case WdfDmaProfileScatterGather64Duplex: status = FxDmaScatterGatherTransaction::_Create( pFxDriverGlobals, Attributes, pDmaEnabler, DmaTransactionHandle ); break; case WdfDmaProfileSystem: case WdfDmaProfileSystemDuplex: status = FxDmaSystemTransaction::_Create(pFxDriverGlobals, Attributes, pDmaEnabler, DmaTransactionHandle); break; default: NT_ASSERTMSG("Unknown profile for DMA enabler", FALSE); status = STATUS_UNSUCCESSFUL; break; } return status; }
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; }
VOID CBUpdateCardState( PSMARTCARD_EXTENSION SmartcardExtension, UCHAR IccState, BOOLEAN SystemWakeUp ) { ULONG oldState; NTSTATUS status; KIRQL irql; WDFREQUEST request; PDEVICE_EXTENSION DeviceExtension; KeAcquireSpinLock( &SmartcardExtension->OsData->SpinLock, &irql ); SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBUpdateCardState: Enter \n" ) ); oldState = (SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ? SCARD_PRESENT : SCARD_ABSENT); SmartcardExtension->ReaderCapabilities.CurrentState = (IccState == PSCR_ICC_PRESENT ? SCARD_PRESENT : SCARD_ABSENT); SmartcardDebug( DEBUG_DRIVER, ( "PSCR!CBUpdateCardState: Smart card %s\n", IccState == PSCR_ICC_PRESENT ? "inserted" : "removed") ); if ( SmartcardExtension->OsData->NotificationIrp != NULL && (SystemWakeUp && (oldState == SCARD_PRESENT || SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_PRESENT) || SmartcardExtension->ReaderCapabilities.CurrentState != oldState)) { PIRP notificationIrp ; notificationIrp = InterlockedExchangePointer( &(SmartcardExtension->OsData->NotificationIrp), NULL ); DeviceExtension = GetDeviceExtension(WdfWdmDeviceGetWdfDeviceHandle(SmartcardExtension->OsData->DeviceObject)); KeReleaseSpinLock( &SmartcardExtension->OsData->SpinLock, irql ); status = WdfIoQueueRetrieveNextRequest( DeviceExtension->NotificationQueue, &request); if (NT_SUCCESS(status)) { SmartcardDebug( DEBUG_DRIVER, ( "PSCR!CBUpdateCardState: Completing Irp %p\n", notificationIrp) ); WdfRequestCompleteWithInformation(request, status, 0); } else { NT_ASSERTMSG("WdfIoQueueRetrieveNextRequest failed", status == STATUS_NO_MORE_ENTRIES); } } else { KeReleaseSpinLock( &SmartcardExtension->OsData->SpinLock, irql ); } SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBUpdateCardState: Exit \n" ) ); }
// // Io events callbacks. // VOID MarsEvtIoDeviceControl( 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 --*/ { PFDO_DATA fdoData = NULL; WDFDEVICE device; NTSTATUS status = STATUS_SUCCESS; PVOID inBuffer = NULL, outBuffer = NULL; size_t bytesReturned = 0; size_t size = 0; PAGED_CODE(); //DbgPrint(("Started MarsEvtIODeviceControl\n")); device = WdfIoQueueGetDevice(Queue); fdoData = MarsFdoGetData(device); //Gets device context // // Get the ioctl input & output buffers // if (InputBufferLength != 0) { status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &inBuffer, &size); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } } if (OutputBufferLength != 0) { status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &outBuffer, &size); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } } switch (IoControlCode) { case IOCTL_MARS_GET_DRIVER_VERSION: if (OutputBufferLength < sizeof(USHORT)) { status = STATUS_BUFFER_TOO_SMALL; break; } *(PUSHORT)outBuffer = fdoData->DriverVersion; bytesReturned = sizeof(USHORT); break; case IOCTL_MARS_GET_FUNCTION_NUMBER: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } *(PUCHAR)outBuffer = fdoData->FunctionNumber; bytesReturned = sizeof(UCHAR); break; case IOCTL_MARS_GET_FUNCTION_FOCUS: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } *(PUCHAR)outBuffer = fdoData->FunctionFocus; bytesReturned = sizeof(UCHAR); break; case IOCTL_MARS_SET_FUNCTION_FOCUS: if (InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } fdoData->FunctionFocus = *(PUCHAR)inBuffer; break; //--------------------------------------------------- // // SDP_BUS_WIDTH // //--------------------------------------------------- case IOCTL_MARS_GET_BUS_WIDTH: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_BUS_WIDTH, outBuffer, sizeof(UCHAR)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } break; case IOCTL_MARS_SET_BUS_WIDTH: if (InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_BUS_WIDTH, inBuffer, sizeof(UCHAR)); break; //--------------------------------------------------- // // SDP_BUS_CLOCK // //--------------------------------------------------- case IOCTL_MARS_GET_BUS_CLOCK: if (OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_BUS_CLOCK, outBuffer, sizeof(ULONG)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(ULONG); } break; case IOCTL_MARS_SET_BUS_CLOCK: if (InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_BUS_CLOCK, inBuffer, sizeof(ULONG)); break; //--------------------------------------------------- // // SDP_FUNCTION_BLOCK_LENGTH // //--------------------------------------------------- case IOCTL_MARS_GET_BLOCKLEN: if (OutputBufferLength < sizeof(USHORT)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_FUNCTION_BLOCK_LENGTH, outBuffer, sizeof(SHORT)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(USHORT); } break; case IOCTL_MARS_SET_BLOCKLEN: if (InputBufferLength < sizeof(USHORT)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_FUNCTION_BLOCK_LENGTH, inBuffer, sizeof(SHORT)); break; //--------------------------------------------------- // // SDP_FN0_BLOCK_LENGTH // //--------------------------------------------------- case IOCTL_MARS_GET_FN0_BLOCKLEN: if (OutputBufferLength < sizeof(USHORT)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_FN0_BLOCK_LENGTH, outBuffer, sizeof(SHORT)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(USHORT); } break; case IOCTL_MARS_SET_FN0_BLOCKLEN: if (InputBufferLength < sizeof(USHORT)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_FN0_BLOCK_LENGTH, inBuffer, sizeof(SHORT)); break; //--------------------------------------------------- // // SDP_BUS_INTERFACE_CONTROL // //--------------------------------------------------- case IOCTL_MARS_GET_BUS_INTERFACE_CONTROL: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_BUS_INTERFACE_CONTROL, outBuffer, sizeof(UCHAR)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } break; case IOCTL_MARS_SET_BUS_INTERFACE_CONTROL: if (InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_BUS_INTERFACE_CONTROL, inBuffer, sizeof(UCHAR)); break; //--------------------------------------------------- // // SDP_FUNCTION_INT_ENABLE // //--------------------------------------------------- case IOCTL_MARS_GET_INT_ENABLE: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioGetProperty(device, SDP_FUNCTION_INT_ENABLE, outBuffer, sizeof(UCHAR)); if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } break; case IOCTL_MARS_SET_INT_ENABLE: if (InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioSetProperty(device, SDP_FUNCTION_INT_ENABLE, inBuffer, sizeof(UCHAR)); break; //--------------------------------------------------- // // READ/WRITE BYTE // //--------------------------------------------------- case IOCTL_MARS_READ_BYTE: if ((InputBufferLength < sizeof(ULONG)) || (OutputBufferLength < sizeof(UCHAR))) { status = STATUS_BUFFER_TOO_SMALL; break; } status = SdioReadWriteByte(device, fdoData->FunctionFocus, (PUCHAR)outBuffer, *(PULONG)inBuffer, FALSE); if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } break; case IOCTL_MARS_WRITE_BYTE: if ((InputBufferLength < sizeof(ULONG)*2)) {//||(OutputBufferLength < sizeof(UCHAR))) { status = STATUS_BUFFER_TOO_SMALL; break; } // BUGBUG: check for output buffer length status = SdioReadWriteByte(device, fdoData->FunctionFocus, (PUCHAR)(&((PULONG)inBuffer)[1]), *(PULONG)inBuffer, TRUE); // BUGBUG: Return the right size if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } break; //--------------------------------------------------- // // Mode settings // //--------------------------------------------------- case IOCTL_MARS_SET_TRANSFER_MODE: bytesReturned = 0; break; case IOCTL_MARS_TOGGLE_MODE: if (OutputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (fdoData->DriverVersion < SDBUS_DRIVER_VERSION_2) { status = STATUS_INVALID_DEVICE_REQUEST; break; } fdoData->BlockMode = fdoData->BlockMode ? 0 : 1; *(PUCHAR)outBuffer = fdoData->BlockMode; bytesReturned = sizeof(UCHAR); break; case IOCTL_MARS_TOGGLE_NOISY: if (OutputBufferLength < sizeof(BOOLEAN)) { status = STATUS_BUFFER_TOO_SMALL; break; } NoisyMode = NoisyMode ? 0 : 1; *(PBOOLEAN)outBuffer = NoisyMode; bytesReturned = sizeof(BOOLEAN); if (NoisyMode) { KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Noisy mode\n")); } else { KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Quiet mode\n")); } break; default: NT_ASSERTMSG("Invalid IOCTL request\n", FALSE); status = STATUS_INVALID_DEVICE_REQUEST; } WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; }
// // Internal Function: UartCtlSetHandflow // VOID UartCtlSetHandflow( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_HANDFLOW pHandFlow = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveInputBuffer(Request, sizeof(SERIAL_HANDFLOW), (PVOID*)(& pHandFlow), NULL); if (!NT_SUCCESS(status)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Failed to retrieve input buffer for WDFREQUEST %p - " "%!STATUS!", Request, status); } if (NT_SUCCESS(status)) { // // Make sure there are no invalid bits set in // the control and handshake // if ((pHandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) || (pHandFlow->FlowReplace & SERIAL_FLOW_INVALID)) { status = STATUS_INVALID_PARAMETER; TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Invalid bit in SERIAL_HANDFLOW %p - " "%!STATUS!", pHandFlow, status); } } if (NT_SUCCESS(status)) { // // Software flow control and in-band signaling // have not been implemented in this sample. // if ((pHandFlow->ControlHandShake & SERIAL_DSR_SENSITIVITY) || (pHandFlow->ControlHandShake & SERIAL_ERROR_ABORT) || (pHandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE) || (pHandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT) || (pHandFlow->FlowReplace & SERIAL_AUTO_RECEIVE) || (pHandFlow->FlowReplace & SERIAL_ERROR_CHAR) || (pHandFlow->FlowReplace & SERIAL_NULL_STRIPPING) || (pHandFlow->FlowReplace & SERIAL_BREAK_CHAR) || (pHandFlow->FlowReplace & SERIAL_XOFF_CONTINUE) || ((pHandFlow->FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { status = STATUS_NOT_IMPLEMENTED; TraceMessage( TRACE_LEVEL_WARNING, TRACE_FLAG_CONTROL, "Specified SERIAL_HANDFLOW %p has not been implemented - " "%!STATUS!", pHandFlow, status); } } if (NT_SUCCESS(status)) { // // Make sure the DTR mode is valid // if ((pHandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { status = STATUS_INVALID_PARAMETER; TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "Cannot set handflow with invalid DTR mode %lu - " "%!STATUS!", pHandFlow->ControlHandShake, status); } } if (NT_SUCCESS(status)) { WdfSpinLockAcquire(pDevExt->ReceiveBufferSpinLock); WdfInterruptAcquireLock(pDevExt->WdfInterrupt); BOOLEAN newFlowControl; BOOLEAN prevFlowControl = UsingRXFlowControl(pDevExt); pDevExt->HandFlow = *pHandFlow; newFlowControl = UsingRXFlowControl(pDevExt); WdfInterruptReleaseLock(pDevExt->WdfInterrupt); // Empty software FIFO before changing flow control if (newFlowControl != prevFlowControl) { if (!newFlowControl) { if (pDevExt->FIFOBufferBytes > 0) { // If switching from flow control to no flow control, // read bytes from the software FIFO to ring buffer before // asserting flow control lines. // Shouldn't have a cached buffer and bytes in the software FIFO NT_ASSERT(!HasCachedReceiveBuffer(pDevExt)); // Using a new status variable so the IOCTL doesn't fail if // the driver can't read the software FIFO to SerCx ring buffer, which // may happen after the file has closed. NTSTATUS fifoStatus = SerCxRetrieveReceiveBuffer(Device, SERIAL_SOFTWARE_FIFO_SIZE, &pDevExt->PIOReceiveBuffer); // Read bytes from software FIFO and return the buffer if (NT_SUCCESS(fifoStatus)) { // Read the software FIFO bytes into the ring buffer. // This function won't return the buffer. UartReceiveBytesFromSoftwareFIFO(pDevExt); // The software FIFO has been read out and should be empty now. NT_ASSERT(pDevExt->FIFOBufferBytes == 0); fifoStatus = SerCxProgressReceive( Device, pDevExt->ReceiveProgress, SerCxStatusSuccess); if (!NT_SUCCESS(fifoStatus)) { TraceMessage( TRACE_LEVEL_ERROR, TRACE_FLAG_CONTROL, "%!FUNC! Failed to return buffer - %!STATUS!", fifoStatus); NT_ASSERTMSG("SerCxProgressReceive shouldn't fail", NT_SUCCESS(fifoStatus)); } pDevExt->PerfStats.ReceivedCount += pDevExt->ReceiveProgress; pDevExt->ReceiveProgress = 0; pDevExt->PIOReceiveBuffer.Buffer = NULL; } else { TraceMessage( TRACE_LEVEL_WARNING, TRACE_FLAG_CONTROL, "SerCxRetrieveReceiveBuffer failed - %!STATUS!", fifoStatus); } } } else { // If switching from no flow control to flow control, // the software FIFO should already be empty. NT_ASSERT(pDevExt->FIFOBufferBytes == 0); } } WdfInterruptAcquireLock(pDevExt->WdfInterrupt); // If software FIFO empty, re-assert flow control // Automatic flow control MUST be re-enabled here if it's being used. if (pDevExt->FIFOBufferBytes == 0) { UartFlowReceiveAvailable(Device); } WdfInterruptReleaseLock(pDevExt->WdfInterrupt); WdfSpinLockRelease(pDevExt->ReceiveBufferSpinLock); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
VOID ControllerCompleteTransfer( _In_ PPBC_DEVICE pDevice, _In_ PPBC_REQUEST pRequest, _In_ BOOLEAN AbortSequence ) /*++ Routine Description: This routine completes a data transfer. Unless there are more transfers remaining in the sequence, the request is completed. Arguments: pDevice - a pointer to the PBC device context pRequest - a pointer to the PBC request context AbortSequence - specifies whether the driver should abort the ongoing sequence or begin the next transfer Return Value: None. The request is completed asynchronously. --*/ { FuncEntry(TRACE_FLAG_TRANSFER); NT_ASSERT(pDevice != NULL); NT_ASSERT(pRequest != NULL); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Transfer (index %lu) %s with %Iu bytes for address 0x%lx " "(SPBREQUEST %p)", pRequest->TransferIndex, NT_SUCCESS(pRequest->Status) ? "complete" : "error", pRequest->Information, pDevice->pCurrentTarget->Settings.Address, pRequest->SpbRequest); // // Update request context with information from this transfer. // pRequest->TotalInformation += pRequest->Information; pRequest->Information = 0; // // Check if there are more transfers // in the sequence. // if (!AbortSequence) { pRequest->TransferIndex++; if (pRequest->TransferIndex < pRequest->TransferCount) { // // Configure the request for the next transfer. // pRequest->Status = PbcRequestConfigureForIndex( pRequest, pRequest->TransferIndex); if (NT_SUCCESS(pRequest->Status)) { // // Configure controller and kick-off read. // Request will be completed asynchronously. // PbcRequestDoTransfer(pDevice,pRequest); goto exit; } } } // // If not already cancelled, unmark request cancellable. // if (pRequest->Status != STATUS_CANCELLED) { NTSTATUS cancelStatus; cancelStatus = WdfRequestUnmarkCancelable(pRequest->SpbRequest); if (!NT_SUCCESS(cancelStatus)) { // // WdfRequestUnmarkCancelable should only fail if the request // has already been or is about to be cancelled. If it does fail // the request must NOT be completed - the cancel callback will do // this. // NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if the request has already been or is about to be cancelled", cancelStatus == STATUS_CANCELLED); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_TRANSFER, "Failed to unmark SPBREQUEST %p as cancelable - %!STATUS!", pRequest->SpbRequest, cancelStatus); goto exit; } } // // Done or error occurred. Set interrupt mask to 0. // Doing this keeps the DPC from re-enabling interrupts. // PbcDeviceSetInterruptMask(pDevice, 0); // // Clear the target's current request. This will prevent // the request context from being accessed once the request // is completed (and the context is invalid). // pDevice->pCurrentTarget->pCurrentRequest = NULL; // // Clear the controller's current target if any of // 1. request is type sequence // 2. request position is single // (did not come between lock/unlock) // Otherwise wait until unlock. // if ((pRequest->Type == SpbRequestTypeSequence) || (pRequest->SequencePosition == SpbRequestSequencePositionSingle)) { pDevice->pCurrentTarget = NULL; } // // Mark the IO complete. Request not // completed here. // pRequest->bIoComplete = TRUE; exit: FuncExit(TRACE_FLAG_TRANSFER); }
NTSTATUS UpdateBufferLocationAndIoctl( _Inout_ PIRP Irp, _Out_ PULONG UpdatedIoctl ) /*++ Routine Description: The buffers are swapped in the following manner. Incoming Irp: ============== Irp->UserBuffer contains HID_XFER_PACKET which may have both input and output data/buffer. struct HID_XFER_PACKET { PUCHAR reportBuffer; // output buffer ULONG reportBufferLen; // output buffer length UCHAR reportId; // input data }; Input/output buffer location: Irp->UserBuffer Updated Irp that is sent down: ============================== For IOCTLs that have both input and output: Input buffer location : Type3InputBuffer (= PHID_XFER_PACKET->reportId) Output buffer location: Irp->UserBuffer (= PHID_XFER_PACKET->reportBuffer) For IOCTLs that have two inputs: Input buffer location: Type3InputBuffer (= PHID_XFER_PACKET->reportBuffer) Input data : Parameters.DeviceIoControl.OutputBufferLength (= PHID_XFER_PACKET->reportId) --*/ { PHID_XFER_PACKET hidPacket; PIO_STACK_LOCATION currStack, nextStack; NTSTATUS status; ULONG ioctlCode, newIoctlCode; currStack = IoGetCurrentIrpStackLocation(Irp); nextStack = IoGetNextIrpStackLocation(Irp); status = STATUS_SUCCESS; ioctlCode = nextStack->Parameters.DeviceIoControl.IoControlCode; hidPacket = (PHID_XFER_PACKET) Irp->UserBuffer; if (hidPacket == NULL) { status = STATUS_INVALID_PARAMETER; return status; } // // Store original buffer pointer in current stack location so we can revert // it back in completion routine // NT_ASSERTMSG("Type3InputBuffer is not NULL, not expected", currStack->Parameters.DeviceIoControl.Type3InputBuffer == NULL); currStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->UserBuffer; switch (currStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_HID_GET_FEATURE: // METHOD_OUT_DIRECT, KM/UM case IOCTL_HID_GET_INPUT_REPORT: // METHOD_OUT_DIRECT, KM/UM // // These IOCTLs have input and output buffer combined together // we separate them out. // if (currStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_XFER_PACKET)) { status = STATUS_INVALID_PARAMETER; return status; } // // Setup input data // nextStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)&hidPacket->reportId; nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(hidPacket->reportId); // // Setup output buffer // Irp->UserBuffer = (PVOID) hidPacket->reportBuffer; nextStack->Parameters.DeviceIoControl.OutputBufferLength = hidPacket->reportBufferLen; break; case IOCTL_HID_WRITE_REPORT: // METHOD_NEITHER, KM case IOCTL_HID_SET_FEATURE: // METHOD_IN_DIRECT, KM/UM case IOCTL_HID_SET_OUTPUT_REPORT: // METHOD_IN_DIRECT, KM/UM // // These IOCTLS have two inputs: // 1) input buffer (PHID_XFER_PACKET->reportBuffer & reportBufferlength) // 2) input data (PHID_XFER_PACKET->reportId) // Input buffer is placed in Type3InputBuffer and its size in // InputBufferLength // Input data is placed in outputBufferlength // if (currStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) { status = STATUS_INVALID_PARAMETER; return status; } nextStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) hidPacket->reportBuffer; nextStack->Parameters.DeviceIoControl.InputBufferLength = hidPacket->reportBufferLen; nextStack->Parameters.DeviceIoControl.OutputBufferLength = hidPacket->reportId; // // Use a scratch buffer allocated as a global buffer, sized // to maximum possible reportlength (MAXUCHAR) and store it temporarily // at Irp->UserBuffer since we've set a non-zero output buffer length. // Note that UMDF will not copy the buffer content to user-mode driver's // buffer because it's an output buffer meant to written to, by the // user-mode driver and not read. // Irp->UserBuffer = G_ScratchBuffer; break; default: NT_ASSERTMSG("Unexpected IOCTL", FALSE); break; } // // For those IOCTLs that are not METHOD_NEITHER, we map to new IOCTL // code that is METHOD_NEITHER. // switch(ioctlCode) { case IOCTL_HID_SET_FEATURE: // METHOD_IN_DIRECT, KM/UM newIoctlCode = IOCTL_UMDF_HID_SET_FEATURE; // METHOD_NEITHER break; case IOCTL_HID_GET_FEATURE: // METHOD_OUT_DIRECT, KM/UM newIoctlCode = IOCTL_UMDF_HID_GET_FEATURE; // METHOD_NEITHER break; case IOCTL_HID_GET_INPUT_REPORT: // METHOD_OUT_DIRECT, KM/UM newIoctlCode = IOCTL_UMDF_HID_GET_INPUT_REPORT; // METHOD_NEITHER break; case IOCTL_HID_SET_OUTPUT_REPORT: // METHOD_IN_DIRECT, KM/UM newIoctlCode = IOCTL_UMDF_HID_SET_OUTPUT_REPORT; // METHOD_NEITHER break; default: // // keep the ioctl code unchanged // newIoctlCode = ioctlCode; break; } *UpdatedIoctl = newIoctlCode; return status; }
NTSTATUS HidUmdfInternalIoctlWorker( _In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp ) /*++ Routine Description: IOCTL handler. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION currStack, nextStack; ULONG ioctlCode, newIoctlCode; BOOLEAN setCompletionRoutine = FALSE; NTSTATUS status = STATUS_SUCCESS; BOOLEAN modeChanged = FALSE; PULONG temp = NULL; currStack = IoGetCurrentIrpStackLocation(Irp); // // Copy current stack to next instead of skipping. We do this to preserve // current stack information provided by hidclass driver to the minidriver // IoCopyCurrentIrpStackLocationToNext(Irp); // // HIDclass uses INTERNAL_IOCTL but since UMDF doesn't yet have support for // internal IOCTLS we change the IOCTL type to DEVICE_CONTROL for next stack // so that UMDF stack can handle it as normal IOCTL. // Note that user mode apps cannot open a handle to minidriver since // HIDClass doesn't allow that (it own's minidriver's dispatch table), // and therefore they can't send these IOCTLs to UMDF minidriver by calling // win32 API. // nextStack = IoGetNextIrpStackLocation(Irp); nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; // // Some IOCTLs are not of type METHOD_NEITHER and are forwarded by // HIDClass to minidriver. We modify those IOCTLs to use METHOD_NEITHER // and send it down to UMDF driver. // ioctlCode = nextStack->Parameters.DeviceIoControl.IoControlCode; newIoctlCode = ioctlCode; switch(ioctlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: // METHOD_NEITHER, KM case IOCTL_HID_GET_REPORT_DESCRIPTOR: // METHOD_NEITHER, KM case IOCTL_HID_READ_REPORT: // METHOD_NEITHER, KM case IOCTL_HID_ACTIVATE_DEVICE: // METHOD_NEITHER, KM case IOCTL_HID_DEACTIVATE_DEVICE: // METHOD_NEITHER, KM case IOCTL_HID_GET_DEVICE_ATTRIBUTES: // METHOD_NEITHER, KM case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: // METHOD_NEITHER, KM // // Nothing to do. These IOCTLs have been listed for completeness. // break; case IOCTL_HID_WRITE_REPORT: // METHOD_NEITHER, KM case IOCTL_HID_SET_FEATURE: // METHOD_IN_DIRECT, KM/UM case IOCTL_HID_GET_FEATURE: // METHOD_OUT_DIRECT, KM/UM case IOCTL_HID_GET_INPUT_REPORT: // METHOD_OUT_DIRECT, KM/UM case IOCTL_HID_SET_OUTPUT_REPORT: // METHOD_IN_DIRECT, KM/UM // // These IOCTLs use HID_XFER_PACKET. They need their buffer location // updated. See comments in function for IOCTL specific updates. // status = UpdateBufferLocationAndIoctl(Irp, &newIoctlCode); if (!NT_SUCCESS(status)) { KdPrint(("HidUmdf: Ioctl %s failed status 0x%x\n", DbgHidInternalIoctlString(ioctlCode), status)); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } // // set completion routine // setCompletionRoutine = TRUE; break; case IOCTL_GET_PHYSICAL_DESCRIPTOR: // METHOD_OUT_DIRECT, KM/UM // // These IOCTLs are not METHOD_NEITHER but hidclass places buffers at // locations that are standard locations for METHOD_NEITHER // (Type3InputBuffer and Irp->UserBuffer), so we modify the IOCTL type // to use METHOD_NEITHER so that UMDF can provide the buffers from // standard METHOD_NEITHER buffer locations. // newIoctlCode = IOCTL_UMDF_GET_PHYSICAL_DESCRIPTOR; break; case IOCTL_HID_GET_STRING: // METHOD_NEITHER, KM // // This is a METHOD_NEITHER IOCTL. Hidclass places an input // ULONG value, and not a buffer, at Type3inputBuffer location. // We store the input value in Irp->AssocatedIrp.SystemBuffer location // and store pointer to Irp->AssocatedIrp.SystemBuffer at // Type3InputBuffer so that lower driver can access it as input buffer. // // // swap current SystemBuffer content with Type3inputBuffer // temp = Irp->AssociatedIrp.SystemBuffer; Irp->AssociatedIrp.SystemBuffer = currStack->Parameters.DeviceIoControl.Type3InputBuffer; currStack->Parameters.DeviceIoControl.Type3InputBuffer = temp; // // store the address of SystemBuffer in next stack's Type3InputBuffer // and set buffer size // nextStack->Parameters.DeviceIoControl.Type3InputBuffer = &Irp->AssociatedIrp.SystemBuffer; nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG); setCompletionRoutine = TRUE; break; case IOCTL_HID_GET_INDEXED_STRING: // METHOD_OUT_DIRECT, KM/UM // // This is a METHOD_OUT_DIRECT IOCTL however hidclass places buffer/value // in a mix of locations (Type3InputBuffer for input instead of // Irp->AssociatedIrp.SystemBuffer and Irp->MdlAddress for output). // Also, the input is not a buffer but a ULONG value. // // We store the address of next stack's Type3InputBuffer that contains // the input value at Irp->AssiciatedIrp.SystemBuffer // (standard location for METHOD_OUT_DIRECT), and keep the output buffer // location (Irp->UserBuffer) unchanged since it's already at standard // location. The input buffer location is reverted back to original in // completion routine. // // // store SystemBuffer in curr stack's Type3inputBuffer so we // can get it back in completion routine. // currStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->AssociatedIrp.SystemBuffer; // // store the address of next stack's Type3InputBuffer in SystemBuffer // and set buffer size. // Irp->AssociatedIrp.SystemBuffer = &nextStack->Parameters.DeviceIoControl.Type3InputBuffer; nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG); setCompletionRoutine = TRUE; break; default: NT_ASSERTMSG("Unexpected IOCTL", FALSE); break; } // // update ioctl code for next stack location // nextStack->Parameters.DeviceIoControl.IoControlCode = newIoctlCode; if (Irp->RequestorMode == UserMode) { Irp->RequestorMode = KernelMode; setCompletionRoutine = TRUE; modeChanged = TRUE; } if (setCompletionRoutine) { IoSetCompletionRoutine(Irp, UserIoctlCompletion, (modeChanged ? (PVOID)Irp : NULL), // context TRUE, TRUE, TRUE ); } return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp); }
VOID CdSetFileObject ( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFILE_OBJECT FileObject, _In_ TYPE_OF_OPEN TypeOfOpen, PFCB Fcb, _In_opt_ PCCB Ccb ) /*++ Routine Description: This routine will initialize the FileObject context fields based on the input type and data structures. Arguments: FileObject - Supplies the file object pointer being initialized. TypeOfOpen - Sets the type of open. Fcb - Fcb for this file object. Ignored for UnopenedFileObject. Ccb - Ccb for the handle corresponding to this file object. Will not be present for stream file objects. Return Value: None. --*/ { PAGED_CODE(); UNREFERENCED_PARAMETER( IrpContext ); // // We only have values 0 to 7 available so make sure we didn't // inadvertantly add a new type. // NT_ASSERTMSG( "FileObject types exceed available bits\n", BeyondValidType <= 8 ); // // Setting a file object to type UnopenedFileObject means just // clearing all of the context fields. All the other input // if (TypeOfOpen == UnopenedFileObject) { FileObject->FsContext = FileObject->FsContext2 = NULL; return; } // // Check that the 3 low-order bits of the Ccb are clear. // NT_ASSERTMSG( "Ccb is not quad-aligned\n", !FlagOn( ((ULONG_PTR) Ccb), TYPE_OF_OPEN_MASK )); // // We will or the type of open into the low order bits of FsContext2 // along with the Ccb value. // The Fcb is stored into the FsContext field. // FileObject->FsContext = Fcb; FileObject->FsContext2 = Ccb; #pragma warning( suppress: 4213 ) SetFlag( ((ULONG_PTR) FileObject->FsContext2), TypeOfOpen ); // // Set the Vpb field in the file object. // FileObject->Vpb = Fcb->Vcb->Vpb; return; }
/*++//////////////////////////////////////////////////////////////////////////// ClassAcquireRemoveLockEx() Routine Description: This routine is called to acquire the remove lock on the device object. While the lock is held, the caller can assume that no pending pnp REMOVE requests will be completed. The lock should be acquired immediately upon entering a dispatch routine. It should also be acquired before creating any new reference to the device object if there's a chance of releasing the reference before the new one is done. This routine will return TRUE if the lock was successfully acquired or FALSE if it cannot be because the device object has already been removed. Arguments: DeviceObject - the device object to lock Tag - Used for tracking lock allocation and release. If an irp is specified when acquiring the lock then the same Tag must be used to release the lock before the Tag is completed. Return Value: The value of the IsRemoved flag in the device extension. If this is non-zero then the device object has received a Remove irp and non-cleanup IRP's should fail. If the value is REMOVE_COMPLETE, the caller should not even release the lock. --*/ ULONG ClassAcquireRemoveLockEx( _In_ PDEVICE_OBJECT DeviceObject, PVOID Tag, _In_ PCSTR File, _In_ ULONG Line ) // This function implements the acquisition of Tag #pragma warning(suppress:28104) { PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; // // Grab the remove lock // #if DBG LONG lockValue; lockValue = InterlockedIncrement(&commonExtension->RemoveLock); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassAcquireRemoveLock: " "Acquired for Object %p & irp %p - count is %d\n", DeviceObject, Tag, lockValue)); NT_ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ", (lockValue > 0)); NT_ASSERTMSG("RemoveLock increased to meet LockHighWatermark", ((LockHighWatermark == 0) || (lockValue != LockHighWatermark))); if (commonExtension->IsRemoved != REMOVE_COMPLETE) { PRTL_GENERIC_TABLE removeTrackingList = NULL; REMOVE_TRACKING_BLOCK trackingBlock; PREMOVE_TRACKING_BLOCK insertedTrackingBlock = NULL; BOOLEAN newElement = FALSE; KIRQL oldIrql; trackingBlock.Tag = Tag; trackingBlock.File = File; trackingBlock.Line = Line; KeQueryTickCount((&trackingBlock.TimeLocked)); KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock, &oldIrql); removeTrackingList = commonExtension->RemoveTrackingList; if (removeTrackingList != NULL) { insertedTrackingBlock = RtlInsertElementGenericTable(removeTrackingList, &trackingBlock, sizeof(REMOVE_TRACKING_BLOCK), &newElement); } if (insertedTrackingBlock != NULL) { if (!newElement) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: " "already tracking Tag %p\n", Tag)); TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: " "acquired in file %s on line %d\n", insertedTrackingBlock->File, insertedTrackingBlock->Line)); // NT_ASSERT(FALSE); } } else { commonExtension->RemoveTrackingUntrackedCount++; TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: " "Cannot track Tag %p - currently %d untracked requsts\n", Tag, commonExtension->RemoveTrackingUntrackedCount)); } KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql); } #else UNREFERENCED_PARAMETER(Tag); UNREFERENCED_PARAMETER(File); UNREFERENCED_PARAMETER(Line); InterlockedIncrement(&commonExtension->RemoveLock); #endif return (commonExtension->IsRemoved); }
/*++//////////////////////////////////////////////////////////////////////////// ClassReleaseRemoveLock() Routine Description: This routine is called to release the remove lock on the device object. It must be called when finished using a previously locked reference to the device object. If an Tag was specified when acquiring the lock then the same Tag must be specified when releasing the lock. When the lock count reduces to zero, this routine will signal the waiting remove Tag to delete the device object. As a result the DeviceObject pointer should not be used again once the lock has been released. Arguments: DeviceObject - the device object to lock Tag - The irp (if any) specified when acquiring the lock. This is used for lock tracking purposes Return Value: none --*/ VOID ClassReleaseRemoveLock( _In_ PDEVICE_OBJECT DeviceObject, PIRP Tag ) // This function implements the release of Tag #pragma warning(suppress:28103) { PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; LONG lockValue; #if DBG PRTL_GENERIC_TABLE removeTrackingList = NULL; REMOVE_TRACKING_BLOCK searchDataBlock; BOOLEAN found = FALSE; BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE); KIRQL oldIrql; if(isRemoved) { TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen")); InterlockedDecrement(&(commonExtension->RemoveLock)); return; } KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock, &oldIrql); removeTrackingList = commonExtension->RemoveTrackingList; if (removeTrackingList != NULL) { searchDataBlock.Tag = Tag; found = RtlDeleteElementGenericTable(removeTrackingList, &searchDataBlock); } if(!found) { if(commonExtension->RemoveTrackingUntrackedCount == 0) { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: " "Couldn't find Tag %p in the lock tracking list\n", Tag)); NT_ASSERT(FALSE); } else { TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: " "Couldn't find Tag %p in the lock tracking list - " "may be one of the %d untracked requests still outstanding\n", Tag, commonExtension->RemoveTrackingUntrackedCount)); commonExtension->RemoveTrackingUntrackedCount--; NT_ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0); } } KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql); #endif lockValue = InterlockedDecrement(&commonExtension->RemoveLock); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: " "Released for Object %p & irp %p - count is %d\n", DeviceObject, Tag, lockValue)); NT_ASSERT(lockValue >= 0); NT_ASSERTMSG("RemoveLock decreased to meet LockLowWatermark", ((LockLowWatermark == 0) || !(lockValue == LockLowWatermark))); if(lockValue == 0) { NT_ASSERT(commonExtension->IsRemoved); // // The device needs to be removed. Signal the remove event // that it's safe to go ahead. // TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: " "Release for object %p & irp %p caused lock to go to zero\n", DeviceObject, Tag)); KeSetEvent(&commonExtension->RemoveEvent, IO_NO_INCREMENT, FALSE); } return; }