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

📄 pcnet32_dev.c

📁 newos is new operation system
💻 C
📖 第 1 页 / 共 2 页
字号:
	write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STOP);	// set up the interrupt handler	int_set_io_interrupt_handler(nic->irq, &pcnet32_int, nic, "pcnet32");	SHOW_FLOW(3, "device mapped irq 0x%x", nic->irq + 0x20);	// fetch ethernet address	for (i = 0; i < 6; i++)	{		nic->mac_addr[i] = READ_8(nic, i);	}	SHOW_FLOW(3, "MAC Address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",		  nic->mac_addr[0],		  nic->mac_addr[1],		  nic->mac_addr[2],		  nic->mac_addr[3],		  nic->mac_addr[4],		  nic->mac_addr[5]);	return 0;}void pcnet32_start(pcnet32 *nic){	int i = 0;	struct pcnet32_init *init;	SHOW_FLOW(3, "starting %p", nic);	SHOW_FLOW0(3, "resetting device");	READ_32(nic, PCNET_IO_RESET);	WRITE_32(nic, PCNET_IO_RESET, 0);	// give the device time to figure it out	thread_snooze(10000);	// set us up in 32-bit wide structure mode	WRITE_32(nic, PCNET_IO_DATAPORT, 0);	write_bcr(nic, PCNET_BCR_SWMODE, 0x0002);	// now we build the initialization block in the	// buffer area (which is unused right now)	init = (struct pcnet32_init*)nic->buffers;	memset(init, 0, sizeof(struct pcnet32_init));	init->flags = nic->init_mode;	memcpy(init->paddr, &nic->mac_addr, sizeof(nic->mac_addr));	init->rxaddr = nic->rxring_phys;	init->txaddr = nic->txring_phys;	write_csr(nic, PCNET_CSR_IADDR0, nic->buffers_phys & 0xffff);	write_csr(nic, PCNET_CSR_IADDR1, (nic->buffers_phys >> 16) & 0xffff);	write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_INIT);	// wait for it to finish initializing.	while ( !(read_csr(nic, PCNET_CSR_STATUS) & PCNET_STATUS_IDON) );	// Initialize the rxring	for (i = 0; i < nic->rxring_count; i++)		rxdesc_init(nic, i);	// Initialize the txring	memset(nic->txring, 0, nic->txring_count * sizeof(struct pcnet32_txdesc));	// write the start and interrupt enable bits.	write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STRT | PCNET_STATUS_IENA);	// for the sake of verification, we'll read csr0 and dprint it.	SHOW_FLOW(3, "csr0 (status) = 0x%.4x", read_csr(nic, PCNET_CSR_STATUS));	// start the thread	thread_resume_thread(nic->thread);}void pcnet32_stop(pcnet32 *nic){	SHOW_FLOW(3, "Stopping pcnet device %p", nic);	// start the thread	thread_suspend_thread(nic->thread);	// stop the device.	write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STOP);}void pcnet32_delete(pcnet32 *nic){        sem_delete(nic->interrupt_sem);        vm_delete_region(vm_get_kernel_aspace_id(), nic->buffers_region);        vm_delete_region(vm_get_kernel_aspace_id(), nic->txring_region);        mutex_destroy(&nic->rxring_mutex);        sem_delete(nic->rxring_sem);        vm_delete_region(vm_get_kernel_aspace_id(), nic->rxring_region);        kfree(nic);}static void rxdesc_init(pcnet32 *nic, uint16 index){	uint16 masked_index = RXRING_INDEX(nic, index);	struct pcnet32_rxdesc *desc = nic->rxring + masked_index;	uint32 buffer = BUFFER_PHYS(nic, RXRING_BUFFER(nic, masked_index));	desc->buffer_addr = buffer;	desc->buffer_length = -nic->rx_buffersize;	desc->message_length = 0;	desc->user = 0;	// enable the controller to write to this receive buffer.	desc->status = PCNET_RXSTATUS_OWN;}ssize_t pcnet32_xmit(pcnet32 *nic, const char *ptr, ssize_t len){	uint16 index = 0;	uint8 *buffer = NULL;	SHOW_FLOW(3, "nic %p data %p len %d", nic, ptr, len);	index = TXRING_INDEX(nic, nic->txring_head);	SHOW_FLOW(3, "using txring index %d", index);	// XXX need support for spanning packets in case a size other than 2048 is used.        // Examine OWN bit of tx descriptor at tx_queue_tail;	// if (OWN == 1) return "Out of buffer";	if ((len > nic->tx_buffersize) ||	    (nic->txring[index].status & PCNET_TXSTATUS_OWN))	{		SHOW_FLOW0(3, "packet was too large or no more txbuffers.");		return ERR_VFS_INSUFFICIENT_BUF;	}	// Get buffer address from descriptor at end_tx_queue;	buffer = TXRING_BUFFER(nic, index);	nic->txring[index].buffer_addr = BUFFER_PHYS(nic, buffer);	// Copy packet to tx buffer;	memcpy(buffer, ptr, len);	// Set up BCNT field of descriptor;	nic->txring[index].buffer_length = -len;	// Set OWN, STP, and ENP bits of descriptor;	nic->txring[index].status |= PCNET_TXSTATUS_OWN |		PCNET_TXSTATUS_STP | PCNET_TXSTATUS_ENP;	// tx_queue_tail = tx_queue_tail + 1;	// if (tx_queue_tail > last_tx_descriptor) tx_queue_tail = first_tx_descriptor;	nic->txring_head++;	// set the transmit demand bit in CSR0	modify_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_TDMD, PCNET_STATUS_TDMD);	// return "OK";	return len;}ssize_t pcnet32_rx(pcnet32 *nic, char *buf, ssize_t buf_len){	uint16 index = 0;	ssize_t real_len = -1;	SHOW_FLOW(3, "nic %p data %p buf_len %d", nic, buf, buf_len);	// here we loop through consuming rxring descriptors until we get	// one suitable for returning.	while (true)	{		// consume 1 descriptor at a time, whether it's an error or a		// valid packet.		sem_acquire(nic->rxring_sem, 1);		SHOW_FLOW(3, "nic %p rx semaphore was signalled", nic);		// the semaphor has been released at least once, so we will		// lock the rxring and grab the next available descriptor.		mutex_lock(&nic->rxring_mutex);		// grab the index we want.		index = RXRING_INDEX(nic, nic->rxring_tail);		if (nic->rxring[index].status & PCNET_RXSTATUS_ERR)		{			SHOW_FLOW(3, "rxring descriptor %d reported an error: 0x%.4x",				  index, nic->rxring[index].status);		}		if (nic->rxring[index].status & PCNET_RXSTATUS_OWN)		{			SHOW_FLOW(3, "warning: descriptor %d should have been owned by the software is owned by the hardware.", index);			nic->rxring_tail++;			mutex_unlock(&nic->rxring_mutex);			continue; // skip this descriptor altogether.		}		else if ((size_t)buf_len >= nic->rxring[index].message_length) // got one		{			real_len = nic->rxring[index].message_length;			// copy the buffer			memcpy(buf, RXRING_BUFFER(nic, index), real_len);			// reinitialize the buffer and give it back to the controller.			rxdesc_init(nic, index);			SHOW_FLOW(3, "Got index %d, len %d and cleared it, returning to caller. rxstatus = 0x%x.", index,				  nic->rxring[index].message_length, nic->rxring[index].status);			// move the tail up.			nic->rxring_tail++;			mutex_unlock(&nic->rxring_mutex);			return real_len;		} else {			// there is a packet, but it's too large for the buffer.			// So we don't want to do anything with the ring, we just			// want to unlock our mutex and return.			mutex_unlock(&nic->rxring_mutex);			return ERR_TOO_BIG;		}	}	return real_len;}// these two return false when there is nothing left to do.static bool pcnet32_rxint(pcnet32 *nic){	uint32 index;	index = RXRING_INDEX(nic, nic->rxring_head);	SHOW_FLOW(3, "Next rxring index (%d) status = 0x%x.", index, nic->rxring[index].status);	if ( !(nic->rxring[index].status & PCNET_RXSTATUS_OWN) )	{		SHOW_FLOW(3, "Got packet len %d, index %d", nic->rxring[index].message_length, index);		nic->rxring_head++;		sem_release(nic->rxring_sem, 1);		return true;	}	SHOW_FLOW0(3, "No more packets.");	return false;}static int pcnet32_thread(void *data){	pcnet32 *nic = (pcnet32 *)data;	while (true)	{		sem_acquire(nic->interrupt_sem, 1);		SHOW_FLOW(3, "Acquired semaphore, status = 0x%x", nic->interrupt_status);		// check if there is a 'fatal error' (BABL and MERR)		if ((nic->interrupt_status & PCNET_STATUS_ERR) &&		    (nic->interrupt_status & PCNET_STATUS_BABL ||		     nic->interrupt_status & PCNET_STATUS_MERR))		{			// fatal error. Stop everything and reinitialize the device.			pcnet32_stop(nic);			pcnet32_start(nic);		}		mutex_lock(&nic->rxring_mutex);		while (pcnet32_rxint(nic));		mutex_unlock(&nic->rxring_mutex);		// re-enable pcnet interrupts		write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_IENA);		SHOW_FLOW(3, "Finished iteration, status = 0x%x", read_csr(nic, PCNET_CSR_STATUS));	}	return 0;}static int pcnet32_int(void* data){	pcnet32 *nic = (pcnet32 *)data;	uint32 status;	acquire_spinlock(&nic->control_lock);	int_disable_interrupts();	status = read_csr(nic, PCNET_CSR_STATUS);	SHOW_FLOW(3, "handling irq: status 0x%x", status);	// clear the bits that caused this to happen and disable pcnet interrupts	// for the time being	write_csr(nic, PCNET_CSR_STATUS, status & ~PCNET_STATUS_IENA);	int_restore_interrupts();        release_spinlock(&nic->control_lock);	nic->interrupt_status = status;	sem_release_etc(nic->interrupt_sem, 1, SEM_FLAG_NO_RESCHED);	SHOW_FLOW(3, "interrupt handled. pcnet status 0x%.8x", read_csr(nic, PCNET_CSR_STATUS));	return INT_RESCHEDULE;}

⌨️ 快捷键说明

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