?? 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 int
depca_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 int
depca_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 int
depca_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 void
set_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 + -