/***************************************************************************** @doc INT EXT ****************************************************************************** * $ProjectName: $ * $ProjectRevision: $ *----------------------------------------------------------------------------- * $Source: z:/pr/cmbs0/sw/sccmn50m.ms/rcs/sccmnt5.c $ * $Revision: 1.7 $ *----------------------------------------------------------------------------- * $Author: WFrischauf $ *----------------------------------------------------------------------------- * History: see EOF *----------------------------------------------------------------------------- * * Copyright © OMNIKEY AG ******************************************************************************/ #include #include "sccmn50m.h" // // We do not need these functions after init anymore // #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGEABLE, SCCMN50M_AddDevice) #pragma alloc_text(PAGEABLE, SCCMN50M_CreateDevice) #if DBG #pragma optimize ("", off) #endif BOOLEAN DeviceSlot[MAXIMUM_SMARTCARD_READERS]; /***************************************************************************** Routine Description: This routine is called at system initialization time to initialize this driver. Arguments: DriverObject - Supplies the driver object. RegistryPath - Supplies the registry path for this driver. Return Value: STATUS_SUCCESS - We could initialize at least one device. STATUS_NO_SUCH_DEVICE - We could not initialize even one device. *****************************************************************************/ NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; ULONG device; SmartcardDebug( DEBUG_TRACE, ("%s!DriverEntry: Enter - %s %s\n", DRIVER_NAME, __DATE__, __TIME__) ) // Initialize the Driver Object with driver's entry points DriverObject->DriverUnload = SCCMN50M_DriverUnload; DriverObject->MajorFunction[IRP_MJ_CREATE] = SCCMN50M_CreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = SCCMN50M_CreateClose; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SCCMN50M_Cleanup; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SCCMN50M_DeviceControl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = SCCMN50M_SystemControl; DriverObject->MajorFunction[IRP_MJ_PNP] = SCCMN50M_PnP; DriverObject->MajorFunction[IRP_MJ_POWER] = SCCMN50M_Power; DriverObject->DriverExtension->AddDevice = SCCMN50M_AddDevice; return status; } /***************************************************************************** Routine Description: Creates a new device without starting it. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_AddDevice ( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ) { NTSTATUS status; PDEVICE_OBJECT DeviceObject = NULL; UCHAR PropertyBuffer[1024]; ULONG ResultLength; PAGED_CODE(); SmartcardDebug( DEBUG_TRACE, ( "%s!AddDevice: Enter\n", DRIVER_NAME) ); try { PDEVICE_EXTENSION deviceExtension; // create a device instance status = SCCMN50M_CreateDevice( DriverObject, PhysicalDeviceObject, &DeviceObject ); if (status != STATUS_SUCCESS) { leave; } deviceExtension = DeviceObject->DeviceExtension; // and attach to the PDO ATTACHED_DEVICE_OBJECT = IoAttachDeviceToDeviceStack( DeviceObject, PhysicalDeviceObject ); ASSERT(ATTACHED_DEVICE_OBJECT != NULL); if (ATTACHED_DEVICE_OBJECT == NULL) { SmartcardLogError( DriverObject, SCCMN50M_CANT_CONNECT_TO_ASSIGNED_PORT, NULL, status ); status = STATUS_UNSUCCESSFUL; leave; } // register our new device status = IoRegisterDeviceInterface( PhysicalDeviceObject, &SmartCardReaderGuid, NULL, &deviceExtension->PnPDeviceName ); ASSERT(status == STATUS_SUCCESS); DeviceObject->Flags |= DO_BUFFERED_IO; DeviceObject->Flags |= DO_POWER_PAGABLE; DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } finally { if (status != STATUS_SUCCESS) { SCCMN50M_RemoveDevice(DeviceObject); } } SmartcardDebug( DEBUG_TRACE, ( "%s!AddDevice: Exit %x\n", DRIVER_NAME, status) ); return status; } /***************************************************************************** Routine Description: Trys to read the reader name from the registry Arguments: DriverObject context of call SmartcardExtension ptr to smartcard extension Return Value: none ******************************************************************************/ VOID SCCMN50M_SetVendorAndIfdName( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PSMARTCARD_EXTENSION SmartcardExtension ) { RTL_QUERY_REGISTRY_TABLE parameters[3]; UNICODE_STRING vendorNameU; ANSI_STRING vendorNameA; UNICODE_STRING ifdTypeU; ANSI_STRING ifdTypeA; HANDLE regKey = NULL; RtlZeroMemory (parameters, sizeof(parameters)); RtlZeroMemory (&vendorNameU, sizeof(vendorNameU)); RtlZeroMemory (&vendorNameA, sizeof(vendorNameA)); RtlZeroMemory (&ifdTypeU, sizeof(ifdTypeU)); RtlZeroMemory (&ifdTypeA, sizeof(ifdTypeA)); try { // // try to read the reader name from the registry // if that does not work, we will use the default // (hardcoded) name // if (IoOpenDeviceRegistryKey(PhysicalDeviceObject, PLUGPLAY_REGKEY_DEVICE, KEY_READ, ®Key) != STATUS_SUCCESS) { SmartcardDebug(DEBUG_ERROR, ("%s!SetVendorAndIfdName: IoOpenDeviceRegistryKey failed\n",DRIVER_NAME)); leave; } parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[0].Name = L"VendorName"; parameters[0].EntryContext = &vendorNameU; parameters[0].DefaultType = REG_SZ; parameters[0].DefaultData = &vendorNameU; parameters[0].DefaultLength = 0; parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[1].Name = L"IfdType"; parameters[1].EntryContext = &ifdTypeU; parameters[1].DefaultType = REG_SZ; parameters[1].DefaultData = &ifdTypeU; parameters[1].DefaultLength = 0; if (RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR) regKey, parameters, NULL, NULL) != STATUS_SUCCESS) { SmartcardDebug(DEBUG_ERROR, ("%s!SetVendorAndIfdName: RtlQueryRegistryValues failed\n",DRIVER_NAME)); leave; } if (RtlUnicodeStringToAnsiString(&vendorNameA,&vendorNameU,TRUE) != STATUS_SUCCESS) { SmartcardDebug(DEBUG_ERROR, ("%s!SetVendorAndIfdName: RtlUnicodeStringToAnsiString failed\n",DRIVER_NAME)); leave; } if (RtlUnicodeStringToAnsiString(&ifdTypeA,&ifdTypeU,TRUE) != STATUS_SUCCESS) { SmartcardDebug(DEBUG_ERROR, ("%s!SetVendorAndIfdName: RtlUnicodeStringToAnsiString failed\n",DRIVER_NAME)); leave; } if (vendorNameA.Length == 0 || vendorNameA.Length > MAXIMUM_ATTR_STRING_LENGTH || ifdTypeA.Length == 0 || ifdTypeA.Length > MAXIMUM_ATTR_STRING_LENGTH) { SmartcardDebug(DEBUG_ERROR, ("%s!SetVendorAndIfdName: vendor name or ifdtype not found or to long\n",DRIVER_NAME)); leave; } RtlCopyMemory(SmartcardExtension->VendorAttr.VendorName.Buffer, vendorNameA.Buffer, vendorNameA.Length); SmartcardExtension->VendorAttr.VendorName.Length = vendorNameA.Length; RtlCopyMemory(SmartcardExtension->VendorAttr.IfdType.Buffer, ifdTypeA.Buffer, ifdTypeA.Length); SmartcardExtension->VendorAttr.IfdType.Length = ifdTypeA.Length; SmartcardDebug(DEBUG_DRIVER, ("%s!SetVendorAndIfdName: overwritting vendor name and ifdtype\n",DRIVER_NAME)); } finally { if (vendorNameU.Buffer != NULL) { RtlFreeUnicodeString(&vendorNameU); } if (vendorNameA.Buffer != NULL) { RtlFreeAnsiString(&vendorNameA); } if (ifdTypeU.Buffer != NULL) { RtlFreeUnicodeString(&ifdTypeU); } if (ifdTypeA.Buffer != NULL) { RtlFreeAnsiString(&ifdTypeA); } if (regKey != NULL) { ZwClose (regKey); } } } /***************************************************************************** Routine Description: This routine creates an object for the physical device specified and sets up the deviceExtension. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_CreateDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PDEVICE_OBJECT *DeviceObject ) { PDEVICE_EXTENSION deviceExtension; NTSTATUS status = STATUS_SUCCESS; ULONG deviceInstance; PREADER_EXTENSION readerExtension; PSMARTCARD_EXTENSION smartcardExtension; UNICODE_STRING DriverID; RTL_QUERY_REGISTRY_TABLE ParamTable[2]; UNICODE_STRING RegistryPath; DWORD dwStart; UNICODE_STRING Tmp; WCHAR Buffer[64]; // this is a list of our supported data rates PAGED_CODE(); *DeviceObject = NULL; for ( deviceInstance = 0;deviceInstance < MAXIMUM_SMARTCARD_READERS;deviceInstance++ ) { if (DeviceSlot[deviceInstance] == FALSE) { DeviceSlot[deviceInstance] = TRUE; break; } } if (deviceInstance == MAXIMUM_SMARTCARD_READERS) { SmartcardLogError( DriverObject, SCCMN50M_CANT_CREATE_MORE_DEVICES, NULL, 0 ); return STATUS_INSUFFICIENT_RESOURCES; } // // construct the device name // DriverID.Buffer = Buffer; DriverID.MaximumLength = sizeof(Buffer); DriverID.Length = 0; RtlInitUnicodeString(&Tmp,CARDMAN_DEVICE_NAME); RtlCopyUnicodeString(&DriverID,&Tmp); DriverID.Buffer[(DriverID.Length)/sizeof(WCHAR)-1] = L'0' + (WCHAR)deviceInstance; // Create the device object status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &DriverID, FILE_DEVICE_SMARTCARD, 0, FALSE, DeviceObject ); if (status != STATUS_SUCCESS) { SmartcardLogError( DriverObject, SCCMN50M_CANT_CREATE_DEVICE, NULL, 0 ); return status; } SmartcardDebug( DEBUG_DRIVER, ( "%s!CreateDevice: Device created\n", DRIVER_NAME) ); // set up the device extension. deviceExtension = (*DeviceObject)->DeviceExtension; deviceExtension->DeviceInstance = deviceInstance; smartcardExtension = &deviceExtension->SmartcardExtension; // Used for stop / start notification KeInitializeEvent( &deviceExtension->ReaderStarted, NotificationEvent, FALSE ); // This event signals that the serial driver has been closed KeInitializeEvent( &deviceExtension->SerialCloseDone, NotificationEvent, TRUE ); // Used to keep track of open close calls KeInitializeEvent( &deviceExtension->ReaderClosed, NotificationEvent, TRUE ); KeInitializeSpinLock(&deviceExtension->SpinLock); // Allocate data struct space for smart card reader smartcardExtension->ReaderExtension = ExAllocatePool( NonPagedPool, sizeof(READER_EXTENSION) ); if (smartcardExtension->ReaderExtension == NULL) { SmartcardLogError( DriverObject, SCCMN50M_NO_MEMORY, NULL, 0 ); return STATUS_INSUFFICIENT_RESOURCES; } readerExtension = smartcardExtension->ReaderExtension; RtlZeroMemory(readerExtension, sizeof(READER_EXTENSION)); // ---------------------------------------------- // initialize mutex // ---------------------------------------------- KeInitializeMutex(&smartcardExtension->ReaderExtension->CardManIOMutex,0L); // Write the version of the lib we use to the smartcard extension smartcardExtension->Version = SMCLIB_VERSION; smartcardExtension->SmartcardRequest.BufferSize = smartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE; // // Now let the lib allocate the buffer for data transmission // We can either tell the lib how big the buffer should be // by assigning a value to BufferSize or let the lib // allocate the default size // status = SmartcardInitialize(smartcardExtension); if (status != STATUS_SUCCESS) { SmartcardLogError( DriverObject, (smartcardExtension->OsData ? SCCMN50M_WRONG_LIB_VERSION : SCCMN50M_NO_MEMORY), NULL, 0 ); return status; } // Save deviceObject smartcardExtension->OsData->DeviceObject = *DeviceObject; // Set up call back functions smartcardExtension->ReaderFunction[RDF_TRANSMIT] = SCCMN50M_Transmit; smartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = SCCMN50M_SetProtocol; smartcardExtension->ReaderFunction[RDF_CARD_POWER] = SCCMN50M_CardPower; smartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = SCCMN50M_CardTracking; smartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = SCCMN50M_IoCtlVendor; SCCMN50M_InitializeSmartcardExtension(smartcardExtension,deviceInstance); // try to overwrite with registry values SCCMN50M_SetVendorAndIfdName(PhysicalDeviceObject, smartcardExtension); // save the current power state of the reader readerExtension->ReaderPowerState = PowerReaderWorking; return STATUS_SUCCESS; } /***************************************************************************** Routine Description: Open the serial device, start card tracking and register our device interface. If any of the calls here fails we don't care to rollback since a stop will be called later which we then use to clean up. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_StartDevice( IN PDEVICE_OBJECT DeviceObject ) { NTSTATUS status; PIRP irp; SmartcardDebug( DEBUG_TRACE, ( "%s!StartDevice: Enter\n", DRIVER_NAME) ); irp = IoAllocateIrp( (CCHAR) (DeviceObject->StackSize + 1), FALSE ); ASSERT(irp != NULL); if (irp == NULL) { return STATUS_NO_MEMORY; } _try { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION pSmartcardExtension = &deviceExtension->SmartcardExtension; PIO_STACK_LOCATION irpStack; HANDLE handle = 0; IO_STATUS_BLOCK ioStatusBlock; // // Open the underlying serial driver. // This is necessary for two reasons: // a) The serial driver can't be used without opening it // b) The call will go through serenum first which informs // it to stop looking/polling for new devices. // irp->UserIosb = &ioStatusBlock; IoSetNextIrpStackLocation(irp); irpStack = IoGetCurrentIrpStackLocation(irp); irpStack->MajorFunction = IRP_MJ_CREATE; irpStack->Parameters.Create.Options = 0; irpStack->Parameters.Create.ShareAccess = 0; irpStack->Parameters.Create.FileAttributes = 0; irpStack->Parameters.Create.EaLength = 0; status = SCCMN50M_CallSerialDriver( ATTACHED_DEVICE_OBJECT, irp ); if (status != STATUS_SUCCESS) { leave; } KeClearEvent(&deviceExtension->SerialCloseDone); pSmartcardExtension->SmartcardReply.BufferLength = pSmartcardExtension->SmartcardReply.BufferSize; pSmartcardExtension->SmartcardRequest.BufferLength = 0; pSmartcardExtension->ReaderExtension->SerialIoControlCode = IOCTL_SERENUM_GET_PORT_NAME; status = SCCMN50M_SerialIo(pSmartcardExtension); // // Channel id which the reader is using, // in our case the Portnumber // WCHAR are used. e.g. COM3 pSmartcardExtension->ReaderCapabilities.Channel = pSmartcardExtension->SmartcardReply.Buffer[6] -'0'; status = SCCMN50M_InitializeCardMan(&deviceExtension->SmartcardExtension); if (status != STATUS_SUCCESS) { leave; } status = SCCMN50M_StartCardTracking(deviceExtension); if (status != STATUS_SUCCESS) { leave; } status = IoSetDeviceInterfaceState( &deviceExtension->PnPDeviceName, TRUE ); if (status != STATUS_SUCCESS) { leave; } deviceExtension->IoCount = 0; KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was set\n",DRIVER_NAME)); } _finally { if (status == STATUS_SHARED_IRQ_BUSY) { SmartcardLogError( DeviceObject, SCCMN50M_IRQ_BUSY, NULL, status ); } IoFreeIrp(irp); } SmartcardDebug( DEBUG_TRACE, ( "%s!StartDevice: Exit\n", DRIVER_NAME) ); return status; } /***************************************************************************** Routine Description: Finishes card tracking requests and closes the connection to the serial driver. Arguments: Return Value: *****************************************************************************/ VOID SCCMN50M_StopDevice( IN PDEVICE_EXTENSION DeviceExtension ) { NTSTATUS status; PUCHAR requestBuffer; PSMARTCARD_EXTENSION smartcardExtension; SmartcardDebug( DEBUG_TRACE, ( "%s!StopDevice: Enter\n", DRIVER_NAME) ); if (KeReadStateEvent(&DeviceExtension->SerialCloseDone) == 0l) { smartcardExtension = &DeviceExtension->SmartcardExtension; SCCMN50M_StopCardTracking(DeviceExtension); SCCMN50M_CloseSerialDriver (smartcardExtension->OsData->DeviceObject); // now wait until the connetion to serial is closed status = KeWaitForSingleObject( &DeviceExtension->SerialCloseDone, Executive, KernelMode, FALSE, NULL ); ASSERT(status == STATUS_SUCCESS); } SmartcardDebug( DEBUG_TRACE, ( "%s!StopDevice: Exit\n", DRIVER_NAME) ); } NTSTATUS SCCMN50M_SystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++ --*/ { PDEVICE_EXTENSION DeviceExtension; NTSTATUS status = STATUS_SUCCESS; DeviceExtension = DeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject, Irp); return status; } /***************************************************************************** Routine Description: This is our IOCTL dispatch function Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_DeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; NTSTATUS status; KIRQL irql; PIO_STACK_LOCATION irpSp; SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Enter\n",DRIVER_NAME)); irpSp = IoGetCurrentIrpStackLocation(Irp); PAGED_CODE(); #if DBG switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SMARTCARD_EJECT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_EJECT")); break; case IOCTL_SMARTCARD_GET_ATTRIBUTE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_ATTRIBUTE")); break; case IOCTL_SMARTCARD_GET_LAST_ERROR: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_LAST_ERROR")); break; case IOCTL_SMARTCARD_GET_STATE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_STATE")); break; case IOCTL_SMARTCARD_IS_ABSENT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_ABSENT")); break; case IOCTL_SMARTCARD_IS_PRESENT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_PRESENT")); break; case IOCTL_SMARTCARD_POWER: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_POWER")); break; case IOCTL_SMARTCARD_SET_ATTRIBUTE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_ATTRIBUTE")); break; case IOCTL_SMARTCARD_SET_PROTOCOL: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_PROTOCOL")); break; case IOCTL_SMARTCARD_SWALLOW: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SWALLOW")); break; case IOCTL_SMARTCARD_TRANSMIT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_TRANSMIT")); break; default: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceControl: %s\n", DRIVER_NAME, "Vendor specific or unexpected IOCTL")); break; } #endif if (KeReadStateEvent(&deviceExtension->SerialCloseDone) != 0l) { // Device has been removed // fail the call status = STATUS_DEVICE_REMOVED; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } status = SmartcardAcquireRemoveLock(&deviceExtension->SmartcardExtension); if (status != STATUS_SUCCESS) { // the device has been removed. Fail the call status = STATUS_DEVICE_REMOVED; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; IoCompleteRequest(Irp, IO_NO_INCREMENT); SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Exit %x\n",DRIVER_NAME,status)); return status; } KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); if (deviceExtension->IoCount < 0) { SmartcardDebug(DEBUG_DRIVER, ("%s!waiting for Event ReaderStarted\n",DRIVER_NAME)); KeReleaseSpinLock(&deviceExtension->SpinLock, irql); status = KeWaitForSingleObject( &deviceExtension->ReaderStarted, Executive, KernelMode, FALSE, NULL ); ASSERT(status == STATUS_SUCCESS); KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); } ASSERT(deviceExtension->IoCount >= 0); deviceExtension->IoCount++; KeReleaseSpinLock(&deviceExtension->SpinLock, irql); // wait for update thread KeWaitForSingleObject( &deviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, Executive, KernelMode, FALSE, NULL ); status = SCCMN50M_UpdateCurrentState(&(deviceExtension->SmartcardExtension)); status = SmartcardDeviceControl( &(deviceExtension->SmartcardExtension), Irp ); // release for update thread KeReleaseMutex( &deviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, FALSE ); SmartcardReleaseRemoveLock(&deviceExtension->SmartcardExtension); KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); deviceExtension->IoCount--; ASSERT(deviceExtension->IoCount >= 0); KeReleaseSpinLock(&deviceExtension->SpinLock, irql); SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Exit %x\n",DRIVER_NAME,status)); return status; } /***************************************************************************** Routine Description: This function closes the connection to the serial driver when the reader has been removed (unplugged). This function runs as a system thread at IRQL == PASSIVE_LEVEL. It waits for the remove event that is set by the IoCompletionRoutine Arguments: Return Value: *****************************************************************************/ VOID SCCMN50M_CloseSerialDriver( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; NTSTATUS status; PIRP irp; PIO_STACK_LOCATION irpStack; IO_STATUS_BLOCK ioStatusBlock; SmartcardDebug( DEBUG_TRACE, ( "%s!CloseSerialDriver: Enter\n", DRIVER_NAME) ); // // first mark this device as 'gone'. // This will prevent that someone can re-open the device // status = IoSetDeviceInterfaceState( &deviceExtension->PnPDeviceName, FALSE ); irp = IoAllocateIrp( (CCHAR) (DeviceObject->StackSize + 1), FALSE ); ASSERT(irp != NULL); if (irp) { SmartcardDebug( DEBUG_DRIVER, ( "%s!CloseSerialDriver: Sending IRP_MJ_CLOSE\n", DRIVER_NAME) ); IoSetNextIrpStackLocation(irp); // // We send down a close to the serial driver. This close goes // through serenum first which will trigger it to start looking // for changes on the com-port. Since our device is gone it will // call the device removal event of our PnP dispatch. // irp->UserIosb = &ioStatusBlock; irpStack = IoGetCurrentIrpStackLocation( irp ); irpStack->MajorFunction = IRP_MJ_CLOSE; status = SCCMN50M_CallSerialDriver( ATTACHED_DEVICE_OBJECT, irp ); ASSERT(status == STATUS_SUCCESS); IoFreeIrp(irp); } // now 'signal' that we closed the serial driver KeSetEvent(&deviceExtension->SerialCloseDone, 0, FALSE); SmartcardDebug( DEBUG_TRACE, ( "%s!CloseSerialDriver: Exit\n", DRIVER_NAME) ); } /***************************************************************************** Routine Description: Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_IoCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event ) { UNREFERENCED_PARAMETER (DeviceObject); if (Irp->Cancel) { Irp->IoStatus.Status = STATUS_CANCELLED; } else { Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED; } KeSetEvent (Event, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } /***************************************************************************** Routine Description: Send an Irp to the serial driver. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_CallSerialDriver( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; KEVENT Event; // Copy our stack location to the next. IoCopyCurrentIrpStackLocationToNext(Irp); // // initialize an event for process synchronization. The event is passed // to our completion routine and will be set when the serial driver is done // KeInitializeEvent( &Event, NotificationEvent, FALSE ); // Our IoCompletionRoutine sets only our event IoSetCompletionRoutine ( Irp, SCCMN50M_IoCompletion, &Event, TRUE, TRUE, TRUE ); if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_POWER) { status = PoCallDriver(DeviceObject, Irp); } else { // Call the serial driver status = IoCallDriver(DeviceObject, Irp); } // Wait until the serial driver has processed the Irp if (status == STATUS_PENDING) { status = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); ASSERT (STATUS_SUCCESS == status); status = Irp->IoStatus.Status; } return status; } /***************************************************************************** Routine Description: Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_PnP( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PUCHAR requestBuffer; NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension; PREADER_EXTENSION readerExtension = smartcardExtension->ReaderExtension; PDEVICE_OBJECT AttachedDeviceObject; PIO_STACK_LOCATION irpStack; IO_STATUS_BLOCK ioStatusBlock; BOOLEAN deviceRemoved = FALSE, irpSkipped = FALSE; KIRQL irql; PDEVICE_CAPABILITIES DeviceCapabilities; PAGED_CODE(); SmartcardDebug( DEBUG_TRACE, ( "%s!PnPDeviceControl: Enter\n", DRIVER_NAME) ); status = SmartcardAcquireRemoveLock(smartcardExtension); ASSERT(status == STATUS_SUCCESS); if (status != STATUS_SUCCESS) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } AttachedDeviceObject = ATTACHED_DEVICE_OBJECT; irpStack = IoGetCurrentIrpStackLocation(Irp); // Now look what the PnP manager wants... switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_START_DEVICE\n", DRIVER_NAME) ); // We have to call the underlying driver first status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); ASSERT(NT_SUCCESS(status)); if (NT_SUCCESS(status)) { status = SCCMN50M_StartDevice(DeviceObject); } break; case IRP_MN_QUERY_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_STOP_DEVICE\n", DRIVER_NAME) ); KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); if (deviceExtension->IoCount > 0) { // we refuse to stop if we have pending io KeReleaseSpinLock(&deviceExtension->SpinLock, irql); status = STATUS_DEVICE_BUSY; } else { // stop processing requests deviceExtension->IoCount = -1; KeClearEvent(&deviceExtension->ReaderStarted); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was cleared\n",DRIVER_NAME)); KeReleaseSpinLock(&deviceExtension->SpinLock, irql); status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); } break; case IRP_MN_CANCEL_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_CANCEL_STOP_DEVICE\n", DRIVER_NAME) ); status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); if (status == STATUS_SUCCESS) { // we can continue to process requests deviceExtension->IoCount = 0; KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was set\n",DRIVER_NAME)); } break; case IRP_MN_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_STOP_DEVICE\n", DRIVER_NAME) ); SCCMN50M_StopDevice(deviceExtension); // // we don't do anything since a stop is only used // to reconfigure hw-resources like interrupts and io-ports // status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); break; case IRP_MN_QUERY_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_REMOVE_DEVICE\n", DRIVER_NAME) ); // disable the interface (and ignore possible errors) IoSetDeviceInterfaceState(&deviceExtension->PnPDeviceName, FALSE); // now look if someone is currently connected to us if (KeReadStateEvent(&deviceExtension->ReaderClosed) == 0l) { // // someone is connected, fail the call // we will enable the device interface in // IRP_MN_CANCEL_REMOVE_DEVICE again // status = STATUS_UNSUCCESSFUL; break; } // pass the call to the next driver in the stack status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); break; case IRP_MN_CANCEL_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_CANCEL_REMOVE_DEVICE\n", DRIVER_NAME) ); status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); if (status == STATUS_SUCCESS) { status = IoSetDeviceInterfaceState(&deviceExtension->PnPDeviceName, TRUE); ASSERT(status == STATUS_SUCCESS); } break; case IRP_MN_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_REMOVE_DEVICE\n", DRIVER_NAME) ); SCCMN50M_RemoveDevice(DeviceObject); status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); deviceRemoved = TRUE; break; // --------------------- // IRP_MN_QUERY_CAPABILITIES // --------------------- case IRP_MN_QUERY_CAPABILITIES: SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_CAPABILITIES\n", DRIVER_NAME)); // // Get the packet. // DeviceCapabilities=irpStack->Parameters.DeviceCapabilities.Capabilities; if (DeviceCapabilities->Version == 1 && DeviceCapabilities->Size == sizeof(DEVICE_CAPABILITIES)) { // // Set the capabilities. // // We cannot wake the system. DeviceCapabilities->SystemWake = PowerSystemUnspecified; DeviceCapabilities->DeviceWake = PowerDeviceUnspecified; // We have no latencies DeviceCapabilities->D1Latency = 0; DeviceCapabilities->D2Latency = 0; DeviceCapabilities->D3Latency = 0; // No locking or ejection DeviceCapabilities->LockSupported = FALSE; DeviceCapabilities->EjectSupported = FALSE; // Device can be physically removed. DeviceCapabilities->Removable = TRUE; // No docking device DeviceCapabilities->DockDevice = FALSE; // Device can not be removed any time // it has a removable media DeviceCapabilities->SurpriseRemovalOK = FALSE; } // // Pass the IRP down // status = SCCMN50M_CallSerialDriver(AttachedDeviceObject, Irp); break; // end, case IRP_MN_QUERY_CAPABILITIES default: #if DBG switch (irpStack->MinorFunction) { case IRP_MN_QUERY_DEVICE_RELATIONS : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_DEVICE_RELATIONS\n", DRIVER_NAME)); break; case IRP_MN_QUERY_INTERFACE : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_INTERFACE\n", DRIVER_NAME)); break; case IRP_MN_QUERY_CAPABILITIES : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_CAPABILITIES\n", DRIVER_NAME)); break; case IRP_MN_QUERY_RESOURCES : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_RESOURCES\n", DRIVER_NAME)); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_RESOURCE_REQUIEREMENTS\n", DRIVER_NAME)); break; case IRP_MN_QUERY_DEVICE_TEXT : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_QUERY_DEVICE_TEXT\n", DRIVER_NAME)); break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n", DRIVER_NAME)); break; default : case IRP_MN_READ_CONFIG : // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_READ_CONFIG\n", DRIVER_NAME)); break; // This is an Irp that is only useful for underlying drivers SmartcardDebug( DEBUG_DRIVER, ("%s!PnPDeviceControl: IRP_MN_...%lx\n", DRIVER_NAME, irpStack->MinorFunction)); break; } #endif IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(AttachedDeviceObject, Irp); irpSkipped = TRUE; break; } if (irpSkipped == FALSE) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } if (deviceRemoved == FALSE) { SmartcardReleaseRemoveLock(smartcardExtension); } SmartcardDebug( DEBUG_TRACE, ( "%s!PnPDeviceControl: Exit %lx\n", DRIVER_NAME, status) ); return status; } /***************************************************************************** Routine Description: This function is called when the underlying stacks completed the power transition. Arguments: Return Value: *****************************************************************************/ VOID SCCMN50M_SystemPowerCompletion( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatus ) { UNREFERENCED_PARAMETER (DeviceObject); UNREFERENCED_PARAMETER (MinorFunction); UNREFERENCED_PARAMETER (PowerState); UNREFERENCED_PARAMETER (IoStatus); KeSetEvent(Event, 0, FALSE); } /***************************************************************************** Routine Description: This routine is called after the underlying stack powered UP the serial port, so it can be used again. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_DevicePowerCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PSMARTCARD_EXTENSION SmartcardExtension ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); UCHAR pbAtrBuffer[MAXIMUM_ATR_LENGTH]; ULONG ulAtrLength; ULONG ulOldState; NTSTATUS status; KIRQL irql; SmartcardDebug(DEBUG_TRACE, ("%s!DevicePowerCompletion: Enter\n",DRIVER_NAME)); // We have to remember the old card state because // it is overwritten by SCCMN50M_InitializeCardMan ulOldState=SmartcardExtension->ReaderExtension->ulOldCardState; status = SCCMN50M_InitializeCardMan(SmartcardExtension); // Set back the previous state SmartcardExtension->ReaderExtension->ulOldCardState = ulOldState; if (status != STATUS_SUCCESS) { SmartcardDebug(DEBUG_DRIVER, ("%s!InitializeCardMan failed ! %lx\n",DRIVER_NAME,status)); } // // We issue a power request in because // we powered down the card before // //SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET; //status = SCCMN50M_PowerOn (SmartcardExtension,&ulAtrLength,pbAtrBuffer,sizeof(pbAtrBuffer)); // // If a card was present before power down or now there is // a card in the reader, we complete any pending card monitor // request, since we do not really know what card is now in the // reader. // KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); if (SmartcardExtension->ReaderExtension->CardPresent || SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) { deviceExtension->SmartcardExtension.ReaderExtension->ulOldCardState = UNKNOWN; deviceExtension->SmartcardExtension.ReaderExtension->ulNewCardState = UNKNOWN; } KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); status = SCCMN50M_StartCardTracking(deviceExtension); if (status != STATUS_SUCCESS) { SmartcardDebug(DEBUG_ERROR, ("%s!StartCardTracking failed ! %lx\n",DRIVER_NAME,status)); } // save the current power state of the reader SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; SmartcardReleaseRemoveLock(SmartcardExtension); // inform the power manager of our state. PoSetPowerState (DeviceObject, DevicePowerState, irpStack->Parameters.Power.State); PoStartNextPowerIrp(Irp); // signal that we can process ioctls again deviceExtension->IoCount = 0; KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was set\n",DRIVER_NAME)); SmartcardDebug(DEBUG_TRACE, ("%s!DevicePowerCompletion: Exit\n",DRIVER_NAME)); return STATUS_SUCCESS; } /***************************************************************************** Routine Description: The power dispatch routine. This driver is the power policy owner of the device stack, because this driver knows about the connected reader. Therefor this driver will translate system power states to device power states. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code *****************************************************************************/ typedef enum _ACTION { Undefined = 0, SkipRequest, WaitForCompletion, CompleteRequest, MarkPending } ACTION; NTSTATUS SCCMN50M_Power ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension; PDEVICE_OBJECT AttachedDeviceObject; POWER_STATE powerState; ACTION action = SkipRequest; KEVENT event; KIRQL irql; PAGED_CODE(); SmartcardDebug( DEBUG_TRACE, ("%s!Power: Enter\n", DRIVER_NAME) ); status = SmartcardAcquireRemoveLock(smartcardExtension); ASSERT(status == STATUS_SUCCESS); if (!NT_SUCCESS(status)) { PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } AttachedDeviceObject = ATTACHED_DEVICE_OBJECT; if (irpStack->Parameters.Power.Type == DevicePowerState && irpStack->MinorFunction == IRP_MN_SET_POWER) { switch (irpStack->Parameters.Power.State.DeviceState) { case PowerDeviceD0: // Turn on the reader SmartcardDebug( DEBUG_DRIVER, ("%s!Power: PowerDevice D0\n", DRIVER_NAME) ); // // First, we send down the request to the bus, in order // to power on the port. When the request completes, // we turn on the reader // IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine ( Irp, SCCMN50M_DevicePowerCompletion, smartcardExtension, TRUE, TRUE, TRUE ); action = WaitForCompletion; break; case PowerDeviceD3: SCCMN50M_StopCardTracking(deviceExtension); // Turn off the reader SmartcardDebug( DEBUG_DRIVER, ("%s!Power: PowerDevice D3\n", DRIVER_NAME) ); PoSetPowerState ( DeviceObject, DevicePowerState, irpStack->Parameters.Power.State ); // save the current card state KeAcquireSpinLock(&smartcardExtension->OsData->SpinLock, &irql); smartcardExtension->ReaderExtension->CardPresent = smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT; if (smartcardExtension->ReaderExtension->CardPresent) { KeReleaseSpinLock(&smartcardExtension->OsData->SpinLock, irql); smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN; status = SCCMN50M_PowerOff(smartcardExtension); ASSERT(status == STATUS_SUCCESS); } else { KeReleaseSpinLock(&smartcardExtension->OsData->SpinLock, irql); } // save the current power state of the reader smartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderOff; action = SkipRequest; break; default: action = SkipRequest; break; } } if (irpStack->Parameters.Power.Type == SystemPowerState) { // // The system wants to change the power state. // We need to translate the system power state to // a corresponding device power state. // POWER_STATE_TYPE powerType = DevicePowerState; ASSERT(smartcardExtension->ReaderExtension->ReaderPowerState != PowerReaderUnspecified); switch (irpStack->MinorFunction) { KIRQL irql; case IRP_MN_QUERY_POWER: SmartcardDebug( DEBUG_DRIVER, ("%s!Power: Query Power\n", DRIVER_NAME) ); switch (irpStack->Parameters.Power.State.SystemState) { case PowerSystemMaximum: case PowerSystemWorking: case PowerSystemSleeping1: case PowerSystemSleeping2: action = SkipRequest; break; case PowerSystemSleeping3: case PowerSystemHibernate: case PowerSystemShutdown: KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); if (deviceExtension->IoCount == 0) { // Block any further ioctls deviceExtension->IoCount = -1; KeClearEvent(&deviceExtension->ReaderStarted); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was cleared\n",DRIVER_NAME)); action = SkipRequest; } else { // can't go to sleep mode since the reader is busy. status = STATUS_DEVICE_BUSY; action = CompleteRequest; } KeReleaseSpinLock(&deviceExtension->SpinLock, irql); break; } break; case IRP_MN_SET_POWER: SmartcardDebug( DEBUG_DRIVER, ("%s!Power: PowerSystem S%d\n", DRIVER_NAME, irpStack->Parameters.Power.State.SystemState - 1) ); switch (irpStack->Parameters.Power.State.SystemState) { case PowerSystemMaximum: case PowerSystemWorking: case PowerSystemSleeping1: case PowerSystemSleeping2: if (smartcardExtension->ReaderExtension->ReaderPowerState == PowerReaderWorking) { // We're already in the right state action = SkipRequest; break; } // wake up the underlying stack... powerState.DeviceState = PowerDeviceD0; action = MarkPending; break; case PowerSystemSleeping3: case PowerSystemHibernate: case PowerSystemShutdown: KeAcquireSpinLock(&deviceExtension->SpinLock, &irql); if (deviceExtension->IoCount == 0) { // Block any further ioctls deviceExtension->IoCount = -1; KeClearEvent(&deviceExtension->ReaderStarted); SmartcardDebug(DEBUG_DRIVER, ("%s!Event ReaderStarted was cleared\n",DRIVER_NAME)); action = SkipRequest; } else { // can't go to sleep mode since the reader is busy. status = STATUS_DEVICE_BUSY; action = CompleteRequest; } KeReleaseSpinLock(&deviceExtension->SpinLock, irql); if (smartcardExtension->ReaderExtension->ReaderPowerState == PowerReaderOff) { // We're already in the right state action = SkipRequest; break; } powerState.DeviceState = PowerDeviceD3; // first, inform the power manager of our new state. PoSetPowerState ( DeviceObject, SystemPowerState, powerState ); action = MarkPending; break; default: action = SkipRequest; break; } } } switch (action) { case CompleteRequest: Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; SmartcardReleaseRemoveLock(smartcardExtension); PoStartNextPowerIrp(Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case MarkPending: // initialize the event we need in the completion function KeInitializeEvent(&event, NotificationEvent, FALSE); // request the device power irp status = PoRequestPowerIrp (DeviceObject, IRP_MN_SET_POWER, powerState, SCCMN50M_SystemPowerCompletion, &event, NULL); ASSERT(status == STATUS_PENDING); if (status == STATUS_PENDING) { // wait until the device power irp completed status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); SmartcardReleaseRemoveLock(smartcardExtension); if (powerState.SystemState == PowerSystemWorking) { PoSetPowerState (DeviceObject, SystemPowerState, powerState); } PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(AttachedDeviceObject, Irp); } else { SmartcardReleaseRemoveLock(smartcardExtension); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } break; case SkipRequest: SmartcardReleaseRemoveLock(smartcardExtension); PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(AttachedDeviceObject, Irp); break; case WaitForCompletion: status = PoCallDriver(AttachedDeviceObject, Irp); break; default: ASSERT(FALSE); SmartcardReleaseRemoveLock(smartcardExtension); break; } SmartcardDebug( DEBUG_TRACE, ("%s!Power: Exit %lx\n", DRIVER_NAME, status) ); return status; } /***************************************************************************** Routine Description: This routine is called by the I/O system when the device is opened or closed. Arguments: DeviceObject - Pointer to device object for this miniport Irp - IRP involved. Return Value: STATUS_SUCCESS. *****************************************************************************/ NTSTATUS SCCMN50M_CreateClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; if (irpStack->MajorFunction == IRP_MJ_CREATE) { status = SmartcardAcquireRemoveLock(&deviceExtension->SmartcardExtension); if (status != STATUS_SUCCESS) { status = STATUS_DEVICE_REMOVED; } else { LARGE_INTEGER timeout; timeout.QuadPart = 0; // test if the device has been opened already status = KeWaitForSingleObject( &deviceExtension->ReaderClosed, Executive, KernelMode, FALSE, &timeout ); if (status == STATUS_SUCCESS) { KeClearEvent(&deviceExtension->ReaderClosed); SmartcardDebug( DEBUG_DRIVER, ("%s!CreateClose: Open\n", DRIVER_NAME) ); } else { // the device is already in use status = STATUS_UNSUCCESSFUL; SmartcardReleaseRemoveLock(&deviceExtension->SmartcardExtension); } } } else { SmartcardDebug( DEBUG_DRIVER, ("%s!CreateClose: Close\n", DRIVER_NAME) ); SmartcardReleaseRemoveLock(&deviceExtension->SmartcardExtension); KeSetEvent(&deviceExtension->ReaderClosed, 0, FALSE); } Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } /***************************************************************************** Routine Description: This routine is called by the I/O system when the irp should be cancelled Arguments: DeviceObject - Pointer to device object for this miniport Irp - IRP involved. Return Value: STATUS_CANCELLED *****************************************************************************/ NTSTATUS SCCMN50M_Cancel( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension; SmartcardDebug( DEBUG_TRACE, ("%s!Cancel: Enter\n", DRIVER_NAME) ); ASSERT(Irp == smartcardExtension->OsData->NotificationIrp); IoReleaseCancelSpinLock( Irp->CancelIrql ); SCCMN50M_CompleteCardTracking(smartcardExtension); SmartcardDebug( DEBUG_TRACE, ("%s!Cancel: Exit\n", DRIVER_NAME) ); return STATUS_CANCELLED; } /***************************************************************************** Routine Description: This routine is called when the calling application terminates. We can actually only have the notification irp that we have to cancel. Arguments: Return Value: *****************************************************************************/ NTSTATUS SCCMN50M_Cleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension; NTSTATUS status = STATUS_SUCCESS; BOOLEAN fCancelIrp = FALSE; SmartcardDebug( DEBUG_TRACE, ("%s!Cleanup: Enter\n", DRIVER_NAME) ); if (Irp != smartcardExtension->OsData->NotificationIrp) fCancelIrp = TRUE; // We need to complete the notification irp SCCMN50M_CompleteCardTracking(smartcardExtension); if (fCancelIrp == TRUE) { SmartcardDebug( DEBUG_DRIVER, ("%s!Cleanup: Completing IRP %lx\n", DRIVER_NAME, Irp) ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } SmartcardDebug( DEBUG_TRACE, ("%s!Cleanup: Exit\n", DRIVER_NAME) ); return STATUS_SUCCESS; } /***************************************************************************** Routine Description: Remove the device from the system. Arguments: Return Value: *****************************************************************************/ VOID SCCMN50M_RemoveDevice( PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION deviceExtension; PSMARTCARD_EXTENSION smartcardExtension; NTSTATUS status; PAGED_CODE(); if (DeviceObject == NULL) { return; } deviceExtension = DeviceObject->DeviceExtension; smartcardExtension = &deviceExtension->SmartcardExtension; SmartcardDebug( DEBUG_TRACE, ( "%s!RemoveDevice: Enter\n", DRIVER_NAME) ); if (smartcardExtension->OsData) { // complete pending card tracking requests (if any) SCCMN50M_CompleteCardTracking(smartcardExtension); ASSERT(smartcardExtension->OsData->NotificationIrp == NULL); } // Wait until we can safely unload the device SmartcardReleaseRemoveLockAndWait(smartcardExtension); ASSERT(deviceExtension->DeviceInstance < MAXIMUM_SMARTCARD_READERS); ASSERT(DeviceSlot[deviceExtension->DeviceInstance] == TRUE); // Mark this slot as available DeviceSlot[deviceExtension->DeviceInstance] = FALSE; SCCMN50M_StopDevice(deviceExtension); if (ATTACHED_DEVICE_OBJECT) { IoDetachDevice(ATTACHED_DEVICE_OBJECT); } if (deviceExtension->PnPDeviceName.Buffer != NULL) { RtlFreeUnicodeString(&deviceExtension->PnPDeviceName); } if (smartcardExtension->OsData != NULL) { SmartcardExit(smartcardExtension); } if (smartcardExtension->ReaderExtension != NULL) { ExFreePool(smartcardExtension->ReaderExtension); } IoDeleteDevice(DeviceObject); SmartcardDebug( DEBUG_TRACE, ( "%s!RemoveDevice: Exit\n", DRIVER_NAME) ); } /***************************************************************************** Routine Description: The driver unload routine. This is called by the I/O system when the device is unloaded from memory. Arguments: DriverObject - Pointer to driver object created by system. Return Value: STATUS_SUCCESS. *****************************************************************************/ VOID SCCMN50M_DriverUnload( IN PDRIVER_OBJECT DriverObject ) { PAGED_CODE(); SmartcardDebug( DEBUG_TRACE, ("%s!DriverUnload\n", DRIVER_NAME) ); } /***************************************************************************** Routine Description: Arguments: Return Value: *****************************************************************************/ VOID SCCMN50M_CompleteCardTracking( IN PSMARTCARD_EXTENSION SmartcardExtension ) { KIRQL ioIrql, keIrql; PIRP notificationIrp; IoAcquireCancelSpinLock(&ioIrql); KeAcquireSpinLock( &SmartcardExtension->OsData->SpinLock, &keIrql ); notificationIrp = SmartcardExtension->OsData->NotificationIrp; SmartcardExtension->OsData->NotificationIrp = NULL; KeReleaseSpinLock( &SmartcardExtension->OsData->SpinLock, keIrql ); if (notificationIrp) { IoSetCancelRoutine( notificationIrp, NULL ); } IoReleaseCancelSpinLock(ioIrql); if (notificationIrp) { // finish the request if (notificationIrp->Cancel) { notificationIrp->IoStatus.Status = STATUS_CANCELLED; } else { notificationIrp->IoStatus.Status = STATUS_SUCCESS; } SmartcardDebug( DEBUG_DRIVER, ("%s!CompleteCardTracking: Completing NotificationIrp %lxh IoStatus=%lxh\n", DRIVER_NAME, notificationIrp, notificationIrp->IoStatus.Status ) ); notificationIrp->IoStatus.Information = 0; IoCompleteRequest( notificationIrp, IO_NO_INCREMENT ); } } /***************************************************************************** * History: * $Log: sccmnt5.c $ * Revision 1.7 2001/01/22 08:39:42 WFrischauf * No comment given * * Revision 1.6 2000/09/25 10:46:24 WFrischauf * No comment given * * Revision 1.5 2000/08/24 09:05:45 TBruendl * No comment given * * Revision 1.4 2000/08/14 12:41:06 TBruendl * bug fix in CreateDevice * * Revision 1.3 2000/07/28 09:24:15 TBruendl * Changes for OMNIKEY on Whistler CD * * Revision 1.6 2000/03/03 09:50:51 TBruendl * No comment given * * Revision 1.5 2000/03/01 09:32:07 TBruendl * R02.20.0 * * Revision 1.4 1999/12/13 07:57:18 TBruendl * bug fixes for hiberantion tests of MS test suite * * Revision 1.3 1999/11/04 07:53:24 WFrischauf * bug fixes due to error reports 2 - 7 * * Revision 1.2 1999/06/10 09:03:59 TBruendl * No comment given * * Revision 1.1 1999/02/02 13:34:41 TBruendl * This is the first release (R01.00) of the IFD handler for CardMan running under NT5.0. * * *****************************************************************************/