📄 pcnet32_dev.c
字号:
/*** 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 + -