⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pscrnt.c

📁 SmartCard驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    ASSERT(deviceExtension->IoCount >= 0);
    deviceExtension->IoCount++;
    KeReleaseSpinLock(&deviceExtension->SpinLock, irql);

    timeout.QuadPart = 0;

    status = KeWaitForSingleObject(         
        &deviceExtension->ReaderRemoved,
        Executive,
        KernelMode,
        FALSE,
        &timeout
        );

    if (status == STATUS_SUCCESS) {
     	
        status = STATUS_DEVICE_REMOVED;

    } else {
     	
        status = SmartcardAcquireRemoveLock(&deviceExtension->SmartcardExtension);
    }

    if (status != STATUS_SUCCESS) {

        // the device has been removed. Fail the call
        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_DEVICE_REMOVED;
    }

	status = SmartcardDeviceControl(
		&(deviceExtension->SmartcardExtension),
		Irp
		);

    SmartcardReleaseRemoveLock(&deviceExtension->SmartcardExtension);

    KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
    deviceExtension->IoCount--;
    ASSERT(deviceExtension->IoCount >= 0);
    KeReleaseSpinLock(&deviceExtension->SpinLock, irql);

    return status;
}

NTSTATUS
PscrGenericIOCTL(
	PSMARTCARD_EXTENSION SmartcardExtension
	)
/*++

PscrGenericIOCTL:
	Performs generic callbacks to the reader

Arguments:
	SmartcardExtension	context of the call

Return Value:
	STATUS_SUCCESS

--*/
{
	NTSTATUS				NTStatus;
	PIRP					Irp;
	PIO_STACK_LOCATION		IrpStack;

	SmartcardDebug( 
		DEBUG_TRACE, 
		( "PSCR!PscrGenericIOCTL: Enter\n" )
		);

	//
	//	get pointer to current IRP stack location
	//
	Irp			= SmartcardExtension->OsData->CurrentIrp;
	IrpStack	= IoGetCurrentIrpStackLocation( Irp );
	//
	// assume error
	//
	NTStatus = STATUS_INVALID_DEVICE_REQUEST;
	Irp->IoStatus.Information = 0;
	//
	//	dispatch IOCTL
	//
	switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )
	{
		case IOCTL_PSCR_COMMAND:

			NTStatus = CmdPscrCommand(
				SmartcardExtension->ReaderExtension,
				(PUCHAR)Irp->AssociatedIrp.SystemBuffer,
				IrpStack->Parameters.DeviceIoControl.InputBufferLength,
				(PUCHAR)Irp->AssociatedIrp.SystemBuffer,
				IrpStack->Parameters.DeviceIoControl.OutputBufferLength,
				(PULONG) &Irp->IoStatus.Information
				);
			//
			//	the command could change the active file in the reader file
			//	system, so make sure that the status file will be selected
			//	before the next read
			//
			SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE;
			break;

		case IOCTL_GET_VERSIONS:

			if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
				SIZEOF_VERSION_CONTROL )
			{
				NTStatus = STATUS_BUFFER_TOO_SMALL;
			}
			else
			{
				PVERSION_CONTROL	VersionControl;

				VersionControl = (PVERSION_CONTROL)Irp->AssociatedIrp.SystemBuffer;

				VersionControl->SmclibVersion	= SmartcardExtension->Version;
				VersionControl->DriverMajor		= PSCR_MAJOR_VERSION;
				VersionControl->DriverMinor		= PSCR_MINOR_VERSION;

				//	update firmware version (changed after update)
				CmdGetFirmwareRevision(
					SmartcardExtension->ReaderExtension
					);
				VersionControl->FirmwareMajor =
					SmartcardExtension->ReaderExtension->FirmwareMajor;

				VersionControl->FirmwareMinor =
					SmartcardExtension->ReaderExtension->FirmwareMinor;

				VersionControl->UpdateKey =
					SmartcardExtension->ReaderExtension->UpdateKey;

				Irp->IoStatus.Information = SIZEOF_VERSION_CONTROL;
				NTStatus = STATUS_SUCCESS;
			}
			break;

		case IOCTL_SET_TIMEOUT:
			{
				ULONG	NewLimit;
				//
				//	get new timeout limit
				//
				if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength ==
					sizeof( ULONG )) 
				{
					NewLimit = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
				}
				else
				{
					NewLimit = 0;
				}
				//
				//	report actual timeout limit
				//
				if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength ==
					sizeof( ULONG ))
				{
					*(PULONG)Irp->AssociatedIrp.SystemBuffer = 
						SmartcardExtension->ReaderExtension->MaxRetries * DELAY_PSCR_WAIT;
					Irp->IoStatus.Information = sizeof( ULONG );
				}
				//
				//	set new timeout limit
				//
				if( NewLimit != 0 )
				{
					SmartcardExtension->ReaderExtension->MaxRetries =
						(NewLimit + DELAY_PSCR_WAIT - 1) / DELAY_PSCR_WAIT;
				}
			}
			NTStatus = STATUS_SUCCESS;
			break;

		case IOCTL_GET_CONFIGURATION:
			//
			//	return IOBase and IRQ
			//
			if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
				SIZEOF_PSCR_CONFIGURATION )
			{
				NTStatus = STATUS_BUFFER_TOO_SMALL;
			}
			else
			{
				PPSCR_CONFIGURATION	PSCRConfiguration;

				PSCRConfiguration = 
					(PPSCR_CONFIGURATION)Irp->AssociatedIrp.SystemBuffer;
				PSCRConfiguration->IOBase = 
					SmartcardExtension->ReaderExtension->IOBase;
				PSCRConfiguration->IRQ = 
					SmartcardExtension->ReaderExtension->CurrentIRQ;

				Irp->IoStatus.Information = SIZEOF_PSCR_CONFIGURATION;
				NTStatus = STATUS_SUCCESS;
			}
			break;

		default:
			break;
	}
	//
	//	set status of the packet
	//
	Irp->IoStatus.Status = NTStatus;

	SmartcardDebug( 
		DEBUG_TRACE, 
		( "PSCR!PscrGenericIOCTL: Exit\n" )
		);
	
	return( NTStatus );
}

BOOLEAN
PscrIrqServiceRoutine(
    PKINTERRUPT			Interrupt,
	PDEVICE_EXTENSION	DeviceExtension
	)
/*++

PscrIrqServiceRoutine:
	because the device not supports shared interrupts, the call is passed
	to the DPC routine immediately and the IRQ is reported as served

Arguments:
    Interrupt			interrupt object related to the interrupt
	DeviceExtension		context of call

Return Value:
	STATUS_SUCCESS

--*/
{
	SmartcardDebug( 
		DEBUG_TRACE, 
		("PSCR!PscrIrqServiceRoutine: Enter\n")
		);
	//
    // When someone yanks out the card the interrupt handler gets called,
    // but since there is no card anymore when don't need to schedule a DPC
    //

	//
	//	the interrupt is caused by a freeze event. the interface will be
	//	cleared either by PscrRead() or the DPC routine (depending on
	//	which is called first)
	//
	DeviceExtension->SmartcardExtension.ReaderExtension->FreezePending = TRUE;

    InterlockedIncrement(&DeviceExtension->PendingInterrupts);

	KeInsertQueueDpc(
		&DeviceExtension->DpcObject,
		DeviceExtension,
		&DeviceExtension->SmartcardExtension
		);

	SmartcardDebug( 
		DEBUG_TRACE, 
		( "PSCR!PscrIrqServiceRoutine: Exit\n" )
		);

	return TRUE;
}

VOID
PscrDpcRoutine(
	PKDPC					Dpc,
	PDEVICE_OBJECT			DeviceObject,
	PDEVICE_EXTENSION		DeviceExtension,
	PSMARTCARD_EXTENSION	SmartcardExtension
    )
/*++

PscrDpcRoutine:
	finishes interrupt requests. the freeze event data of the reader will be read
	& the card state will be updated if data valid

Arguments:
	Dpc					dpc object related to the call
	DeviceObject		context of the device
	DeviceExtension		passed as system argument 1
	SmartcardExtension	passed as system argument 2

Return Value:
	void

--*/
{
  	NTSTATUS status = STATUS_SUCCESS;
    UCHAR Event;

	SmartcardDebug( 
		DEBUG_TRACE, 
		( "PSCR!PscrInterruptEvent: IoBase %xh\n", 
		SmartcardExtension->ReaderExtension->IOBase)
		);

	//
	//	In case of a card change the reader provides a TLV packet describing
	//	the event ('freeze event'). If PscrRead was called before the DPC
	//	routine is called, this event was cleared; in this case the card state
	//	will be updated by reading the card status file
	//

	if( DeviceExtension->IoCount > 0 ) {

		SmartcardExtension->ReaderExtension->RequestCancelled = TRUE;
	}

    do {

        ASSERT(DeviceExtension->PendingInterrupts < 10);

	    SmartcardDebug( 
		    DEBUG_TRACE, 
		    ( "PSCR!PscrInterruptEvent: PendingInterrupts = %ld\n", 
		    DeviceExtension->PendingInterrupts)
		    );
        PscrFreeze( SmartcardExtension );

    } while (InterlockedDecrement(&DeviceExtension->PendingInterrupts) > 0);
}

void
PscrFreeze(
	PSMARTCARD_EXTENSION	SmartcardExtension
	)

/*++
PscrFreeze:
	Read & evaluate freeze data

Arguments:
	ReaderExtension	context of call
	pDevice			device which causes the freeze event

Return Value:
	STATUS_SUCCESS
	STATUS_UNSUCCESSFUL

--*/
{
	NTSTATUS NTStatus = STATUS_UNSUCCESSFUL;
	PREADER_EXTENSION ReaderExtension;
	PPSCR_REGISTERS	IOBase;
	UCHAR TLVList[9], CardState;
	ULONG NBytes;
	ULONG Idx, Retries, Status;
	UCHAR ReadFreeze[] = { 0x12, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x01, 0xA6 };

	ReaderExtension	= SmartcardExtension->ReaderExtension;
	IOBase = ReaderExtension->IOBase;

	ReaderExtension->RequestCancelled = FALSE;

    for (Retries = 0; Retries < 5; Retries++) {

		Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg );

		ReaderExtension->InvalidStatus = TRUE;
		if(!( Status & PSCR_DATA_AVAIL_BIT ))
		{
			PscrWriteDirect(
				ReaderExtension,
				ReadFreeze,
				sizeof( ReadFreeze ),
				&NBytes
				);

            SysDelay(15);
		}

		NTStatus = PscrRead( 
			ReaderExtension,
			(PUCHAR) TLVList,
			sizeof( TLVList ),
			&NBytes
			);
		ReaderExtension->InvalidStatus = FALSE;

		if( NT_SUCCESS( NTStatus ) && ( NBytes == 9 ))
		{
			//	get result
			if( ( TLVList[ PSCR_NAD ] == 0x21 ) && 
				( TLVList[ PSCR_INF ] == TAG_FREEZE_EVENTS ))
			{
                CardState = 
                    (TLVList[PSCR_INF + 2] == DEVICE_ICC1 ? PSCR_ICC_PRESENT : PSCR_ICC_ABSENT);

	            SmartcardDebug( 
		            DEBUG_TRACE, 
		            ( "PSCR!PscrFreeze: CardState = %d\n", 
		            CardState)
		            );

            	CBUpdateCardState(SmartcardExtension, CardState, FALSE);
			}
		}
	} 
}

NTSTATUS
PscrCancel(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

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

--*/

{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
	PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;

    SmartcardDebug(
        DEBUG_TRACE,
        ("PSCR!PscrCancel: Enter\n")
        );

    ASSERT(Irp == smartcardExtension->OsData->NotificationIrp);

    smartcardExtension->OsData->NotificationIrp = NULL;

	Irp->IoStatus.Information = 0;
	Irp->IoStatus.Status = STATUS_CANCELLED;

    IoReleaseCancelSpinLock(
        Irp->CancelIrql
        );

	SmartcardDebug(
		DEBUG_DRIVER,
		("PSCR!PscrCancel: Completing wait for Irp = %lx\n",
        Irp)
		);

	IoCompleteRequest(
		Irp,
		IO_NO_INCREMENT
		);

    SmartcardDebug(
        DEBUG_TRACE,
        ("PSCR!PscrCancel: Exit\n")
        );

    return STATUS_CANCELLED;
}

NTSTATUS
PscrCleanup(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

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

--*/

{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
	PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
	NTSTATUS status = STATUS_SUCCESS;

    SmartcardDebug(
        DEBUG_TRACE,
        ("%s!PscrCleanup: Enter\n",
        DRIVER_NAME)
        );

    IoAcquireCancelSpinLock(&(Irp->CancelIrql));

    if (smartcardExtension->OsData->NotificationIrp) {

        // We need to complete the notification irp
		IoSetCancelRoutine( 
            smartcardExtension->OsData->NotificationIrp, 
            NULL 
            );

        PscrCancel(
            DeviceObject,
            smartcardExtension->OsData->NotificationIrp
            );
    } else {     	

        IoReleaseCancelSpinLock( Irp->CancelIrql );
    }

	SmartcardDebug(
		DEBUG_DRIVER,
		("%s!PscrCleanup: 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!PscrCleanup: Exit\n",
        DRIVER_NAME)
        );

    return STATUS_SUCCESS;
}

void
SysDelay(
	ULONG Timeout
	)
/*++

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

--*/
{
	LARGE_INTEGER	SysTimeout;

	if( KeGetCurrentIrql() >= DISPATCH_LEVEL )
	{
		ULONG	Cnt = 20 * Timeout;

		while( Cnt-- )
		{
			//	KeStallExecutionProcessor: counted in us
			KeStallExecutionProcessor( 50 );
		}
	}
	else
	{
		SysTimeout.QuadPart = (LONGLONG)-10 * 1000 * Timeout;

		//	KeDelayExecutionThread: counted in 100 ns
		KeDelayExecutionThread( KernelMode, FALSE, &SysTimeout );
	}
	return;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -