📄 3c505.c
字号:
/****************************************************** * * open the board * ******************************************************/static int elp_open(struct net_device *dev){ elp_device *adapter; int retval; adapter = dev->priv; if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to open device\n", dev->name); /* * make sure we actually found the device */ if (adapter == NULL) { printk(KERN_ERR "%s: Opening a non-existent physical device\n", dev->name); return -EAGAIN; } /* * disable interrupts on the board */ outb_control(0, dev); /* * clear any pending interrupts */ inb_command(dev->base_addr); adapter_reset(dev); /* * no receive PCBs active */ adapter->rx_active = 0; adapter->busy = 0; adapter->send_pcb_semaphore = 0; adapter->rx_backlog.in = 0; adapter->rx_backlog.out = 0; spin_lock_init(&adapter->lock); /* * install our interrupt service routine */ if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) { printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq); return retval; } if ((retval = request_dma(dev->dma, dev->name))) { free_irq(dev->irq, dev); printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma); return retval; } adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE); if (!adapter->dma_buffer) { printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name); free_dma(dev->dma); free_irq(dev->irq, dev); return -ENOMEM; } adapter->dmaing = 0; /* * enable interrupts on the board */ outb_control(CMDE, dev); /* * configure adapter memory: we need 10 multicast addresses, default==0 */ if (elp_debug >= 3) printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY; adapter->tx_pcb.data.memconf.cmd_q = 10; adapter->tx_pcb.data.memconf.rcv_q = 20; adapter->tx_pcb.data.memconf.mcast = 10; adapter->tx_pcb.data.memconf.frame = 20; adapter->tx_pcb.data.memconf.rcv_b = 20; adapter->tx_pcb.data.memconf.progs = 0; adapter->tx_pcb.length = sizeof(struct Memconf); adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) printk(KERN_ERR "%s: couldn't send memory configuration command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) TIMEOUT_MSG(__LINE__); } /* * configure adapter to receive broadcast messages and wait for response */ if (elp_debug >= 3) printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) printk(KERN_ERR "%s: couldn't send 82586 configure command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) TIMEOUT_MSG(__LINE__); } /* enable burst-mode DMA */ /* outb(0x1, dev->base_addr + PORT_AUXDMA); */ /* * queue receive commands to provide buffering */ prime_rx(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: %d receive PCBs active\n", dev->name, adapter->rx_active); /* * device is now officially open! */ netif_start_queue(dev); return 0;}/****************************************************** * * send a packet to the adapter * ******************************************************/static int send_packet(struct net_device *dev, struct sk_buff *skb){ elp_device *adapter = dev->priv; unsigned long target; unsigned long flags; /* * make sure the length is even and no shorter than 60 bytes */ unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1); if (test_and_set_bit(0, (void *) &adapter->busy)) { if (elp_debug >= 2) printk(KERN_DEBUG "%s: transmit blocked\n", dev->name); return FALSE; } adapter->stats.tx_bytes += nlen; /* * send the adapter a transmit packet command. Ignore segment and offset * and make sure the length is even */ adapter->tx_pcb.command = CMD_TRANSMIT_PACKET; adapter->tx_pcb.length = sizeof(struct Xmit_pkt); adapter->tx_pcb.data.xmit_pkt.buf_ofs = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */ adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen; if (!send_pcb(dev, &adapter->tx_pcb)) { adapter->busy = 0; return FALSE; } /* if this happens, we die */ if (test_and_set_bit(0, (void *) &adapter->dmaing)) printk(KERN_DEBUG "%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; adapter->current_dma.start_time = jiffies; if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) { memcpy(adapter->dma_buffer, skb->data, nlen); memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len); target = isa_virt_to_bus(adapter->dma_buffer); } else { target = isa_virt_to_bus(skb->data); } adapter->current_dma.skb = skb; flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_mode(dev->dma, 0x48); /* dma memory -> io */ set_dma_addr(dev->dma, target); set_dma_count(dev->dma, nlen); outb_control(adapter->hcr_val | DMAE | TCEN, dev); enable_dma(dev->dma); release_dma_lock(flags); if (elp_debug >= 3) printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name); return TRUE;}/* * The upper layer thinks we timed out */ static void elp_timeout(struct net_device *dev){ elp_device *adapter = dev->priv; int stat; stat = inb_status(dev->base_addr); printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); if (elp_debug >= 1) printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat); dev->trans_start = jiffies; adapter->stats.tx_dropped++; netif_wake_queue(dev);}/****************************************************** * * start the transmitter * return 0 if sent OK, else return 1 * ******************************************************/static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev){ unsigned long flags; elp_device *adapter = dev->priv; spin_lock_irqsave(&adapter->lock, flags); check_3c505_dma(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len); netif_stop_queue(dev); /* * send the packet at skb->data for skb->len */ if (!send_packet(dev, skb)) { if (elp_debug >= 2) { printk(KERN_DEBUG "%s: failed to transmit packet\n", dev->name); } spin_unlock_irqrestore(&adapter->lock, flags); return 1; } if (elp_debug >= 3) printk(KERN_DEBUG "%s: packet of length %d sent\n", dev->name, (int) skb->len); /* * start the transmit timeout */ dev->trans_start = jiffies; prime_rx(dev); spin_unlock_irqrestore(&adapter->lock, flags); netif_start_queue(dev); return 0;}/****************************************************** * * return statistics on the board * ******************************************************/static struct net_device_stats *elp_get_stats(struct net_device *dev){ elp_device *adapter = (elp_device *) dev->priv; if (elp_debug >= 3) printk(KERN_DEBUG "%s: request for stats\n", dev->name); /* If the device is closed, just return the latest stats we have, - we cannot ask from the adapter without interrupts */ if (!netif_running(dev)) return &adapter->stats; /* send a get statistics command to the board */ adapter->tx_pcb.command = CMD_NETWORK_STATISTICS; adapter->tx_pcb.length = 0; adapter->got[CMD_NETWORK_STATISTICS] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) printk(KERN_ERR "%s: couldn't send get statistics command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); return &adapter->stats; } } /* statistics are now up to date */ return &adapter->stats;}static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);}static u32 netdev_get_msglevel(struct net_device *dev){ return debug;}static void netdev_set_msglevel(struct net_device *dev, u32 level){ debug = level;}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel,};/****************************************************** * * close the board * ******************************************************/static int elp_close(struct net_device *dev){ elp_device *adapter; adapter = dev->priv; if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to close device\n", dev->name); netif_stop_queue(dev); /* Someone may request the device statistic information even when * the interface is closed. The following will update the statistics * structure in the driver, so we'll be able to give current statistics. */ (void) elp_get_stats(dev); /* * disable interrupts on the board */ outb_control(0, dev); /* * release the IRQ */ free_irq(dev->irq, dev); free_dma(dev->dma); free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE)); return 0;}/************************************************************ * * Set multicast list * num_addrs==0: clear mc_list * num_addrs==-1: set promiscuous mode * num_addrs>0: set mc_list * ************************************************************/static void elp_set_mc_list(struct net_device *dev){ elp_device *adapter = (elp_device *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; int i; unsigned long flags; if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name); spin_lock_irqsave(&adapter->lock, flags); if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { /* send a "load multicast list" command to the board, max 10 addrs/cmd */ /* if num_addrs==0 the list will be cleared */ adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST; adapter->tx_pcb.length = 6 * dev->mc_count; for (i = 0; i < dev->mc_count; i++) { memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr, 6); dmi = dmi->next; } adapter->got[CMD_LOAD_MULTICAST_LIST] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) printk(KERN_ERR "%s: couldn't send set_multicast command\n", dev->name); else { unsigned long timeout = jiffies + TIMEOUT; while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) { TIMEOUT_MSG(__LINE__); } } if (dev->mc_count) adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI; else /* num_addrs == 0 */ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; } else adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC; /* * configure adapter to receive messages (as specified above) * and wait for response */ if (elp_debug >= 3) printk(KERN_DEBUG "%s: sending 82586 configure command\n", dev->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -