?? 3c501.c
字號:
outb(TX_NORM, TX_CMD);
outb(RX_NORM, RX_CMD);
outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
#endif
outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
dev->tbusy = 0;
dev->trans_start = jiffies;
}
if (skb == NULL) {
dev_tint(dev);
return 0;
}
/* Fill in the ethernet header. */
if (!skb->arp && dev->rebuild_header(skb->data, dev)) {
skb->dev = dev;
arp_queue (skb);
return 0;
}
skb->arp=1;
if (skb->len <= 0)
return 0;
/* Avoid timer-based retransmission conflicts. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
unsigned char *buf = skb->data;
el_status.tx_pkt_start = gp_start;
el_status.collisions = 0;
outb(AX_SYS, AX_CMD);
inb(RX_STATUS);
inb(TX_STATUS);
outb(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
outw(gp_start, GP_LOW);
outsb(DATAPORT,buf,skb->len);
outw(gp_start, GP_LOW);
outb(AX_XMIT, AX_CMD); /* Trigger xmit. */
dev->trans_start = jiffies;
}
if (el_debug > 2)
printk(" queued xmit.\n");
if (skb->free)
kfree_skb (skb, FREE_WRITE);
return 0;
}
/* The typical workload of the driver:
Handle the ether interface interrupts. */
static void
el_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
/*struct device *dev = (struct device *)(irq2dev_map[irq]);*/
struct device *dev = eldev;
int axsr; /* Aux. status reg. */
short ioaddr;
if (eldev->irq != irq) {
printk (EL_NAME ": irq %d for unknown device\n", irq);
return;
}
ioaddr = dev->base_addr;
axsr = inb(AX_STATUS);
if (el_debug > 3)
printk("%s: el_interrupt() aux=%#02x", dev->name, axsr);
if (dev->interrupt)
printk("%s: Reentering the interrupt driver!\n", dev->name);
dev->interrupt = 1;
if (dev->tbusy) {
int txsr = inb(TX_STATUS);
if (el_debug > 6)
printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),
inw(RX_LOW));
if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
" gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));
dev->tbusy = 0;
mark_bh(INET_BH);
} else if (txsr & TX_16COLLISIONS) {
if (el_debug)
printk("%s: Transmit failed 16 times, ethernet jammed?\n",
dev->name);
outb(AX_SYS, AX_CMD);
el_status.stats.tx_aborted_errors++;
} else if (txsr & TX_COLLISION) { /* Retrigger xmit. */
if (el_debug > 6)
printk(" retransmitting after a collision.\n");
outb(AX_SYS, AX_CMD);
outw(el_status.tx_pkt_start, GP_LOW);
outb(AX_XMIT, AX_CMD);
el_status.stats.collisions++;
dev->interrupt = 0;
return;
} else {
el_status.stats.tx_packets++;
if (el_debug > 6)
printk(" Tx succeeded %s\n",
(txsr & TX_RDY) ? "." : "but tx is busy!");
dev->tbusy = 0;
mark_bh(INET_BH);
}
} else {
int rxsr = inb(RX_STATUS);
if (el_debug > 5)
printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),
inw(RX_LOW));
/* Just reading rx_status fixes most errors. */
if (rxsr & RX_MISSED)
el_status.stats.rx_missed_errors++;
if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */
el_status.stats.rx_length_errors++;
if (el_debug > 5) printk(" runt.\n");
} else if (rxsr & RX_GOOD) {
el_receive(eldev);
} else { /* Nothing? Something is broken! */
if (el_debug > 2)
printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
dev->name, rxsr);
el_reset(eldev);
}
if (el_debug > 3)
printk(".\n");
}
outb(AX_RX, AX_CMD);
outb(0x00, RX_BUF_CLR);
inb(RX_STATUS); /* Be certain that interrupts are cleared. */
inb(TX_STATUS);
dev->interrupt = 0;
return;
}
/* We have a good packet. Well, not really "good", just mostly not broken.
We must check everything to see if it is good. */
static void
el_receive(struct device *dev)
{
int sksize, pkt_len;
struct sk_buff *skb;
pkt_len = inw(RX_LOW);
if (el_debug > 4)
printk(" el_receive %d.\n", pkt_len);
if ((pkt_len < 60) || (pkt_len > 1536)) {
if (el_debug)
printk("%s: bogus packet, length=%d\n", dev->name, pkt_len);
el_status.stats.rx_over_errors++;
return;
}
outb(AX_SYS, AX_CMD);
sksize = sizeof(struct sk_buff) + pkt_len;
skb = alloc_skb(sksize, GFP_ATOMIC);
outw(0x00, GP_LOW);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
el_status.stats.rx_dropped++;
return;
} else {
skb->mem_len = sksize;
skb->mem_addr = skb;
skb->len = pkt_len;
skb->dev = dev;
insb(DATAPORT, skb->data, pkt_len);
#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
el_status.stats.rx_packets++;
}
return;
}
static void
el_reset(struct device *dev)
{
if (el_debug> 2)
printk("3c501 reset...");
outb(AX_RESET, AX_CMD); /* Reset the chip */
outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */
{
int i;
for (i = 0; i < 6; i++) /* Set the station address. */
outb(dev->dev_addr[i], el_base + i);
}
outb(0, RX_BUF_CLR); /* Set rx packet area to 0. */
cli(); /* Avoid glitch on writes to CMD regs */
outb(TX_NORM, TX_CMD); /* tx irq on done, collision */
outb(RX_NORM, RX_CMD); /* Set Rx commands. */
inb(RX_STATUS); /* Clear status. */
inb(TX_STATUS);
dev->interrupt = 0;
dev->tbusy = 0;
sti();
}
static int
el1_close(struct device *dev)
{
int ioaddr = dev->base_addr;
if (el_debug > 2)
printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr);
dev->tbusy = 1;
dev->start = 0;
/* Free and disable the IRQ. */
free_irq(dev->irq);
outb(AX_RESET, AX_CMD); /* Reset the chip */
irq2dev_map[dev->irq] = 0;
return 0;
}
static struct enet_statistics *
el1_get_stats(struct device *dev)
{
return &el_status.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)
{
if (num_addrs > 0) {
outb(RX_MULT, RX_CMD);
inb(RX_STATUS); /* Clear status. */
} else if (num_addrs < 0) {
outb(RX_PROM, RX_CMD);
inb(RX_STATUS);
} else {
outb(RX_NORM, RX_CMD);
inb(RX_STATUS);
}
}
#endif
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -m486 -c -o 3c501.o 3c501.c"
* kept-new-versions: 5
* End:
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -