static IO_ALLOCATION_ACTION NTAPI SoundProgramDMA( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context) { PDEVICE_EXTENSION Device = DeviceObject->DeviceExtension; ULONG zzz; PUCHAR VirtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Device->Mdl); DPRINT("IoMapTransfer\n"); IoMapTransfer(Device->Adapter, Device->Mdl, MapRegisterBase, (PUCHAR) MmGetMdlVirtualAddress(Device->Mdl), &Device->BufferSize, // is this right? TRUE); DPRINT("VBuffer == 0x%x (really 0x%x?) Bufsize == %u\n", Device->VirtualBuffer, MmGetPhysicalAddress(Device->VirtualBuffer), Device->BufferSize); DPRINT("Writing %u bytes of garbage...\n", Device->BufferSize); // Write some garbage: for (zzz = 0; zzz < Device->BufferSize; zzz ++) *(VirtualAddress + zzz) = (UCHAR) zzz % 200; DPRINT("done\n"); KeSetEvent(Context, 0, FALSE); return KeepObject; }
/* * @implemented */ VOID EXPORT NdisMCompleteBufferPhysicalMapping( IN NDIS_HANDLE MiniportAdapterHandle, IN PNDIS_BUFFER Buffer, IN ULONG PhysicalMapRegister) /* * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping * ARGUMENTS: * - MiniportAdapterHandle: handle originally input to MiniportInitialize * - Buffer: NDIS_BUFFER to complete the mapping on * - PhyscialMapRegister: the chosen map register * NOTES: * - May be called at IRQL <= DISPATCH_LEVEL */ { PLOGICAL_ADAPTER Adapter; VOID *CurrentVa; ULONG Length; ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); ASSERT(MiniportAdapterHandle && Buffer); Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; CurrentVa = MmGetMdlVirtualAddress(Buffer); Length = MmGetMdlByteCount(Buffer); Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->FlushAdapterBuffers( Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer, Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister, CurrentVa, Length, Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice); }
/* * @implemented */ VOID EXPORT NdisMCompleteDmaTransfer(OUT PNDIS_STATUS Status, IN NDIS_HANDLE MiniportDmaHandle, IN PNDIS_BUFFER Buffer, IN ULONG Offset, IN ULONG Length, IN BOOLEAN WriteToDevice) { PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle; PDMA_ADAPTER AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject; NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n", MiniportDmaHandle, Buffer, Offset, Length, WriteToDevice)); if (!AdapterObject->DmaOperations->FlushAdapterBuffers(AdapterObject, Buffer, DmaBlock->MapRegisterBase, (PUCHAR)MmGetMdlVirtualAddress(Buffer) + Offset, Length, WriteToDevice)) { NDIS_DbgPrint(MIN_TRACE, ("FlushAdapterBuffers failed\n")); *Status = NDIS_STATUS_FAILURE; return; } AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject); NDIS_DbgPrint(MAX_TRACE, ("returning success\n")); *Status = NDIS_STATUS_SUCCESS; }
static VOID OvsFreeMDLAndData(PMDL mdl) { PVOID data; data = MmGetMdlVirtualAddress(mdl); NdisFreeMdl(mdl); OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); }
/////////////////////////////////////////////////////////////////////////////// // // OsrAdapterControlWrite // // This is routine is called by the I/O Manager when the Adapter resources // (such as map registers) requested by the OsrStartWriteIrp function are // available for our use. // // INPUTS: // // DeviceObject - Address of the DEVICE_OBJECT for our device. // // MapRegisterBase - Base address of the Map registers that have been // reserved by the I/O Manager and HAL for our use. // // Context - address of the Write Irp for the operation to be started on the // device. // // OUTPUTS: // // None. // // RETURNS: // // DeallocateObjectKeepRegisters - indicates that the map registers that // were allocated to us should not be deallocated at this time. // We will deallocate them with the Read operation completes. // // IRQL: // // This routine is called at IRQL_DISPATCH_LEVEL. // // NOTES: // /////////////////////////////////////////////////////////////////////////////// IO_ALLOCATION_ACTION OsrAdapterControlWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP NotUsed, IN PVOID MapRegisterBase, IN PVOID Context) { PIRP irp = (PIRP) Context; PIO_STACK_LOCATION ioStack; POSR_DEVICE_EXT devExt; PUCHAR baseVa; #if DBG DbgPrint("AdapterControlWrite: Irp = 0x%0x\n", irp); #endif devExt = DeviceObject->DeviceExtension; ioStack = IoGetCurrentIrpStackLocation(irp); devExt->WriteLength = ioStack->Parameters.Write.Length - devExt->WriteSoFar; #if DBG DbgPrint("AdapterControlWrite: Length remaining = %d. \n", devExt->WriteLength); #endif // // Get set-up for the transfer // devExt->WriteMapRegBase = MapRegisterBase; baseVa = MmGetMdlVirtualAddress(irp->MdlAddress); devExt->WriteStartingOffset = devExt->WriteSoFar; // // Get the base address and length of the segment to write. // devExt->WritePaToDevice = IoMapTransfer(devExt->WriteAdapter, irp->MdlAddress, MapRegisterBase, baseVa+(devExt->WriteSoFar), &devExt->WriteLength, TRUE); // WriteToDevice // // Update the length transfered so far // devExt->WriteSoFar += devExt->WriteLength; // // Put the request on the device // (VOID)KeSynchronizeExecution(devExt->InterruptObject, OsrStartWriteOnDevice, DeviceObject); return(DeallocateObjectKeepRegisters); }
VOID MemFreePoolMemoryForMdl( __in PMDL Mem ) { PVOID PagedMem; PagedMem = MmGetMdlVirtualAddress(Mem); if (Mem->MdlFlags & MDL_PAGES_LOCKED) MmUnlockPages(Mem); ExFreePoolWithTag(PagedMem,VFD_POOL_TAG); }
NTSTATUS ssh_interceptor_iodevice_dispatch_write(PDEVICE_OBJECT device, PIRP irp) { SshInterceptorIoDevice io_dev = SSH_NTDEV_TO_SSHDEV(device); PIO_STACK_LOCATION irp_stack = IoGetCurrentIrpStackLocation(irp); unsigned len; unsigned char *buf; NTSTATUS status = STATUS_UNSUCCESSFUL; len = irp_stack->Parameters.Write.Length; #ifdef SSH_IM_INTERCEPTOR /* Aggressive optimization: use directly the user-mode virtual address. This is safe as long as we know that we are running in the context of the policy manager thread - and this case we are. */ buf = MmGetMdlVirtualAddress(irp->MdlAddress); #else buf = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); #endif /* */ /* We can't expect that write operation always succeeds. We could run out of memory in 'packetizer' and later we'll be in a deep trouble if we always tell that we successfully delivered the data... */ if (ssh_interceptor_pktizer_receive(len, buf, &io_dev->pktizer)) { status = STATUS_SUCCESS; } else { len = 0; status = STATUS_UNSUCCESSFUL; } irp->IoStatus.Status = status; irp->IoStatus.Information = len; IoCompleteRequest(irp, IO_NETWORK_INCREMENT); return status; }
//--------------------------------------------------------------------------- NTSTATUS DriverRead(IN PDEVICE_OBJECT vDeviceObject, IN PIRP vIrp) { Debug("Enter DriverRead"); if(0 == vIrp->MdlAddress) { vIrp->IoStatus.Information = 0; vIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(vIrp,IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } PVOID tVirtualAddress = MmGetMdlVirtualAddress(vIrp->MdlAddress); ULONG tLength = MmGetMdlByteCount(vIrp->MdlAddress); RtlFillMemory(tVirtualAddress,tLength,'A'); vIrp->IoStatus.Information = tLength; vIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(vIrp,IO_NO_INCREMENT); Debug("Leave DriverRead"); return STATUS_SUCCESS; }
VOID XNdisGetFirstBufferFromPacket(PNDIS_PACKET Packet, PNDIS_BUFFER *FirstBuffer, PVOID *FirstBufferVA, PUINT FirstBufferLength, PUINT TotalBufferLength) { PNDIS_BUFFER _Buffer; _Buffer = (Packet)->Private.Head; *(FirstBuffer) = _Buffer; *(FirstBufferVA) = MmGetMdlVirtualAddress(_Buffer); if (_Buffer != NULL) { *(FirstBufferLength) = MmGetMdlByteCount(_Buffer); _Buffer = _Buffer->Next; } else *(FirstBufferLength) = 0; *(TotalBufferLength) = *(FirstBufferLength); while (_Buffer != NULL) { *(TotalBufferLength) += MmGetMdlByteCount(_Buffer); _Buffer = _Buffer->Next; } }
//*********************************************************************************** // Name: MpFreeSGList // // Description: // frees sgdma list // // Return value: // None // // Parameters: // // NOTE: None // ********************************************************************************** VOID MpFreeSGList( IN PKIP_NDIS_ADAPTER pAdapter, IN PNDIS_PACKET Packet ) { PSCATTER_GATHER_LIST pSGL; PDMA_ADAPTER SystemAdapterObject = NDIS_GetSystemAdapterObject( pAdapter->NdisMiniportHandle ); pSGL = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo); if ( SystemAdapterObject ){ SystemAdapterObject->DmaOperations->PutScatterGatherList( SystemAdapterObject, pSGL, TRUE ); } if ( (Packet->Private.Flags & NDIS_FLAGS_USES_SG_BUFFER_LIST ) == NDIS_FLAGS_USES_SG_BUFFER_LIST ){ PNPAGED_LOOKASIDE_LIST SGListLookasideList = NDIS_GetSGListLookasideList( pAdapter->NdisMiniportHandle ); Packet->Private.Flags &= ~NDIS_FLAGS_USES_SG_BUFFER_LIST; pSGL = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved); if ( pSGL && SGListLookasideList ){ ExFreeToNPagedLookasideList( SGListLookasideList, pSGL ); } NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved) = NULL; } else if ( ( Packet->Private.Flags & NDIS_FLAGS_DOUBLE_BUFFERED ) == NDIS_FLAGS_DOUBLE_BUFFERED ){ PNDIS_BUFFER NdisBuffer; PVOID NdisBufferVA; Packet->Private.Flags &= ~NDIS_FLAGS_DOUBLE_BUFFERED; NdisBuffer = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, NdisReserved); if ( NdisBuffer ){ NdisBufferVA = MmGetMdlVirtualAddress(NdisBuffer); NdisFreeBuffer( NdisBuffer ); if ( NdisBufferVA ){ ExFreePoolWithTag(NdisBufferVA,MODULE_TAG); } } } }
dVoid kdi_FlushDMABuffers ( /* INPUT PARAMETERS: */ dVoidPtr context, dBoolean write_operation, dVoidPtr phy_data_ptr, dUDWord bytes_transferred_so_far, dUDWord total_bytes_of_transfer /* UPDATE PARAMETERS: */ /* OUTPUT PARAMETERS: */ ) /* COMMENTS: ***************************************************************** * * DEFINITIONS: *************************************************************/ { /* DATA: ********************************************************************/ KdiContextPtr kdi_context = (KdiContextPtr)context; /* CODE: ********************************************************************/ IoFlushAdapterBuffers( kdi_context->adapter_object, phy_data_ptr, kdi_context->map_register_base, (dVoidPtr)( (dUDWord) MmGetMdlVirtualAddress((PMDL) phy_data_ptr ) + bytes_transferred_so_far ), total_bytes_of_transfer, write_operation ); }
VOID NTAPI ClasspBuildRequestEx( IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PIRP Irp, IN PSCSI_REQUEST_BLOCK Srb ) /*++ ClasspBuildRequestEx() Routine Description: This routine allocates and builds an Srb for a read or write request. The block address and length are supplied by the Irp. The retry count is stored in the current stack for use by ClassIoComplete which processes these requests when they complete. The Irp is ready to be passed to the port driver when this routine returns. Arguments: FdoExtension - Supplies the device extension associated with this request. Irp - Supplies the request to be issued. Srb - Supplies an SRB to be used for the request. Note: If the IRP is for a disk transfer, the byteoffset field will already have been adjusted to make it relative to the beginning of the disk. Return Value: NT Status --*/ { PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; PCDB cdb; ULONG logicalBlockAddress; USHORT transferBlocks; // This function is obsolete, but still called by CDROM.SYS . // DBGWARN(("ClasspBuildRequestEx is OBSOLETE !")); // // Prepare the SRB. // RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); // // Calculate relative sector address. // logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, FdoExtension->SectorShift)); // // Write length to SRB. // Srb->Length = sizeof(SCSI_REQUEST_BLOCK); // // Set up IRP Address. // Srb->OriginalRequest = Irp; // // Set up target ID and logical unit number. // Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; Srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); // // Save byte count of transfer in SRB Extension. // Srb->DataTransferLength = currentIrpStack->Parameters.Read.Length; // // Initialize the queue actions field. // Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; // // Queue sort key is Relative Block Address. // Srb->QueueSortKey = logicalBlockAddress; // // Indicate auto request sense by specifying buffer and size. // Srb->SenseInfoBuffer = FdoExtension->SenseData; Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; // // Set timeout value of one unit per 64k bytes of data. // Srb->TimeOutValue = ((Srb->DataTransferLength + 0xFFFF) >> 16) * FdoExtension->TimeOutValue; // // Zero statuses. // Srb->SrbStatus = Srb->ScsiStatus = 0; Srb->NextSrb = 0; // // Indicate that 10-byte CDB's will be used. // Srb->CdbLength = 10; // // Fill in CDB fields. // cdb = (PCDB)Srb->Cdb; transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> FdoExtension->SectorShift); // // Move little endian values into CDB in big endian format. // cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1; cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0; // // Set transfer direction flag and Cdb command. // if (currentIrpStack->MajorFunction == IRP_MJ_READ) { DebugPrint((3, "ClassBuildRequest: Read Command\n")); SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN); cdb->CDB10.OperationCode = SCSIOP_READ; } else { DebugPrint((3, "ClassBuildRequest: Write Command\n")); SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT); cdb->CDB10.OperationCode = SCSIOP_WRITE; } // // If this is not a write-through request, then allow caching. // if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) { SET_FLAG(Srb->SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE); } else { // // If write caching is enable then force media access in the // cdb. // if (FdoExtension->DeviceFlags & DEV_WRITE_CACHE) { cdb->CDB10.ForceUnitAccess = TRUE; } } if(TEST_FLAG(Irp->Flags, (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO))) { SET_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING); } // // OR in the default flags from the device object. // SET_FLAG(Srb->SrbFlags, FdoExtension->SrbFlags); // // Set up major SCSI function. // nextIrpStack->MajorFunction = IRP_MJ_SCSI; // // Save SRB address in next stack for port driver. // nextIrpStack->Parameters.Scsi.Srb = Srb; // // Save retry count in current IRP stack. // currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; // // Set up IoCompletion routine address. // IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); }
/*++//////////////////////////////////////////////////////////////////////////// RetryRequest() Routine Description: This is a wrapper around the delayed retry DPC routine, RetryRequestDPC. This reinitializes the necessary fields, queues the request, and sets a timer to call the DPC if someone hasn't already done so. Arguments: DeviceObject - Supplies the device object associated with this request. Irp - Supplies the request to be retried. Srb - Supplies a Pointer to the SCSI request block to be retied. Associated - Indicates this is an associated Irp created by split request. RetryInterval - How long, in seconds, before retrying the request. Return Value: None --*/ VOID NTAPI RetryRequest( PDEVICE_OBJECT DeviceObject, PIRP Irp, PSCSI_REQUEST_BLOCK Srb, BOOLEAN Associated, ULONG RetryInterval ) { PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ULONG transferByteCount; // This function is obsolete but is still used by some of our class drivers. // DBGWARN(("RetryRequest is OBSOLETE !")); // // Determine the transfer count of the request. If this is a read or a // write then the transfer count is in the Irp stack. Otherwise assume // the MDL contains the correct length. If there is no MDL then the // transfer length must be zero. // if (currentIrpStack->MajorFunction == IRP_MJ_READ || currentIrpStack->MajorFunction == IRP_MJ_WRITE) { transferByteCount = currentIrpStack->Parameters.Read.Length; } else if (Irp->MdlAddress != NULL) { // // Note this assumes that only read and write requests are spilt and // other request do not need to be. If the data buffer address in // the MDL and the SRB don't match then transfer length is most // likely incorrect. // ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress)); transferByteCount = Irp->MdlAddress->ByteCount; } else { transferByteCount = 0; } // // this is a safety net. this should not normally be hit, since we are // not guaranteed to be an fdoExtension // ASSERT(!TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); // // Reset byte count of transfer in SRB Extension. // Srb->DataTransferLength = transferByteCount; // // Zero SRB statuses. // Srb->SrbStatus = Srb->ScsiStatus = 0; // // Set the no disconnect flag, disable synchronous data transfers and // disable tagged queuing. This fixes some errors. // NOTE: Cannot clear these flags, just add to them // SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); CLEAR_FLAG(Srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); Srb->QueueTag = SP_UNTAGGED; // // Set up major SCSI function. // nextIrpStack->MajorFunction = IRP_MJ_SCSI; // // Save SRB address in next stack for port driver. // nextIrpStack->Parameters.Scsi.Srb = Srb; IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); { LARGE_INTEGER retry100ns; retry100ns.QuadPart = RetryInterval; // seconds retry100ns.QuadPart *= (LONGLONG)1000 * 1000 * 10; ClassRetryRequest(DeviceObject, Irp, retry100ns); } return; } // end RetryRequest()
NDIS_STATUS LpxReceiveIndication ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookAheadBufferSize, IN UINT PacketSize ) /*++ Routine Description: This routine receives control from the physical provider as an indication that a frame has been received on the physical link. This routine is time critical, so we only allocate a buffer and copy the packet into it. We also perform minimal validation on this packet. It gets queued to the device context to allow for processing later. Arguments: BindingContext - The Adapter Binding specified at initialization time. ReceiveContext - A magic cookie for the MAC. HeaderBuffer - pointer to a buffer containing the packet header. HeaderBufferSize - the size of the header. LookaheadBuffer - pointer to a buffer containing the negotiated minimum amount of buffer I get to look at (not including header). LookaheadBufferSize - the size of the above. May be less than asked for, if that's all there is. PacketSize - Overall size of the packet (not including header). Return Value: NDIS_STATUS - status of operation, one of: NDIS_STATUS_SUCCESS if packet accepted, NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol, NDIS_any_other_thing if I understand, but can't handle. --*/ { PDEVICE_CONTEXT deviceContext; USHORT protocol; PNDIS_PACKET packet; NDIS_STATUS status; UINT bytesTransfered = 0; UINT startOffset = 0; DebugPrint( 4, ("LpxReceiveIndication, Entered\n") ); deviceContext = (PDEVICE_CONTEXT)ProtocolBindingContext; // // validation // if (HeaderBufferSize != ETHERNET_HEADER_LENGTH) { DebugPrint( 4, ("HeaderBufferSize = %x\n", HeaderBufferSize) ); return NDIS_STATUS_NOT_RECOGNIZED; } RtlCopyMemory( (PUCHAR)&protocol, &((PUCHAR)HeaderBuffer)[12], sizeof(USHORT) ); // // Discard 802.2 LLC SNAP field. // // if Ether Type less than 0x0600 ( 1536 ) // if (NTOHS(protocol) < 0x0600 && protocol != HTONS(0x0060) && // LOOP: Ethernet Loopback protocol != HTONS(0x0200) && // PUP : Xerox PUP packet protocol != HTONS(0x0201)) { // PUPAP: Xerox PUP address trans packet #if __LPX__ NdisCopyLookaheadData( (PUCHAR)&protocol, &((PUCHAR)LookAheadBuffer)[LENGTH_8022LLCSNAP - 2], sizeof(USHORT), deviceContext->MacOptions ); #endif PacketSize -= LENGTH_8022LLCSNAP; LookAheadBufferSize -= LENGTH_8022LLCSNAP; startOffset = LENGTH_8022LLCSNAP; } if (protocol != HTONS(ETH_P_LPX)) { DebugPrint( 4, ("Type = %x\n", protocol) ); return NDIS_STATUS_NOT_RECOGNIZED; } // // Check to see if the device context is initialized. // //ACQUIRE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); if (!FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_START) || FlagOn(deviceContext->LpxFlags, LPX_DEVICE_CONTEXT_STOP)) { //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); DebugPrint( 4,("Device is not initialized. Drop packet\n") ); return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( deviceContext->NdisBindingHandle ); //RELEASE_DPC_SPIN_LOCK( &deviceContext->SpinLock ); // // DROP PACKET for DEBUGGING!!!! // #if 1 //DBG // Enabled for testing if (PacketRxDropRate) { PacketRxCountForDrop++; if ((PacketRxCountForDrop % 1000) <= PacketRxDropRate) { PLPX_HEADER lpxHeader = (PLPX_HEADER)LookAheadBuffer; #if 0 if ((PacketRxCountForDrop % (PacketRxDropRate*20)) == 0) DebugPrint( 1, ("[Drop(%x,%x,%x))]\n", NTOHS(lpxHeader->Lsctl), NTOHS(lpxHeader->Sequence), NTOHS(lpxHeader->AckSequence)) ); #endif DebugPrint( 1, ("D") ); return NDIS_STATUS_NOT_RECOGNIZED; } } #endif ASSERT( startOffset == 0 ); DebugPrint( 4, ("LpxReceiveIndication, PacketSize = %d, LookAheadBufferSize = %d, LPX_HEADER size = %d\n", PacketSize, LookAheadBufferSize, sizeof(LPX_HEADER)) ); if (LookAheadBufferSize >= sizeof(LPX_HEADER)) { PNDIS_BUFFER firstBuffer; PUCHAR packetData; PLPX_HEADER lpxHeader; USHORT lpxHeaderSize; lpxHeader = (PLPX_HEADER)((PBYTE)LookAheadBuffer + startOffset); lpxHeaderSize = sizeof(LPX_HEADER); #if __LPX_OPTION_ADDRESSS__ if (FlagOn(lpxHeader->Option, LPX_OPTION_SOURCE_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } if (FlagOn(lpxHeader->Option, LPX_OPTION_DESTINATION_ADDRESS)) { lpxHeaderSize += ETHERNET_ADDRESS_LENGTH; } #endif if (NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) == lpxHeaderSize) { status = RcvPacketAlloc( deviceContext, 0, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = 0; RESERVED(packet)->PacketRawDataOffset = 0; LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else if (LookAheadBufferSize >= NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK)) { status = RcvPacketAlloc( deviceContext, NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize, &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK) - lpxHeaderSize; RESERVED(packet)->PacketRawDataOffset = 0; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); packetData = MmGetMdlVirtualAddress( firstBuffer ); NdisCopyLookaheadData( packetData, (PBYTE)LookAheadBuffer + startOffset + lpxHeaderSize, RESERVED(packet)->PacketRawDataLength, deviceContext->MacOptions ); LpxTransferDataComplete( deviceContext, packet, NDIS_STATUS_SUCCESS, LookAheadBufferSize ); return NDIS_STATUS_SUCCESS; } } else { status = RcvPacketAlloc( deviceContext, startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK), &packet ); if (status == STATUS_SUCCESS) { NdisCopyLookaheadData( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH, deviceContext->MacOptions ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RtlCopyMemory( &RESERVED(packet)->LpxHeader, lpxHeader, lpxHeaderSize ); RESERVED(packet)->HeaderCopied = TRUE; RESERVED(packet)->PacketRawDataLength = startOffset + NTOHS(lpxHeader->PacketSize & ~LPX_TYPE_MASK); RESERVED(packet)->PacketRawDataOffset = startOffset + lpxHeaderSize; } } } else { PLPX_HEADER lpxHeader; PNDIS_BUFFER firstBuffer; PUCHAR packetData; UINT packetDataLength; ASSERT( FALSE ); status = RcvPacketAlloc( deviceContext, PacketSize, &packet ); if (status == STATUS_SUCCESS) { RtlCopyMemory( &RESERVED(packet)->EthernetHeader, HeaderBuffer, ETHERNET_HEADER_LENGTH ); RESERVED(packet)->EthernetHeader.Type = protocol; RESERVED(packet)->RecvTime = CurrentTime(); RESERVED(packet)->PacketRawDataLength = PacketSize; RESERVED(packet)->PacketRawDataOffset = startOffset; NdisQueryPacket( packet, NULL, NULL, &firstBuffer, NULL ); NdisQueryBufferSafe( firstBuffer, &packetData, &packetDataLength, HighPagePriority ); lpxHeader = (PLPX_HEADER)(packetData + RESERVED(packet)->PacketRawDataOffset); RtlZeroMemory( lpxHeader, sizeof(LPX_HEADER) ); RESERVED(packet)->HeaderCopied = FALSE; } } if (status != NDIS_STATUS_SUCCESS) { return NDIS_STATUS_NOT_RECOGNIZED; } ASSERT( packet->Private.NdisPacketFlags & fPACKET_ALLOCATED_BY_NDIS ); if (deviceContext->NdisBindingHandle) { //ASSERT( FALSE ); NdisTransferData( &status, deviceContext->NdisBindingHandle, MacReceiveContext, 0, //RESERVED(packet)->PacketRawDataOffset, RESERVED(packet)->PacketRawDataLength, packet, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { LPX_ASSERT( FALSE ); status = NDIS_STATUS_SUCCESS; } else if (status == NDIS_STATUS_SUCCESS) { LpxTransferDataComplete( deviceContext, packet, status, bytesTransfered ); } else { LPX_ASSERT( FALSE ); DebugPrint( 1, ("NdisTransferData() failed. STATUS=%08lx\n", status) ); } } else { status = NDIS_STATUS_NOT_RECOGNIZED; DebugPrint( 1, ("Invalid device status. STATUS=%08lx\n", status) ); } return status; }
/*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType) { PMDL newMdl = NULL; PMDL requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; WDF_REQUEST_SEND_OPTIONS sendOptions; PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n")); // First validate input parameters. deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize)); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType)); status = STATUS_INVALID_PARAMETER; goto Exit; } // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType)); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if(RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; PSDrv_DbgPrint(3, ("This is a read operation...\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; PSDrv_DbgPrint(3, ("This is a write operation...\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage. if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // Map the portion of user-buffer described by an mdl to another mdl IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Set REQUEST_CONTEXT parameters. rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; // Set the timeout if (fileContext->nTimeOut != 0) { WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut)); PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut)); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } else { if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n")); return; }
NDIS_STATUS PacketReceiveIndicate ( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize ) { POPEN_INSTANCE open; PIO_STACK_LOCATION irpSp; PIRP irp; PLIST_ENTRY packetListEntry; PNDIS_PACKET pPacket; ULONG sizeToTransfer; NDIS_STATUS status; UINT bytesTransfered = 0; ULONG bufferLength; PPACKET_RESERVED reserved; PMDL pMdl; // DebugPrint(("ReceiveIndicate\n")); open= (POPEN_INSTANCE)ProtocolBindingContext; if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) { return NDIS_STATUS_SUCCESS; } // See if there are any pending read that we can satisfy packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock ); if (packetListEntry == NULL) { // DebugPrint(("No pending read, dropping packets\n")); return NDIS_STATUS_NOT_ACCEPTED; } reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement); pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved); irp = RESERVED(pPacket)->Irp; irpSp = IoGetCurrentIrpStackLocation(irp); // We don't have to worry about the situation where the IRP is cancelled // after we remove it from the queue and before we reset the cancel // routine because the cancel routine has been coded to cancel an IRP // only if it's in the queue. IoSetCancelRoutine(irp, NULL); bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH; sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength; NdisMoveMappedMemory( MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority), HeaderBuffer, HeaderBufferSize ); pMdl=IoAllocateMdl( MmGetMdlVirtualAddress(irp->MdlAddress), MmGetMdlByteCount(irp->MdlAddress), FALSE, FALSE, NULL ); if (pMdl == NULL) { // DebugPrint(("Packet: Read-Failed to allocate Mdl\n")); status = NDIS_STATUS_RESOURCES; goto ERROR; } IoBuildPartialMdl( irp->MdlAddress, pMdl, ((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH, 0 ); pMdl->Next = NULL; RESERVED(pPacket)->pMdl=pMdl; NdisChainBufferAtFront(pPacket,pMdl); NdisTransferData( &status, open->AdapterHandle, MacReceiveContext, 0, sizeToTransfer, pPacket, &bytesTransfered ); if (status == NDIS_STATUS_PENDING) { return NDIS_STATUS_SUCCESS; } ERROR: PacketTransferDataComplete( open, pPacket, status, bytesTransfered ); return NDIS_STATUS_SUCCESS; }
/* * BUGBUG: Need to provide the miniport an IOCTL that causes this to be called * when the transaction is really done. * IOCTL_VIDEO_DMA_COMPLETED * BUGBUG: need to provide a mechanism to miniport so it can determine when * to free the map registers, unlock the pages, etc. * */ VOID pVideoProcessCompletedRequest( PDEVICE_EXTENSION pDE, PDMA_PARAMETERS pIoVrb ) { PIRP pIrp = pIoVrb->pIrp; PIO_STACK_LOCATION pIrpStack = IoGetNextIrpStackLocation(pIrp); PPUBLIC_VIDEO_REQUEST_BLOCK pPVRB = pIoVrb->pVideoRequestBlock; LONG interlockResult; // // Map the buffers if indicated and flush. // if ((pDE->bMapBuffers) && (pIrp->MdlAddress)) { pPVRB->vrp.InputBuffer = (PCHAR)MmGetMdlVirtualAddress(pIrp->MdlAddress) + ((PCHAR)pPVRB->vrp.InputBuffer - pIoVrb->DataOffset); KeFlushIoBuffers(pIrp->MdlAddress, TRUE, FALSE); } // // Flush the adapter buffers if necessary. // if (pIoVrb->pMapRegisterBase) { // // Since we are a master call I/O flush adapter buffers with a NULL // adapter. // IoFlushAdapterBuffers(NULL, pIrp->MdlAddress, pIoVrb->pMapRegisterBase, pPVRB->vrp.InputBuffer, pPVRB->vrp.InputBufferLength, FALSE); // // Free the map registers. // IoFreeMapRegisters(pDE->DmaAdapterObject, pIoVrb->pMapRegisterBase, pIoVrb->NumberOfMapRegisters); // // Clear the MapRegisterBase. // pIoVrb->pMapRegisterBase = NULL; } // // If miniport wants so unlock memory, do so here. At this point release // the DMA_PARAMETERs. // if (pPVRB->bUnlock) { // // Unlock // MmUnlockPages(pIrp->MdlAddress); // // Free Mdls // IoFreeMdl(pIrp->MdlAddress); pIrp->MdlAddress = NULL; // // Free Scattergather list if indicated and clear flag. // if (pPVRB->VRBFlags & VRB_FLAGS_SGLIST_FROM_POOL) { ExFreePool(pIoVrb->pScatterGather); pPVRB->VRBFlags & ~VRB_FLAGS_SGLIST_FROM_POOL; } pVideoPortReleaseDmaParameters(pDE, pIoVrb); } // // Move bytes transferred into Io structure. // pIrp->IoStatus.Information = pPVRB->vrp.InputBufferLength; // // BUGBUG: Check for pending io request??? // }
NDIS_STATUS NTAPI ProSend( IN NDIS_HANDLE MacBindingHandle, IN PNDIS_PACKET Packet) /* * FUNCTION: Forwards a request to send a packet to an NDIS miniport * ARGUMENTS: * MacBindingHandle = Adapter binding handle * Packet = Pointer to NDIS packet descriptor * RETURNS: * NDIS_STATUS_SUCCESS if the packet was successfully sent * NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES */ { PADAPTER_BINDING AdapterBinding; PLOGICAL_ADAPTER Adapter; PNDIS_BUFFER NdisBuffer; PDMA_CONTEXT Context; NDIS_STATUS NdisStatus; UINT PacketLength; KIRQL OldIrql; NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); ASSERT(MacBindingHandle); AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle); ASSERT(AdapterBinding); Adapter = AdapterBinding->Adapter; ASSERT(Adapter); /* if the following is not true, KeRaiseIrql() below will break */ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* XXX what is this crazy black magic? */ Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle; /* * Test the packet to see if it is a MAC loopback. * * We may have to loop this packet if miniport cannot. * If dest MAC address of packet == MAC address of adapter, * this is a loopback frame. */ if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) && MiniAdapterHasAddress(Adapter, Packet)) { #if WORKER_TEST MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE); return NDIS_STATUS_PENDING; #else return ProIndicatePacket(Adapter, Packet); #endif } else { if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0) { NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n")); NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &PacketLength); Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT)); if (!Context) { NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); return NDIS_STATUS_RESOURCES; } Context->Adapter = Adapter; Context->Packet = Packet; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeFlushIoBuffers(NdisBuffer, FALSE, TRUE); NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList( Adapter->NdisMiniportBlock.SystemAdapterObject, Adapter->NdisMiniportBlock.PhysicalDeviceObject, NdisBuffer, MmGetMdlVirtualAddress(NdisBuffer), PacketLength, ScatterGatherSendPacket, Context, TRUE); KeLowerIrql(OldIrql); if (!NT_SUCCESS(NdisStatus)) { NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus)); return NdisStatus; } return NDIS_STATUS_PENDING; } return proSendPacketToMiniport(Adapter, Packet); } }
BOOLEAN VideoPortDoDma( IN PVOID HwDeviceExtension, IN PVIDEO_REQUEST_PACKET pVrp ) { PDEVICE_EXTENSION deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1; PPUBLIC_VIDEO_REQUEST_BLOCK pPVRB; PDMA_PARAMETERS pIoVrb; PIRP pIrp; GET_PVRB_FROM_PVRP(pPVRB, pVrp); pIoVrb = pVideoPortGetDmaParameters(deviceExtension, pPVRB); if (!pIoVrb) { // // Can't get DmaParameter storage. set flag and return // deviceExtension->VRBFlags |= INSUFFICIENT_DMA_RESOURCES; return FALSE; } pIrp = pPVRB->pIrp; deviceExtension->MapDmaParameters = pIoVrb; // // Get Mdl for user buffer. // if (!pPVRB || !IoAllocateMdl(pPVRB->vrp.InputBuffer, pPVRB->vrp.InputBufferLength, FALSE, FALSE, pIrp)) { VideoPortDebugPrint(0, "VideoPortIoStartRequest: Can't allocate Mdl\n"); pPVRB->vrp.StatusBlock->Status = VRB_STATUS_INVALID_REQUEST; VideoPortNotification(RequestComplete, deviceExtension, pIoVrb); VideoPortNotification(NextRequest, deviceExtension); // // Queue a DPC to process the work that was just indicated. // IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL); return FALSE; } // // Save the Mdl virtual address // pIoVrb->DataOffset = MmGetMdlVirtualAddress(pIrp->MdlAddress); // // Determine if the device needs mapped memory. // if (deviceExtension->bMapBuffers) { if (pIrp->MdlAddress) { pIoVrb->DataOffset = MmGetSystemAddressForMdl(pIrp->MdlAddress); pPVRB->vrp.InputBuffer = ((PUCHAR)pIoVrb->DataOffset) + (ULONG)(((PUCHAR)pPVRB->vrp.InputBuffer) - ((PUCHAR)MmGetMdlVirtualAddress(pIrp->MdlAddress))); } } if (deviceExtension->DmaAdapterObject) { // // If the buffer is not mapped then the I/O buffer must be flushed // to aid in cache coherency. // KeFlushIoBuffers(pIrp->MdlAddress, TRUE, TRUE); } // // Determine if this adapter needs map registers // if (deviceExtension->bMasterWithAdapter) { // // Calculate the number of map registers needed for this transfer. // Note that this may be recalculated if the miniport really wants // to do DMA // pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( pPVRB->vrp.InputBuffer, pPVRB->vrp.InputBufferLength ); } // // The miniport may have requested too big of a buffer, so iteratively // chop it in half until we find one we can do. This changes the // vrp.InputBufferLength, which the miniport must check to see how much // is actually sent and queue up the remainder. // while (pIoVrb->NumberOfMapRegisters > deviceExtension->Capabilities.MaximumPhysicalPages) { pPVRB->vrp.InputBufferLength /= 2; pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( pPVRB->vrp.InputBuffer, pPVRB->vrp.InputBufferLength ); } // // Allocate the adapter channel with sufficient map registers // for the transfer. // IoAllocateAdapterChannel( deviceExtension->DmaAdapterObject, // AdapterObject deviceExtension->DeviceObject, // DeviceObject pIoVrb->NumberOfMapRegisters, // NumberOfMapRegisters pVideoPortBuildScatterGather, // ExecutionRoutine (Must return DeallocateObjectKeepRegisters) pIoVrb); // Context // // The execution routine called via IoAllocateChannel will do the // rest of the work so just return. // return TRUE; }
NTSTATUS NTAPI WdmAudReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS Status; PWDMAUD_DEVICE_INFO DeviceInfo; PFILE_OBJECT FileObject; PIO_STACK_LOCATION IoStack; ULONG Length; PMDL Mdl; BOOLEAN Read = TRUE; PWDMAUD_COMPLETION_CONTEXT Context; /* allocate completion context */ Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT)); if (!Context) { /* not enough memory */ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); /* done */ return STATUS_INSUFFICIENT_RESOURCES; } /* get current irp stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */ Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); /* sanity check */ ASSERT(Irp->UserBuffer); /* get the length of the request length */ Length = IoStack->Parameters.Write.Length; /* store outputbuffer length */ IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length; /* setup context */ Context->Length = Length; Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM); Context->Mdl = Irp->MdlAddress; /* store mdl address */ Mdl = Irp->MdlAddress; /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */ Irp->MdlAddress = NULL; if (IoStack->MajorFunction == IRP_MJ_WRITE) { /* probe the write stream irp */ Read = FALSE; Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); } else { /* probe the read stream irp */ Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length); } if (!NT_SUCCESS(Status)) { DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel); Irp->MdlAddress = Mdl; FreeItem(Context); return SetIrpIoStatus(Irp, Status, 0); } /* get device info */ DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer; ASSERT(DeviceInfo); /* now get sysaudio file object */ Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice); Irp->MdlAddress = Mdl; FreeItem(Context); return SetIrpIoStatus(Irp, Status, 0); } /* store file object whose reference is released in the completion callback */ Context->FileObject = FileObject; /* skip current irp stack location */ IoSkipCurrentIrpStackLocation(Irp); /* get next stack location */ IoStack = IoGetNextIrpStackLocation(Irp); /* prepare stack location */ IoStack->FileObject = FileObject; IoStack->Parameters.Write.Length = Length; IoStack->MajorFunction = IRP_MJ_WRITE; IoStack->Parameters.DeviceIoControl.IoControlCode = (Read ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM); IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE); /* mark irp as pending */ // IoMarkIrpPending(Irp); /* call the driver */ Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp); return Status; }
static VOID XenUsb_EvtIoInternalDeviceControl_PVURB( WDFQUEUE queue, WDFREQUEST request, size_t output_buffer_length, size_t input_buffer_length, ULONG io_control_code) { NTSTATUS status; WDFDEVICE device = WdfIoQueueGetDevice(queue); PXENUSB_DEVICE_DATA xudd = GetXudd(device); WDF_REQUEST_PARAMETERS wrp; pvurb_t *pvurb; partial_pvurb_t *partial_pvurb; KIRQL old_irql; UNREFERENCED_PARAMETER(input_buffer_length); UNREFERENCED_PARAMETER(output_buffer_length); UNREFERENCED_PARAMETER(io_control_code); FUNCTION_ENTER(); ASSERT(io_control_code == IOCTL_INTERNAL_PVUSB_SUBMIT_URB); WDF_REQUEST_PARAMETERS_INIT(&wrp); WdfRequestGetParameters(request, &wrp); pvurb = (pvurb_t *)wrp.Parameters.Others.Arg1; ASSERT(pvurb); RtlZeroMemory(&pvurb->rsp, sizeof(pvurb->rsp)); pvurb->status = STATUS_SUCCESS; pvurb->request = request; pvurb->ref = 1; pvurb->total_length = 0; partial_pvurb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*partial_pvurb), XENUSB_POOL_TAG); /* todo - use lookaside */ if (!partial_pvurb) { WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); FUNCTION_EXIT(); return; } KeAcquireSpinLock(&xudd->urb_ring_lock, &old_irql); status = WdfRequestMarkCancelableEx(request, XenUsb_EvtRequestCancelPvUrb); if (!NT_SUCCESS(status)) { KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql); FUNCTION_MSG("WdfRequestMarkCancelableEx returned %08x\n", status); WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); FUNCTION_EXIT(); return; } partial_pvurb->req = pvurb->req; partial_pvurb->mdl = pvurb->mdl; /* 1:1 right now, but may need to split up large pvurb into smaller partial_pvurb's */ partial_pvurb->pvurb = pvurb; partial_pvurb->other_partial_pvurb = NULL; partial_pvurb->on_ring = FALSE; if (!partial_pvurb->mdl) { partial_pvurb->req.nr_buffer_segs = 0; partial_pvurb->req.buffer_length = 0; } else { ULONG remaining = MmGetMdlByteCount(partial_pvurb->mdl); USHORT offset = (USHORT)MmGetMdlByteOffset(partial_pvurb->mdl); int i; partial_pvurb->req.buffer_length = (USHORT)MmGetMdlByteCount(partial_pvurb->mdl); partial_pvurb->req.nr_buffer_segs = (USHORT)ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(partial_pvurb->mdl), MmGetMdlByteCount(partial_pvurb->mdl)); for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) { partial_pvurb->req.seg[i].gref = XnGrantAccess(xudd->handle, (ULONG)MmGetMdlPfnArray(partial_pvurb->mdl)[i], FALSE, INVALID_GRANT_REF, (ULONG)'XUSB'); partial_pvurb->req.seg[i].offset = (USHORT)offset; partial_pvurb->req.seg[i].length = (USHORT)min((USHORT)remaining, (USHORT)PAGE_SIZE - offset); offset = 0; remaining -= partial_pvurb->req.seg[i].length; FUNCTION_MSG("seg = %d\n", i); FUNCTION_MSG(" gref = %d\n", partial_pvurb->req.seg[i].gref); FUNCTION_MSG(" offset = %d\n", partial_pvurb->req.seg[i].offset); FUNCTION_MSG(" length = %d\n", partial_pvurb->req.seg[i].length); } FUNCTION_MSG("buffer_length = %d\n", partial_pvurb->req.buffer_length); FUNCTION_MSG("nr_buffer_segs = %d\n", partial_pvurb->req.nr_buffer_segs); } InsertTailList(&xudd->partial_pvurb_queue, &partial_pvurb->entry); PutRequestsOnRing(xudd); KeReleaseSpinLock(&xudd->urb_ring_lock, old_irql); FUNCTION_EXIT(); }
VOID HalpCopyBufferMap( IN PMDL Mdl, IN PTRANSLATION_ENTRY TranslationEntry, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice ) /*++ Routine Description: This routine copies the speicific data between the user's buffer and the map register buffer. First a the user buffer is mapped if necessary, then the data is copied. Finally the user buffer will be unmapped if neccessary. Arguments: Mdl - Pointer to the MDL that describes the pages of memory that are being read or written. TranslationEntry - The address of the base map register that has been allocated to the device driver for use in mapping the transfer. CurrentVa - Current virtual address in the buffer described by the MDL that the transfer is being done to or from. Length - The length of the transfer. This determines the number of map registers that need to be written to map the transfer. WriteToDevice - Boolean value that indicates whether this is a write to the device from memory (TRUE), or vice versa. Return Value: None. --*/ { PCCHAR bufferAddress; PCCHAR mapAddress; // // Get the system address of the MDL. // bufferAddress = MmGetSystemAddressForMdl(Mdl); // // Calculate the actual start of the buffer based on the system VA and // the current VA. // bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl); mapAddress = (PCCHAR) TranslationEntry->VirtualAddress + BYTE_OFFSET(CurrentVa); // // Copy the data between the user buffer and map buffer // if (WriteToDevice) { RtlMoveMemory( mapAddress, bufferAddress, Length); } else { RtlMoveMemory(bufferAddress, mapAddress, Length); } }
VOID ReadWriteBulkEndPoints( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ ULONG Length, _In_ WDF_REQUEST_TYPE RequestType ) /*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of maximum transfer size. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ { PMDL newMdl=NULL, requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; ULONG maxTransferSize; PPIPE_CONTEXT pipeContext; UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); // // First validate input parameters. // deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Get the pipe associate with this request. // fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; pipeContext = GetPipeContext(pipe); WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if ((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { UsbSamp_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n")); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if (RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; UsbSamp_DbgPrint(3, ("Read operation\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if (!NT_SUCCESS(status)){ UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; UsbSamp_DbgPrint(3, ("Write operation\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // // The transfer request is for totalLength. // We can perform a max of maxTransfersize in each stage. // maxTransferSize = GetMaxTransferSize(pipe, deviceContext); if (totalLength > maxTransferSize) { stageLength = maxTransferSize; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { UsbSamp_DbgPrint(1, ("Failed to alloc mem for mdl\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // // map the portion of user-buffer described by an mdl to another mdl // IoBuildPartialMdl(requestMdl, newMdl, (PVOID) virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfUsbTargetDeviceCreateUrb(deviceContext->WdfUsbTargetDevice, &objectAttribs, &urbMemory, &urb); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateUrb failed %x\n", status)); goto Exit; } #if (NTDDI_VERSION >= NTDDI_WIN8) if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && pipeContext->StreamConfigured == TRUE) { // // For super speed bulk pipe with streams, we specify one of its associated // usbd pipe handles to format an URB for sending or receiving data. // The usbd pipe handle is returned by the HCD via sucessful open-streams request // usbdPipeHandle = GetStreamPipeHandleFromBulkPipe(pipe); } else { usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); } #else usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); #endif UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); if (!NT_SUCCESS(status)) { UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); // // set REQUEST_CONTEXT parameters. // rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); NT_ASSERT(!NT_SUCCESS(status)); } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); return; }
//Handle SCSI WRITE(10) requests NTSTATUS ScsiFilterWrite(PIRP Irp, PIO_STACK_LOCATION StackLocation, PSCSI_REQUEST_BLOCK Srb, PCDB Cdb) { ULONG LBA; USHORT TransferLength; ULONG BufferOffset; PVOID SystemBuffer; KIRQL OldIrql; NTSTATUS status; //Extract logical block address and transfer length from Cdb and fix endian LBA = swap_endian<ULONG>(*(ULONG *)&Cdb->CDB10.LogicalBlockByte0); TransferLength = swap_endian<USHORT>(*(USHORT *)&Cdb->CDB10.TransferBlocksMsb); //Logical block address must be 0 for MBR if(Srb->DataTransferLength >= 512 && LBA == 0) { DbgPrint("{ScsiFilter} Intercepted MBR write request (LBA: %X, Size: %X)\n", LBA, TransferLength); //Calculate the offset into the MDL address that ScsiRequestBlock->DataBuffer points to BufferOffset = (ULONG)Srb->DataBuffer - (ULONG)MmGetMdlVirtualAddress(Irp->MdlAddress); SystemBuffer = (PVOID)((ULONG)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + BufferOffset); if(SystemBuffer) { //Write to the fake MBR (spin-lock is probably overkill here) KeAcquireSpinLock(&FakeMbrWriteLock, &OldIrql); memcpy(FakeMbr, SystemBuffer, 512); KeReleaseSpinLock(&FakeMbrWriteLock, OldIrql); //If the request was only trying to write the MBR, we can just complete the request ourselves if(Srb->DataTransferLength == 512) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = NULL; Srb->SrbStatus = SRB_STATUS_SUCCESS; Srb->ScsiStatus = SCSISTAT_GOOD; //Complete IRP without calling real Miniport IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } //If the request was trying to read the MBR and more, we need to pass the rest of the request on else { //Edit request to only write the sector(s) after the MBR *(ULONG*)&Srb->DataBuffer += 512; Srb->DataTransferLength -= 512; *(USHORT *)&Cdb->CDB10.TransferBlocksMsb = swap_endian<USHORT>(TransferLength - 1); *(ULONG *)&Cdb->CDB10.LogicalBlockByte0 = swap_endian<ULONG >(LBA + 1); //Call original Miniport to process request status = OriginalScsi(TargetDevice, Irp); //A Driver may need the original DataBuffer *(ULONG*)&Srb->DataBuffer -= 512; //If request is successful, TransferLength is the bytes read from disk //We add 512 bytes so it looks like the MBR was read from disk as well if(NT_SUCCESS(status)) Srb->DataTransferLength += 512; return status; } } } return OriginalScsi(TargetDevice, Irp); }
__drv_when(Length == 0, __drv_reportError(Length cannot be zero)) size_t Length ) { // // Stub this out by calling the regular initialize method. Eventually // the regular initialize method will call this instead. // return WDFEXPORT(WdfDmaTransactionInitialize)( DriverGlobals, DmaTransaction, EvtProgramDmaFunction, DmaDirection, Mdl, (PVOID) (((ULONG_PTR) MmGetMdlVirtualAddress(Mdl)) + Offset), Length ); } _Must_inspect_result_ __drv_maxIRQL(DISPATCH_LEVEL) NTSTATUS WDFEXPORT(WdfDmaTransactionInitialize)( __in PWDF_DRIVER_GLOBALS DriverGlobals, __in WDFDMATRANSACTION DmaTransaction, __in PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, __in
NTSTATUS USBSTOR_SendRequest( IN PDEVICE_OBJECT DeviceObject, IN PIRP OriginalRequest, IN UCHAR CommandLength, IN PUCHAR Command, IN ULONG TransferDataLength, IN PUCHAR TransferData, IN ULONG RetryCount) { PIRP_CONTEXT Context; PPDO_DEVICE_EXTENSION PDODeviceExtension; PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; PUCHAR MdlVirtualAddress; // // first allocate irp context // Context = USBSTOR_AllocateIrpContext(); if (!Context) { // // no memory // return STATUS_INSUFFICIENT_RESOURCES; } // // get PDO device extension // PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; // // now build the cbw // USBSTOR_BuildCBW((ULONG)Context->cbw, TransferDataLength, PDODeviceExtension->LUN, CommandLength, Command, Context->cbw); DPRINT("CBW %p\n", Context->cbw); DumpCBW((PUCHAR)Context->cbw); // // now initialize the urb // UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle, Context->cbw, NULL, sizeof(CBW), USBD_TRANSFER_DIRECTION_OUT, NULL); // // initialize rest of context // Context->Irp = OriginalRequest; Context->TransferData = TransferData; Context->TransferDataLength = TransferDataLength; Context->FDODeviceExtension = FDODeviceExtension; Context->PDODeviceExtension = PDODeviceExtension; Context->RetryCount = RetryCount; // // is there transfer data // if (Context->TransferDataLength) { // // check if the original request already does have an mdl associated // if (OriginalRequest) { if ((OriginalRequest->MdlAddress != NULL) && (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE)) { // // Sanity check that the Mdl does describe the TransferData for read/write // if (CommandLength == UFI_READ_WRITE_CMD_LEN) { MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress); // // is there an offset // if (MdlVirtualAddress != Context->TransferData) { // // lets build an mdl // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // now build the partial mdl // IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength); } } if (!Context->TransferBufferMDL) { // // I/O paging request // Context->TransferBufferMDL = OriginalRequest->MdlAddress; } } else { // // allocate mdl for buffer, buffer must be allocated from NonPagedPool // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // build mdl for nonpaged pool // MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); } } else { // // allocate mdl for buffer, buffer must be allocated from NonPagedPool // Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); if (!Context->TransferBufferMDL) { // // failed to allocate MDL // return STATUS_INSUFFICIENT_RESOURCES; } // // build mdl for nonpaged pool // MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); } } // // now allocate the request // Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) { FreeItem(Context->cbw); FreeItem(Context); return STATUS_INSUFFICIENT_RESOURCES; } if (OriginalRequest) { // // mark orignal irp as pending // IoMarkIrpPending(OriginalRequest); } // // send request // USBSTOR_SendCBW(Context, Irp); // // done // return STATUS_PENDING; }
void * hax_map_user_pages(hax_memdesc_user *memdesc, uint64 uva_offset, uint64 size, hax_kmap_user *kmap) { ULONG base_size; uint64 uva_offset_low, uva_offset_high; uint64 base_uva, start_uva; PMDL pmdl; PVOID kva; if (!memdesc) { hax_error("%s: memdesc == NULL\n", __func__); return NULL; } if (!memdesc->pmdl) { hax_error("%s: memdesc->pmdl == NULL\n", __func__); return NULL; } if (!kmap) { hax_error("%s: kmap == NULL\n", __func__); return NULL; } // Size of the underlying UVA range base_size = MmGetMdlByteCount(memdesc->pmdl); // Align the lower bound of the UVA subrange to 4KB uva_offset_low = uva_offset & pgmask(PG_ORDER_4K); // Align the upper bound of the UVA subrange to 4KB uva_offset_high = (uva_offset + size + PAGE_SIZE_4K - 1) & pgmask(PG_ORDER_4K); if (uva_offset_high > base_size) { hax_error("%s: Invalid UVA subrange: uva_offset=0x%llx, size=0x%llx," " base_size=0x%llx\n", __func__, uva_offset, size, base_size); return NULL; } // Start of the underlying UVA range base_uva = (uint64)MmGetMdlVirtualAddress(memdesc->pmdl); // Start of the UVA subrange start_uva = base_uva + uva_offset_low; // Recalculate the size of the UVA subrange size = uva_offset_high - uva_offset_low; // Create a new MDL for the UVA subrange pmdl = IoAllocateMdl((PVOID)start_uva, size, FALSE, FALSE, NULL); if (!pmdl) { hax_error("%s: Failed to create MDL for UVA subrange: start_uva=0x%llx," " size=0x%llx\n", __func__, start_uva, size); return NULL; } // Associate the new MDL with the existing MDL IoBuildPartialMdl(memdesc->pmdl, pmdl, (PVOID)start_uva, size); kva = MmGetSystemAddressForMdlSafe(pmdl, NormalPagePriority); if (!kva) { hax_error("%s: Failed to create KVA mapping for UVA subrange:" " start_uva=0x%llx, size=0x%llx\n", __func__, start_uva, size); IoFreeMdl(pmdl); return NULL; } kmap->pmdl = pmdl; return kva; }
VOID NICWritePacket( __in PFDO_DATA FdoData, __in PIRP Irp, __in BOOLEAN bFromQueue ) /*++ Routine Description: Do the work to send a packet Assumption: Send spinlock has been acquired Arguments: FdoData Pointer to our FdoData Packet The packet bFromQueue TRUE if it's taken from the send wait queue Return Value: --*/ { PMP_TCB pMpTcb = NULL; ULONG packetLength; PVOID virtualAddress; DebugPrint(TRACE, DBG_WRITE, "--> NICWritePacket, Irp= %p\n", Irp); // // Get the next free TCB and initialize it to represent the // request buffer. // pMpTcb = FdoData->CurrSendTail; ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); // // If the adapter is not ready, fail the request. // if(MP_IS_NOT_READY(FdoData)) { MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_DEVICE_NOT_READY); return; } pMpTcb->FirstBuffer = Irp->MdlAddress; virtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress); pMpTcb->BufferCount = 1; pMpTcb->PacketLength = packetLength = MmGetMdlByteCount(Irp->MdlAddress); pMpTcb->PhysBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, packetLength); pMpTcb->Irp = Irp; MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE); // // Call the send handler, it only needs to deal with the frag list // NICSendPacket(FdoData, pMpTcb, Irp->Tail.Overlay.DriverContext[3]); FdoData->nBusySend++; ASSERT(FdoData->nBusySend <= FdoData->NumTcb); FdoData->CurrSendTail = FdoData->CurrSendTail->Next; DebugPrint(TRACE, DBG_WRITE, "<-- NICWritePacket\n"); return; }
NTSTATUS VfatWriteDiskPartial( IN PVFAT_IRP_CONTEXT IrpContext, IN PLARGE_INTEGER WriteOffset, IN ULONG WriteLength, IN ULONG BufferOffset, IN BOOLEAN Wait) { PIRP Irp; PIO_STACK_LOCATION StackPtr; NTSTATUS Status; PVOID Buffer; DPRINT("VfatWriteDiskPartial(IrpContext %p, WriteOffset %I64x, WriteLength %u, BufferOffset %x, Wait %u)\n", IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait); Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset; again: DPRINT("Building asynchronous FSD Request...\n"); Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE); if (Irp == NULL) { DPRINT("IoAllocateIrp failed\n"); return STATUS_UNSUCCESSFUL; } Irp->UserIosb = NULL; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); StackPtr = IoGetNextIrpStackLocation(Irp); StackPtr->MajorFunction = IRP_MJ_WRITE; StackPtr->MinorFunction = 0; StackPtr->Flags = 0; StackPtr->Control = 0; StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice; StackPtr->FileObject = NULL; StackPtr->CompletionRoutine = NULL; StackPtr->Parameters.Read.Length = WriteLength; StackPtr->Parameters.Read.ByteOffset = *WriteOffset; if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp)) { DPRINT("IoAllocateMdl failed\n"); IoFreeIrp(Irp); return STATUS_UNSUCCESSFUL; } IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength); IoSetCompletionRoutine(Irp, VfatReadWritePartialCompletion, IrpContext, TRUE, TRUE, TRUE); if (Wait) { KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE); IrpContext->RefCount = 1; } else { InterlockedIncrement((PLONG)&IrpContext->RefCount); } DPRINT("Calling IO Driver...\n"); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, Irp); if (Wait && Status == STATUS_PENDING) { KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL); Status = IrpContext->Irp->IoStatus.Status; } if (Status == STATUS_VERIFY_REQUIRED) { PDEVICE_OBJECT DeviceToVerify; DPRINT1("Media change detected!\n"); /* Find the device to verify and reset the thread field to empty value again. */ DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread()); IoSetDeviceToVerify(PsGetCurrentThread(), NULL); Status = IoVerifyVolume(DeviceToVerify, FALSE); if (NT_SUCCESS(Status)) { DPRINT1("Volume verification successful; Reissuing write request\n"); goto again; } } return Status; }
NTSTATUS NICWrite( __in PFDO_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: This routine handles the hardware specific write request. If the device is not ready, fail the request. Otherwise get scatter-gather list for the request buffer and send the list to the hardware for DMA. Arguments: FdoData - Pointer to the device context. Irp - Pointer to the write request. Return Value: NT Status code. --*/ { NTSTATUS returnStatus, status; PVOID virtualAddress; ULONG pageCount = 0, length = 0; PMDL tempMdl, mdl; KIRQL oldIrql; #if defined(DMA_VER2) PVOID sgListBuffer; #endif DebugPrint(TRACE, DBG_WRITE, "--> PciDrvWrite %p\n", Irp); Irp->Tail.Overlay.DriverContext[3] = NULL; Irp->Tail.Overlay.DriverContext[2] = NULL; returnStatus = status = STATUS_SUCCESS; // // Is this adapter ready for sending? // if (MP_SHOULD_FAIL_SEND(FdoData)) { DebugPrint(ERROR, DBG_WRITE, "Device not ready %p\n", Irp); returnStatus = status = STATUS_DEVICE_NOT_READY; goto Error; } tempMdl = mdl = Irp->MdlAddress; // // Check for zero length buffer // if (mdl == NULL || MmGetMdlByteCount(mdl) == 0) { DebugPrint(ERROR, DBG_WRITE, "Zero length buffer %p\n", Irp); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Calculate the total packet length and the number of pages // spanned by all the buffers by walking the MDL chain. // NOTE: If this driver is used in the miniport configuration, it will // not get chained MDLs because the upper filter (NDISEDGE.SYS) // coalesces the fragements to a single contiguous buffer before presenting // the packet to us. // while(tempMdl != NULL) { virtualAddress = MmGetMdlVirtualAddress(tempMdl); length += MmGetMdlByteCount(tempMdl); pageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, length); tempMdl = tempMdl->Next; } if (length < NIC_MIN_PACKET_SIZE) { // // This will never happen in our case because the ndis-edge // pads smaller size packets with zero to make it NIC_MIN_PACKET_SIZE // long. // DebugPrint(ERROR, DBG_WRITE, "Packet size is less than %d\n", NIC_MIN_PACKET_SIZE); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Check to see if the packet spans more than the physical pages // our hardware can handle or the pageCount exceeds the total number of // map registers allocated. If so, we should coalesce the scattered // buffers to fit the limit. We can't really break the transfers and // DMA in small chunks because each packets has to be DMA'ed in one shot. // The code on how to colesce the packet for this hardware is present // in the original E100BEX sample. // if (pageCount > NIC_MAX_PHYS_BUF_COUNT || pageCount > FdoData->AllocatedMapRegisters) { // TODO: Packet needs to be coalesced DebugPrint(ERROR, DBG_WRITE, "Packet needs to be coalesced\n"); status = returnStatus = STATUS_INVALID_DEVICE_REQUEST; goto Error; } // // Build a scatter-gather list of the packet buffer and send the packet. // // If DMA_VER2 is not defined, use GetScatterGatherList. If the driver // is meant to work on XP and above, define DMA_VER2, so that you can // use BuildScatterGatherList. // // Since Build/GetScatterGatherList should be called at DISPATCH_LEVEL // let us raise the IRQL. // KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); // // Let us mark the IRP pending, because NICProcessSGList is an asynchronous // callback and we wouldn't know the status of the IRP. This IRP may either // get completed by the DPC handler after the DMA transfer or may // get queued if we are low on resources. So the safest thing // to do for us here is return STATUS_PENDING irrespective of what happens // to the IRP. // IoMarkIrpPending(Irp); returnStatus = STATUS_PENDING; #if defined(DMA_VER2) sgListBuffer = ExAllocateFromNPagedLookasideList( &FdoData->SGListLookasideList); if (sgListBuffer) { Irp->Tail.Overlay.DriverContext[2] = sgListBuffer; status = FdoData->DmaAdapterObject->DmaOperations->BuildScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE, sgListBuffer, FdoData->ScatterGatherListSize); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "BuildScatterGatherList %x\n", status); ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sgListBuffer); Irp->Tail.Overlay.DriverContext[2] = NULL; } } #else status = FdoData->DmaAdapterObject->DmaOperations->GetScatterGatherList( FdoData->DmaAdapterObject, FdoData->Self, mdl, MmGetMdlVirtualAddress(mdl), length, NICProcessSGList, Irp, TRUE); if (!NT_SUCCESS(status)) { DebugPrint(ERROR, DBG_WRITE, "GetScatterGatherList %x\n", status); } #endif KeLowerIrql(oldIrql); Error: if(!NT_SUCCESS(status)){ // // Our call to get the scatter-gather list failed. We know the // NICProcessSGList is not called for sure in that case. So let us // complete the IRP here with failure status. Since we marked the // IRP pending, we have no choice but to return status-pending // even though we are completing the IRP in the incoming thread // context. // NICCompleteSendRequest(FdoData, Irp, status, 0, FALSE); } DebugPrint(LOUD, DBG_WRITE, "<-- PciDrvWrite %x\n", returnStatus); return returnStatus; }