/***************************************************************************** @doc INT EXT ****************************************************************************** * $ProjectName: $ * $ProjectRevision: $ *----------------------------------------------------------------------------- * $Source: z:/pr/cmbp0/sw/cmbp0.ms/rcs/cmbp0wdm.c $ * $Revision: 1.11 $ *----------------------------------------------------------------------------- * $Author: WFrischauf $ *----------------------------------------------------------------------------- * History: see EOF *----------------------------------------------------------------------------- * * Copyright © 2000 OMNIKEY AG ******************************************************************************/ #include #ifdef NT4 #include #else #include #endif #include #include BOOLEAN DeviceSlot[CMMOB_MAX_DEVICE]; // this is a list of our supported data rates ULONG SupportedDataRates[] = { 9600, 19200, 38400, 76800, 115200, 153600, 192000, 307200}; // this is a list of our supported clock frequencies ULONG SupportedCLKFrequencies[] = { 4000, 8000}; /***************************************************************************** DriverEntry: entry function of the driver. setup the callbacks for the OS and try to initialize a device object for every device in the system Arguments: DriverObject context of the driver RegistryPath path to the registry entry for the driver Return Value: STATUS_SUCCESS STATUS_UNSUCCESSFUL ******************************************************************************/ NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) { NTSTATUS NTStatus = STATUS_SUCCESS; ULONG ulDevice; //#if DBG // SmartcardSetDebugLevel(DEBUG_ALL); //#endif SmartcardDebug(DEBUG_TRACE, ("%s!DriverEntry: Enter - %s %s\n",DRIVER_NAME,__DATE__,__TIME__)); // // tell the system our entry points // DriverObject->MajorFunction[IRP_MJ_CREATE] = CMMOB_CreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = CMMOB_CreateClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CMMOB_DeviceIoControl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CMMOB_SystemControl; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CMMOB_Cleanup; DriverObject->DriverUnload = CMMOB_UnloadDriver; #ifndef NT4 DriverObject->MajorFunction[IRP_MJ_PNP] = CMMOB_PnPDeviceControl; DriverObject->MajorFunction[IRP_MJ_POWER] = CMMOB_PowerDeviceControl; DriverObject->DriverExtension->AddDevice = CMMOB_AddDevice; SmartcardDebug(DEBUG_TRACE, ("%s!DriverEntry: PnP Version\n",DRIVER_NAME)); #else // // try to initialize all devices // for (ulDevice = 0; ulDevice < CMMOB_MAX_DEVICE; ulDevice++) { // // create and start all connected devices // if (CMMOB_CreateAndStartDevice(DriverObject) != STATUS_SUCCESS) { break; } } // // report a failure if no device was found // if (DriverObject->DeviceObject == NULL) { NTStatus = STATUS_UNSUCCESSFUL; SmartcardLogError(DriverObject, CMMOB_NO_DEVICE_FOUND, NULL, 0); } #endif SmartcardDebug(DEBUG_TRACE, ("%s!DriverEntry: Exit %x\n",DRIVER_NAME,NTStatus)); return NTStatus; } /***************************************************************************** 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 CMMOB_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: creates a new device object for the driver, allocates & initializes all neccessary structures (i.e. SmartcardExtension & ReaderExtension). Arguments: DriverObject context of call DeviceObject ptr to the created device object Return Value: STATUS_SUCCESS STATUS_INSUFFICIENT_RESOURCES NTStatus returned by smclib.sys ******************************************************************************/ NTSTATUS CMMOB_CreateDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PDEVICE_OBJECT *DeviceObject ) { NTSTATUS NTStatus = STATUS_SUCCESS; NTSTATUS RegStatus; RTL_QUERY_REGISTRY_TABLE ParamTable[2]; UNICODE_STRING RegistryPath; UNICODE_STRING RegistryValue; WCHAR szRegValue[256]; UNICODE_STRING DeviceName; UNICODE_STRING Tmp; WCHAR Buffer[64]; SmartcardDebug(DEBUG_TRACE, ( "%s!CreateDevice: Enter\n",DRIVER_NAME )); try { ULONG ulDeviceInstance; PDEVICE_EXTENSION DeviceExtension; PREADER_EXTENSION ReaderExtension; PSMARTCARD_EXTENSION SmartcardExtension; *DeviceObject = NULL; for (ulDeviceInstance = 0; ulDeviceInstance < CMMOB_MAX_DEVICE; ulDeviceInstance++) { if (DeviceSlot[ulDeviceInstance] == FALSE) { DeviceSlot[ulDeviceInstance] = TRUE; break; } } if (ulDeviceInstance == CMMOB_MAX_DEVICE) { NTStatus = STATUS_INSUFFICIENT_RESOURCES; leave; } // // construct the device name // DeviceName.Buffer = Buffer; DeviceName.MaximumLength = sizeof(Buffer); DeviceName.Length = 0; RtlInitUnicodeString(&Tmp,CARDMAN_MOBILE_DEVICE_NAME); RtlCopyUnicodeString(&DeviceName,&Tmp); DeviceName.Buffer[(DeviceName.Length)/sizeof(WCHAR)-1] = L'0' + (WCHAR)ulDeviceInstance; // // Create the device object // NTStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &DeviceName, FILE_DEVICE_SMARTCARD, 0, TRUE, DeviceObject); if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DriverObject, CMMOB_INSUFFICIENT_RESOURCES, NULL, 0); leave; } // // tell the OS that we supposed to do buffered io // (*DeviceObject)->Flags |= DO_BUFFERED_IO; #ifndef NT4 // this is necessary, that power routine is called at IRQL_PASSIVE (*DeviceObject)->Flags |= DO_POWER_PAGABLE; // tells the IO Manager initialization is done (*DeviceObject)->Flags &= ~DO_DEVICE_INITIALIZING; #endif // // set up the device extension. // DeviceExtension = (*DeviceObject)->DeviceExtension; RtlZeroMemory( DeviceExtension, sizeof( DEVICE_EXTENSION )); SmartcardExtension = &DeviceExtension->SmartcardExtension; // used for synchronise access to lIoCount KeInitializeSpinLock(&DeviceExtension->SpinLockIoCount); // Used for stop / start notification KeInitializeEvent(&DeviceExtension->ReaderStarted, NotificationEvent, FALSE); // Used for update thread notification after hibernation KeInitializeEvent(&DeviceExtension->CanRunUpdateThread, NotificationEvent, TRUE); // // allocate the reader extension // ReaderExtension = ExAllocatePool(NonPagedPool,sizeof( READER_EXTENSION )); if (ReaderExtension == NULL) { SmartcardLogError(DriverObject, CMMOB_INSUFFICIENT_RESOURCES, NULL, 0); NTStatus = STATUS_INSUFFICIENT_RESOURCES; leave; } RtlZeroMemory( ReaderExtension, sizeof( READER_EXTENSION )); SmartcardExtension->ReaderExtension = ReaderExtension; // ---------------------------------------------- // initialize mutex // ---------------------------------------------- KeInitializeMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,0L); // // enter correct version of the lib // SmartcardExtension->Version = SMCLIB_VERSION; // // setup smartcard extension - callback's // SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CMMOB_CardPower; SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CMMOB_Transmit; SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CMMOB_SetProtocol; SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CMMOB_CardTracking; SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = CMMOB_IoCtlVendor; // // setup smartcard extension - vendor attribute // // default values RtlCopyMemory(SmartcardExtension->VendorAttr.VendorName.Buffer, CMMOB_VENDOR_NAME,sizeof(CMMOB_VENDOR_NAME)); SmartcardExtension->VendorAttr.VendorName.Length = sizeof(CMMOB_VENDOR_NAME); RtlCopyMemory(SmartcardExtension->VendorAttr.IfdType.Buffer, CMMOB_PRODUCT_NAME,sizeof(CMMOB_PRODUCT_NAME)); SmartcardExtension->VendorAttr.IfdType.Length = sizeof(CMMOB_PRODUCT_NAME); // try to overwrite with registry values CMMOB_SetVendorAndIfdName(PhysicalDeviceObject, SmartcardExtension); SmartcardExtension->VendorAttr.UnitNo = ulDeviceInstance; SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = CMMOB_MAJOR_VERSION; SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = CMMOB_MINOR_VERSION; SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = CMMOB_BUILD_NUMBER; SmartcardExtension->VendorAttr.IfdSerialNo.Length = 0; // // setup smartcard extension - reader capabilities // SmartcardExtension->ReaderCapabilities.SupportedProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; SmartcardExtension->ReaderCapabilities.ReaderType = SCARD_READER_TYPE_PCMCIA; SmartcardExtension->ReaderCapabilities.MechProperties = 0; SmartcardExtension->ReaderCapabilities.Channel = 0; // set supported frequencies SmartcardExtension->ReaderCapabilities.CLKFrequency.Default = 4000; //not used if CLKFrequenciesSupported is supplied SmartcardExtension->ReaderCapabilities.CLKFrequency.Max = 8000; //not used if CLKFrequenciesSupported is supplied SmartcardExtension->ReaderCapabilities.CLKFrequenciesSupported.Entries = sizeof(SupportedCLKFrequencies) / sizeof(SupportedCLKFrequencies[0]); SmartcardExtension->ReaderCapabilities.CLKFrequenciesSupported.List = SupportedCLKFrequencies; // set supported baud rates SmartcardExtension->ReaderCapabilities.DataRate.Default = 9600; //not used if DataRatesSupported is supplied SmartcardExtension->ReaderCapabilities.DataRate.Max = 307200; //not used if DataRatesSupported is supplied SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries = sizeof(SupportedDataRates) / sizeof(SupportedDataRates[0]); SmartcardExtension->ReaderCapabilities.DataRatesSupported.List = SupportedDataRates; // maximum buffer size SmartcardExtension->ReaderCapabilities.MaxIFSD = 254; // // Current state of the reader // SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN; SmartcardExtension->ReaderExtension->ulOldCardState = UNKNOWN; SmartcardExtension->ReaderExtension->ulNewCardState = UNKNOWN; SmartcardExtension->ReaderExtension->ulFWVersion = 100; // // Initialization of buffers // SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE; SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE; NTStatus = SmartcardInitialize(SmartcardExtension); SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; SmartcardExtension->ReaderExtension->CardParameters.bStopBits=2; SmartcardExtension->ReaderExtension->CardParameters.fSynchronousCard=FALSE; SmartcardExtension->ReaderExtension->CardParameters.fInversRevers=FALSE; SmartcardExtension->ReaderExtension->CardParameters.bClockFrequency=4; SmartcardExtension->ReaderExtension->CardParameters.fT0Mode=FALSE; SmartcardExtension->ReaderExtension->CardParameters.fT0Write=FALSE; SmartcardExtension->ReaderExtension->fReadCIS = FALSE; SmartcardExtension->ReaderExtension->bPreviousFlags1 = 0; if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DriverObject, CMMOB_INSUFFICIENT_RESOURCES, NULL, 0); leave; } // // tell the lib our device object & create symbolic link // SmartcardExtension->OsData->DeviceObject = *DeviceObject; #ifndef NT4 // W2000 is till now the only OS which supports WDM version 1.10 // So check this to determine if we have an Plug&Play able resource manager // Otherwise it is Windows 98 / ME if (IoIsWdmVersionAvailable (1,10)) { DeviceExtension->OSVersion = OS_Windows2000; } else { // Read HKLM\Software\Microsoft\Windows\CurrentVersion\VersionNumber // to determine the version of Windows (95, 98, 98SE and ME) RegistryValue.Length=0; RegistryValue.MaximumLength=sizeof(szRegValue); RegistryValue.Buffer=szRegValue; RtlZeroMemory(ParamTable,sizeof(ParamTable)); ParamTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; ParamTable[0].Name = L"VersionNumber"; ParamTable[0].EntryContext = &RegistryValue; ParamTable[0].DefaultType = REG_SZ; ParamTable[0].DefaultData = &RegistryValue; ParamTable[0].DefaultLength = RegistryValue.MaximumLength; RtlInitUnicodeString(&RegistryPath, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion"); RegStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath.Buffer, ParamTable, NULL, NULL); if (RegStatus == STATUS_SUCCESS) { ULONG ulMajorVersion; ULONG ulMinorVersion; ULONG ulBuild; ULONG ulStrLength; ULONG ulStrPos; ULONG ulStrPosPrevious; ulStrLength=RegistryValue.Length; ulStrPos=0; ulStrPosPrevious=ulStrPos; while (szRegValue[ulStrPos] != L'.' && szRegValue[ulStrPos] != L'\0' && ulStrPos != ulStrLength/sizeof(WCHAR)) { ulStrPos ++; } szRegValue[ulStrPos] = L'\0'; RegistryValue.Length= (USHORT) ((ulStrPos-ulStrPosPrevious)*sizeof(WCHAR)); RtlUnicodeStringToInteger(&RegistryValue,10,&ulMajorVersion); ulStrPos++; if (ulStrPos < ulStrLength/sizeof(WCHAR)) { ulStrPosPrevious=ulStrPos; while (szRegValue[ulStrPos] != L'.' && szRegValue[ulStrPos] != L'\0' && ulStrPos != ulStrLength) { ulStrPos ++; } szRegValue[ulStrPos] = L'\0'; RegistryValue.Length= (USHORT) ((ulStrPos-ulStrPosPrevious)*sizeof(WCHAR)); RegistryValue.Buffer=&szRegValue[ulStrPosPrevious]; RtlUnicodeStringToInteger(&RegistryValue,10,&ulMinorVersion); ulStrPos++; if (ulStrPos < ulStrLength/sizeof(WCHAR)) { ulStrPosPrevious=ulStrPos; while (szRegValue[ulStrPos] != L'.' && szRegValue[ulStrPos] != L'\0' && ulStrPos != ulStrLength) { ulStrPos ++; } szRegValue[ulStrPos] = L'\0'; RegistryValue.Length= (USHORT) ((ulStrPos-ulStrPosPrevious)*sizeof(WCHAR)); RegistryValue.Buffer=&szRegValue[ulStrPosPrevious]; RtlUnicodeStringToInteger(&RegistryValue,10,&ulBuild); } } SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: MS Windows Version %li.%li.%li\n",DRIVER_NAME, ulMajorVersion,ulMinorVersion,ulBuild)); if (ulMajorVersion > 4 || (ulMajorVersion == 4 && ulMinorVersion > 10 )) { DeviceExtension->OSVersion = OS_WindowsME; } else if (ulMajorVersion == 4 && ulMinorVersion == 10 ) { if (ulBuild < 2222) { DeviceExtension->OSVersion = OS_Windows98; } else { DeviceExtension->OSVersion = OS_Windows98SE; } } else { DeviceExtension->OSVersion = OS_Windows95; } } else { // assume it's Windows 98 -> no standby mode DeviceExtension->OSVersion = OS_Windows98; } } SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: Operating system is %s\n",DRIVER_NAME, szOSVersion[DeviceExtension->OSVersion])); if (DeviceExtension->OSVersion == OS_Windows2000) { if (DeviceExtension->PnPDeviceName.Buffer == NULL) { // ---------------------------------------------- // register our new device // ---------------------------------------------- NTStatus = IoRegisterDeviceInterface(PhysicalDeviceObject, &SmartCardReaderGuid, NULL, &DeviceExtension->PnPDeviceName); SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: PnPDeviceName.Buffer = %lx\n",DRIVER_NAME, DeviceExtension->PnPDeviceName.Buffer)); SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: PnPDeviceName.BufferLength = %lx\n",DRIVER_NAME, DeviceExtension->PnPDeviceName.Length)); SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: IoRegisterDeviceInterface returned=%lx\n",DRIVER_NAME,NTStatus)); } else { SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: Interface already exists\n",DRIVER_NAME)); } } else #endif { // ---------------------------------------------- // create symbolic link // ---------------------------------------------- NTStatus = SmartcardCreateLink(&DeviceExtension->LinkDeviceName,&DeviceName); SmartcardDebug(DEBUG_DRIVER, ("%s!CreateDevice: SmartcardCreateLink returned=%lx\n",DRIVER_NAME,NTStatus)); } if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DriverObject, CMMOB_INSUFFICIENT_RESOURCES, NULL, 0); leave; } } finally { if (NTStatus != STATUS_SUCCESS) { CMMOB_UnloadDevice(*DeviceObject); *DeviceObject = NULL; } } SmartcardDebug(DEBUG_TRACE, ( "%s!CreateDevice: Exit %x\n",DRIVER_NAME,NTStatus )); return NTStatus; } /***************************************************************************** Routine Description: get the actual configuration from the passed FullResourceDescriptor and initializes the reader hardware Note: for an NT 4.00 build the resources must be translated by the HAL Arguments: DeviceObject context of call FullResourceDescriptor actual configuration of the reader Return Value: STATUS_SUCCESS NTStatus returned from the HAL (NT 4.00 only ) NTStatus returned by LowLevel routines ******************************************************************************/ NTSTATUS CMMOB_StartDevice( PDEVICE_OBJECT DeviceObject, PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor ) { NTSTATUS NTStatus = STATUS_SUCCESS; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension; PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; ULONG ulCount; ULONG ulCISIndex; UCHAR bTupleCode[2]; UCHAR bFirmware[2]; SmartcardDebug(DEBUG_TRACE, ("%s!StartDevice: Enter\n",DRIVER_NAME)); // // Get the number of resources we need // ulCount = FullResourceDescriptor->PartialResourceList.Count; PartialDescriptor = FullResourceDescriptor->PartialResourceList.PartialDescriptors; // // parse all partial descriptors // while (ulCount--) { switch (PartialDescriptor->Type) { #ifdef MEMORYCARD case CmResourceTypeMemory: { // // 0 - memory, 1 - IO // #ifdef NT4 ULONG AddressSpace = 0; BOOLEAN fTranslated; PHYSICAL_ADDRESS PhysicalAddress; #endif // // Get Mem-length // ReaderExtension->ulMemWindow = PartialDescriptor->u.Memory.Length; ASSERT(PartialDescriptor->u.Memory.Length >= 4096); // // Get Mem-base // #ifndef NT4 ReaderExtension->pMemBase = MmMapIoSpace (PartialDescriptor->u.Memory.Start, PartialDescriptor->u.Memory.Length, FALSE); DeviceExtension->fUnMapMem = TRUE; #else // // let the hal translate the address // fTranslated = HalTranslateBusAddress(FullResourceDescriptor->InterfaceType, FullResourceDescriptor->BusNumber, PartialDescriptor->u.Memory.Start, &AddressSpace, &PhysicalAddress); if (fTranslated == TRUE && AddressSpace == 0) { ReaderExtension->pMemBase = MmMapIoSpace(PhysicalAddress, PartialDescriptor->u.Memory.Length, FALSE); DeviceExtension->fUnMapMem = TRUE; } else { ReaderExtension->pMemBase = (PVOID) PhysicalAddress.LowPart; } #endif SmartcardDebug(DEBUG_TRACE, ("%s!StartDevice: MemBase = %lxh\n",DRIVER_NAME,ReaderExtension->pMemBase)); } break; #endif #ifdef IOCARD case CmResourceTypePort: { #ifdef NT4 // // 0 - memory, 1 - IO // ULONG AddressSpace = 1; BOOLEAN fTranslated; PHYSICAL_ADDRESS PhysicalAddress; #endif // // Get IO-length // ReaderExtension->ulIoWindow = PartialDescriptor->u.Port.Length; ASSERT(PartialDescriptor->u.Port.Length >= 8); // // Get IO-base // #ifndef NT4 #ifndef _WIN64 ReaderExtension->pIoBase = (PVOID) PartialDescriptor->u.Port.Start.LowPart; #else ReaderExtension->pIoBase = (PVOID) PartialDescriptor->u.Port.Start.QuadPart; #endif #else // // let the hal translate the address // fTranslated = HalTranslateBusAddress(FullResourceDescriptor->InterfaceType, FullResourceDescriptor->BusNumber, PartialDescriptor->u.Port.Start, &AddressSpace, &PhysicalAddress); if (fTranslated == TRUE && AddressSpace == 0) { ReaderExtension->pIoBase = MmMapIoSpace(PhysicalAddress, PartialDescriptor->u.Port.Length, FALSE); DeviceExtension->fUnMapMem = TRUE; } else { ReaderExtension->pIoBase = (PVOID) PhysicalAddress.LowPart; } #endif SmartcardDebug(DEBUG_TRACE, ("%s!StartDevice: IoBase = %lxh\n",DRIVER_NAME,ReaderExtension->pIoBase)); } break; #endif default: break; } PartialDescriptor++; } try { // // Base initialized ? // #ifdef MEMORYCARD if (ReaderExtension->pMemBase == NULL) #endif #ifdef IOCARD if (ReaderExtension->pIoBase == NULL) #endif { #ifndef NT4 // // under NT 4.0 the failure of this fct for the second reader // means there is only one device // SmartcardLogError(DeviceObject, CMMOB_ERROR_MEM_PORT, NULL, 0); #endif NTStatus = STATUS_INSUFFICIENT_RESOURCES; leave; } // initialize base addresses #ifdef MEMORYCARD ReaderExtension->pbCISBase= (PUCHAR) ReaderExtension->pMemBase; ReaderExtension->pbRegsBase= ReaderExtension->pbCISBase + 0x400; ReaderExtension->pbDataBase= ReaderExtension->pbCISBase + 0x800; #endif #ifdef IOCARD ReaderExtension->pbRegsBase= (PUCHAR) ReaderExtension->pIoBase; #endif NTStatus=CMMOB_ResetReader (ReaderExtension); SmartcardDebug(DEBUG_DRIVER, ("%s!DEBUG_DRIVER: ResetReader retval = %x\n",DRIVER_NAME, NTStatus)); if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DeviceObject, CMMOB_CANT_INITIALIZE_READER, NULL, 0); leave; } #ifdef IOCARD // // read firmware version from CIS // ReaderExtension->fReadCIS=TRUE; ReaderExtension->fTActive=TRUE; NTStatus=CMMOB_SetFlags1 (ReaderExtension); if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DeviceObject, CMMOB_CANT_INITIALIZE_READER, NULL, 0); leave; } ulCISIndex = 0; do { NTStatus=CMMOB_ReadBuffer(ReaderExtension, ulCISIndex, 2, bTupleCode); if (NTStatus != STATUS_SUCCESS) { leave; } if (bTupleCode[0] == 0x15) { // this is the version tuple // read firmware version NTStatus=CMMOB_ReadBuffer(ReaderExtension, ulCISIndex+2, 2, bFirmware); if (NTStatus != STATUS_SUCCESS) { leave; } SmartcardExtension->ReaderExtension->ulFWVersion = 100*(ULONG)bFirmware[0]+bFirmware[1]; SmartcardDebug(DEBUG_TRACE, ("%s!StartDevice: Firmware version = %li\n", DRIVER_NAME, SmartcardExtension->ReaderExtension->ulFWVersion)); } ulCISIndex += bTupleCode[1] + 2; } while (bTupleCode[1] != 0 && bTupleCode[0] != 0x15 && bTupleCode[0] != 0xFF && ulCISIndex < CMMOB_MAX_CIS_SIZE); ReaderExtension->fReadCIS=FALSE; ReaderExtension->fTActive=FALSE; NTStatus=CMMOB_SetFlags1 (ReaderExtension); if (NTStatus != STATUS_SUCCESS) { SmartcardLogError(DeviceObject, CMMOB_CANT_INITIALIZE_READER, NULL, 0); leave; } #endif // // start update thread // NTStatus = CMMOB_StartCardTracking(DeviceObject); // signal that the reader has been started (again) KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE); #ifndef NT4 if (DeviceExtension->OSVersion == OS_Windows2000) { NTStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,TRUE); } #endif } finally { if (NTStatus != STATUS_SUCCESS) { CMMOB_StopDevice(DeviceObject); } } SmartcardDebug(DEBUG_TRACE, ("%s!StartDevice: Exit %x\n",DRIVER_NAME,NTStatus)); return NTStatus; } /***************************************************************************** Routine Description: Unmap the IO port Arguments: DeviceObject context of call Return Value: void ******************************************************************************/ VOID CMMOB_StopDevice( PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION DeviceExtension; if (DeviceObject == NULL) { return; } SmartcardDebug(DEBUG_TRACE, ( "%s!StopDevice: Enter\n",DRIVER_NAME )); DeviceExtension = DeviceObject->DeviceExtension; KeClearEvent(&DeviceExtension->ReaderStarted); // // stop update thread // CMMOB_StopCardTracking(DeviceObject); // power down the card for saftey reasons if (DeviceExtension->SmartcardExtension.ReaderExtension->ulOldCardState == POWERED) { // we have to wait for the mutex before KeWaitForSingleObject(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, Executive, KernelMode, FALSE, NULL); CMMOB_PowerOffCard(&DeviceExtension->SmartcardExtension); KeReleaseMutex(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, FALSE); } // // unmap ports // if (DeviceExtension->fUnMapMem) { #ifdef MEMORYCARD MmUnmapIoSpace(DeviceExtension->SmartcardExtension.ReaderExtension->pMemBase, DeviceExtension->SmartcardExtension.ReaderExtension->ulMemWindow); #endif #ifdef IOCARD MmUnmapIoSpace(DeviceExtension->SmartcardExtension.ReaderExtension->pIoBase, DeviceExtension->SmartcardExtension.ReaderExtension->ulIoWindow); #endif DeviceExtension->fUnMapMem = FALSE; } SmartcardDebug(DEBUG_TRACE, ( "%s!StopDevice: Exit\n",DRIVER_NAME )); } /***************************************************************************** Routine Description: close connections to smclib.sys and the pcmcia driver, delete symbolic link and mark the slot as unused. Arguments: DeviceObject device to unload Return Value: void ******************************************************************************/ VOID CMMOB_UnloadDevice( PDEVICE_OBJECT DeviceObject ) { PDEVICE_EXTENSION DeviceExtension; if (DeviceObject == NULL) { return; } SmartcardDebug(DEBUG_TRACE, ( "%s!UnloadDevice: Enter\n",DRIVER_NAME )); DeviceExtension = DeviceObject->DeviceExtension; // // It is possible that someone yanks out the pcmcia card when the // resource manager still has a connection to the device. // We need this flag to know that the device has been removed. // DeviceExtension->fDeviceRemoved = TRUE; ASSERT(DeviceExtension->SmartcardExtension.VendorAttr.UnitNo < CMMOB_MAX_DEVICE); // // Mark this slot as available // DeviceSlot[DeviceExtension->SmartcardExtension.VendorAttr.UnitNo] = FALSE; // // report to the lib that the device will be unloaded // if (DeviceExtension->SmartcardExtension.OsData != NULL) { // // finish pending tracking requests // CMMOB_CompleteCardTracking (&DeviceExtension->SmartcardExtension); } #ifdef NT4 // for WDM driver the remove lock is acquired in the PnP routine // so in case of NT4 we have to acquire it her SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension); #endif // Wait until we can safely unload the device SmartcardReleaseRemoveLockAndWait(&DeviceExtension->SmartcardExtension); SmartcardExit(&DeviceExtension->SmartcardExtension); #ifndef NT4 if (DeviceExtension->OSVersion == OS_Windows2000) { // // disable interface // if (DeviceExtension->PnPDeviceName.Buffer != NULL) { // disable our device so no one can open it IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,FALSE); RtlFreeUnicodeString(&DeviceExtension->PnPDeviceName); DeviceExtension->PnPDeviceName.Buffer = NULL; } } else #endif { // // Delete the symbolic link of the smart card reader // if (DeviceExtension->LinkDeviceName.Buffer != NULL) { NTSTATUS NTStatus; NTStatus = IoDeleteSymbolicLink(&DeviceExtension->LinkDeviceName); // // we continue even if an error occurs // ASSERT(NTStatus == STATUS_SUCCESS); RtlFreeUnicodeString(&DeviceExtension->LinkDeviceName); DeviceExtension->LinkDeviceName.Buffer = NULL; } } if (DeviceExtension->SmartcardExtension.ReaderExtension != NULL) { ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension); DeviceExtension->SmartcardExtension.ReaderExtension = NULL; } // // Detach from the pcmcia driver // Under NT 4.0 we did not attach to the pcmcia driver // if (DeviceExtension->AttachedDeviceObject) { IoDetachDevice(DeviceExtension->AttachedDeviceObject); DeviceExtension->AttachedDeviceObject = NULL; } // // delete the device object // IoDeleteDevice(DeviceObject); SmartcardDebug(DEBUG_TRACE, ( "%s!UnloadDevice: Exit\n",DRIVER_NAME )); return; } /***************************************************************************** CMMOB_UnloadDriver: unloads all devices for a given driver object Arguments: DriverObject context of driver Return Value: void ******************************************************************************/ VOID CMMOB_UnloadDriver( PDRIVER_OBJECT DriverObject ) { PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; ULONG ulSizeOfResources; SmartcardDebug(DEBUG_TRACE, ( "%s!UnloadDriver: Enter\n",DRIVER_NAME )); #ifdef NT4 if (DriverObject->DeviceObject != NULL) { ulSizeOfResources = sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); // // allocate memory for the resource descriptor // FullResourceDescriptor = ExAllocatePool(PagedPool,ulSizeOfResources); if (FullResourceDescriptor == NULL) { return; } RtlZeroMemory(FullResourceDescriptor, ulSizeOfResources); // // unload all device objects of that driver object // while (DriverObject->DeviceObject) { CMMOB_StopDevice(DriverObject->DeviceObject); CMMOB_ReportResources(DriverObject, FullResourceDescriptor); CMMOB_UnloadDevice(DriverObject->DeviceObject); } // // free local resources // ExFreePool(FullResourceDescriptor); } #endif SmartcardDebug(DEBUG_TRACE, ( "%s!UnloadDriver: Exit\n",DRIVER_NAME )); } /***************************************************************************** CMMOB_CreateClose: allowes only one open process a time Arguments: DeviceObject context of device Irp context of call Return Value: STATUS_SUCCESS STATUS_DEVICE_BUSY ******************************************************************************/ NTSTATUS CMMOB_CreateClose( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS NTStatus = STATUS_SUCCESS; PDEVICE_EXTENSION DeviceExtension; PSMARTCARD_EXTENSION SmartcardExtension; PIO_STACK_LOCATION IrpStack; SmartcardDebug(DEBUG_TRACE, ("%s!CreateClose: Enter ",DRIVER_NAME)); DeviceExtension = DeviceObject->DeviceExtension; SmartcardExtension = &DeviceExtension->SmartcardExtension; IrpStack = IoGetCurrentIrpStackLocation( Irp ); // // dispatch major function // switch (IrpStack->MajorFunction) { case IRP_MJ_CREATE: SmartcardDebug(DEBUG_IOCTL,("%s!CreateClose: IRP_MJ_CREATE\n",DRIVER_NAME)); if (DeviceExtension->fRemovePending) { NTStatus = STATUS_DEVICE_BUSY; } else { if (InterlockedIncrement(&DeviceExtension->lOpenCount) > 1) { InterlockedDecrement(&DeviceExtension->lOpenCount); NTStatus = STATUS_ACCESS_DENIED; } } break; case IRP_MJ_CLOSE: SmartcardDebug(DEBUG_IOCTL,("%s!CreateClose: IRP_MJ_CLOSE\n",DRIVER_NAME)); if (InterlockedDecrement(&DeviceExtension->lOpenCount) < 0) { InterlockedIncrement(&DeviceExtension->lOpenCount); } break; default: // // unrecognized command // SmartcardDebug(DEBUG_IOCTL,("unexpected IRP\n")); NTStatus = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = NTStatus; IoCompleteRequest( Irp, IO_NO_INCREMENT ); SmartcardDebug(DEBUG_TRACE, ("%s!CreateClose: Exit %x\n",DRIVER_NAME,NTStatus)); return NTStatus; } NTSTATUS CMMOB_SystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PDEVICE_EXTENSION DeviceExtension; NTSTATUS status = STATUS_SUCCESS; DeviceExtension = DeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceExtension->AttachedDeviceObject, Irp); return status; } /***************************************************************************** CMMOB_DeviceIoControl: all IRP's requiring IO are queued to the StartIo routine, other requests are served immediately Arguments: DeviceObject context of device Irp context of call Return Value: STATUS_SUCCESS STATUS_PENDING ******************************************************************************/ NTSTATUS CMMOB_DeviceIoControl( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS NTStatus; PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; KIRQL irql; PIO_STACK_LOCATION irpSL; SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Enter\n",DRIVER_NAME)); irpSL = IoGetCurrentIrpStackLocation(Irp); #if DBG switch (irpSL->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SMARTCARD_EJECT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_EJECT")); break; case IOCTL_SMARTCARD_GET_ATTRIBUTE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_ATTRIBUTE")); break; case IOCTL_SMARTCARD_GET_LAST_ERROR: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_LAST_ERROR")); break; case IOCTL_SMARTCARD_GET_STATE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_GET_STATE")); break; case IOCTL_SMARTCARD_IS_ABSENT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_ABSENT")); break; case IOCTL_SMARTCARD_IS_PRESENT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_IS_PRESENT")); break; case IOCTL_SMARTCARD_POWER: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_POWER")); break; case IOCTL_SMARTCARD_SET_ATTRIBUTE: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_ATTRIBUTE")); break; case IOCTL_SMARTCARD_SET_PROTOCOL: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SET_PROTOCOL")); break; case IOCTL_SMARTCARD_SWALLOW: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_SWALLOW")); break; case IOCTL_SMARTCARD_TRANSMIT: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "IOCTL_SMARTCARD_TRANSMIT")); break; default: SmartcardDebug(DEBUG_IOCTL, ("%s!DeviceIoControl: %s\n", DRIVER_NAME, "Vendor specific or unexpected IOCTL")); break; } #endif KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql); if (DeviceExtension->lIoCount == 0) { KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql); NTStatus = KeWaitForSingleObject(&DeviceExtension->ReaderStarted, Executive, KernelMode, FALSE, NULL); ASSERT(NTStatus == STATUS_SUCCESS); KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql); } ASSERT(DeviceExtension->lIoCount >= 0); DeviceExtension->lIoCount++; KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql); // Can't accept a new io request if: if (DeviceExtension->fDeviceRemoved == TRUE || //flag set when processing IRP_MN_REMOVE_DEVICE DeviceExtension->fRemovePending == TRUE) // flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE { NTStatus = STATUS_DELETE_PENDING; Irp->IoStatus.Status = NTStatus; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql); DeviceExtension->lIoCount--; ASSERT(DeviceExtension->lIoCount >= 0); KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql); return NTStatus; } NTStatus = SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension); if (NTStatus != STATUS_SUCCESS) { // the device has been removed. Fail the call NTStatus = STATUS_DELETE_PENDING; Irp->IoStatus.Status = NTStatus; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql); DeviceExtension->lIoCount--; ASSERT(DeviceExtension->lIoCount >= 0); KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql); SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Exit %x\n",DRIVER_NAME,NTStatus)); return NTStatus; } KeWaitForSingleObject(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, Executive, KernelMode, FALSE, NULL); // get current card state NTStatus = CMMOB_UpdateCurrentState(&DeviceExtension->SmartcardExtension); NTStatus = SmartcardDeviceControl(&DeviceExtension->SmartcardExtension,Irp); KeReleaseMutex(&DeviceExtension->SmartcardExtension.ReaderExtension->CardManIOMutex, FALSE); SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension); KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql); DeviceExtension->lIoCount--; ASSERT(DeviceExtension->lIoCount >= 0); KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql); SmartcardDebug(DEBUG_TRACE, ("%s!DeviceIoControl: Exit %x\n",DRIVER_NAME,NTStatus)); return NTStatus; } /***************************************************************************** Routine Description: This routine is called by the I/O system when the calling thread terminates Arguments: DeviceObject - Pointer to device object for this miniport Irp - IRP involved. Return Value: STATUS_CANCELLED ******************************************************************************/ NTSTATUS CMMOB_Cleanup( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension; SmartcardDebug(DEBUG_TRACE, ("%s!Cleanup: Enter\n",DRIVER_NAME)); if (SmartcardExtension->OsData->NotificationIrp != NULL && // test if there is a pending IRP at all SmartcardExtension->ReaderExtension != NULL && // if the device has been removed ReaderExtension == NULL DeviceExtension->lOpenCount == 1 ) // complete card tracking only if this is the the last close call // otherwise the card tracking of the resource manager is canceled { // // We need to complete the notification irp // CMMOB_CompleteCardTracking(SmartcardExtension); } 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; } /***************************************************************************** SysDelay: performs a required delay. The usage of KeStallExecutionProcessor is very nasty, but it happends only if SysDelay is called in the context of our DPC routine (which is only called if a card change was detected). For 'normal' IO we have Irql < DISPATCH_LEVEL, so if the reader is polled while waiting for response we will not block the entire system Arguments: Timeout delay in milli seconds Return Value: void ******************************************************************************/ VOID SysDelay( ULONG Timeout ) { LARGE_INTEGER SysTimeout; if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { ULONG Cnt = 20 * Timeout; SmartcardDebug(DEBUG_DRIVER, ("%s! Waiting at IRQL >= DISPATCH_LEVEL %l\n",DRIVER_NAME,Timeout)); while (Cnt--) { // // KeStallExecutionProcessor: counted in us // KeStallExecutionProcessor( 50 ); } } else { SysTimeout = RtlConvertLongToLargeInteger(Timeout * -10000L); // // KeDelayExecutionThread: counted in 100 ns // KeDelayExecutionThread( KernelMode, FALSE, &SysTimeout ); } return; } /***************************************************************************** * History: * $Log: cmbp0wdm.c $ * Revision 1.11 2001/01/22 08:12:22 WFrischauf * No comment given * * Revision 1.9 2000/09/25 14:24:33 WFrischauf * No comment given * * Revision 1.8 2000/08/24 09:05:14 TBruendl * No comment given * * Revision 1.7 2000/08/16 16:52:17 WFrischauf * No comment given * * Revision 1.6 2000/08/09 12:46:01 WFrischauf * No comment given * * Revision 1.5 2000/07/27 13:53:06 WFrischauf * No comment given * * ******************************************************************************/