📄 pciscc_drv.c
字号:
/* ---------------------------------------------------------------- */
/* clear RX frame list on driver shutdown */
VOID pciscc_clear_rxlist(
IN PLOCAL_DEVICE_INFO pLDI
)
{
PLIST_ENTRY pEntry;
L1FRAME *l1_frame;
while (!IsListEmpty(&pLDI->RxQueue))
{
pEntry = RemoveHeadList(&pLDI->RxQueue);
l1_frame = CONTAINING_RECORD(pEntry,L1FRAME,list_entry);
pciscc_free(l1_frame);
}
}
VOID pciscc_clear_rxpending(
IN PLOCAL_DEVICE_INFO pLDI
)
{
PLIST_ENTRY pEntry;
PIRP pIrp;
while (!IsListEmpty(&pLDI->RxPending))
{
pEntry = RemoveHeadList(&pLDI->RxPending);
pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
}
/* release registered hardware resources */
VOID pciscc_free_resources(
IN PDRIVER_OBJECT DriverObject
)
{
CM_RESOURCE_LIST NullResourceList;
BOOLEAN ResourceConflict;
RtlZeroMemory((PVOID)&NullResourceList, sizeof(NullResourceList));
IoReportResourceUsage(
NULL,
DriverObject,
&NullResourceList,
sizeof(ULONG),
NULL,
NULL,
0,
FALSE,
&ResourceConflict );
}
/* ---------------------------------------------------------------- */
/* allocate memory at phys. address <= 0xffffffff */
PVOID pciscc_alloc(
IN ULONG uSize
)
{
PHYSICAL_ADDRESS MaxAddr;
MaxAddr.LowPart = 0xffffffff;
MaxAddr.HighPart = 0;
return MmAllocateContiguousMemory(uSize,MaxAddr);
}
/* release previously allocated memory */
VOID pciscc_free(
IN PVOID BaseAddr
)
{
MmFreeContiguousMemory(BaseAddr);
}
/* 32 bit memory read operation */
ULONG ReadL(
IN PLOCAL_DEVICE_INFO pLDI,
IN ULONG Offset
)
{
ULONG BaseAddr = (ULONG)pLDI->MappedAddress;
return READ_REGISTER_ULONG((PVOID)(BaseAddr + Offset));
}
/* 32 bit memory write operation */
VOID WriteL(
IN PLOCAL_DEVICE_INFO pLDI,
IN ULONG Offset,
IN ULONG Value
)
{
ULONG BaseAddr = (ULONG)pLDI->MappedAddress;
WRITE_REGISTER_ULONG((PVOID)(BaseAddr + Offset), Value);
}
/* Calculate phys. bus address */
ULONG VirtToPhys(
IN PVOID Address
)
{
PHYSICAL_ADDRESS PhysAddr = MmGetPhysicalAddress(Address);
return PhysAddr.LowPart;
}
/* ---------------------------------------------------------------- */
/* WinNT PCI chip detection */
NTSTATUS pciscc_nt_config(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath,
IN PLOCAL_DEVICE_INFO pLDI
)
{
ULONG BusNum;
ULONG DevNum;
ULONG MemType = 0;
ULONG AddrLen;
ULONG IrqLevel;
ULONG IrqVector;
ULONG i;
PHYSICAL_ADDRESS Address;
PCI_SLOT_NUMBER SlotNum; /* PCI slot (logical) */
PCI_COMMON_CONFIG Config; /* PCI Config. space */
PCM_RESOURCE_LIST ResourceList; /* Resource usage list */
PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
NTSTATUS Status;
BOOLEAN AddressAssigned = FALSE;
for (BusNum = 0; BusNum < 3; BusNum++)
{
for (DevNum = 0; DevNum < PCI_MAX_DEVICES; DevNum++)
{
SlotNum.u.bits.Reserved = 0;
SlotNum.u.bits.DeviceNumber = DevNum;
SlotNum.u.bits.FunctionNumber = 0;
/* read PCI configuration */
if (HalGetBusData( PCIConfiguration, BusNum, SlotNum.u.AsULONG,
&Config, PCI_COMMON_HDR_LENGTH) < sizeof(PCI_COMMON_HDR_LENGTH))
continue;
/* device found */
if (Config.VendorID == PCI_VENDOR_ID &&
Config.DeviceID == PCI_DEVICE_ID)
{
// Register resource usage
Status = HalAssignSlotResources(RegistryPath, NULL, DriverObject, NULL, PCIBus,
BusNum, SlotNum.u.AsULONG, &ResourceList);
if (!NT_SUCCESS(Status))
{
DbgPrint("PCISCC: Resource assignment problem %8X\n", Status);
return Status;
}
PartialResourceList = &ResourceList->List[0].PartialResourceList;
for (i = 0; i < PartialResourceList->Count; i++)
{
if (PartialResourceList->PartialDescriptors[i].Type == CmResourceTypeMemory && !AddressAssigned)
{
Address = PartialResourceList->PartialDescriptors[i].u.Memory.Start;
AddrLen = PartialResourceList->PartialDescriptors[i].u.Memory.Length;
AddressAssigned = TRUE;
}
if (PartialResourceList->PartialDescriptors[i].Type == CmResourceTypeInterrupt)
{
IrqLevel = PartialResourceList->PartialDescriptors[i].u.Interrupt.Level;
IrqVector = PartialResourceList->PartialDescriptors[i].u.Interrupt.Vector;
}
}
/* Translate the address into a form NT likes. */
HalTranslateBusAddress( PCIBus,
BusNum,
Address,
&MemType,
&pLDI->Address );
pLDI->AddrLen = AddrLen;
/* Translate interrupt vector */
pLDI->IrqVector = HalGetInterruptVector(PCIBus, BusNum, IrqLevel, IrqVector,
&pLDI->IrqLevel, &pLDI->IrqAffinity );
DbgPrint("PCISCC: PEB20534 (DSCC4) chip found at address 0x%X, irq %d\n", Address.LowPart, IrqLevel);
return STATUS_SUCCESS;
}
}
}
DbgPrint("PCISCC: PEB20534 (DSCC4) chip not found\n");
return STATUS_NO_SUCH_DEVICE;
}
NTSTATUS pciscc_init_queues(
IN PLOCAL_DEVICE_INFO pLDI,
IN ULONG chan
)
{
struct rx_desc *first_rdp = NULL;
struct rx_desc *curr_rdp = NULL;
struct rx_desc *last_rdp = NULL;
struct tx_desc *first_tdp = NULL;
struct tx_desc *curr_tdp = NULL;
struct tx_desc *last_tdp = NULL;
PCHANNEL_INFO pChan = &pLDI->Channel[chan];
ULONG err = 0;
ULONG i;
/* allocate TX/RX interrupt queues */
pChan->iq_rx = pLDI->DmaBuffers->iq_rx[chan];
pChan->iq_tx = pLDI->DmaBuffers->iq_tx[chan];
RtlZeroMemory(pChan->iq_rx, 4*CFG_IQLEN);
RtlZeroMemory(pChan->iq_tx, 4*CFG_IQLEN);
pChan->iq_rx_next = pChan->iq_rx;
pChan->iq_tx_next = pChan->iq_tx;
/*
* Prepare circular RX and TX descriptor queues ("FIFO" rings)
* Attention:
* This beast gets _very_ angry if you try to hand it a
* descriptor with a data length of 0. In fact it crashes
* the system by asserting /SERR or something.
*/
/* allocate queues */
pChan->dq_rx = pLDI->DmaBuffers->dq_rx[chan];
pChan->dq_tx = pLDI->DmaBuffers->dq_tx[chan];
RtlZeroMemory(pChan->dq_rx,sizeof(struct rx_desc) * CFG_RX_DESC);
RtlZeroMemory(pChan->dq_tx,sizeof(struct tx_desc) * CFG_TX_DESC);
/* RX queue */
first_rdp = pChan->dq_rx;
for (i=0, curr_rdp = first_rdp; i < CFG_RX_DESC; i++, curr_rdp++) {
if (i > 0) {
curr_rdp->prev = last_rdp;
last_rdp->next = curr_rdp;
last_rdp->nextptr = VirtToPhys(curr_rdp);
}
curr_rdp->l1_frame = pciscc_alloc(sizeof(L1FRAME));
if (curr_rdp->l1_frame == NULL) err++;
curr_rdp->dataptr = VirtToPhys(curr_rdp->l1_frame->frame);
curr_rdp->flags = CFG_MTU*NO;
curr_rdp->feptr = 0;
curr_rdp->result = 0;
last_rdp = curr_rdp;
}
if (err) {
for (i=0; i < CFG_RX_DESC; i++)
{
if (pChan->dq_rx[i].l1_frame)
pciscc_free(pChan->dq_rx[i].l1_frame);
}
return STATUS_NO_MEMORY;
}
last_rdp->next = first_rdp; /* close circular structure */
last_rdp->nextptr = VirtToPhys(first_rdp);
first_rdp->prev = last_rdp;
pChan->dq_rx_next = first_rdp; /* first descriptor to be processed = "first" descriptor in chain */
/* TX queue */
first_tdp = pChan->dq_tx;
for (i=0, curr_tdp = first_tdp; i < CFG_TX_DESC; i++, curr_tdp++) {
if (i > 0) {
curr_tdp->prev = last_tdp;
last_tdp->next = curr_tdp;
last_tdp->nextptr = VirtToPhys(curr_tdp);
}
curr_tdp->l1_frame = NULL;
curr_tdp->dataptr = VirtToPhys(pLDI->DmaBuffers->dummy);
curr_tdp->flags = FE | (8*NO);
curr_tdp->result = 0;
last_tdp = curr_tdp;
}
last_tdp->next = first_tdp; /* close circular structure */
last_tdp->nextptr = VirtToPhys(first_tdp);
first_tdp->prev = last_tdp;
pChan->dq_tx_last = first_tdp; /* last descriptor to be transmitted */
pChan->dq_tx_cleanup = first_tdp; /* first descriptor to be cleaned up */
return STATUS_SUCCESS;
}
/*
* initialize chip, called during driver initialization procedure
* action sequency was carefully chosen, don't mess with it
*/
NTSTATUS pciscc_chip_open(
IN PLOCAL_DEVICE_INFO pLDI
)
{
LARGE_INTEGER time;
LARGE_INTEGER time_expire;
if (pLDI->initialized)
return STATUS_SUCCESS;
/* allocate DMS buffers */
pLDI->DmaBuffers = pciscc_alloc(sizeof(DMA_BUFFERS));
if (pLDI->DmaBuffers == NULL)
return STATUS_NO_MEMORY;
/* peripheral interrupt queue */
pLDI->iq_per = pLDI->DmaBuffers->iq_per;
/* configuration interrupt queue */
pLDI->iq_cfg = pLDI->DmaBuffers->iq_cfg;
/* Map base address */
pLDI->MappedAddress = MmMapIoSpace(pLDI->Address,pLDI->AddrLen,FALSE);
/* Plug in ISR function */
IoConnectInterrupt( &pLDI->IrqObject, pciscc_isr, pLDI, NULL,
pLDI->IrqVector, pLDI->IrqLevel, pLDI->IrqLevel,
LevelSensitive, TRUE, pLDI->IrqAffinity, FALSE );
/* Init queue pointer */
RtlZeroMemory(pLDI->iq_per, 4*CFG_IQLEN);
RtlZeroMemory(pLDI->iq_cfg, 4*CFG_IQLEN);
pLDI->iq_per_next = pLDI->iq_per;
pLDI->iq_cfg_next = pLDI->iq_cfg;
/* global hardware initialization */
WriteL(pLDI,GMODE, (4 * PERCFG) | (3 * LCD) | CMODE);
WriteL(pLDI,IQPBAR,VirtToPhys(pLDI->iq_per));
WriteL(pLDI,IQCFGBAR,VirtToPhys(pLDI->iq_cfg));
WriteL(pLDI,IQLENR2,(((CFG_IQLEN/32)-1)*IQCFGLEN) | (((CFG_IQLEN/32)-1)*IQPLEN));
WriteL(pLDI,FIFOCR1,((32/4)*TFSIZE0)
| ((32/4)*TFSIZE1)
| ((32/4)*TFSIZE2)
| ((32/4)*TFSIZE3));
WriteL(pLDI,FIFOCR2,((24/4)*TFRTHRES0)
| ((24/4)*TFRTHRES1)
| ((24/4)*TFRTHRES2)
| ((24/4)*TFRTHRES3)
| M4_0 | M4_1 | M4_2 | M4_3);
WriteL(pLDI,FIFOCR3,CFG_FIFO_RX_T);
WriteL(pLDI,FIFOCR4,(20*TFFTHRES0)
| (20*TFFTHRES1)
| (20*TFFTHRES2)
| (20*TFFTHRES3));
/* mask out all DMAC interrupts */
WriteL(pLDI,CH0CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH1CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH2CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH3CFG,(MRFI | MTFI | MRERR | MTERR));
/* all SCC cores in reset state */
WriteL(pLDI,SCCBASE[0]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[1]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[2]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[3]+CCR0,0x00000000);
/* mask out all SCC interrupts */
WriteL(pLDI,SCCBASE[0]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[1]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
/* peripheral configuration */
WriteL(pLDI,LCONF,(BTYP*3));
WriteL(pLDI,SSCCON,0x00000000);
WriteL(pLDI,SSCIM,0x00000000);
WriteL(pLDI,GPDIR,0x000000ff);
WriteL(pLDI,GPDATA,0x00000000);
WriteL(pLDI,GPIM,0x00000000);
/* initialize configuration and peripheral IQs */
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,GCMDR, CFGIQCFG | CFGIQP | AR);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox == MAILBOX_OK) {
pLDI->initialized = 1;
return STATUS_SUCCESS;
}
/* global configuration to reset state */
WriteL(pLDI,GMODE,(4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
/* mask all DMAC interrupts */
WriteL(pLDI,CH0CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH1CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH2CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH3CFG,(MRFI | MTFI | MRERR | MTERR));
/* SCC cores to reset state */
WriteL(pLDI,SCCBASE[0]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[1]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[2]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[3]+CCR0,0x00000000);
/* mask all SCC interrupts */
WriteL(pLDI,SCCBASE[0]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[1]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
/* queues no longer exist */
pLDI->iq_per_next = NULL;
pLDI->iq_cfg_next = NULL;
/* Shut down ISR routine */
IoDisconnectInterrupt(pLDI->IrqObject);
/* Unmap memory */
MmUnmapIoSpace(pLDI->MappedAddress,pLDI->AddrLen);
/* Release buffers */
pciscc_free(pLDI->DmaBuffers);
/* Print debug message */
DbgPrint("PCISCC: Interrupt queue error (pciscc_chip_open)\n");
return STATUS_IO_TIMEOUT;
}
/*
* close chip, called when last device (channel) of a chip was closed.
* don't mess up.
*/
VOID pciscc_chip_close(
IN PLOCAL_DEVICE_INFO pLDI
)
{
ULONG chan;
if (!pLDI->initialized)
return;
/* close channels */
for (chan = 0; chan < 4; chan++)
pciscc_channel_close(pLDI,chan);
pLDI->initialized = 0;
/* global configuration to reset state */
WriteL(pLDI,GMODE,(4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
/* mask all DMAC interrupts */
WriteL(pLDI,CH0CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH1CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH2CFG,(MRFI | MTFI | MRERR | MTERR));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -