📄 amcc.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 + -