📄 3c505.c
字号:
default: printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command); break; } } else { printk("%s: failed to read PCB on interrupt\n", dev->name); adapter_reset(dev); } } } while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE))); prime_rx(dev); /* * indicate no longer in interrupt routine */ dev->interrupt = 0;}/****************************************************** * * open the board * ******************************************************/static int elp_open(struct device *dev){ elp_device *adapter; adapter = dev->priv; if (elp_debug >= 3) printk("%s: request to open device\n", dev->name); /* * make sure we actually found the device */ if (adapter == NULL) { printk("%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); /* * interrupt routine not entered */ dev->interrupt = 0; /* * transmitter not busy */ dev->tbusy = 0; /* * 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; /* * install our interrupt service routine */ if (request_irq(dev->irq, &elp_interrupt, 0, "3c505", dev)) { return -EAGAIN; } if (request_dma(dev->dma, "3c505")) { printk("%s: could not allocate DMA channel\n", dev->name); return -EAGAIN; } adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE); if (!adapter->dma_buffer) { printk("Could not allocate DMA buffer\n"); } 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("%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("%s: couldn't send memory configuration command\n", dev->name); else { int 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("%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("%s: couldn't send 82586 configure command\n", dev->name); else { int 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("%s: %d receive PCBs active\n", dev->name, adapter->rx_active); /* * device is now officially open! */ dev->start = 1; MOD_INC_USE_COUNT; return 0; /* Always succeed */}/****************************************************** * * send a packet to the adapter * ******************************************************/static int send_packet(struct 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("%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("%s: tx: DMA %d in progress\n", dev->name, adapter->current_dma.direction); adapter->current_dma.direction = 1; adapter->current_dma.start_time = jiffies; target = virt_to_bus(skb->data); if ((target + nlen) >= MAX_DMA_ADDRESS) { memcpy(adapter->dma_buffer, skb->data, nlen); target = virt_to_bus(adapter->dma_buffer); } 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("%s: DMA transfer started\n", dev->name); return TRUE;}/****************************************************** * * start the transmitter * return 0 if sent OK, else return 1 * ******************************************************/static int elp_start_xmit(struct sk_buff *skb, struct device *dev){ if (dev->interrupt) { printk("%s: start_xmit aborted (in irq)\n", dev->name); return 1; } check_3c505_dma(dev); /* * if the transmitter is still busy, we have a transmit timeout... */ if (dev->tbusy) { elp_device *adapter = dev->priv; int tickssofar = jiffies - dev->trans_start; int stat; if (tickssofar < 1000) return 1; stat = inb_status(dev->base_addr); printk("%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); if (elp_debug >= 1) printk("%s: status %#02x\n", dev->name, stat); dev->trans_start = jiffies; dev->tbusy = 0; adapter->stats.tx_dropped++; } if (elp_debug >= 3) printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len); if (test_and_set_bit(0, (void *) &dev->tbusy)) { printk("%s: transmitter access conflict\n", dev->name); return 1; } /* * send the packet at skb->data for skb->len */ if (!send_packet(dev, skb)) { if (elp_debug >= 2) { printk("%s: failed to transmit packet\n", dev->name); } dev->tbusy = 0; return 1; } if (elp_debug >= 3) printk("%s: packet of length %d sent\n", dev->name, (int) skb->len); /* * start the transmit timeout */ dev->trans_start = jiffies; prime_rx(dev); return 0;}/****************************************************** * * return statistics on the board * ******************************************************/static struct net_device_stats *elp_get_stats(struct device *dev){ elp_device *adapter = (elp_device *) dev->priv; if (elp_debug >= 3) printk("%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 (!dev->start) 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("%s: couldn't send get statistics command\n", dev->name); else { int 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;}/****************************************************** * * close the board * ******************************************************/static int elp_close(struct device *dev){ elp_device *adapter; adapter = dev->priv; if (elp_debug >= 3) printk("%s: request to close device\n", dev->name); /* 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); /* * flag transmitter as busy (i.e. not available) */ dev->tbusy = 1; /* * indicate device is closed */ dev->start = 0; /* * release the IRQ */ free_irq(dev->irq, dev); free_dma(dev->dma); free_pages((unsigned long) adapter->dma_buffer, __get_order(DMA_BUFFER_SIZE)); MOD_DEC_USE_COUNT; 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 device *dev){ elp_device *adapter = (elp_device *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; int i; if (elp_debug >= 3) printk("%s: request to set multicast list\n", dev->name); 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("%s: couldn't send set_multicast command\n", dev->name); else { int 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("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -