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

📄 pciscc_drv.c

📁 高速同步串口芯片PEB20534的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:

/* ---------------------------------------------------------------- */

/* 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 + -