www.pudn.com > LS120--USB.zip > bulkdev.cpp


// bulkdev.cpp - device class implementation for USB Bulk sample driver 
// 
//============================================================================= 
// 
// Compuware Corporation 
// NuMega Lab 
// 9 Townsend West 
// Nashua, NH 03060  USA 
// 
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved. 
// Unpublished - rights reserved under the Copyright laws of the 
// United States. 
// 
//============================================================================= 
 
#include  
#include  
#include "bulkdev.h" 
#include "bulkioct.h" 
 
extern KTrace Tracer;          // Global driver trace object 
 
//////////////////////////////////////////////////////////////////////////////// 
// Constructor 
// 
// This is the constructor for the Functional Device Object, or FDO. It 
// is derived from KPnpDevice, which builds in automatic dispatching of 
// subfunctions of IRP_MJ_POWER and IRP_MJ_PNP to virtual member functions. 
// 
// Input 
//   Pdo       Physical Device Object - this is a pointer to a system device 
//             object that represents the physical device. 
// 
//   Unit      Unit number - this is a number to append to the device's 
//             base device name to form the Logical Device Object's name 
// 
// The object being constructed contains a data member (m_Usb) of type 
// KPnpLowerDevice. By initializing it, the driver binds the FDO to the 
// PDO and creates an interface to the upper edge of the system USB 
// class driver. 
 
