📄 usbnicadap.cpp
字号:
// USBNICAdap.cpp: implementation of the USBNICAdapter class.
//====================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060 USA
//
// Copyright (c) 2002 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//====================================================================
#include "USBNICAdap.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
USBNICAdapter::USBNICAdapter() :
KNdisMiniAdapter(),
m_HaltFlag(FALSE),
m_RxIdleEvent(),
m_RxIrpsOutstanding(0),
m_RxIrpList()
{
}
USBNICAdapter::~USBNICAdapter()
{
}
////////////////////////////////////////////////////////////////////
// NDIS callback handlers
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// USBNICAdapter::Initialize
//
// MiniportInitialize is a required function that sets up a NIC (or
// virtual NIC) for network I/O operations, claims all hardware resources
// necessary to the NIC in the registry, and allocates resources the driver
// needs to carry out network I/O operations
//
// Parameters:
// Medium
// Reference to KNdisMedium object that we have to set the medium
// type our NIC supports
// Config
// Reference to KNdisConfig object that we use to query various
// configuration parameters
// IRQL:
// PASSIVE_LEVEL
// Return Mode:
// Synchronous
//
// TODO:
// 1) Select supported medium in Medium object
// 2) Read config parameters if any using Config object
// 3) Allocate h/w resources, pools, etc.
// 4) Register with NDIS using SetAttributes()
// 5) Register Shutdown Handler
// 6) Initialize and enable the NIC.
// NOTE: Be ready to process INTs even before the function exits
//
NDIS_STATUS USBNICAdapter::Initialize
(IN OUT KNdisMedium& Medium, IN KNdisConfig& Config)
{
TRACE("USBNICAdapter::Initialize() Entered\n");
// Select our the Medium:
if (! Medium.Select(USBNIC_MEDIUM_TYPE) )
KNDIS_RETURN_ERROR (NDIS_STATUS_UNSUPPORTED_MEDIA);
// Get network address (if any) from the Registry. If specified
// it will be used instead of burned permanent address:
if (Config.ReadNetworkAddress(m_CurrentAddress) != NDIS_STATUS_SUCCESS)
m_CurrentAddress.Invalidate();
// Read some other config stuff from the Registry, e.g.
// This is simply an example of how to do it. The value of uMode is never used
ULONG uMode;
Config.Read(KNDIS_STRING_CONST("Mode"), &uMode);
// Now let NDIS know about the BUS the NIC is on. Here's where the NDIS/Adapter-instance
// handshake takes place. This should happen *before* allocating the h/w resources:
SetAttributesEx(NdisInterfaceInternal,NDIS_ATTRIBUTE_DESERIALIZE);
// NDIS WDM Specific
//
// Get the physical and "TopOfStack" device objects from NDIS for our WDM
// device. The "TopOfStack" device object is the device to which we will
// submit IRPs to talk to the bus driver for our device. We will use the PDO, along
// with the "TopOfStack" device object to initialize our lower device object using
// a DriverWorks's KPnpLowerDevice-derived class (such as KUsbLowerDevice).
GetDeviceProperty(&m_PhysicalDeviceObject, NULL, &m_TopOfStackDeviceObject);
// Initialize the IRP pools used to service the bus device for Send and Receive
// NOTE: the wizard generates hard-coded values for the pool sizes. You
// might want to use Config to read those values from the Registry, or use
// some other way of allocating and handling IRPs, e.g. not using the pools at all.
m_TxIrpPool.Initialize(m_TopOfStackDeviceObject, USBNIC_TX_IRPPOOL_SIZE);
// Initialize a pool of receive Irps
m_RxIrpPool.Initialize(m_TopOfStackDeviceObject, USBNIC_RX_IRPPOOL_SIZE);
// Initialize a pool of control Irps
m_CntrlIrpPool.Initialize(m_TopOfStackDeviceObject, USBNIC_CNTRL_IRPPOOL_SIZE);
// Initialize the context block heap. We'll need one block per irp:
m_ContextHeap.Initialize(USBNIC_TX_IRPPOOL_SIZE + USBNIC_RX_IRPPOOL_SIZE + USBNIC_CNTRL_IRPPOOL_SIZE);
// Initialize the lower device object. Since NDIS owns this device object, we
// use the form of Initialize() that takes the "TopOfStackDevice" as the device to which
// calls to the lower device should be directed in lieu of actually attaching to the
// device stack.
m_BusDevice.Initialize(m_TopOfStackDeviceObject, m_PhysicalDeviceObject);
// Initialize the interface and pipe object and activate a device configuration.
// NOTE: This is a SAMPLE code =>
// TODO: Modify the code to match your device specification.
m_Interface.Initialize(
m_BusDevice, // KUsbLowerDevice instance
0, // Interface Number
1, // Configuration Value
0 // Initial Interface Alternate Setting
);
m_ReceivePipe.Initialize(m_BusDevice,0x81);
m_SendPipe.Initialize(m_BusDevice,0x2);
// The Interrupt pipe is NOT used
m_InterruptPipe.Initialize(m_BusDevice,0x83,0x08);
// download the firmware image and tickle the device
if ( ConfigureAndProbeDevice() == STATUS_SUCCESS )
{
m_uMacOptions = NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
NDIS_MAC_OPTION_NO_LOOPBACK;
// This sets up the Receive Frame Area including:
// Allocating internal software Receive Frame Descriptors
// Allocating packet and buffer pools
// Initializing and chaining packets, software RFD, buffers
// Maintains list of software RFD descriptors
//
// This driver's requirement is to further initialize the RFD's
// see global template specialization DescriptorInitialize(..) which
// is called for each descriptor
m_pRxArea = new KNdisSystemReceiveArea< USBNICAdapter, WDM_RFD >(
*this,
USBNIC_RX_IRPPOOL_SIZE
);
m_pRxArea->Initialize();
if (m_pRxArea == NULL)
return STATUS_UNSUCCESSFUL;
}
else
return STATUS_UNSUCCESSFUL;
#if BINARY_COMPATIBLE
m_PacketIndicate.Initialize(this);
#endif
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////
// USBNICAdapter::Halt
//
// MiniportHalt is a required function that deallocates resources when
// the NIC is removed and halts the NIC.
//
// Parameters:
// None
// IRQL:
// PASSIVE_LEVEL
// Return Mode:
// Synchronous
//
// NOTE: Miniports has no "unload" for the driver. The Halt() is the last
// function called into a miniport, so everything should be stopped
// and freed right here. The KNDIS framework takes care of destroying
// the adapter object itself, so this member function is merery required
// to undo things done by the Initialize() above - in the inversed order.
//
// Alternatevely, the driver writer can move all the deallocations to the
// destructor: the destructor will be called immediatelly after Halt()
// returns. Our sample follows this practice.
//
VOID USBNICAdapter::Halt(VOID)
{
TRACE("USBNICAdapter::Halt() Entered\n");
m_HaltFlag = TRUE;
// Cancel all of the IRPs in the Rx IRP list.
PWDM_RFD pWdmRfd = m_RxIrpList.Head();
while (pWdmRfd)
{
if(pWdmRfd->m_Irp->CancelRoutine)
IoCancelIrp(pWdmRfd->m_Irp);
pWdmRfd = m_RxIrpList.Next(pWdmRfd);
}
// Wait for all of the Rx IRPs to be completed
LARGE_INTEGER DueTime;
DueTime.QuadPart = -(10000 * 20000); // 20 seconds
if ( m_RxIdleEvent.Wait() == FALSE )
{
ASSERT(!"All Rx IRPs were not accounted for");
}
// Wait for all of the Tx IRPs to be completed
if ( m_TxIrpPool.Wait(1000) == STATUS_TIMEOUT )
{
ASSERT(!"All Tx IRPs were not accounted for");
}
// Wait for all of the Control IRPs to be completed
if ( m_CntrlIrpPool.Wait(1000) == STATUS_TIMEOUT )
{
ASSERT(!"All Control IRPs were not accounted for");
}
m_BusDevice.DeActivateConfiguration();
// Deallocate our receive area.
TRACE("USBNICAdapter::Halt() Deleting Receive Area\n");
delete m_pRxArea;
m_pRxArea = NULL;
}
////////////////////////////////////////////////////////////////////
// USBNICAdapter::Reset
//
// MiniportReset is a required function that issues a hardware reset
// to the NIC and/or resets the driver's software state.
//
// Parameters:
// AddressingReset
// Points to a variable that MiniportReset sets to TRUE if the
// NDIS library should call MiniportSetInformation to restore
// addressing information to the current values.
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// Asynchronous
NDIS_STATUS USBNICAdapter::Reset
(OUT PBOOLEAN AddressingReset)
{
TRACE("USBNICAdapter::Reset() Entered\n");
// TODO: Reset the card
// This may include sumiting an URB via the control pipe
return NDIS_STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////
// USBNICAdapter::Shutdown
//
// MiniportShutdown does nothing more than restore the NIC to its
// initial state (before the miniport's DriverEntry function runs)
//
// Parameters:
// None
// IRQL:
// If MiniportShutdown is called due to a user-initiated system shutdown,
// it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called
// due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL
// and in the context of whatever component raised the error.
// Return Mode:
// Synchronous
VOID USBNICAdapter::Shutdown(VOID)
{
TRACE("USBNICAdapter::Shutdown() Entered\n");
// This may include sumiting an URB via the control pipe
}
///////////////////////////////////////////////////////////////////////
// USBNICAdapter::CompletionTxRoutine
//
// Parameters:
// pIrp - irp being completed
// Context - context passed when the irp had been submitted
// IRQL:
// IRQL DISPATCH_LEVEL
// Returns:
// Usually, STATUS_MORE_PROCESSING_REQUIRED
// Comments:
// Processes asynchronous "send" IRP completions: this is a "HandleInterrupt()"
// thing for NDIS WDM drivers.So, the logic is similar to HandleInterrupt():
// If a pended Tx packet gets completed, return the packet to NDIS.
// The important point is that if the the irps are be recycled back to the pools they
// came from, STATUS_MORE_PROCESSING_REQUIRED should be returned to the system.
NTSTATUS USBNICAdapter::CompletionTxRoutine(PIRP pIrp, USBNICAdapter::IRP_CONTEXT* Context)
{
//TRACE("USBNICAdapter::CompletionTxRoutine() Entered\n");
NTSTATUS status;
KIrp I(pIrp);
status = I.Status();
if(status)
TRACE("IRP TX completion status = %08X\n",ULONG(I.Status()));
if ( status == STATUS_DEVICE_DATA_ERROR )
{
// The device may have been disconnected
// TODO: add code to handle your case
}
// Complete the packet we just processed
SendComplete(Context->type.m_Packet, NDIS_STATUS_SUCCESS);
// Put the Irp to put back to the Transmit Irp pool
m_TxIrpPool.Free(I);
// Destroy the associated Urb
delete Context->m_pUrb;
// Destroy the Context
delete Context;
if ( status != STATUS_DEVICE_DATA_ERROR )
{
// Update the transmit stats
m_GenStats->xmit_ok++;
// If Packets are in the Queue, dequeue them and send them
KNdisPacket QueuedPacket = m_TxQueue.RemoveHead();
while (QueuedPacket.IsValid())
{
TRACE("Sending Queued Tx Packets\n");
// Retry to transmit previously queued packets
NDIS_STATUS status = Transmit(QueuedPacket);
if (status == NDIS_STATUS_RESOURCES)
{
// The packet can not be transmited because of a lack of resources
// so requeue it for later
m_TxQueue.InsertHead(QueuedPacket);
QueuedPacket = NULL;
}
else
{
// Get the next queued packet
QueuedPacket = m_TxQueue.RemoveHead();
}
}
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
////////////////////////////////////////////////////////////////////
// USBNICAdapter::Send
//
// Transfers a protocol-supplied packet over the network
//
// Parameters:
// Packet
// Points to a packet descriptor specifying the data to be transmitted.
// Flags
// Specifies the packet flags, if any, set by the protocol.
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// Asynchronous
// NOTE:
// The return code determines the ownership of the packet and further
// interaction between NDIS and our driver. Specifically,
//
// NDIS_STATUS_SUCCESS - Done with.
// NDIS_STATUS_PENDING - We keep it until further notice.
// NDIS_STATUS_RESOURCES - We didn't have the resouces *now*, so tell NDIS
// please hold it on until further notice.
//
NDIS_STATUS USBNICAdapter::Send(
IN PNDIS_PACKET Packet,
IN UINT Flags
)
{
//TRACE("USBNICAdapter::Send() Entered\n");
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
// declare for convenience
KNdisPacket pkt(Packet);
// Attempt to transmit the packet
status = Transmit(Packet);
if (status == NDIS_STATUS_RESOURCES)
{
// We can never return NDIS_STATUS_RESOURCES to NDIS, and must
// instead queue This packet for the Deserialized Miniport
m_TxQueue.InsertTail(Packet);
TRACE("!!!Queueing packet\n");
}
// Deserialized drivers always return pending.
return NDIS_STATUS_PENDING;
}
///////////////////////////////////////////////////////////////////////
// USBNICAdapter::Transmit
//
// Parameters:
// Packet - Packet supplied by NDIS to transmit
// IRQL:
// <= DISPATCH_LEVEL
// Returns:
// NDIS_STATUS
// Comments:
// This routine compliments the Send() method. It does the necessary
// checking and builds the URB that must be transmitted.
//
NDIS_STATUS USBNICAdapter::Transmit(PNDIS_PACKET Packet)
{
PURB pUrb;
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
//TRACE("USBNICAdapter::Transmit() Entered\n");
// declare for convenience
KNdisPacket pkt(Packet);
KNdisBuffer buf = pkt.QueryFirstBuffer();
// Get an available IRP from the Tx Irp pool
KIrp I = m_TxIrpPool.Allocate();
// Validate the Irp
if (I.IsNull())
{
// Return failure so that send can queue the packet
return NDIS_STATUS_RESOURCES;
}
// Allocate and initialize the context block:
IRP_CONTEXT* Context = new (&m_ContextHeap) IRP_CONTEXT (this, Packet);
// Validate the new context
if(Context == NULL)
{
m_TxIrpPool.Free(I);
// Return failure so that send can queue the packet
return NDIS_STATUS_RESOURCES;
}
// Copy the data to be transmitted to the transfer buffer
// Also calculate the new size
int count = 2;
int Size = 0;
while (buf.IsValid())
{
Size = buf.Length();
PUCHAR Buffer = (PUCHAR)buf.Address();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -