//**************************************************************************** // 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; }