UsbBulkDevice::UsbBulkDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : 
 
    KPnpDevice( 
        Pdo, 
        KUnitizedName(L"UsbBulk", Unit),  
        FILE_DEVICE_UNKNOWN, 
        KUnitizedName(L"UsbBulk", Unit) 
        ) 
{ 
    Tracer << "UsbBulkDevice::UsbBulkDevice() Entry\n"; 
 
    m_Usb.Initialize(this, Pdo);    // initialize the USB interface 
 
    // initialize description of data in pipe (In Bulk) 
    m_Endpoints[0].Initialize(1, 0, 0, 0x81, &m_Interface, &m_Pipe0); 
 
    // initialize description of data out pipe (Out Bulk) 
    m_Endpoints[1].Initialize(1, 0, 0, 0x2, &m_Interface, &m_Pipe1); 
 
    SetLowerDevice(&m_Usb);         // inform PnP code of our Top-of-stack device 
 
    SetPnpPolicy();                 // use the default Pnp policy 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// Destructor 
// 
// This is the destructor for the Functional Device Object, or FDO. 
 
UsbBulkDevice::~UsbBulkDevice() 
{ 
    Tracer << "UsbBulkDevice::~UsbBulkDevice() Entry\n"; 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// Default handler for IRP_MJ_PNP 
// 
// This routine just passes the IRP through to USBD. It is  
// the default handler for IRP_MJ_PNP. IRPs that correspond to 
// any virtual members of KpnpDevice that handle minor functions of 
// IRP_MJ_PNP and that are not overridden get passed to this routine. 
// 
// For diagnostic purposes, this routine is set up to emit the function 
// name to the debugger. 
// 
NTSTATUS UsbBulkDevice::DefaultPnp(KIrp I)  
{ 
	static char* minors[] = { 
		"IRP_MN_START_DEVICE",	 
		"IRP_MN_QUERY_REMOVE_DEVICE",	 
		"IRP_MN_REMOVE_DEVICE",	 
		"IRP_MN_CANCEL_REMOVE_DEVICE",	 
		"IRP_MN_STOP_DEVICE",	 
		"IRP_MN_QUERY_STOP_DEVICE",	 
		"IRP_MN_CANCEL_STOP_DEVICE",	 
		"IRP_MN_QUERY_DEVICE_RELATIONS",	 
		"IRP_MN_QUERY_INTERFACE",	 
		"IRP_MN_QUERY_CAPABILITIES",	 
		"IRP_MN_QUERY_RESOURCES",	 
		"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",	 
		"IRP_MN_QUERY_DEVICE_TEXT",	 
		"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",	 
		"IRP_MN_undefined",	 
		"IRP_MN_READ_CONFIG",	 
		"IRP_MN_WRITE_CONFIG",	 
		"IRP_MN_EJECT",	 
		"IRP_MN_SET_LOCK",	 
		"IRP_MN_QUERY_ID",	 
		"IRP_MN_QUERY_PNP_DEVICE_STATE",	 
		"IRP_MN_QUERY_BUS_INFORMATION",	 
		"IRP_MN_DEVICE_USAGE_NOTIFICATION", 
		"IRP_MN_SURPRISE_REMOVAL" 
	}; 
 
	ULONG Minor = I.MinorFunction(); 
	CHAR* IrpName; 
 
	if ( Minor < IRP_MN_SURPRISE_REMOVAL ) 
		IrpName = minors[Minor]; 
	else 
		IrpName = ""; 
 
	DbgPrint("Pnp IRP minor function=%s\n", IrpName); 
 
	I.ForceReuseOfCurrentStackLocationInCalldown(); 
	return m_Usb.PnpCall(this, I); 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// Default handler for IRP_MJ_POWER  
// 
// This routine just passes the IRP through to USBD. It is  
// the default handler for IRP_MJ_POWER. 
// 
NTSTATUS UsbBulkDevice::DefaultPower(KIrp I)  
{ 
    I.IndicatePowerIrpProcessed(); 
    I.CopyParametersDown(); 
    return m_Usb.PnpPowerCall(this, I); 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// OnStartDevice - handler for IRP_MJ_PNP/IRP_MN_START_DEVICE 
// 
// This is the routine where the driver initializes the physical device and 
// sets up its USB related data members. 
// 
// This device has one interface and one pipe. Other USB devices 
// are more complex, but it simply a matter of adding more data 
// members to the device class in order to support more interfaces 
// or pipes. 
 
NTSTATUS UsbBulkDevice::OnStartDevice(KIrp I) 
{ 
    NTSTATUS status = STATUS_UNSUCCESSFUL; 
    AC_STATUS acStatus; 
    PUSB_ENDPOINT pTrouble; 
 
    Tracer << "UsbBulkDevice::OnStartDevice() Entry\n"; 
     
// The default Pnp policy has already cleared the IRP with the lower device 
 
// Now we initialize the device object 
 
    acStatus = m_Usb.ActivateConfiguration( 
        1,              // configuration 1 
        2,              // number of endpoints to configure 
        m_Endpoints,    // address of our endpoint table 
        &pTrouble       // gets pointer to problem endpoint, if any 
        ); 
 
 
    switch (acStatus) 
    { 
    case AC_SUCCESS: 
        Tracer << "Configuration OK\n"; 
        status = STATUS_SUCCESS; 
        break; 
 
    case AC_COULD_NOT_LOCATE_INTERFACE: 
        Tracer << "Could not locate interface, endpoint address " 
                << ULONG(pTrouble->m_EndpointAddress) << "\n"; 
        break; 
 
    case AC_COULD_NOT_PRECONFIGURE_INTERFACE: 
        Tracer << "Could not get configuration descriptor\n"; 
        break; 
 
    case AC_CONFIGURATION_REQUEST_FAILED: 
        Tracer << "Board did not accept configuration URB\n"; 
        break; 
 
    case AC_FAILED_TO_INITIALIZE_INTERFACE_OBJECT: 
        Tracer << "Failed to initialize interface for pipe["  
                << ULONG(pTrouble-m_Endpoints) << "]\n"; 
        break; 
 
    case AC_FAILED_TO_LOCATE_ENDPOINT_ADDRESS: 
        Tracer << "Failed to locate endpoint address for pipe["  
                << ULONG(pTrouble-m_Endpoints) << "]\n"; 
        break; 
    } 
 
    return status;  // base class completes the IRP 
} 
 
 
///////////////////////////////////////////////////////////////////////// 
// OnStopDevice 
// 
// The system calls this when the device is stopped 
 
NTSTATUS UsbBulkDevice::OnStopDevice(KIrp I) 
{ 
    Tracer << "UsbBulkDevice::OnStopDevice() Entry\n"; 
 
    return m_Usb.Unconfigure(); 
 
    // base class passes to lower device 
} 
 
///////////////////////////////////////////////////////////////////////// 
// OnRemoveDevice 
// 
// The system calls this when the device is removed. 
 
NTSTATUS UsbBulkDevice::OnRemoveDevice(KIrp I) 
{ 
    Tracer << "UsbBulkDevice::OnRemoveDevice() Entry\n"; 
 
    // Our PnP policy will take care of  
    // (1) giving the IRP to USBD 
    // (2) detaching the PDO 
    // (3) deleting the device object 
 
    return STATUS_SUCCESS; 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// Dispatchers 
// 
// Nothing to do on Create and Close. A real driver would add additional 
// dispatchers for data operations such as Read and Write. The compiler 
// will combine identically coded functions. 
 
NTSTATUS UsbBulkDevice::Create(KIrp I) 
{  
    Tracer << "UsbBulkDevice::Create() Entry\n"; 
 
    I.ForceReuseOfCurrentStackLocationInCalldown(); 
    NTSTATUS status = m_Usb.PnpCall(this, I); 
 
    Tracer << "UsbBulkDevice:Create Status " << (ULONG)status << "\n"; 
 
    return status; 
} 
 
 
NTSTATUS UsbBulkDevice::Close(KIrp I) 
{ 
    Tracer << "UsbBulkDevice::Close() Entry\n"; 
 
    I.ForceReuseOfCurrentStackLocationInCalldown(); 
    NTSTATUS status = m_Usb.PnpCall(this, I); 
 
    Tracer << "UsbBulkDevice:Close Status " << (ULONG)status << "\n"; 
 
    return status; 
} 
 
 
NTSTATUS UsbBulkDevice::InternalDeviceControl(KIrp I) 
{  
    Tracer << "UsbBulkDevice::InternalDeviceControl() Entry\n"; 
 
    I.ForceReuseOfCurrentStackLocationInCalldown(); 
    NTSTATUS status = m_Usb.PnpCall(this, I); 
 
    Tracer << "UsbBulkDevice::InternalDeviceControl Status " 
            << (ULONG)status << "\n"; 
 
    return status; 
} 
 
 
///////////////////////////////////////////////////////////////////////// 
// DeviceControl 
// 
// The system calls this when an application issues DeviceIoControl 
// 
NTSTATUS UsbBulkDevice::DeviceControl(KIrp I) 
{  
    Tracer << "UsbBulkDevice::DeviceControl() Entry\n"; 
 
#pragma warning(disable:4065) // switch with no cases 
 
    switch (I.IoctlCode()) 
    { 
    default: 
        Tracer << "UNKNOWN [ID=" << I.IoctlCode() << "] );\n", 
        I.Information() = 0; 
        return I.PnpComplete(this, STATUS_INVALID_PARAMETER); 
    } 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// Default handler for IRP_MJ_READ 
// 
// This routine is the default handler for IRP_MJ_READ. 
// Incoming IRPs are passed on to the USB device, synchronously. 
// 
// The KPnpDevice class handles restricting IRP flow 
// if the device is stopping or being removed. 
// 
NTSTATUS UsbBulkDevice::Read(KIrp I)  
{ 
    NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 
 
    Tracer << "UsbBulkDevice::Read() Entry\n"; 
 
    PUCHAR pBuffer = (PUCHAR)I.BufferedReadDest(); 
 
    ULONG  dwTotalSize = I.ReadSize(CURRENT); 
    ULONG  dwBytesRead = 0; 
 
    // Create an URB to do actual Bulk read from Pipe0 
    PURB pUrb = m_Pipe0.BuildBulkTransfer(pBuffer,      // Where is data coming from? 
                                          dwTotalSize,  // How much data to read? 
                                          TRUE,         // direction (TRUE = IN) 
                                          NULL);        // Link to next URB 
 
	if ( pUrb != NULL) 
	{ 
	    // Submit the URB to our USB device, synchronously - say less is OK 
		pUrb->UrbBulkOrInterruptTransfer.TransferFlags = 
				(USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK); 
 
        status = m_Pipe0.SubmitUrb(pUrb, NULL, NULL); 
 
        if ( NT_SUCCESS(status) )  
        { 
	            dwBytesRead = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength; 
 
				if (dwBytesRead > 0)  
					Tracer << "Read() got " << dwTotalSize	<< " bytes from USB\n"; 
	    } 
 
		delete pUrb; 
	} 
 
	 
    I.Information() = dwBytesRead; 
    return I.PnpComplete(this, status, IO_NO_INCREMENT); 
} 
 
 
//////////////////////////////////////////////////////////////////////////////// 
// Default handler for IRP_MJ_WRITE 
// 
// This routine is the default handler for IRP_MJ_WRITE. 
// Incoming IRPs just send data down to the USB device, synchronously. 
// 
// The KPnpDevice class handles restricting IRP flow 
// if the device is stopping or being removed. 
// 
NTSTATUS UsbBulkDevice::Write(KIrp I)  
{ 
    NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; 
 
    Tracer << "UsbBulkDevice::Write() Entry\n"; 
 
    PVOID pBuffer     = I.BufferedWriteSource(); 
    ULONG dwTotalSize = I.WriteSize(CURRENT); 
    ULONG dwBytesSent = 0; 
     
    // Create an URB to do actual Bulk read from Pipe0 
 
	KMemory Mdl(pBuffer, dwTotalSize); 
 
	Mdl.SetPageArray(); 
 
    PURB pUrb = m_Pipe1.BuildBulkTransfer(Mdl,          // Where is data coming from? 
                                          dwTotalSize,  // How much data to read? 
                                          FALSE,        // direction (FALSE = OUT) 
                                          NULL);        // Link to next URB 
 
    // Submit the URB to our USB device, synchronously 
    if (pUrb != NULL)  
    { 
        status = m_Pipe1.SubmitUrb(pUrb, NULL, NULL); 
 
        if ( NT_SUCCESS(status) )  
        { 
            dwBytesSent = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength; 
 
            Tracer << "Write() posted "  << dwTotalSize << " bytes to USB\n"; 
        } 
 
		delete pUrb; 
    } 
 
    I.Information() = dwBytesSent; 
    return I.PnpComplete(this, status, IO_NO_INCREMENT); 
}