556 lines
14 KiB
C
556 lines
14 KiB
C
|
/*++
|
|||
|
Copyright (C) Microsoft Corporation, 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
mcdwmi.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the changer class driver - WMI support routines.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
#include "mchgr.h"
|
|||
|
|
|||
|
//
|
|||
|
// Internal routines
|
|||
|
//
|
|||
|
NTSTATUS
|
|||
|
ChangerWMIGetParameters(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
OUT PGET_CHANGER_PARAMETERS changerParameters
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// List of WMI GUIDs
|
|||
|
//
|
|||
|
GUIDREGINFO ChangerWmiFdoGuidList[] =
|
|||
|
{
|
|||
|
{
|
|||
|
WMI_CHANGER_PARAMETERS_GUID,
|
|||
|
1,
|
|||
|
0
|
|||
|
},
|
|||
|
|
|||
|
{
|
|||
|
WMI_CHANGER_PROBLEM_WARNING_GUID,
|
|||
|
1,
|
|||
|
WMIREG_FLAG_EVENT_ONLY_GUID
|
|||
|
},
|
|||
|
|
|||
|
{
|
|||
|
WMI_CHANGER_PROBLEM_DEVICE_ERROR_GUID,
|
|||
|
1,
|
|||
|
WMIREG_FLAG_EXPENSIVE
|
|||
|
},
|
|||
|
};
|
|||
|
|
|||
|
GUID ChangerDriveProblemEventGuid = WMI_CHANGER_PROBLEM_WARNING_GUID;
|
|||
|
|
|||
|
//
|
|||
|
// GUID index. It should match the list defined above
|
|||
|
//
|
|||
|
#define ChangerParametersGuid 0
|
|||
|
#define ChangerProblemWarningGuid 1
|
|||
|
#define ChangerProblemDevErrorGuid 2
|
|||
|
|
|||
|
//
|
|||
|
// ISSUE: 02/29/2000 - nramas : Should make wmi routines pagable
|
|||
|
//
|
|||
|
/*
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
|
|||
|
#pragma alloc_text(PAGE,
|
|||
|
|
|||
|
#endif
|
|||
|
*/
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerFdoQueryWmiRegInfo(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
OUT ULONG *RegFlags,
|
|||
|
OUT PUNICODE_STRING InstanceName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to retrieve the list of
|
|||
|
guids or data blocks that the driver wants to register with WMI. This
|
|||
|
routine may not pend or block. Driver should NOT call
|
|||
|
ClassWmiCompleteRequest.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose data block is being queried
|
|||
|
|
|||
|
*RegFlags returns with a set of flags that describe the guids being
|
|||
|
registered for this device. If the device wants enable and disable
|
|||
|
collection callbacks before receiving queries for the registered
|
|||
|
guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
|
|||
|
returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
|
|||
|
the instance name is determined from the PDO associated with the
|
|||
|
device object. Note that the PDO must have an associated devnode. If
|
|||
|
WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
|
|||
|
name for the device.
|
|||
|
|
|||
|
InstanceName returns with the instance name for the guids if
|
|||
|
WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
|
|||
|
caller will call ExFreePool with the buffer returned.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// Use devnode for FDOs
|
|||
|
//
|
|||
|
*RegFlags = WMIREG_FLAG_INSTANCE_PDO;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerFdoQueryWmiDataBlock(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN ULONG BufferAvail,
|
|||
|
OUT PUCHAR Buffer
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to query for the contents of
|
|||
|
a data block. When the driver has finished filling the data block it
|
|||
|
must call ClassWmiCompleteRequest to complete the irp. The driver can
|
|||
|
return STATUS_PENDING if the irp cannot be completed immediately.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose data block is being queried
|
|||
|
|
|||
|
Irp is the Irp that makes this request
|
|||
|
|
|||
|
GuidIndex is the index into the list of guids provided when the
|
|||
|
device registered
|
|||
|
|
|||
|
BufferAvail on has the maximum size available to write the data
|
|||
|
block.
|
|||
|
|
|||
|
Buffer on return is filled with the returned data block
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|||
|
PMCD_INIT_DATA mcdInitData;
|
|||
|
ULONG sizeNeeded = 0;
|
|||
|
|
|||
|
switch (GuidIndex) {
|
|||
|
case ChangerParametersGuid: {
|
|||
|
GET_CHANGER_PARAMETERS changerParameters;
|
|||
|
PWMI_CHANGER_PARAMETERS outBuffer;
|
|||
|
|
|||
|
sizeNeeded = sizeof(WMI_CHANGER_PARAMETERS);
|
|||
|
if (BufferAvail < sizeNeeded) {
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status = ChangerWMIGetParameters(DeviceObject,
|
|||
|
&changerParameters);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
outBuffer = (PWMI_CHANGER_PARAMETERS)Buffer;
|
|||
|
outBuffer->NumberOfSlots = changerParameters.NumberStorageElements;
|
|||
|
outBuffer->NumberOfDrives = changerParameters.NumberDataTransferElements;
|
|||
|
outBuffer->NumberOfIEPorts = changerParameters.NumberIEElements;
|
|||
|
outBuffer->NumberOfTransports = changerParameters.NumberTransportElements;
|
|||
|
outBuffer->NumberOfDoors = changerParameters.NumberOfDoors;
|
|||
|
outBuffer->MagazineSize = changerParameters.MagazineSize;
|
|||
|
outBuffer->NumberOfCleanerSlots = changerParameters.NumberCleanerSlots;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case ChangerProblemDevErrorGuid: {
|
|||
|
PWMI_CHANGER_PROBLEM_DEVICE_ERROR changerDeviceError;
|
|||
|
|
|||
|
mcdInitData = IoGetDriverObjectExtension(DeviceObject->DriverObject,
|
|||
|
ChangerClassInitialize);
|
|||
|
|
|||
|
if (mcdInitData == NULL) {
|
|||
|
status = STATUS_NO_SUCH_DEVICE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (!(mcdInitData->ChangerPerformDiagnostics)) {
|
|||
|
status = STATUS_NOT_IMPLEMENTED;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
sizeNeeded = sizeof(WMI_CHANGER_PROBLEM_DEVICE_ERROR);
|
|||
|
if (BufferAvail < sizeNeeded) {
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
changerDeviceError = (PWMI_CHANGER_PROBLEM_DEVICE_ERROR)Buffer;
|
|||
|
RtlZeroMemory(changerDeviceError,
|
|||
|
sizeof(WMI_CHANGER_PROBLEM_DEVICE_ERROR));
|
|||
|
status = mcdInitData->ChangerPerformDiagnostics(DeviceObject,
|
|||
|
changerDeviceError);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
default: {
|
|||
|
sizeNeeded = 0;
|
|||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
} // switch (GuidIndex)
|
|||
|
|
|||
|
status = ClassWmiCompleteRequest(DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
sizeNeeded,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerWMIGetParameters(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
OUT PGET_CHANGER_PARAMETERS changerParameters
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Sends the IOCTL to get the changer parameters
|
|||
|
|
|||
|
Arguments :
|
|||
|
|
|||
|
DeviceObject The changer device objcet
|
|||
|
ChangerParameters buffer in which the changer parameters is returned.
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
NT Status.
|
|||
|
--*/
|
|||
|
{
|
|||
|
KEVENT event;
|
|||
|
PDEVICE_OBJECT topOfStack;
|
|||
|
PIRP irp = NULL;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|||
|
|
|||
|
topOfStack = IoGetAttachedDeviceReference(DeviceObject);
|
|||
|
|
|||
|
//
|
|||
|
// Send down irp to get the changer parameters
|
|||
|
//
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_CHANGER_GET_PARAMETERS,
|
|||
|
topOfStack,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
changerParameters,
|
|||
|
sizeof(GET_CHANGER_PARAMETERS),
|
|||
|
FALSE,
|
|||
|
&event,
|
|||
|
&ioStatus);
|
|||
|
if (irp != NULL) {
|
|||
|
status = IoCallDriver(topOfStack, irp);
|
|||
|
if (status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|||
|
status = ioStatus.Status;
|
|||
|
}
|
|||
|
} else {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
ObDereferenceObject(topOfStack);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerWmiFunctionControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN CLASSENABLEDISABLEFUNCTION Function,
|
|||
|
IN BOOLEAN Enable
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to enabled or disable event
|
|||
|
generation or data block collection. A device should only expect a
|
|||
|
single enable when the first event or data consumer enables events or
|
|||
|
data collection and a single disable when the last event or data
|
|||
|
consumer disables events or data collection. Data blocks will only
|
|||
|
receive collection enable/disable if they were registered as requiring
|
|||
|
it.
|
|||
|
|
|||
|
This function can be used to enable\disable datablock collection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose data block is being queried
|
|||
|
|
|||
|
GuidIndex is the index into the list of guids provided when the
|
|||
|
device registered
|
|||
|
|
|||
|
Function specifies which functionality is being enabled or disabled
|
|||
|
|
|||
|
Enable is TRUE then the function is being enabled else disabled
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
if (Function == DataBlockCollection) {
|
|||
|
DebugPrint((3,
|
|||
|
"ChangerWmiFunctionControl : Irp %p - %s DataBlockCollection",
|
|||
|
" for Device %p.\n",
|
|||
|
Irp, Enable ? "Enable " : "Disable ", DeviceObject));
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// ISSUE: 03/01/2000 - nramas
|
|||
|
// Need to handle EventGeneration. But now we don't do polling
|
|||
|
// of the changers to detect failure. So, for now disallow
|
|||
|
// EventGeneration
|
|||
|
//
|
|||
|
DebugPrint((1,
|
|||
|
"ChangerWmiFunctionControl : Unknown function %d for ",
|
|||
|
"Device %p, Irp %p\n",
|
|||
|
Function, DeviceObject, Irp));
|
|||
|
|
|||
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
}
|
|||
|
|
|||
|
status = ClassWmiCompleteRequest(DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
0,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerFdoExecuteWmiMethod(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN ULONG MethodId,
|
|||
|
IN ULONG InBufferSize,
|
|||
|
IN ULONG OutBufferSize,
|
|||
|
IN PUCHAR Buffer
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to execute a method. When the
|
|||
|
driver has finished filling the data block it must call
|
|||
|
ClassWmiCompleteRequest to complete the irp. The driver can
|
|||
|
return STATUS_PENDING if the irp cannot be completed immediately.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose data block is being queried
|
|||
|
|
|||
|
Irp is the Irp that makes this request
|
|||
|
|
|||
|
GuidIndex is the index into the list of guids provided when the
|
|||
|
device registered
|
|||
|
|
|||
|
MethodId has the id of the method being called
|
|||
|
|
|||
|
InBufferSize has the size of the data block passed in as the input to
|
|||
|
the method.
|
|||
|
|
|||
|
OutBufferSize on entry has the maximum size available to write the
|
|||
|
returned data block.
|
|||
|
|
|||
|
Buffer is filled with the returned data block
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
|
|||
|
|
|||
|
DebugPrint((3,
|
|||
|
"ChangerFdoExecuteMethod : Device %p, Irp %p, ",
|
|||
|
"GuidIndex %d\n",
|
|||
|
DeviceObject, Irp, GuidIndex));
|
|||
|
|
|||
|
if (GuidIndex > ChangerProblemDevErrorGuid) {
|
|||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
status = ClassWmiCompleteRequest(DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
0,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerFdoSetWmiDataBlock(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN ULONG BufferSize,
|
|||
|
IN PUCHAR Buffer
|
|||
|
)
|
|||
|
/*+
|
|||
|
|
|||
|
Routine Description :
|
|||
|
|
|||
|
This routine is called to set the contents of a datablock.
|
|||
|
When the driver is finished setting the buffer, it must call
|
|||
|
ClassWmiCompleteRequest to complete the irp. The driver can
|
|||
|
return STATUS_PENDING if the irp cannot be completed immediately.
|
|||
|
|
|||
|
Arguments :
|
|||
|
|
|||
|
Device object of the device being referred.
|
|||
|
|
|||
|
Irp is the WMI Irp
|
|||
|
|
|||
|
GuidIndex is the index of the guid for which the data is being set
|
|||
|
|
|||
|
BufferSize is the size of the data block
|
|||
|
|
|||
|
Buffer is the pointer to the data block
|
|||
|
|
|||
|
Return valus :
|
|||
|
|
|||
|
NTSTATUS returned by ClassWmiCompleteRequest
|
|||
|
STATUS_WMI_READ_ONLY if the datablock cannot be modified.
|
|||
|
STATUS_WMI_GUID_NOT_FOUND if an invalid guid index is passed
|
|||
|
-*/
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_WMI_READ_ONLY;
|
|||
|
|
|||
|
DebugPrint((3,
|
|||
|
"ChangerWmiSetBlock : Device %p, Irp %p, ",
|
|||
|
"GuidIndex %d\n",
|
|||
|
DeviceObject, Irp, GuidIndex));
|
|||
|
|
|||
|
if (GuidIndex > ChangerProblemDevErrorGuid) {
|
|||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
status = ClassWmiCompleteRequest(DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
0,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
|
|||
|
DebugPrint((3, "ChangerSetWmiDataBlock : Device %p, Irp %p, returns %x\n",
|
|||
|
DeviceObject, Irp, status));
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ChangerFdoSetWmiDataItem(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN ULONG GuidIndex,
|
|||
|
IN ULONG DataItemId,
|
|||
|
IN ULONG BufferSize,
|
|||
|
IN PUCHAR Buffer
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback into the driver to query for the contents of
|
|||
|
a data block. When the driver has finished filling the data block it
|
|||
|
must call ClassWmiCompleteRequest to complete the irp. The driver can
|
|||
|
return STATUS_PENDING if the irp cannot be completed immediately.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject is the device whose data block is being queried
|
|||
|
|
|||
|
Irp is the Irp that makes this request
|
|||
|
|
|||
|
GuidIndex is the index into the list of guids provided when the
|
|||
|
device registered
|
|||
|
|
|||
|
DataItemId has the id of the data item being set
|
|||
|
|
|||
|
BufferSize has the size of the data item passed
|
|||
|
|
|||
|
Buffer has the new values for the data item
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS returned by ClassWmiCompleteRequest
|
|||
|
STATUS_WMI_READ_ONLY if the datablock cannot be modified.
|
|||
|
STATUS_WMI_GUID_NOT_FOUND if an invalid guid index is passed
|
|||
|
|
|||
|
-*/
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_WMI_READ_ONLY;
|
|||
|
|
|||
|
DebugPrint((3,
|
|||
|
"TapeSetWmiDataItem, Device %p, Irp %p, GuiIndex %d",
|
|||
|
" BufferSize %#x Buffer %p\n",
|
|||
|
DeviceObject, Irp,
|
|||
|
GuidIndex, DataItemId,
|
|||
|
BufferSize, Buffer));
|
|||
|
|
|||
|
if (GuidIndex > ChangerProblemDevErrorGuid) {
|
|||
|
status = STATUS_WMI_GUID_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
status = ClassWmiCompleteRequest(DeviceObject,
|
|||
|
Irp,
|
|||
|
status,
|
|||
|
0,
|
|||
|
IO_NO_INCREMENT);
|
|||
|
|
|||
|
DebugPrint((3, "TapeSetWmiDataItem Device %p, Irp %p returns %lx\n",
|
|||
|
DeviceObject, Irp, status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|