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); }