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

📄 pciscc_drv.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			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 + -