📄 depca.c
字号:
depca_interrupt(int reg_ptr){ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); struct device *dev = (struct device *)(irq2dev_map[irq]); struct depca_private *lp; int csr0, ioaddr, nicsr; if (dev == NULL) { printk ("depca_interrupt(): irq %d for unknown device.\n", irq); return; } 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 = inw(DEPCA_NICSR); nicsr |= (IM|LED); outw(nicsr, DEPCA_NICSR); outw(CSR0, DEPCA_ADDR); csr0 = inw(DEPCA_DATA); /* Acknowledge all of the current interrupt sources ASAP. */ outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); if (depca_debug > 5) printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, inw(DEPCA_DATA)); if (csr0 & RINT) /* Rx interrupt (packet arrived) */ depca_rx(dev); if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx(dev); /* Clear the interrupts we've handled. */ outw(CSR0, DEPCA_ADDR); outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); if (depca_debug > 4) { printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, inw(DEPCA_ADDR), inw(DEPCA_DATA)); } /* Unmask the DEPCA board interrupts and turn off the LED */ nicsr = (nicsr & ~IM & ~LED); outw(nicsr, DEPCA_NICSR); dev->interrupt = UNMASK_INTERRUPTS; return;}static intdepca_rx(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int entry = lp->cur_rx & lp->rmask; /* If we own the next entry, it's a new packet. Send it up. */ for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) { int status = lp->rx_ring[entry].base >> 16 ; 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 { /* Malloc up new buffer, compatible with net-2e. */ short pkt_len = lp->rx_ring[entry].msg_length; int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; skb = alloc_skb(sksize, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } skb->mem_len = sksize; skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; memcpy(skb->data, (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), pkt_len); /* ** Notify the upper protocol layers that there is another ** packet to handle */#ifdef HAVE_NETIF_RX netif_rx(skb);#else skb->lock = 0; if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { kfree_skbmem(skb, sksize); lp->stats.rx_dropped++; break; }#endif lp->stats.rx_packets++; } /* turn over ownership of the current entry back to the LANCE */ lp->rx_ring[entry].base |= R_OWN; } /* ** We should check that at least two ring entries are free. If not, ** we should free one and mark stats->rx_dropped++. */ return 0;}/*** Buffer sent - check for buffer errors.*/static intdepca_tx(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int dirty_tx = lp->dirty_tx & lp->rmask; if (depca_debug > 5) printk("%s: Cleaning tx ring, dirty %d clean %d.\n", dev->name, dirty_tx, (lp->cur_tx & lp->rmask)); /* ** While the dirty entry is not the current one AND ** the LANCE doesn't own it... */ for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0; dirty_tx = ++lp->dirty_tx & lp->rmask) { unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]); int status = lp->tx_ring[dirty_tx].base >> 16; if (status < 0) { /* Packet not yet sent! */ printk("interrupt for packet not yet sent!\n"); break; } if (status & T_ERR) { /* There was an major error, log it. */ int err_status = lp->tx_ring[dirty_tx].misc; lp->stats.tx_errors++; if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++; /* We should re-init() after the FIFO error. */ } else if (status & (T_MORE | T_ONE)) { lp->stats.collisions++; } else { lp->stats.tx_packets++; } if (depca_debug > 5) printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n", dev->name, dirty_tx, tmdp[0], tmdp[1], tmdp[2], tmdp[3]); } /*mark_bh(INET_BH);*/ return 0;}static intdepca_close(struct device *dev){ int ioaddr = dev->base_addr; dev->start = 0; dev->tbusy = 1; outw(CSR0, DEPCA_ADDR); if (depca_debug > 1) { printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA)); } /* ** We stop the DEPCA here -- it occasionally polls ** memory if we don't. */ outw(STOP, DEPCA_DATA); free_irq(dev->irq); irq2dev_map[dev->irq] = 0; return 0;}static void LoadCSRs(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int ioaddr = dev->base_addr; outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA); outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA); outw(CSR3, DEPCA_ADDR); /* ALE control */ outw(ACON, DEPCA_DATA); outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */}static int InitRestartDepca(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; int ioaddr = dev->base_addr; int i, status=0; outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ outw(INIT, DEPCA_DATA); /* initialize DEPCA */ /* wait for lance to complete initialisation */ for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); if (i!=100) { /* clear IDON by writing a "1", enable interrupts and start lance */ outw(IDON | INEA | STRT, DEPCA_DATA); if (depca_debug > 2) { printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n", dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA)); } } else { status = -1; printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n", dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA)); } return status;}static struct enet_statistics *depca_get_stats(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; /* Null body since there is no framing error counter */ return &lp->stats;}#ifdef HAVE_MULTICAST/*** Set or clear the multicast filter for this adaptor.** num_addrs == -1 Promiscuous mode, receive all packets** num_addrs == 0 Normal mode, clear multicast list** num_addrs > 0 Multicast mode, receive normal and MC packets, and do** best-effort filtering.*/static voidset_multicast_list(struct device *dev, int num_addrs, void *addrs){ short ioaddr = dev->base_addr; struct depca_private *lp = (struct depca_private *)dev->priv; /* We take the simple way out and always enable promiscuous mode. */ STOP_DEPCA; /* Temporarily stop the depca. */ lp->init_block.mode = PROM; /* Set promiscuous mode */ if (num_addrs >= 0) { short multicast_table[4]; int i; SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table); /* We don't use the multicast table, but rely on upper-layer filtering. */ memset(multicast_table, (num_addrs==0) ? 0 : -1, sizeof(multicast_table)); for (i = 0; i < 4; i++) { lp->init_block.filter[i] = multicast_table[i]; } lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ } else { lp->init_block.mode |= PROM; /* Set promiscuous mode */ } outw(CSR0, DEPCA_ADDR); outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */}/*** Calculate the hash code and update the logical address filter** from a list of ethernet multicast addresses.** Derived from a 'C' program in the AMD data book:** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", ** Pub #17781, Rev. A, May 1993*/static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table){ char j, ctrl, bit, octet, hashcode; short int i; long int CRC, poly = (long int) CRC_POLYNOMIAL; for (i=0;i<num_addrs;i++) { /* for each address in the list */ if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */ CRC = (long int) 0xffffffff; /* init CRC for each address */ for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */ for(j=0;j<8;j++) { /* process each address bit */ bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01; ctrl = ((CRC < 0) ? 1 : 0); /* shift the control bit */ CRC <<= 1; /* shift the CRC */ if (bit ^ ctrl) { /* (bit) XOR (control bit) */ CRC ^= poly; /* (CRC) XOR (polynomial) */ } } } hashcode = (CRC & 0x00000001); /* hashcode is 6 LSb of CRC ... */ for (j=0;j<5;j++) { /* ... in reverse order. */ hashcode <<= 1; CRC >>= 1; hashcode |= (CRC & 0x00000001); } octet = hashcode >> 3; /* bit[3-5] -> octet in filter */ /* bit[0-2] -> bit in octet */ multicast_table[octet] |= (1 << (hashcode & 0x07)); } } return;}#endif /* HAVE_MULTICAST *//*** Look for a particular board name in the on-board Remote Diagnostics** and Boot (RDB) ROM. This will also give us a clue to the network RAM** base address.*/static char *DepcaSignature(unsigned long mem_addr){ unsigned long i,j,k; static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE; static char thisName[DEPCA_NAME_LENGTH]; char tmpstr[17]; for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */ tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */ } tmpstr[i]=(char)NULL; strcpy(thisName,""); for (i=0;*signatures[i]!=(char)NULL && *thisName==(char)NULL;i++) { for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) { if (signatures[i][k] == tmpstr[j]) { /* track signature */ k++; } else { /* lost signature; begin search again */ k=0; } } if (k == strlen(signatures[i])) { strcpy(thisName,signatures[i]); } } return thisName; /* return the device name string */}/*** Look for a special sequence in the Ethernet station address PROM that** is common across all DEPCA products.*/static int DevicePresent(short ioaddr){ static short fp=1,sigLength=0; static char devSig[] = PROBE_SEQUENCE; char data; int i, j, status = 0; static char asc2hex(char value);/* ** Convert the ascii signature to a hex equivalent & pack in place */ if (fp) { /* only do this once!... */ for (i=0,j=0;devSig[i]!=(char)NULL && !status;i+=2,j++) { if ((devSig[i]=asc2hex(devSig[i]))>=0) { devSig[i]<<=4; if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){ devSig[j]=devSig[i]+devSig[i+1]; } else { status= -1; } } else { status= -1; } } sigLength=j; fp = 0; }/* ** Search the Ethernet address ROM for the signature. Since the ROM address** counter can start at an arbitrary point, the search must include the entire** probe sequence length plus the length of the (signature - 1).** Stop the search IMMEDIATELY after the signature is found so that the** PROM address counter is correctly positioned at the start of the** ethernet address for later read out.*/ if (!status) { for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) { data = inb(ioaddr); if (devSig[j] == data) { /* track signature */ j++; } else { /* lost signature; begin search again */ j=0; } } if (j!=sigLength) { status = -ENODEV; /* search failed */ } } return status;}static char asc2hex(char value){ value -= 0x30; /* normalise to 0..9 range */ if (value >= 0) { if (value > 9) { /* but may not be 10..15 */ value &= 0x1f; /* make A..F & a..f be the same */ value -= 0x07; /* normalise to 10..15 range */ if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */ value = -1; /* ...signal error */ } } } else { /* outside 0..9 range... */ value = -1; /* ...signal error */ } return value; /* return hex char or error */}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c depca.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -