📄 send.c
字号:
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
send.c
Abstract:
USB device driver - Transmit io code
Environment:
kernel mode only
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
Revision History:
--*/
#include <ndis.h>
#include <ntdef.h>
#include <windef.h>
#include "stdarg.h"
#include "stdio.h"
#include "debug.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "common.h"
#include "HPNA_2K.h"
/*****************************************************************************
*
* Function: SendPacket
*
* Synopsis: Send a packet to the USB driver and add the sent irp and io context to
* To the pending send queue; this que is really just needed for possible later error cancellation
*
*
* Arguments: MiniportAdapterContext - pointer to current ir device object
* pPacketToSend - pointer to packet to send
* Flags - any flags set by protocol
Type - CONTEXT_TYPE enum for whether it's a real NDIS_PACKET
or dummy packet for a SetSpeed/Check Media busy call
*
* Returns: NDIS_STATUS_PENDING - This is generally what we should
* return. We will call NdisMSendComplete
* when the USB driver completes the
* send.
* STATUS_UNSUCCESSFUL - The packet was invalid.
*
* Unsupported returns:
* NDIS_STATUS_SUCCESS - We should never return this since
* results will always be pending from
* the USB driver.
* NDIS_STATUS_RESOURCES-This indicates to the protocol that the
* device currently has no resources to complete
* the request. The protocol will resend
* the request when it receives either
* NdisMSendResourcesAvailable or
* NdisMSendComplete from the device.
*
*
*
*****************************************************************************/
NTSTATUS
SendPacket(
IN PUSB_DEVICE Device,
IN PVOID pPacketToSend,
IN UINT Flags,
IN CONTEXT_TYPE Type
)
{
PIRP pIrp;
UINT BytesToWrite =0;
NTSTATUS status;
BOOLEAN fConvertedPacket;
ULONG siz;
PURB urb = NULL;
PDEVICE_OBJECT urbTargetDev;
PIO_STACK_LOCATION nextStack;
PMDL mdl = NULL;
PUSB_CONTEXT pCur, thisContext;
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
thisContext = (PUSB_CONTEXT) GetFreeContext( Device );
if ( NULL == thisContext )
{
status = STATUS_UNSUCCESSFUL;
goto done;
}
thisContext->Packet = pPacketToSend;
thisContext->Type = Type;
urb = thisContext->Urb;
NdisZeroMemory( urb, Device->UrbLen );
if ( CONTEXT_NDIS_PACKET == Type )
{
ASSERT( NULL != pPacketToSend );
//
// Get the packet's entire length
//
NdisQueryPacket( (PNDIS_PACKET)pPacketToSend, NULL, NULL, NULL, &BytesToWrite);
BytesToWrite += USB_PACKET_LENGTH;
thisContext->BufLen = BytesToWrite;
NdisZeroMemory(
thisContext->Buffer,
thisContext->BufLen
);
//
// Convert the packet to an usb frame and copy into our buffer
// and send the irp.
//
fConvertedPacket = NdisToUsbPacket(
Device,
pPacketToSend,
(PUCHAR)thisContext->Buffer,
MAX_PACKET_SIZE+USB_PACKET_LENGTH
);
if (fConvertedPacket == FALSE)
{
status = STATUS_UNSUCCESSFUL;
goto done;
}
}
/* else if ( CONTEXT_SETSPEED == Type )
{
// set up the single byte required to send to device to change speeds
BytesToWrite = 1;
Device->OutBoundHeader = Device->linkSpeedInfo->headerLinkSpeed;
thisContext->Buffer[0] = Device->OutBoundHeader;
}*/
else if ( CONTEXT_TERMINATOR == Type )
{
// We need to Send a zero-lengh USB ( not NDIS) packet as a terminator
// when we have previously sent a packet with a length that is an exact multiple of
// Device->UsbInterface->Pipes[1]->MaximumPacketSize (64)
//
BytesToWrite = 0;
}
thisContext->BufLen = BytesToWrite;
//
// Now that we have created the urb, we will send a
// request to the USB device object.
//
urbTargetDev = Device->pUsbDevObj;
// make an irp sending to usbhub
pIrp = IoAllocateIrp( (CCHAR)(Device->pUsbDevObj->StackSize +1), FALSE );
if ( NULL == pIrp )
{
status = STATUS_UNSUCCESSFUL;
goto done;
}
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
pIrp->IoStatus.Information = 0;
thisContext->Irp = pIrp;
// Build our URB for USBD
urb->UrbBulkOrInterruptTransfer.Hdr.Length =
(USHORT) sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
urb->UrbBulkOrInterruptTransfer.Hdr.Function =
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.PipeHandle =
Device->BulkOutPipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferFlags =
USBD_TRANSFER_DIRECTION_OUT ;
// short packet is not treated as an error.
urb->UrbBulkOrInterruptTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBuffer = thisContext->Buffer;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int) BytesToWrite;
//
// Call the class driver to perform the operation.
nextStack = IoGetNextIrpStackLocation(pIrp);
ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(
pIrp, // irp to use
UsbIoCompleteWrite, // routine to call when irp is done
DEV_TO_CONTEXT(thisContext), // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Call IoCallDriver to send the irp to the usb port.
//
UsbIncIoCount( Device );
status = IoCallDriver( urbTargetDev, pIrp );
//
// The USB driver should always return STATUS_PENDING when
// it receives a write irp
//
ASSERT(status == STATUS_PENDING);
// We need to Send a zero-lengh USB ( not NDIS) packet as a terminator
// when we have previously sent a packet with a length that is an exact multiple of
// ((PUSB_INFO) Device->pUsbInfo)->UsbInterface->Pipes[1]->MaximumPacketSize (64)
// BUGBUG? we'll indicate send complete before sending terminator
if ( BytesToWrite && ( BytesToWrite % 64 == 0))
{ // ((PUSB_INFO) Device->pUsbInfo)->UsbInterface->Pipes[1].MaximumPacketSize ) == 0) {
SendPacket( Device, NULL, 0, CONTEXT_TERMINATOR );
}
done:
return status;
}
/*****************************************************************************
*
* Function: UsbIoCompleteWrite
*
* Synopsis:
*
* Arguments: pUsbDevObj - pointer to the USB device object which
* completed the irp
* pIrp - the irp which was completed by the
* device object
* Context - the context given to IoSetCompletionRoutine
* before calling IoCallDriver on the irp
* The Context is a pointer to the ir device object.
*
* Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
* (IofCompleteRequest) to stop working on the irp.
*
* Algorithm:
* 1a) Indicate to the protocol the status of the write.
* 1b) Return ownership of the packet to the protocol.
*
* 2) If any more packets are queue for sending, send another packet
* to USBD.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -