//****************************************************************************
// File NTDEMOCL.C
//
// Windows NT kernel mode sample client
//
// Copyright (c) APSoft., 1993-2000.
// All rights reserved.
//
//****************************************************************************
#include <ntddk.h> // Windows NT DDK main include file
#include <cs_sdk.h> // Include CS definitions
#define NT_DEVICE_NAME L"\\Device\\NTDEMOCL"
#define DOS_DEVICE_NAME L"\\DosDevices\\CW_CLIENT"
CS_HND ClientHandle = 0; // Client handle
//****************************************************************************
// --- CallBackFunction ---
//
// Purpose: Callback function to be provided by RegisterClient. Print number
// of callback function in the Kernel Debugger and returns SUCCESS
// to caller.
// Input: CB_REGS * Parameters - Pointer to callback register structure.
// Output: none
// Written: by Timo Geusch 2/25/97
//****************************************************************************
void __cdecl CallBackFunction(CB_REGS *Parameters)
{
if (Parameters != NULL) // Validate pointer
{
switch (Parameters->wStatus)
{
// Only MTD drivers need to answer MTD request. This driver should
// never receive such request and therefore case below is added only
// for security.
case MTD_REQUEST:
Parameters->wStatus = BAD_FUNCTION;
break;
// Add events to process there...
// Please return status SUCCESS for all unprocessed events
default:
DbgPrint("NTDEMOCL callback function called with function code %u\n",
Parameters->wFunction);
Parameters->wStatus = SUCCESS;
break;
} // switch()...
}
}
//****************************************************************************
// --- DoCardServices ---
//
// Purpose: Call Windows NT Card Services driver. Provides the same call inter-
// face as the DOS/Win16 function does.
// Input: enum CS_SUBFUNC SubFunc - CS function to call; see file cs_sdk.h
// CS_HND * pHandle - Pointer to client handle storage
// void * * fp - Pointer to Misc pointer storage
// WORD wArgLen - Argument length
// void * pArg - Pointer to Argument buffer
// Output: enum RETCODE - Return code
// Written: by Timo Geusch 2/25/97
//****************************************************************************
enum RETCODE DoCardServices(enum CS_SUBFUNC SubFunc, WORD *pHandle,
void * * fp, WORD wArgLen, void * pArg)
{
enum RETCODE retcode = GENERAL_FAILURE;
// Assumes error
PDEVICE_OBJECT pCS = 0; // Pointer to CS device object
PFILE_OBJECT pFileObjCS = 0; // Pointer to CS file object
DWORD dwParsSize; // Size of IOCTL parameters block
NT_CSPARS *pCSParsIn; // Pointer to IOCTL parameters block
NT_CSPARS *pCSParsOut; // Pointer to IOCTL parameters block
UNICODE_STRING uszCSDeviceName; // Unicode name of CS Device
//-------------------------- Attach to CS driver -----------------------------
// Note: In real case you will attach to CS in DriverEntry routine and
// the code below will be moved there
RtlInitUnicodeString(&uszCSDeviceName, L"\\Device\\" CS_DEVICE_NAME);
if (IoGetDeviceObjectPointer(&uszCSDeviceName, FILE_ANY_ACCESS,
&pFileObjCS, &pCS) != STATUS_SUCCESS)
{
pCS = 0; // Just for be sure
return retcode; // Return error code
}
//-------------------- Allocate communication buffers ------------------------
dwParsSize = sizeof(NT_CSPARS) +wArgLen;// Size of parameters for the
// request
pCSParsIn = ExAllocatePool(NonPagedPool, dwParsSize);
pCSParsOut = ExAllocatePool(NonPagedPool, dwParsSize);
//----------- Copy request parameters to communication buffer ----------------
if (pCSParsIn && pCSParsOut)
{
RtlZeroMemory(pCSParsIn, dwParsSize);
pCSParsIn->SubFunc = SubFunc;
if (pHandle != NULL) // Security checking
pCSParsIn->Handle = *pHandle;
if (fp != NULL) // Security checking
pCSParsIn->fp = *fp;
pCSParsIn->dwArgBufferLength = wArgLen;
if (wArgLen && pArg != NULL) // Security checking
RtlCopyMemory(&pCSParsIn->ArgBuffer[0], pArg, wArgLen);
//------------------------- Build IRP for CS call ----------------------------
if (pCS != 0)
{
PIRP pIrp = 0; // Pointer to Request Structure
IO_STATUS_BLOCK IOStatus; // Status block
KEVENT Event; // Event Object
KeInitializeEvent(&Event, NotificationEvent, FALSE );
// Initialize Event Object
pIrp = IoBuildDeviceIoControlRequest(
(ULONG)IOCTL_PCMCIA_CardServices,
pCS, // Command to process
pCSParsIn, // Input parameter buffer
dwParsSize, // Size of data transferred
pCSParsOut, // Output parameter buffer
dwParsSize, // Size of return buffer
FALSE, // No overlapped I/O
&Event, //
&IOStatus); //
//-------------------------- Call Card Services ------------------------------
if (pIrp != NULL) // IRP was allocated successfully
{ // Execute CS request
// Note: IoCallDriver not necessary returns STATUS_SUCCESS.
// However NT_SUCCESS() returns TRUE, if value is correct.
if (NT_SUCCESS(IoCallDriver(pCS, pIrp)))
retcode = pCSParsOut->retcode;
}
}
//----------- Copy request parameters from communication buffer --------------
if(retcode == SUCCESS)
{
if (pHandle != NULL) // Security checking
*pHandle = (WORD)pCSParsOut->Handle;
if (fp != NULL) // Security checking
*fp = pCSParsOut->fp;
if (wArgLen && pArg != NULL) // Security checking
RtlCopyMemory(pArg, &pCSParsOut->ArgBuffer[0], wArgLen);
}
}
//-------------------- Free used communication buffers -----------------------
if (pCSParsIn)
ExFreePool(pCSParsIn);
if (pCSParsOut)
ExFreePool(pCSParsOut);
//----------------------- Detach from Card Services --------------------------
// Note: In real case you will dettach from CS in DriverUnload routine and
// the code below will be moved there
if (pCS != 0 && pFileObjCS != 0)
{
ObDereferenceObject(pFileObjCS);
}
return retcode; // Status returned
}
//****************************************************************************
// --- DemoOpenClose ---
//
// Purpose: This standard NT routine called by OS in response to Open/Close
// requests. This code is copied from NT DDK sample of generic driver
// Input: IN PDEVICE_OBJECT DeviceObject - Pointer to device object
// IN PIRP Irp - Pointer to IRP packet
// Output: NTSTATUS - Always STATUS_SUCCESS
//****************************************************************************
NTSTATUS DemoOpenClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
//
// No need to do anything.
//
//
// Fill these in before calling IoCompleteRequest.
//
// DON'T get cute and try to use the status field of
// the irp in the return status. That IRP IS GONE as
// soon as you call IoCompleteRequest.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
//****************************************************************************
// --- DemoUnload ---
//
// Purpose: This code is copied from NT DDK sample of generic driver. NT call
// this routine during driver unload
// Input: IN PDRIVER_OBJECT DriverObject - Pointer to the driver object
// Output: none
// Note: Typical CS aware driver will deregister client and detach from CS
// in this routine. This sample just deregister the client. Please
// refer to DoCardServices() function above for code which detach from
// CS
//****************************************************************************
VOID DemoUnload(IN PDRIVER_OBJECT DriverObject)
{
void * Argument = NULL;
UNICODE_STRING uniWin32NameString;
//------------------------- Deregister the client ----------------------------
if (DoCardServices(CS_DEREGCLIENT, &ClientHandle, &Argument, 0, NULL)
== SUCCESS)
DbgPrint("NTDEMOCL: CS Client successfully deregistered\n");
else
DbgPrint("NTDEMOCL: Unable to deregister CS Client. "
"You probably did not release all client resources\n");
//--------------------------- End of Award code ------------------------------
//
// Create counted string version of our Win32 device name.
//
RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME);
//
// Delete the link from our device name to a name in the Win32 namespace.
//
IoDeleteSymbolicLink( &uniWin32NameString );
//
// Finally delete our device object
//
IoDeleteDevice( DriverObject->DeviceObject );
}
//****************************************************************************
// --- DriverEntry ---
//
// Purpose: This code is copied from NT DDK sample of generic driver. NT call
// this routine during driver load
// Input: IN PDRIVER_OBJECT DriverObject - Pointer to the driver object
// IN PUNICODE_STRING RegistryPath - Pointer to registry path
// Output: NTSTATUS - NT status code
// Written: by Alexei A. Piatetsky 24-07-97
//****************************************************************************
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
//------------------------ Award added code begin ----------------------------
RClARGS RegisterClient; // Card Services call structure
CSINFO CSInfo; // Card Services call structure
void * pCallBackFunction = CallBackFunction;
// Card Services callback routine
void * fp = NULL; // Card Services call dummy argument
CS_HND h = 0; // Card Services call dummy argument
//------------------------- Award added code end -----------------------------
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS status;
UNICODE_STRING uniNtNameString;
UNICODE_STRING uniWin32NameString;
//
// Create counted string version of our device name.
//
RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME );
//
// Create the device object
//
status = IoCreateDevice(
DriverObject,
0, // We don't use a device extension
&uniNtNameString,
FILE_DEVICE_UNKNOWN,
0, // No standard device characteristics
FALSE, // This isn't an exclusive device
&deviceObject
);
if ( NT_SUCCESS(status) )
{
//
// Create dispatch points for create/open, close, unload.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = DemoOpenClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DemoOpenClose;
DriverObject->DriverUnload = DemoUnload;
//
// Create counted string version of our Win32 device name.
//
RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
//
// Create a link from our device name to a name in the Win32 namespace.
//
status = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString );
if (!NT_SUCCESS(status))
{
IoDeleteDevice( DriverObject->DeviceObject );
}
else
{
//////////////////////////////////////////////////////////////////////////////
//------------------------ Award added code begin ----------------------------
//////////////////////////////////////////////////////////////////////////////
//----------------------- Check for CS installation --------------------------
RtlZeroMemory(&CSInfo, sizeof(CSINFO));
if (DoCardServices(CS_GETCSINFO, &h, &fp, sizeof(CSINFO), &CSInfo)
== SUCCESS)
{
// Check for valid CS signature
if (CSInfo.sigCS == 'SC')
{
DbgPrint("NTDEMOCL: Detect Card Services driver\n");
DbgPrint(" Driver revision: %X.%02X\n",
CSInfo.wRevision / 0x100, CSInfo.wRevision % 0x100);
DbgPrint(" Compliance level: %X.%02X\n",
CSInfo.wRelease / 0x100, CSInfo.wRelease % 0x100);
DbgPrint(" Installed Sockets: %u\n",
CSInfo.wNumSockets);
DbgPrint(" Max functions/socket: %u\n",
CSInfo.wFuncsPerSkt);
DbgPrint(" Card Services Vendor: %s\n",
CSInfo.szVendor);
//-------------------------- Register CS client ------------------------------
// Note: This code register I/O client which receives
// notifications for all events. Please modify client
// attributes and event mask below in order to match
// your requirements
RegisterClient.wAttr = 0x1C;
// Register I/O client, wants to be
// notified of ALL card insertions
RegisterClient.wEventMask = 0x0FFF;
// Notify of all events
RegisterClient.dwDataOff = 0; // No pointer to data
RegisterClient.wClientData = 0;
RegisterClient.wCSLevel = 0x0500;
// Only works with CS level 5.00
// and above
if (DoCardServices(CS_REGCLIENT, &ClientHandle,
&pCallBackFunction, sizeof(RClARGS),
&RegisterClient) == SUCCESS)
DbgPrint("NTDEMOCL: CS Client registered. "
"Client handle = %u\n", ClientHandle);
else
DbgPrint("NTDEMOCL: Unable to register CS client\n");
}
else
DbgPrint("NTDEMOCL: Invalid Card Services Info\n");
}
else
DbgPrint("NTDEMOCL: Fail to retrieve Card Services Info\n");
}
}
return status;
}