📄 depca.c
字号:
static intdepca_hw_init(struct device *dev, u_long ioaddr){ struct depca_private *lp; int i, j, offset, netRAM, mem_len, status=0; s16 nicsr; u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES; STOP_DEPCA; nicsr = inb(DEPCA_NICSR); nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); outb(nicsr, DEPCA_NICSR); if (inw(DEPCA_DATA) == STOP) { do { strcpy(name, (adapter_name ? adapter_name : "")); mem_start = (mem ? mem & 0xf0000 : mem_base[mem_chkd++]); DepcaSignature(name, mem_start); } while (!mem && mem_base[mem_chkd] && (adapter == unknown)); if ((adapter != unknown) && mem_start) { /* found a DEPCA device */ dev->base_addr = ioaddr; if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */ printk("%s: %s at 0x%04lx (EISA slot %d)", dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f)); } else { /* ISA port address */ printk("%s: %s at 0x%04lx", dev->name, name, ioaddr); } printk(", h/w address "); status = get_hw_addr(dev); for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */ printk("%2.2x:", dev->dev_addr[i]); } printk("%2.2x", dev->dev_addr[i]); if (status == 0) { /* Set up the maximum amount of network RAM(kB) */ netRAM = ((adapter != DEPCA) ? 64 : 48); if ((nicsr & _128KB) && (adapter == de422)) netRAM = 128; offset = 0x0000; /* Shared Memory Base Address */ if (nicsr & BUF) { offset = 0x8000; /* 32kbyte RAM offset*/ nicsr &= ~BS; /* DEPCA RAM in top 32k */ netRAM -= 32; } mem_start += offset; /* (E)ISA start address */ if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) + NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) + sizeof(struct depca_init))) <= (netRAM<<10)) { printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start); /* Enable the shadow RAM. */ if (adapter != DEPCA) { nicsr |= SHE; outb(nicsr, DEPCA_NICSR); } /* Define the device private memory */ dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; lp = (struct depca_private *)dev->priv; memset((char *)dev->priv, 0, sizeof(struct depca_private)); lp->adapter = adapter; sprintf(lp->adapter_name,"%s (%s)", name, dev->name); request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name); /* Initialisation Block */ lp->sh_mem = mem_start; mem_start += sizeof(struct depca_init); /* Tx & Rx descriptors (aligned to a quadword boundary) */ mem_start = (mem_start + ALIGN) & ~ALIGN; lp->rx_ring = (struct depca_rx_desc *)mem_start; mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC); lp->tx_ring = (struct depca_tx_desc *)mem_start; mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC); lp->bus_offset = mem_start & 0x00ff0000; mem_start &= LA_MASK; /* LANCE re-mapped start address */ lp->dma_buffs = mem_start; /* Finish initialising the ring information. */ lp->rxRingMask = NUM_RX_DESC - 1; lp->txRingMask = NUM_TX_DESC - 1; /* Calculate Tx/Rx RLEN size for the descriptors. */ for (i=0, j = lp->rxRingMask; j>0; i++) { j >>= 1; } lp->rx_rlen = (s32)(i << 29); for (i=0, j = lp->txRingMask; j>0; i++) { j >>= 1; } lp->tx_rlen = (s32)(i << 29); /* Load the initialisation block */ depca_init_ring(dev); /* Initialise the control and status registers */ LoadCSRs(dev); /* Enable DEPCA board interrupts for autoprobing */ nicsr = ((nicsr & ~IM)|IEN); outb(nicsr, DEPCA_NICSR); /* 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 unsigned char irqnum; autoirq_setup(0); /* Assign the correct irq list */ switch (lp->adapter) { case DEPCA: case de100: case de101: depca_irq = de1xx_irq; break; case de200: case de201: case de202: case de210: depca_irq = de2xx_irq; break; case de422: depca_irq = de422_irq; break; } /* Trigger an initialization just for the interrupt. */ outw(INEA | INIT, DEPCA_DATA); irqnum = autoirq_report(1); if (!irqnum) { printk(" and failed to detect IRQ line.\n"); status = -ENXIO; } else { for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) { if (irqnum == depca_irq[i]) { dev->irq = irqnum; printk(" and uses IRQ%d.\n", dev->irq); } } if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); status = -ENXIO; } }#endif /* MODULE */ } else { printk(" and assigned IRQ%d.\n", dev->irq); } if (status) release_region(ioaddr, DEPCA_TOTAL_SIZE); } else { printk(",\n requests %dkB RAM: only %dkB is available!\n", (mem_len>>10), netRAM); status = -ENXIO; } } else { printk(" which has an Ethernet PROM CRC error.\n"); status = -ENXIO; } } else { status = -ENXIO; } if (!status) { if (depca_debug > 1) { printk(version); } /* The DEPCA-specific entries in the device structure. */ dev->open = &depca_open; dev->hard_start_xmit = &depca_start_xmit; dev->stop = &depca_close; dev->get_stats = &depca_get_stats; dev->set_multicast_list = &set_multicast_list; dev->do_ioctl = &depca_ioctl; dev->mem_start = 0; /* Fill in the generic field of the device structure. */ ether_setup(dev); } else { /* Incorrectly initialised hardware */ if (dev->priv) { kfree_s(dev->priv, sizeof(struct depca_private)); dev->priv = NULL; } } } else { status = -ENXIO; } return status;}static intdepca_open(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; s16 nicsr; int status = 0; irq2dev_map[dev->irq] = dev; STOP_DEPCA; nicsr = inb(DEPCA_NICSR); /* Make sure the shadow RAM is enabled */ if (adapter != DEPCA) { nicsr |= SHE; outb(nicsr, DEPCA_NICSR); } /* Re-initialize the DEPCA... */ depca_init_ring(dev); LoadCSRs(dev); depca_dbg_open(dev); if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, NULL)) { printk("depca_open(): Requested IRQ%d is busy\n",dev->irq); status = -EAGAIN; } else { /* Enable DEPCA board interrupts and turn off LED */ nicsr = ((nicsr & ~IM & ~LED)|IEN); outb(nicsr, DEPCA_NICSR); outw(CSR0,DEPCA_ADDR); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; status = InitRestartDepca(dev); if (depca_debug > 1){ printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA)); printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR)); } } MOD_INC_USE_COUNT; return status;}/* Initialize the lance Rx and Tx descriptor rings. */static voiddepca_init_ring(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_int i; u_long p; /* Lock out other processes whilst setting up the hardware */ set_bit(0, (void *)&dev->tbusy); lp->rx_new = lp->tx_new = 0; lp->rx_old = lp->tx_old = 0; /* Initialize the base addresses and length of each buffer in the ring */ for (i = 0; i <= lp->rxRingMask; i++) { writel((p=lp->dma_buffs+i*RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base); writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length); lp->rx_memcpy[i]=(char *)(p+lp->bus_offset); } for (i = 0; i <= lp->txRingMask; i++) { writel((p=lp->dma_buffs+(i+lp->txRingMask+1)*TX_BUFF_SZ) & 0x00ffffff, &lp->tx_ring[i].base); lp->tx_memcpy[i]=(char *)(p+lp->bus_offset); } /* Set up the initialization block */ lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen; lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen; SetMulticastFilter(dev); for (i = 0; i < ETH_ALEN; i++) { lp->init_block.phys_addr[i] = dev->dev_addr[i]; } lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ return;}/* ** Writes a socket buffer to TX descriptor ring and starts transmission */static intdepca_start_xmit(struct sk_buff *skb, struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; int status = 0; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 1*HZ) { status = -1; } else { printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA)); STOP_DEPCA; depca_init_ring(dev); LoadCSRs(dev); dev->interrupt = UNMASK_INTERRUPTS; dev->start = 1; dev->tbusy=0; dev->trans_start = jiffies; InitRestartDepca(dev); dev_kfree_skb(skb, FREE_WRITE); } return status; } else if (skb == NULL) { dev_tint(dev); } else if (skb->len > 0) { /* Enforce 1 process per h/w access */ if (set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); status = -1; } else { if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ status = load_packet(dev, skb); if (!status) { /* Trigger an immediate send demand. */ outw(CSR0, DEPCA_ADDR); outw(INEA | TDMD, DEPCA_DATA); dev->trans_start = jiffies; dev_kfree_skb(skb, FREE_WRITE); } if (TX_BUFFS_AVAIL) { dev->tbusy=0; } } else { status = -1; } } } return status;}/*** The DEPCA interrupt handler. */static voiddepca_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct device *dev = (struct device *)(irq2dev_map[irq]); struct depca_private *lp; s16 csr0, nicsr; u_long ioaddr; if (dev == NULL) { printk ("depca_interrupt(): irq %d for unknown device.\n", irq); } else { lp = (struct depca_private *)dev->priv; ioaddr = dev->base_addr; if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = MASK_INTERRUPTS; /* mask the DEPCA board interrupts and turn on the LED */ nicsr = inb(DEPCA_NICSR); nicsr |= (IM|LED); outb(nicsr, DEPCA_NICSR); outw(CSR0, DEPCA_ADDR); csr0 = inw(DEPCA_DATA); /* Acknowledge all of the current interrupt sources ASAP. */ outw(csr0 & INTE, DEPCA_DATA); if (csr0 & RINT) /* Rx interrupt (packet arrived) */ depca_rx(dev); if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx(dev); if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */ dev->tbusy = 0; /* clear TX busy flag */ mark_bh(NET_BH); } /* Unmask the DEPCA board interrupts and turn off the LED */ nicsr = (nicsr & ~IM & ~LED); outb(nicsr, DEPCA_NICSR); dev->interrupt = UNMASK_INTERRUPTS; } return;}static intdepca_rx(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int i, entry; s32 status; for (entry=lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry=lp->rx_new){ status = readl(&lp->rx_ring[entry].base) >> 16 ; if (status & R_STP) { /* Remember start of frame */ lp->rx_old = entry; } if (status & R_ENP) { /* Valid frame status */ if (status & R_ERR) { /* There was an error. */ lp->stats.rx_errors++; /* Update the error stats. */ if (status & R_FRAM) lp->stats.rx_frame_errors++; if (status & R_OFLO) lp->stats.rx_over_errors++; if (status & R_CRC) lp->stats.rx_crc_errors++; if (status & R_BUFF) lp->stats.rx_fifo_errors++; } else { short len, pkt_len = readw(&lp->rx_ring[entry].msg_length); struct sk_buff *skb; skb = dev_alloc_skb(pkt_len+2); if (skb != NULL) { unsigned char *buf; skb_reserve(skb,2); /* 16 byte align the IP header */ buf = skb_put(skb,pkt_len); skb->dev = dev; if (entry < lp->rx_old) { /* Wrapped buffer */ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], len); memcpy_fromio(buf + len, lp->rx_memcpy[0], pkt_len-len); } else { /* Linear buffer */ memcpy_fromio(buf, lp->rx_memcpy[lp->rx_old], pkt_len); } /* ** Notify the upper protocol layers that there is another ** packet to handle */ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* ** Update stats */ lp->stats.rx_packets++; for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) { if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) { lp->pktStats.bins[i]++; i = DEPCA_PKT_STAT_SZ; } } if (buf[0] & 0x01) { /* Multicast/Broadcast */ if ((*(s16 *)&buf[0] == -1) && (*(s16 *)&buf[2] == -1) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -