📄 ewrk3.c
字号:
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 intewrk3_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) { irq2dev_map[dev->irq] = dev; /* For latched interrupts */ if (request_irq(dev->irq, (void *)ewrk3_interrupt, 0, "ewrk3", NULL)) { 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 voidewrk3_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 intewrk3_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; dev_kfree_skb(skb, FREE_WRITE); } } else if (skb == NULL) { dev_tint(dev); } 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 (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 (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, FREE_WRITE); } 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 voidewrk3_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct device *dev = (struct device *)(irq2dev_map[irq]); 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 intewrk3_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 = 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); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -