欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

ewrk3.c

powerpc内核mpc8241linux系统下net驱动程序
C
第 1 页 / 共 4 页
字号:
						/*						   ** Determine the base address and window length for the EWRK3						   ** RAM from the memory base register.						 */						mem_start = inb(EWRK3_MBR);						shmem_length = 0;						if (mem_start != 0) {							if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {								mem_start *= SHMEM_64K;								shmem_length = SHMEM_64K;							} else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {								mem_start *= SHMEM_32K;								shmem_length = SHMEM_32K;							} else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {								mem_start = mem_start * SHMEM_2K + 0x80000;								shmem_length = SHMEM_2K;							} else {								status = -ENXIO;							}						}						/*						   ** See the top of this source code for comments about						   ** uncommenting this line.						 *//*          FORCE_2K_MODE; */						if (!status) {							if (hard_strapped) {								printk("      is hard strapped.\n");							} else if (mem_start) {								printk("      has a %dk RAM window", (int) (shmem_length >> 10));								printk(" at 0x%.5lx", mem_start);							} else {								printk("      is in I/O only mode");							}							/* private area & initialise */							dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private),							     GFP_KERNEL);							if (dev->priv == NULL) {								return -ENOMEM;							}							lp = (struct ewrk3_private *) dev->priv;							memset(dev->priv, 0, sizeof(struct ewrk3_private));							lp->shmem_base = mem_start;							lp->shmem_length = shmem_length;							lp->lemac = lemac;							lp->hard_strapped = hard_strapped;							lp->mPage = 64;							if (cmr & CMR_DRAM)								lp->mPage <<= 1;	/* 2 DRAMS on module */							sprintf(lp->adapter_name, "%s (%s)", name, dev->name);							request_region(iobase, EWRK3_TOTAL_SIZE, lp->adapter_name);							lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;							if (!hard_strapped) {								/*								   ** Enable EWRK3 board interrupts for autoprobing								 */								icr |= ICR_IE;	/* Enable interrupts */								outb(icr, EWRK3_ICR);								/* The DMA channel may be passed in on this parameter. */								dev->dma = 0;								/* To auto-IRQ we enable the initialization-done and DMA err,								   interrupts. For now we will always get a DMA error. */								if (dev->irq < 2) {#ifndef MODULE									u_char irqnum;									autoirq_setup(0);									/*									   ** Trigger a TNE interrupt.									 */									icr |= ICR_TNEM;									outb(1, EWRK3_TDQ);	/* Write to the TX done queue */									outb(icr, EWRK3_ICR);	/* Unmask the TXD interrupt */									irqnum = irq[((icr & IRQ_SEL) >> 4)];									dev->irq = autoirq_report(1);									if ((dev->irq) && (irqnum == dev->irq)) {										printk(" and uses IRQ%d.\n", dev->irq);									} else {										if (!dev->irq) {											printk(" and failed to detect IRQ line.\n");										} else if ((irqnum == 1) && (lemac == LeMAC2)) {											printk(" and an illegal IRQ line detected.\n");										} else {											printk(", but incorrect IRQ line detected.\n");										}										status = -ENXIO;									}									DISABLE_IRQs;	/* Mask all interrupts */#endif				/* MODULE */								} else {									printk(" and requires IRQ%d.\n", dev->irq);								}							}							if (status)								release_region(iobase, EWRK3_TOTAL_SIZE);						} else {							status = -ENXIO;						}					}				}			} else {				status = -ENXIO;			}		}		if (!status) {			if (ewrk3_debug > 1) {				printk(version);			}			/* The EWRK3-specific entries in the device structure. */			dev->open = &ewrk3_open;			dev->hard_start_xmit = &ewrk3_queue_pkt;			dev->stop = &ewrk3_close;			dev->get_stats = &ewrk3_get_stats;			dev->set_multicast_list = &set_multicast_list;			dev->do_ioctl = &ewrk3_ioctl;			dev->mem_start = 0;			/* Fill in the generic field of the device structure. */			ether_setup(dev);		}	} else {		status = -ENXIO;	}	return status;}static int ewrk3_open(struct device *dev){	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;	u_long iobase = dev->base_addr;	int i, status = 0;	u_char icr, csr;	/*	   ** Stop the TX and RX...	 */	STOP_EWRK3;	if (!lp->hard_strapped) {		if (request_irq(dev->irq, (void *) ewrk3_interrupt, 0, "ewrk3", dev)) {			printk("ewrk3_open(): Requested IRQ%d is busy\n", dev->irq);			status = -EAGAIN;		} else {			/*			   ** Re-initialize the EWRK3...			 */			ewrk3_init(dev);			if (ewrk3_debug > 1) {				printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);				printk("  physical address: ");				for (i = 0; i < 5; i++) {					printk("%2.2x:", (u_char) dev->dev_addr[i]);				}				printk("%2.2x\n", (u_char) dev->dev_addr[i]);				if (lp->shmem_length == 0) {					printk("  no shared memory, I/O only mode\n");				} else {					printk("  start of shared memory: 0x%08lx\n", lp->shmem_base);					printk("  window length: 0x%04lx\n", lp->shmem_length);				}				printk("  # of DRAMS: %d\n", ((inb(EWRK3_CMR) & 0x02) ? 2 : 1));				printk("  csr:  0x%02x\n", inb(EWRK3_CSR));				printk("  cr:   0x%02x\n", inb(EWRK3_CR));				printk("  icr:  0x%02x\n", inb(EWRK3_ICR));				printk("  cmr:  0x%02x\n", inb(EWRK3_CMR));				printk("  fmqc: 0x%02x\n", inb(EWRK3_FMQC));			}			dev->tbusy = 0;			dev->start = 1;			dev->interrupt = UNMASK_INTERRUPTS;			/*			   ** Unmask EWRK3 board interrupts			 */			icr = inb(EWRK3_ICR);			ENABLE_IRQs;		}	} else {		dev->start = 0;		dev->tbusy = 1;		printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);		printk("      Run the 'ewrk3setup' utility or remove the hard straps.\n");	}	MOD_INC_USE_COUNT;	return status;}/*   ** Initialize the EtherWORKS 3 operating conditions */static void ewrk3_init(struct device *dev){	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;	u_char csr, page;	u_long iobase = dev->base_addr;	/*	   ** Enable any multicasts	 */	set_multicast_list(dev);	/*	   ** Clean out any remaining entries in all the queues here	 */	while (inb(EWRK3_TQ));	while (inb(EWRK3_TDQ));	while (inb(EWRK3_RQ));	while (inb(EWRK3_FMQ));	/*	   ** Write a clean free memory queue	 */	for (page = 1; page < lp->mPage; page++) {	/* Write the free page numbers */		outb(page, EWRK3_FMQ);	/* to the Free Memory Queue */	}	lp->lock = 0;		/* Ensure there are no locks */	START_EWRK3;		/* Enable the TX and/or RX */}/*   ** Writes a socket buffer to the free page queue */static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev){	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;	u_long iobase = dev->base_addr;	int status = 0;	u_char icr, csr;	/* Transmitter timeout, serious problems. */	if (dev->tbusy || lp->lock) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < QUEUE_PKT_TIMEOUT) {			status = -1;		} else if (!lp->hard_strapped) {			printk("%s: transmit timed/locked out, status %04x, resetting.\n",			       dev->name, inb(EWRK3_CSR));			/*			   ** Mask all board interrupts			 */			DISABLE_IRQs;			/*			   ** Stop the TX and RX...			 */			STOP_EWRK3;			ewrk3_init(dev);			/*			   ** Unmask EWRK3 board interrupts			 */			ENABLE_IRQs;			dev->tbusy = 0;			dev->trans_start = jiffies;		}	} else if (skb->len > 0) {		/*		   ** Block a timer-based transmit from overlapping.  This could better be		   ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.		 */		if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)			printk("%s: Transmitter access conflict.\n", dev->name);		DISABLE_IRQs;	/* So that the page # remains correct */		/*		   ** Get a free page from the FMQ when resources are available		 */		if (inb(EWRK3_FMQC) > 0) {			u_long buf = 0;			u_char page;			if ((page = inb(EWRK3_FMQ)) < lp->mPage) {				/*				   ** Set up shared memory window and pointer into the window				 */				while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */				if (lp->shmem_length == IO_ONLY) {					outb(page, EWRK3_IOPR);				} else if (lp->shmem_length == SHMEM_2K) {					buf = lp->shmem_base;					outb(page, EWRK3_MPR);				} else if (lp->shmem_length == SHMEM_32K) {					buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);					outb((page >> 4), EWRK3_MPR);				} else if (lp->shmem_length == SHMEM_64K) {					buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);					outb((page >> 5), EWRK3_MPR);				} else {					status = -1;					printk("%s: Oops - your private data area is hosed!\n", dev->name);				}				if (!status) {					/*					   ** Set up the buffer control structures and copy the data from					   ** the socket buffer to the shared memory .					 */					if (lp->shmem_length == IO_ONLY) {						int i;						u_char *p = skb->data;						outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);						outb((char) (skb->len & 0xff), EWRK3_DATA);						outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);						outb((char) 0x04, EWRK3_DATA);						for (i = 0; i < skb->len; i++) {							outb(*p++, EWRK3_DATA);						}						outb(page, EWRK3_TQ);	/* Start sending pkt */					} else {						writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf);	/* ctrl byte */						buf += 1;						writeb((char) (skb->len & 0xff), (char *) buf);		/* length (16 bit xfer) */						buf += 1;						if (lp->txc) {							writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);							buf += 1;							writeb(0x04, (char *) buf);	/* index byte */							buf += 1;							writeb(0x00, (char *) (buf + skb->len));	/* Write the XCT flag */							memcpy_toio(buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */							outb(page, EWRK3_TQ);	/* Start sending pkt */							memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);							writeb(0xff, (char *) (buf + skb->len));	/* Write the XCT flag */						} else {							writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);							buf += 1;							writeb(0x04, (char *) buf);	/* index byte */							buf += 1;							memcpy_toio((char *) buf, skb->data, skb->len);		/* Write data bytes */							outb(page, EWRK3_TQ);	/* Start sending pkt */						}					}					dev->trans_start = jiffies;					dev_kfree_skb(skb);				} else {	/* return unused page to the free memory queue */					outb(page, EWRK3_FMQ);				}				lp->lock = 0;	/* unlock the page register */			} else {				printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",				       (u_char) page);			}		} else {			printk("ewrk3_queue_pkt(): No free resources...\n");			printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));		}		/* Check for free resources: clear 'tbusy' if there are some */		if (inb(EWRK3_FMQC) > 0) {			dev->tbusy = 0;		}		ENABLE_IRQs;	}	return status;}/*   ** The EWRK3 interrupt handler. */static void ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev = dev_id;	struct ewrk3_private *lp;	u_long iobase;	u_char icr, cr, csr;	if (dev == NULL) {		printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq);	} else {		lp = (struct ewrk3_private *) dev->priv;		iobase = dev->base_addr;		if (dev->interrupt)			printk("%s: Re-entering the interrupt handler.\n", dev->name);		dev->interrupt = MASK_INTERRUPTS;		/* get the interrupt information */		csr = inb(EWRK3_CSR);		/*		   ** Mask the EWRK3 board interrupts and turn on the LED		 */		DISABLE_IRQs;		cr = inb(EWRK3_CR);		cr |= CR_LED;		outb(cr, EWRK3_CR);		if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */			ewrk3_rx(dev);		if (csr & CSR_TNE)	/* Tx interrupt (packet sent) */			ewrk3_tx(dev);		/*		   ** Now deal with the TX/RX disable flags. These are set when there		   ** are no more resources. If resources free up then enable these		   ** interrupts, otherwise mask them - failure to do this will result		   ** in the system hanging in an interrupt loop.		 */		if (inb(EWRK3_FMQC)) {	/* any resources available? */			lp->irq_mask |= ICR_TXDM | ICR_RXDM;	/* enable the interrupt source */			csr &= ~(CSR_TXD | CSR_RXD);	/* ensure restart of a stalled TX or RX */			outb(csr, EWRK3_CSR);			dev->tbusy = 0;		/* clear TX busy flag */			mark_bh(NET_BH);		} else {			lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM);		/* disable the interrupt source */		}		/* Unmask the EWRK3 board interrupts and turn off the LED */		cr &= ~CR_LED;		outb(cr, EWRK3_CR);		dev->interrupt = UNMASK_INTERRUPTS;		ENABLE_IRQs;	}	return;}static int ewrk3_rx(struct device *dev){	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;	u_long iobase = dev->base_addr;	int i, status = 0;	u_char page, tmpPage = 0, tmpLock = 0;	u_long buf = 0;	while (inb(EWRK3_RQC) && !status) {	/* Whilst there's incoming data */		if ((page = inb(EWRK3_RQ)) < lp->mPage) {	/* Get next entry's buffer page */			/*			   ** Preempt any process using the current page register. Check for			   ** an existing lock to reduce time taken in I/O transactions.			 */			if ((tmpLock = test_and_set_bit(0, (void *) &lp->lock)) == 1) {		/* Assert lock */				if (lp->shmem_length == IO_ONLY) {	/* Get existing page */					tmpPage = inb(EWRK3_IOPR);				} else {					tmpPage = inb(EWRK3_MPR);				}			}			/*			   ** Set up shared memory window and pointer into the window			 */			if (lp->shmem_length == IO_ONLY) {

⌨️ 快捷键说明

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