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

📄 amcc.cpp

📁 The PCI Local bus concept was developed to break the PC data I/O bottleneck and clearly opens the d
💻 CPP
字号:
/*

AMCC.cpp

Sheldon Instruments, Inc.

Abstract:

	Functions for communicating with AMCC 5933/5920.  Used by IOctl.cpp.

Revision History:

    23Mar1999 - created by Robert Updike
	24Feb2000 - added SheldonUnMapDirect.  Robert Updike
	2002-07-10: mik
		Using byte count for SheldonConfigRead.

*/

#include "driver.h"

/*

Function Name:

	SheldonNVRead

Routine Description:

    Read from the NVRam.

Arguments:

	Irp - I/O request being serviced

	pdx - pointer to the device extension.

Return Value:

    STATUS_SUCCESS if successful
	STATUS_TIMEOUT if timeout occurs

*/
NTSTATUS SheldonNVRamRead(PIRP Irp, PDEVICE_EXTENSION pdx)
{
	PULONG params;
	PUCHAR NV_Control_Reg, NV_Data_Reg;
	ULONG Attempts = 0;

	params = (PULONG) Irp->AssociatedIrp.SystemBuffer;		
	NV_Control_Reg = ((PUCHAR) (pdx->base[AMCC_OPREGS])) + AMCC_NV_CONTROL_REG_OFFSET;
	NV_Data_Reg=((PUCHAR) (pdx->base[AMCC_OPREGS])) + AMCC_NV_DATA_REG_OFFSET;

/////////////////
// IO and memory mapped
/////////////////
	if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
		// wait while device busy
		while(Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_REGISTER_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if(Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// once free, set the control reg for low address
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_LOW_ADDRESS_COMMAND);
		// then write the low part of the address
		WRITE_REGISTER_UCHAR(NV_Data_Reg, (UCHAR) (*params & 0x000000FF));
		// set up for high half of address
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_HIGH_ADDRESS_COMMAND);
		// then write the high part of the address
		WRITE_REGISTER_UCHAR(NV_Data_Reg, (UCHAR) ((*params >> 8) & 0x000000FF));
		// now send the read command
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_READ_COMMAND);

		Attempts = 0;	// reset the timeout counter

		// wait while device busy
		while(Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_REGISTER_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if(Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// now read the data and put it into the outgoing buffer
		*params = (ULONG) READ_REGISTER_UCHAR(NV_Data_Reg);
	}
	else {
		// wait while device busy
		while(Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_PORT_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if(Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// once free, set the control reg for low address
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_LOW_ADDRESS_COMMAND);
		// then write the low part of the address
		WRITE_PORT_UCHAR(NV_Data_Reg, (UCHAR) (*params & 0x000000FF));
		// set up for high half of address
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_HIGH_ADDRESS_COMMAND);
		// then write the high part of the address
		WRITE_PORT_UCHAR(NV_Data_Reg, (UCHAR) ((*params >> 8) & 0x000000FF));
		// now send the read command
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_READ_COMMAND);

		Attempts = 0;	// reset the timeout counter

		// wait while device busy
		while(Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_PORT_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if(Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// now read the data and put it into the outgoing buffer
		*params = (ULONG) READ_PORT_UCHAR(NV_Data_Reg);
	}

	return STATUS_SUCCESS;
}

/*

Function Name:

	SheldonNVRAMWrite

Routine Description:

    Write to the NVRam.

Arguments:

	Irp - I/O request being serviced

	pdx - pointer to the device extension.

Return Value:

    STATUS_SUCCESS if successful
	STATUS_TIMEOUT if timeout occurs

*/
NTSTATUS SheldonNVRamWrite(PIRP Irp, PDEVICE_EXTENSION pdx)
{
	PULONG params;
	PUCHAR NV_Control_Reg, NV_Data_Reg;
	ULONG Attempts = 0;

	params = (PULONG) Irp->AssociatedIrp.SystemBuffer;		
	NV_Control_Reg = ((PUCHAR) (pdx->base[AMCC_OPREGS])) + AMCC_NV_CONTROL_REG_OFFSET;
	NV_Data_Reg=((PUCHAR) (pdx->base[AMCC_OPREGS])) + AMCC_NV_DATA_REG_OFFSET;

/////////////////
// IO and memory mapped
/////////////////
	if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
		// wait while device busy
		while (Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_REGISTER_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if (Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// once free, set the control reg for low address
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_LOW_ADDRESS_COMMAND);
		// then write the low part of the address
		WRITE_REGISTER_UCHAR(NV_Data_Reg, (UCHAR) (params[SI_NV_OFFSET_INDEX] & 0x000000FF));
		// set up for high half of address
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_HIGH_ADDRESS_COMMAND);
		// then write the high part of the address
		WRITE_REGISTER_UCHAR(NV_Data_Reg, (UCHAR) ((params[SI_NV_OFFSET_INDEX] >> 8) & 0x000000FF));
		// now send a dummy command to latch the address
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_NO_COMMAND);
		// now set the data into the data reg
		WRITE_REGISTER_UCHAR(NV_Data_Reg, (UCHAR) params[SI_NV_WRITE_DATA_INDEX]);
		// now send the write command
		WRITE_REGISTER_UCHAR(NV_Control_Reg, AMCC_NV_WRITE_COMMAND);

		// wait while device busy
		while (Attempts<AMCC_NV_MAX_ATTEMPTS && (READ_REGISTER_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if (Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;
	}
	else {
		// wait while device busy
		while (Attempts < AMCC_NV_MAX_ATTEMPTS && (READ_PORT_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if (Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;

		// once free, set the control reg for low address
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_LOW_ADDRESS_COMMAND);
		// then write the low part of the address
		WRITE_PORT_UCHAR(NV_Data_Reg, (UCHAR) (params[SI_NV_OFFSET_INDEX] & 0x000000FF));
		// set up for high half of address
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_HIGH_ADDRESS_COMMAND);
		// then write the high part of the address
		WRITE_PORT_UCHAR(NV_Data_Reg, (UCHAR) ((params[SI_NV_OFFSET_INDEX] >> 8) & 0x000000FF));
		// now send a dummy command to latch the address
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_NO_COMMAND);
		// now set the data into the data reg
		WRITE_PORT_UCHAR(NV_Data_Reg, (UCHAR) params[SI_NV_WRITE_DATA_INDEX]);
		// now send the write command
		WRITE_PORT_UCHAR(NV_Control_Reg, AMCC_NV_WRITE_COMMAND);

		// wait while device busy
		while (Attempts<AMCC_NV_MAX_ATTEMPTS && (READ_PORT_UCHAR(NV_Control_Reg) & AMCC_NV_BUSY_MASK))
			Attempts++;

		if (Attempts == AMCC_NV_MAX_ATTEMPTS)
			return STATUS_TIMEOUT;
	}

	return STATUS_SUCCESS;
}

/*

Function Name:

	SheldonUnMapDirect

Routine Description:

    Frees the memory allocated by SheldonMapDirect.

Arguments:

	pdx - pointer to the device extension.

Return Value:

    STATUS_SUCCESS if successful
	NT status code

*/
NTSTATUS SheldonUnMapDirect(PDEVICE_EXTENSION pdx)
{
	NTSTATUS ntStatus = STATUS_SUCCESS;
	int i;

	KdPrint(("SIWDM - Entering SheldonUnMapDirect\n"));

	for(i=0;i<PCI_TYPE0_ADDRESSES;i++)
	{
		if(pdx->Direct_Baddr[i] != NULL)
		{
			__try
			{
				MmUnmapLockedPages((PVOID) pdx->Direct_Baddr[i], pdx->Mdl[i]);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				ntStatus = GetExceptionCode();
				KdPrint(("SIWDM - SheldonUnMapDirect:  Fail to Unmap Mdl[%x]\n", i));
				KdPrint(("SIWDM - SheldonUnMapDirect:  Error Code %x\n", ntStatus));
			}

			pdx->Direct_Baddr[i] = NULL;
		}

		if(pdx->Mdl[i] != NULL)
		{
			__try
			{
				IoFreeMdl(pdx->Mdl[i]);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				ntStatus = GetExceptionCode();
				KdPrint(("SIWDM - SheldonUnMapDirect:  Fail to Free Mdl[%x]\n", i));
				KdPrint(("SIWDM - SheldonUnMapDirect:  Error Code %x\n", ntStatus));
			}

			pdx->Mdl[i] = NULL;
		}
	}

	KdPrint(("SIWDM - Exiting SheldonUnMapDirect\n"));

    return ntStatus;
}

/*

Function Name:

	SheldonConfigRead

Routine Description:

    Enables the user application to read the PCI configuration space for the device.
	This function creates an IRP which is passed down to the PCI bus driver, which handles
	the request.

Arguments:

	fdo - pointer to the function device object

	Irp - I/O request being serviced

	pdx - pointer to the device extension.

Return Value:

    STATUS_SUCCESS if successful
	NT status code

*/
NTSTATUS SheldonConfigRead(IN PDEVICE_OBJECT fdo, PIRP Irp, PDEVICE_EXTENSION pdx)
{
	PULONG params;
	NTSTATUS ntStatus;
	PIO_STACK_LOCATION ConfigIrpStack;
	PIRP ConfigIrp;
	KEVENT ConfigEvent;
	ULONG byteCount;

	// read the configuration space of the device
	params = (PULONG) Irp->AssociatedIrp.SystemBuffer;

	byteCount = params[SI_CONFIG_COUNT_INDEX];

	// write number of bytes coming back, before this param is overwritten
	Irp->IoStatus.Information = byteCount;

	ConfigIrp = IoAllocateIrp(fdo->StackSize, FALSE);
	
	if(ConfigIrp == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;

	KeInitializeEvent(&ConfigEvent, NotificationEvent, FALSE);

	IoSetCompletionRoutine
	(
		ConfigIrp, 
		(PIO_COMPLETION_ROUTINE) OnRequestComplete, 
		&ConfigEvent, 
		TRUE, TRUE, TRUE
	);

	ConfigIrpStack = IoGetNextIrpStackLocation(ConfigIrp);

	if(ConfigIrpStack == NULL)
		return STATUS_INSUFFICIENT_RESOURCES;

	ConfigIrpStack -> MajorFunction = IRP_MJ_PNP;
	ConfigIrpStack -> MinorFunction = IRP_MN_READ_CONFIG;
	ConfigIrpStack -> Parameters.ReadWriteConfig.Buffer = (PVOID) &(params[SI_CONFIG_READ_DATA_INDEX]);
	ConfigIrpStack -> Parameters.ReadWriteConfig.Offset = params[SI_CONFIG_OFFSET_INDEX];
	ConfigIrpStack -> Parameters.ReadWriteConfig.Length = byteCount;

	ntStatus = IoCallDriver(fdo, ConfigIrp);

	if(ntStatus == STATUS_PENDING)
	{
		KeWaitForSingleObject(&ConfigEvent, Executive, KernelMode, FALSE, NULL);
		ntStatus = ConfigIrp->IoStatus.Status;
	}

	IoFreeIrp(ConfigIrp);

	return ntStatus;
}

⌨️ 快捷键说明

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