www.pudn.com > pcmcia_sample.rar > PcmciaDevice.cpp
// PcmciaDevice.cpp // Implementation of PcmciaDevice device class // // Generated by DriverWizard version DriverStudio 2.7.0 (Build 562) // Requires Compuware's DriverWorks classes // #pragma warning(disable:4065) // Allow switch statement with no cases #include#include "..\PcmciaDeviceinterface.h" #include "Pcmcia.h" #include "PcmciaDevice.h" #pragma hdrstop("Pcmcia.pch") extern KTrace t; // Global driver trace object GUID PcmciaDevice_Guid = PcmciaDevice_CLASS_GUID; //////////////////////////////////////////////////////////////////////// // PcmciaDevice::PcmciaDevice // // Routine Description: // 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. // // Parameters: // 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 // // Return Value: // None // // Comments: // The object being constructed contains a data member (m_Lower) 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 class driver. // PcmciaDevice::PcmciaDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : KPnpDevice(Pdo, &PcmciaDevice_Guid) { t << "Entering PcmciaDevice::PcmciaDevice (constructor)\n"; // Check constructor status if ( ! NT_SUCCESS(m_ConstructorStatus) ) { return; } // Remember our unit number m_Unit = Unit; // Initialize the lower device m_Lower.Initialize(this, Pdo); // Inform the base class of the lower edge device object SetLowerDevice(&m_Lower); // Initialize the PnP Policy settings to the "standard" policy SetPnpPolicy(); // TODO: Customize the PnP Policy for this device by setting // flags in m_Policies. // Initialize the Power Policy settings to the "standard" policy SetPowerPolicy(); // TODO: Customize the Power Policy for this device by setting // flags in m_PowerPolicies. } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::~PcmciaDevice // // Routine Description: // This is the destructor for the Functional Device Object, or FDO. // // Parameters: // None // // Return Value: // None // // Comments: // None // PcmciaDevice::~PcmciaDevice() { t << "Entering PcmciaDevice::~PcmciaDevice() (destructor)\n"; } //////////////////////////////////////////////////////////////////////// // PNPMinorFunctionName // // Routine Description: // Return a string describing the Plug and Play minor function // // Parameters: // mn - Minor function code // // Return Value: // char * - Ascii name of minor function // // Comments: // This function is used for tracing the IRPs. Remove the function, // or conditionalize it for debug-only builds, if you want to save // space in the driver image. // char *PNPMinorFunctionName(ULONG mn) { 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_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", "IRP_MN_QUERY_LEGACY_BUS_INFORMATION" }; if (mn > 0x18) // IRP_MN_QUERY_LEGACY_BUS_INFORMATION return " "; else return minors[mn]; } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::DefaultPnp // // Routine Description: // Default handler for IRP_MJ_PNP // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result returned from lower device // // Comments: // This routine just passes the IRP through to the lower device. 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. // NTSTATUS PcmciaDevice::DefaultPnp(KIrp I) { t << "Entering PcmciaDevice::DefaultPnp with IRP minor function=" << PNPMinorFunctionName(I.MinorFunction()) << EOL; I.ForceReuseOfCurrentStackLocationInCalldown(); return m_Lower.PnpCall(this, I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::DefaultPower // // Routine Description: // Default handler for IRP_MJ_POWER // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result returned from lower device // // Comments: // This routine just passes the IRP through to the lower device. It is // the default handler for IRP_MJ_POWER. // NTSTATUS PcmciaDevice::DefaultPower(KIrp I) { t << "Entering PcmciaDevice::DefaultPower\n"; I.IndicatePowerIrpProcessed(); I.CopyParametersDown(); return m_Lower.PnpPowerCall(this, I); } //////////////////////////////////////////////////////////////////////////////// // PcmciaDevice::SystemControl // // Routine Description: // Default handler for IRP_MJ_SYSTEM_CONTROL // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result returned from lower device // // Comments: // This routine just passes the IRP through to the next device since this driver // is not a WMI provider. // NTSTATUS PcmciaDevice::SystemControl(KIrp I) { t << "Entering PcmciaDevice::SystemControl\n"; I.ForceReuseOfCurrentStackLocationInCalldown(); return m_Lower.PnpCall(this, I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::OnStartDevice // // Routine Description: // Handler for IRP_MJ_PNP subfcn IRP_MN_START_DEVICE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // Initialize the physical device. Typically, the driver initializes // physical resources here. Call I.AllocatedResources() for a list // of the raw resources that the system has assigned to the device, // or I.TranslatedResources() for the translated resource list. // NTSTATUS PcmciaDevice::OnStartDevice(KIrp I) { t << "Entering PcmciaDevice::OnStartDevice\n"; NTSTATUS status = STATUS_SUCCESS; I.Information() = 0; // The default Pnp policy has already cleared the IRP with the lower device // Initialize the physical device object. // Get the list of raw resources from the IRP PCM_RESOURCE_LIST pResListRaw = I.AllocatedResources(); // Get the list of translated resources from the IRP PCM_RESOURCE_LIST pResListTranslated = I.TranslatedResources(); // TODO: Add device-specific code to start your device. // The base class will handle completion return status; } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::OnStopDevice // // Routine Description: // Handler for IRP_MJ_PNP subfcn IRP_MN_STOP_DEVICE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // The system calls this when the device is stopped. // The driver should release any hardware resources // in this routine. // // The base class passes the irp to the lower device. // NTSTATUS PcmciaDevice::OnStopDevice(KIrp I) { NTSTATUS status = STATUS_SUCCESS; t << "Entering PcmciaDevice::OnStopDevice\n"; // TODO: Add device-specific code to stop your device return status; // The following macro simply allows compilation at Warning Level 4 // If you reference this parameter in the function simply remove the macro. UNREFERENCED_PARAMETER(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::OnRemoveDevice // // Routine Description: // Handler for IRP_MJ_PNP subfcn IRP_MN_REMOVE_DEVICE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // The system calls this when the device is removed. // Our PnP policy will take care of // (1) giving the IRP to the lower device // (2) detaching the PDO // (3) deleting the device object // NTSTATUS PcmciaDevice::OnRemoveDevice(KIrp I) { t << "Entering PcmciaDevice::OnRemoveDevice\n"; // TODO: Add device-specific code to remove your device return STATUS_SUCCESS; // The following macro simply allows compilation at Warning Level 4 // If you reference this parameter in the function simply remove the macro. UNREFERENCED_PARAMETER(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::OnDevicePowerUp // // Routine Description: // Handler for IRP_MJ_POWER with minor function IRP_MN_SET_POWER // for a request to go to power on state from low power state // // Parameters: // I - IRP containing POWER request // // Return Value: // NTSTATUS - Status code indicating success or failure // // Comments: // This routine implements the OnDevicePowerUp function. // This function was called by the framework from the completion // routine of the IRP_MJ_POWER dispatch handler in KPnpDevice. // The bus driver has completed the IRP and this driver can now // access the hardware device. // This routine runs at dispatch level. // NTSTATUS PcmciaDevice::OnDevicePowerUp(KIrp I) { NTSTATUS status = STATUS_SUCCESS; t << "Entering PcmciaDevice::OnDevicePowerUp\n"; // TODO: Service the device. // Restore any context to the hardware device that // was saved during the handling of a power down request. // See the OnDeviceSleep function. // Do NOT complete this IRP. // return status; // The following macro simply allows compilation at Warning Level 4 // If you reference this parameter in the function simply remove the macro. UNREFERENCED_PARAMETER(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::OnDeviceSleep // // Routine Description: // Handler for IRP_MJ_POWER with minor function IRP_MN_SET_POWER // for a request to go to a low power state from a high power state // // Parameters: // I - IRP containing POWER request // // Return Value: // NTSTATUS - Status code indicating success or failure // // Comments: // This routine implements the OnDeviceSleep function. // This function was called by the framework from the IRP_MJ_POWER // dispatch handler in KPnpDevice prior to forwarding to the PDO. // The hardware has yet to be powered down and this driver can now // access the hardware device. // This routine runs at passive level. // NTSTATUS PcmciaDevice::OnDeviceSleep(KIrp I) { NTSTATUS status = STATUS_SUCCESS; t << "Entering PcmciaDevice::OnDeviceSleep\n"; // TODO: Service the device. // Save any context to the hardware device that will be required // during a power up request. See the OnDevicePowerUp function. // Do NOT complete this IRP. The base class handles forwarding // this IRP to the PDO. // return status; // The following macro simply allows compilation at Warning Level 4 // If you reference this parameter in the function simply remove the macro. UNREFERENCED_PARAMETER(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::Create // // Routine Description: // Handler for IRP_MJ_CREATE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // NTSTATUS PcmciaDevice::Create(KIrp I) { NTSTATUS status; t << "Entering PcmciaDevice::Create, " << I << EOL; // TODO: Add driver specific create handling code here // Generally a create IRP is targeted at our FDO, so we don't need // to pass it down to the PDO. We have found for some devices, the // PDO is not expecting this Irp and returns an error code. // The default wizard code, therefore completes the Irp here using // PnpComplete(). The following commented code could be used instead // of PnpComplete() to pass the Irp to the PDO, which would complete it. // // I.ForceReuseOfCurrentStackLocationInCalldown(); // status = m_Lower.PnpCall(this, I); status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT); t << "PcmciaDevice::Create Status " << (ULONG)status << EOL; return status; } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::Close // // Routine Description: // Handler for IRP_MJ_CLOSE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // NTSTATUS PcmciaDevice::Close(KIrp I) { NTSTATUS status; t << "Entering PcmciaDevice::Close, " << I << EOL; // TODO: Add driver specific close handling code here // Generally a close IRP is targeted at our FDO, so we don't need // to pass it down to the PDO. We have found for some devices, the // PDO is not expecting this Irp and returns an error code. // The default wizard code, therefore completes the Irp here using // PnpComplete(). The following commented code could be used instead // of PnpComplete() to pass the Irp to the PDO, which would complete it. // // I.ForceReuseOfCurrentStackLocationInCalldown(); // status = m_Lower.PnpCall(this, I); status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT); t << "PcmciaDevice::Close Status " << (ULONG)status << EOL; return status; } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::Cleanup // // Routine Description: // Handler for IRP_MJ_CLEANUP // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // NTSTATUS PcmciaDevice::CleanUp(KIrp I) { t << "Entering CleanUp, " << I << EOL; // TODO: Insert your code to respond to the CLEANUP message. // This code cleans up the single Wizard created queue. If you // have created additional queues, or have any outstanding Irps // stored in some other fashion in your driver, you should clean // these up as well for the file object specified in the cleanup Irp. m_DriverManagedQueue.PnpCleanUp(this, I.FileObject()); return I.PnpComplete(this, STATUS_SUCCESS); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::SerialRead // // Routine Description: // Handler for serialized READ // // Parameters: // I - Current IRP // // Return Value: // None // // Comments: // This routine is called when the IRP is removed from the // STARTIO queue. This guarantees that multiple requests are // never processed simultaneously. // // This routine is called at dispatch level. // void PcmciaDevice::SerialRead(KIrp I) { t << "Entering PcmciaDevice::SerialRead, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; // Declare a memory object KMemory Mem(I.Mdl()); // Use the memory object to create a pointer to the caller's buffer PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG dwTotalSize = I.ReadSize(CURRENT); // Requested read size ULONG dwBytesRead = 0; // Count of bytes read // TODO: If the read can be satisfied immediately, set the Information // and Status fields now, then call NextIrp to complete this IRP // and start processing the next IRP in the queue. // TODO: If the data is not yet available, initiate a request to the // physical device here, and defer the Information, Status, // and NextIrp handling until the hardware indicates that the // read is complete. Typically, this might be handled in a // DPC that is called after the hardware finishes transferring // the data. // TODO: To satisfy the read now, transfer data from the device to // caller's buffer at "pBuffer". Then, indicate how much data was // transferred: I.Information() = dwBytesRead; I.Status() = status; // PnpNextIrp completes this IRP and starts processing // for the next IRP in the driver managed queue. // TODO: The Wizard creates a single queue for all Irps. // If you have created additional queues, select // the appropriate queue for this Irp here. m_DriverManagedQueue.PnpNextIrp(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::Read // // Routine Description: // Handler for IRP_MJ_READ // // Parameters: // I Current IRP // // Return Value: // NTSTATUS Result code // // Comments: // This routine handles read requests. // // The KPnpDevice class handles restricting IRP flow // if the device is stopping or being removed. // NTSTATUS PcmciaDevice::Read(KIrp I) { t << "Entering PcmciaDevice::Read, " << I << EOL; // TODO: Check the incoming request. Replace "FALSE" in the following // line with a check that returns TRUE if the request is not valid. if (FALSE) // If (Request is invalid) { // Invalid parameter in the Read request I.Information() = 0; return I.PnpComplete(this, STATUS_INVALID_PARAMETER); } // Always ok to read 0 elements. if (I.ReadSize() == 0) { I.Information() = 0; return I.PnpComplete(this, STATUS_SUCCESS); } // Queue the IRP for processing in the driver managed queue. // The actual read function is performed in SerialRead // TODO: The Wizard creates a single queue for all Irps. // If you have created additional queues, select // the appropriate queue for this Irp here. return m_DriverManagedQueue.QueueIrp(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::SerialWrite // // Routine Description: // Handler for serialized WRITE // // Parameters: // I - Current IRP // // Return Value: // None // // Comments: // This routine is called when the IRP is removed from the // STARTIO queue. This guarantees that multiple requests are // never processed simultaneously. // void PcmciaDevice::SerialWrite(KIrp I) { t << "Entering PcmciaDevice::SerialWrite, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; // Declare a memory object KMemory Mem(I.Mdl()); // Use the memory object to create a pointer to the caller's buffer PUCHAR pBuffer = (PUCHAR) Mem.MapToSystemSpace(); ULONG dwTotalSize = I.WriteSize(CURRENT); ULONG dwBytesSent = 0; // TODO: If the write can be satisfied immediately, set the Information // and Status fields now, then call NextIrp to complete this IRP // and start processing the next IRP in the queue. // TODO: If the device cannot accept all of the data yet, initiate a // request to the physical device here, and defer the Information, // Status, and NextIrp handling until the hardware indicates that // the write is complete. Typically, this might be handled in a // DPC that is called after the hardware finishes transferring // the data. // TODO: To satisfy the write now, transfer data to the device // from caller's buffer at "pBuffer". Then, indicate how much // data was transferred: I.Information() = dwBytesSent; I.Status() = status; // PnpNextIrp completes this IRP and starts processing // for the next IRP in the driver managed queue. // TODO: The Wizard creates a single queue for all Irps. // If you have created additional queues, select // the appropriate queue for this Irp here. m_DriverManagedQueue.PnpNextIrp(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::Write // // Routine Description: // Handler for IRP_MJ_WRITE // // Parameters: // I - Current IRP // // Return Value: // NTSTATUS - Result code // // Comments: // This routine handles write requests. // // The KPnpDevice class handles restricting IRP flow // if the device is stopping or being removed. // NTSTATUS PcmciaDevice::Write(KIrp I) { t << "Entering PcmciaDevice::Write, " << I << EOL; // TODO: Check the incoming request. Replace "FALSE" in the following // line with a check that returns TRUE if the request is not valid. if (FALSE) { // Invalid parameter in the Write request I.Information() = 0; return I.PnpComplete(this, STATUS_INVALID_PARAMETER); } // Always ok to write 0 elements. if (I.WriteSize() == 0) { I.Information() = 0; return I.PnpComplete(this, STATUS_SUCCESS); } // Queue the IRP for processing in the driver managed queue. // The actual write function is performed in SerialWrite // TODO: The Wizard creates a single queue for all Irps. // If you have created additional queues, select // the appropriate queue for this Irp here. return m_DriverManagedQueue.QueueIrp(I); } //////////////////////////////////////////////////////////////////////// // PcmciaDevice::DeviceControl // // Routine Description: // Handler for IRP_MJ_DEVICE_CONTROL // // Parameters: // I - Current IRP // // Return Value: // None // // Comments: // This routine is the first handler for Device Control requests. // Some function codes may be handled immediately, // while others may be serialized through the StartIo routine. // // The KPnpDevice class handles restricting IRP flow // if the device is stopping or being removed. // NTSTATUS PcmciaDevice::DeviceControl(KIrp I) { NTSTATUS status; t << "Entering PcmciaDevice::Device Control, " << I << EOL; switch (I.IoctlCode()) { default: // Unrecognized IOCTL request status = STATUS_INVALID_PARAMETER; break; } // If the IRP was queued, or its IOCTL handler deferred processing using some // driver specific scheme, the status variable is set to STATUS_PENDING. // In this case we simply return that status, and the IRP will be completed // later. Otherwise, complete the IRP using the status returned by the // IOCTL handler. if (status == STATUS_PENDING) { return status; } else { return I.PnpComplete(this, status); } } //////////////////////////////////////////////////////////////////////////////// // PcmciaDevice_DriverManagedQueue::StartIo // // Routine Description: // This routine is called when an IRP is taken off // the Driver Managed Queue (used for serializing I/O) and // presented for processing. // // Parameters: // I - IRP removed from queue // // Return Value: // None // // Comments: // VOID PcmciaDevice_DriverManagedQueue::StartIo(KIrp I) { t << "Entering PcmciaDevice_DriverManagedQueue StartIo, " << I; // The KDriverManagedQueueEx class gives us the Irp in a non-cancelable state // (cancel routine set to NULL) so we can process it without having to worry // about clearing the cancel routine first, as is the case with system queuing, // or the legacy class KDriverManagedQueue. You may want to set a different cancel // routine here, or at other points during the processing of this Irp. // Find the device class so we can call the serialized // routines in the device class. The handlers can be // moved to the DriverManagedQueue class if it is more // convenient. PcmciaDevice *pDev = (PcmciaDevice *) KDevicePTR(I.DeviceObject()); // Start processing request. // Switch on the IRP's function: switch (I.MajorFunction()) { case IRP_MJ_READ: pDev->SerialRead(I); break; case IRP_MJ_WRITE: pDev->SerialWrite(I); break; case IRP_MJ_DEVICE_CONTROL: switch (I.IoctlCode()) { default: // We queued a request that shouldn't have been queued // (should never get here) ASSERT(FALSE); break; } break; default: // Error - unexpected IRP received // NextIrp completes this IRP and starts processing // for the next IRP in the queue. ASSERT(FALSE); I.Status() = STATUS_INVALID_PARAMETER; PnpNextIrp(I); break; } }