📄 pciscc_drv.c
字号:
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_STATE_2:
if (RdCnt < sizeof(ULONG))
break;
pIOBuffer[0] = pciscc_state(pLDI,2);
Result = sizeof(ULONG);
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_STATE_3:
if (RdCnt < sizeof(ULONG))
break;
pIOBuffer[0] = pciscc_state(pLDI,3);
Result = sizeof(ULONG);
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_INFO_0:
if (RdCnt > sizeof(L1_STATISTICS))
RdCnt = sizeof(L1_STATISTICS);
RtlCopyMemory(pIOBuffer, &pLDI->Channel[0].stats, RdCnt);
Result = RdCnt;
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_INFO_1:
if (RdCnt < sizeof(L1_STATISTICS))
RdCnt = sizeof(L1_STATISTICS);
RtlCopyMemory(pIOBuffer, &pLDI->Channel[1].stats, RdCnt);
Result = RdCnt;
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_INFO_2:
if (RdCnt < sizeof(L1_STATISTICS))
RdCnt = sizeof(L1_STATISTICS);
RtlCopyMemory(pIOBuffer, &pLDI->Channel[2].stats, RdCnt);
Result = RdCnt;
Status = STATUS_SUCCESS;
break;
case PCISCC_GET_INFO_3:
if (RdCnt < sizeof(L1_STATISTICS))
RdCnt = sizeof(L1_STATISTICS);
RtlCopyMemory(pIOBuffer, &pLDI->Channel[3].stats, RdCnt);
Result = RdCnt;
Status = STATUS_SUCCESS;
break;
case PCISCC_NONBLOCK_READ:
pLDI->ReadMode = 0;
pciscc_clear_rxpending(pLDI);
Status = STATUS_SUCCESS;
break;
case PCISCC_BLOCK_READ:
pLDI->ReadMode = 1;
Status = STATUS_SUCCESS;
break;
default:
Status = STATUS_NOT_IMPLEMENTED;
break;
}
KeReleaseSpinLock(&pLDI->Lock,OldIrql);
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = Result;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return Status;
}
/* unload driver */
VOID pciscc_unload(
IN PDRIVER_OBJECT DriverObject
)
{
DbgPrint("PCISCC: Driver unloaded\n");
}
/* completion routine */
NTSTATUS pciscc_complete(
IN PDEVICE_OBJECT pDO,
IN PIRP pIrp,
IN PVOID Context
)
{
PKEVENT pEvent;
pEvent = (PKEVENT) Context;
if (pIrp->PendingReturned)
IoMarkIrpPending(pIrp);
KeSetEvent(pEvent, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/* pending IRP cancel routine */
VOID pciscc_cancel(
IN PDEVICE_OBJECT pDO,
IN PIRP pIrp
)
{
PLOCAL_DEVICE_INFO pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension;
KIRQL OldIrql;
IoReleaseCancelSpinLock(pIrp->CancelIrql);
KeAcquireSpinLock(&pLDI->Lock,&OldIrql);
if (!IsListEmpty(&pIrp->Tail.Overlay.ListEntry))
{
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
KeReleaseSpinLock(&pLDI->Lock,OldIrql);
}
/* ---------------------------------------------------------------- */
/* 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);
}
}
/* ---------------------------------------------------------------- */
/* 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;
}
/* ---------------------------------------------------------------- */
/* Win2000 PNP config */
NTSTATUS pciscc_2k_config(
IN PDEVICE_OBJECT pDO,
IN PIRP pIrp
)
{
PLOCAL_DEVICE_INFO pLDI = pDO->DeviceExtension;
PIO_STACK_LOCATION pIrpStack;
PCM_RESOURCE_LIST ResourceList;
PCM_RESOURCE_LIST ResourceListTranslated;
PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
ULONG i;
BOOLEAN AddressAssigned = FALSE;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
ResourceList = pIrpStack->Parameters.StartDevice.AllocatedResources;
ResourceListTranslated = pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
if ((ResourceList == NULL) || (ResourceListTranslated == NULL))
return STATUS_INSUFFICIENT_RESOURCES;
PartialResourceList = &ResourceListTranslated->List[0].PartialResourceList;
for (i = 0; i < PartialResourceList->Count; i++)
{
if (PartialResourceList->PartialDescriptors[i].Type == CmResourceTypeMemory && !AddressAssigned)
{
pLDI->Address = PartialResourceList->PartialDescriptors[i].u.Memory.Start;
pLDI->AddrLen = PartialResourceList->PartialDescriptors[i].u.Memory.Length;
AddressAssigned = TRUE;
}
if (PartialResourceList->PartialDescriptors[i].Type == CmResourceTypeInterrupt)
{
pLDI->IrqLevel = (KIRQL)PartialResourceList->PartialDescriptors[i].u.Interrupt.Level;
pLDI->IrqVector = PartialResourceList->PartialDescriptors[i].u.Interrupt.Vector;
pLDI->IrqAffinity = PartialResourceList->PartialDescriptors[i].u.Interrupt.Affinity;
}
}
DbgPrint("PCISCC: PnP reports PEB20534 (DSCC4) chip at address 0x%X\n",pLDI->Address.LowPart);
return STATUS_SUCCESS;
}
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -