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

📄 pcnet32_dev.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** Copyright 2001, Graham Batty. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/debug.h>#include <kernel/heap.h>#include <kernel/vm.h>#include <kernel/int.h>#include <kernel/lock.h>#include <kernel/sem.h>#include <kernel/module.h>#include <kernel/arch/cpu.h>#include <kernel/arch/i386/cpu.h>#include <kernel/net/ethernet.h>#include <kernel/bus/pci/pci.h>#include <string.h>#include "pcnet32_dev.h"#include "pcnet32_priv.h"//#define _PCNET32_VERBOSE#ifdef _PCNET32_VERBOSE# define debug_level_flow 3# define debug_level_error 3# define debug_level_info 3# define DEBUG_MSG_PREFIX "PCNET_DEV -- "# include <kernel/debug_ext.h>#else# define SHOW_FLOW(a,b,...)# define SHOW_FLOW0(a,b)#endif// mapping of initialization block rx and txlengthsstatic uint16 gringlens[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };#define WRITE_8(nic, reg, dat) \	(nic)->bus->write_io_8((nic)->io_port + (reg), dat)#define WRITE_16(nic, reg, dat) \	(nic)->bus->write_io_16((nic)->io_port + (reg), dat)#define WRITE_32(nic, reg, dat) \	(nic)->bus->write_io_32((nic)->io_port + (reg), dat)#define READ_8(nic, reg) \	(nic)->bus->read_io_8((nic)->io_port + (reg))#define READ_16(nic, reg) \	(nic)->bus->read_io_16((nic)->io_port + (reg))#define READ_32(nic, reg) \	(nic)->bus->read_io_32((nic)->io_port + (reg))#define RXRING_INDEX(_nic, _index) ((_index) & (_nic->rxring_count - 1))#define TXRING_INDEX(_nic, _index) ((_index) & (_nic->txring_count - 1))#define RXRING_BUFFER(_nic, _index) ((_nic)->rx_buffers + ((_index) * (_nic)->rx_buffersize))#define TXRING_BUFFER(_nic, _index) ((_nic)->tx_buffers + ((_index) * (_nic)->tx_buffersize))#define BUFFER_PHYS(_nic, _buffer) (addr_t)((_nic)->buffers_phys + ((_buffer) - (_nic)->buffers))static int pcnet32_int(void*);// call this to enable a receive buffer so the controller can fill it.static void rxdesc_init(pcnet32 *nic, uint16 index);static int pcnet32_thread(void *nic);static uint16 read_csr(pcnet32 *nic, uint32 reg){	WRITE_32(nic, PCNET_IO_ADDRPORT, reg);	return READ_32(nic, PCNET_IO_DATAPORT);}/* XX this function is not usedstatic uint16 read_bcr(pcnet32 *nic, uint32 reg){	WRITE_32(nic, PCNET_IO_ADDRPORT, reg);	return READ_32(nic, PCNET_IO_CONFIGPORT);}*/static void write_csr(pcnet32 *nic, uint32 reg, uint16 data){	WRITE_32(nic, PCNET_IO_ADDRPORT, reg);	WRITE_32(nic, PCNET_IO_DATAPORT, data);}// XX this function is not used (but perhaps should be in some places?static void modify_csr(pcnet32 *nic, uint32 reg, uint16 bits, uint16 set){	uint16 oldset;	acquire_spinlock(&nic->control_lock);	int_disable_interrupts();	// do stuff	oldset = read_csr(nic, reg);	oldset |= (bits & set);	oldset &= ~(bits & ~set);	write_csr(nic, reg, oldset);	int_restore_interrupts();	release_spinlock(&nic->control_lock);}static void write_bcr(pcnet32 *nic, uint32 reg, uint16 data){	WRITE_32(nic, PCNET_IO_ADDRPORT, reg);	WRITE_32(nic, PCNET_IO_CONFIGPORT, data);}pcnet32 *pcnet32_new(pci_module_hooks *bus, uint32 initmode, uint16 rxbuffer_size, uint16 txbuffer_size){	pcnet32 *nic = NULL;	uint16 rxring_count = gringlens[(initmode & PCNET_INIT_RXLEN_MASK) >> PCNET_INIT_RXLEN_POS];	uint16 txring_count = gringlens[(initmode & PCNET_INIT_TXLEN_MASK) >> PCNET_INIT_TXLEN_POS];	SHOW_FLOW(3, "initmode: 0x%.8x, rxring: (%d, %d), txring: (%d, %d)",		  initmode,		  rxring_count, rxbuffer_size,		  txring_count, txbuffer_size);	nic = (pcnet32*)kmalloc(sizeof(pcnet32));	if (nic == NULL)		goto err_none;	memset(nic, 0, sizeof(pcnet32));	nic->bus = bus;	nic->init_mode = initmode;	// Make it a 256-descriptor ring. 256*32 bytes long.	nic->rxring_count = rxring_count;	nic->rx_buffersize = rxbuffer_size;	nic->rxring_tail =	nic->rxring_head = 0;	nic->rxring_region = vm_create_anonymous_region(		vm_get_kernel_aspace_id(), "pcnet32_rxring", (void**)&nic->rxring,		REGION_ADDR_ANY_ADDRESS, nic->rxring_count * sizeof(struct pcnet32_rxdesc),		REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL | LOCK_RW);	if (nic->rxring_region < 0)		goto err_after_kmalloc;	memset(nic->rxring, 0, nic->rxring_count * sizeof(struct pcnet32_rxdesc));	vm_get_page_mapping(vm_get_kernel_aspace_id(),			    (addr_t)nic->rxring, &nic->rxring_phys);	SHOW_FLOW(3, "rxring physical address: 0x%x", nic->rxring_phys);	nic->rxring_sem = sem_create(0, "pcnet32_rxring");	if (nic->rxring_sem < 0)		goto err_after_rxring_region;	if (mutex_init(&nic->rxring_mutex, "pcnet32_rxring") < 0)		goto err_after_rxring_sem;	// setup_transmit_descriptor_ring;	nic->txring_count = txring_count;	nic->tx_buffersize = txbuffer_size;	nic->txring_head = 0;	nic->txring_region = vm_create_anonymous_region(		vm_get_kernel_aspace_id(), "pcnet32_txring", (void**)&nic->txring,		REGION_ADDR_ANY_ADDRESS, nic->txring_count * sizeof(struct pcnet32_txdesc),		REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL | LOCK_RW);	if (nic->txring_region < 0)		goto err_after_rxring_mutex;	memset(nic->txring, 0, nic->txring_count * sizeof(struct pcnet32_txdesc));	vm_get_page_mapping(vm_get_kernel_aspace_id(),			    (addr_t)nic->txring, &nic->txring_phys);	SHOW_FLOW(3, "txring physical address: 0x%x", nic->txring_phys);	// allocate the actual buffers	nic->buffers_region = vm_create_anonymous_region(		vm_get_kernel_aspace_id(), "pcnet32_buffers", (void**)&nic->buffers,		REGION_ADDR_ANY_ADDRESS,		(nic->rxring_count * nic->rx_buffersize) +		(nic->txring_count * nic->tx_buffersize),		REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL | LOCK_RW);	if (nic->buffers_region < 0)		goto err_after_txring_region;	vm_get_page_mapping(vm_get_kernel_aspace_id(),			    (addr_t)nic->buffers, &nic->buffers_phys);	nic->rx_buffers = (uint8*)nic->buffers;	nic->tx_buffers = (uint8*)(nic->buffers + nic->rxring_count * nic->rx_buffersize);	// create the thread	nic->interrupt_sem = sem_create(0, "pcnet32_interrupt");	if (nic->interrupt_sem < 0)		goto err_after_buffers_region;	nic->thread = thread_create_kernel_thread("pcnet32_isr", pcnet32_thread, nic);	if (nic->thread < 0)		goto err_after_interrupt_sem;	SHOW_FLOW(3, "thread created, id: 0x%x", nic->thread);	thread_set_priority(nic->thread, THREAD_HIGHEST_PRIORITY);	return nic;err_after_interrupt_sem:	sem_delete(nic->interrupt_sem);err_after_buffers_region:	vm_delete_region(vm_get_kernel_aspace_id(), nic->buffers_region);err_after_txring_region:	vm_delete_region(vm_get_kernel_aspace_id(), nic->txring_region);err_after_rxring_mutex:	mutex_destroy(&nic->rxring_mutex);err_after_rxring_sem:	sem_delete(nic->rxring_sem);err_after_rxring_region:	vm_delete_region(vm_get_kernel_aspace_id(), nic->rxring_region);err_after_kmalloc:	kfree(nic);err_none:	return NULL;}int pcnet32_detect(pcnet32 *dev){	int i;	pci_module_hooks *pci;	pci_info pinfo;	bool foundit = false;	if (module_get(PCI_BUS_MODULE_NAME, 0, (void**)&pci))	{		SHOW_FLOW0(3, "Could not find PCI Bus.");		return -1;	}	for (i = 0; pci->get_nth_pci_info(i, &pinfo) >= NO_ERROR; i++)	{		if (pinfo.vendor_id == AMD_VENDORID &&		    (pinfo.device_id == PCNET_DEVICEID ||		     pinfo.device_id == PCHOME_DEVICEID))		{			foundit = true;			break;		}	}	if (!foundit)	{		SHOW_FLOW0(3, "Could not find PCNET32 Compatible Device");		return -1;	}	dev->irq = pinfo.u.h0.interrupt_line;	for (i = 0; i < 6; i++)	{		if (pinfo.u.h0.base_registers[i] > 0xffff)		{			dev->phys_base = pinfo.u.h0.base_registers[i];			dev->phys_size = pinfo.u.h0.base_register_sizes[i];			SHOW_FLOW(3, "base 0x%lx, size 0x%lx\n", dev->phys_base, dev->phys_size);		} else if (pinfo.u.h0.base_registers[i] > 0) {			dev->io_port = pinfo.u.h0.base_registers[i];			SHOW_FLOW(3, "io_port 0x%x\n", dev->io_port);		}	}	return 0;}int pcnet32_init(pcnet32 *nic){	int i;	SHOW_FLOW(3, "detected device at irq %d, memory base 0x%lx, size 0x%lx, io port base 0x%x",		  nic->irq, nic->phys_base, nic->phys_size, nic->io_port);	if(nic->phys_base > 0) {		nic->io_region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "pcnet32_region",			(void **)&nic->virt_base, REGION_ADDR_ANY_ADDRESS, nic->phys_size,			LOCK_KERNEL|LOCK_RW, nic->phys_base);		if(nic->io_region < 0) {			SHOW_FLOW(3, "error allocating device physical region at %x",				  nic->phys_base);			return nic->io_region;		}		SHOW_FLOW(3, "device mapped at virtual address 0x%lx", nic->virt_base);	} else {		nic->io_region = -1;		nic->virt_base = 0; // should generate a panic if someone tries to use it	}	// before we do this we set up our interrupt handler,	// we want to make sure the device is in a semi-known state, so we	// do a little control register stuff here.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -