Esempio n. 1
0
File: dma.c Progetto: GYGit/reactos
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;
}
Esempio n. 2
0
File: io.c Progetto: GYGit/reactos
/*
 * @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);
}
Esempio n. 3
0
File: io.c Progetto: GYGit/reactos
/*
 * @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;
}
Esempio n. 4
0
static VOID
OvsFreeMDLAndData(PMDL mdl)
{
    PVOID data;

    data = MmGetMdlVirtualAddress(mdl);
    NdisFreeMdl(mdl);
    OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
}
Esempio n. 5
0
///////////////////////////////////////////////////////////////////////////////
//
//  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);
}        
Esempio n. 6
0
VOID MemFreePoolMemoryForMdl(
    __in PMDL Mem
)
{
    PVOID PagedMem;

    PagedMem = MmGetMdlVirtualAddress(Mem);

    if (Mem->MdlFlags & MDL_PAGES_LOCKED)
        MmUnlockPages(Mem);

    ExFreePoolWithTag(PagedMem,VFD_POOL_TAG);
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
//---------------------------------------------------------------------------
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;
}
Esempio n. 9
0
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);
			}
		}
	}
}
Esempio n. 11
0
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 );

}
Esempio n. 12
0
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);

}
Esempio n. 13
0
/*++////////////////////////////////////////////////////////////////////////////

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()
Esempio n. 14
0
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;
}
Esempio n. 15
0
/*++
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
/*
 *   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???
    //


}
Esempio n. 18
0
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);
    }
}
Esempio n. 19
0
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;

}
Esempio n. 20
0
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;
}
Esempio n. 21
0
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();
}
Esempio n. 22
0
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);

    }

}
Esempio n. 23
0
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;
}
Esempio n. 24
0
//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
Esempio n. 26
0
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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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;

}
Esempio n. 29
0
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;
}
Esempio n. 30
0
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;
}