saa9730.c
来自「linux 内核源代码」· C语言 代码 · 共 1,140 行 · 第 1/3 页
C
1,140 行
/* Clear the EVM LAN interrupt. */ evm_saa9730_clear_lan_int(lp); /* Service pending transmit interrupts. */ if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) lan_saa9730_tx(dev); /* Service pending receive interrupts. */ if (readl(&lp->lan_saa9730_regs->DmaStatus) & (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); /* Enable the EVM LAN interrupt. */ evm_saa9730_unblock_lan_int(lp); return IRQ_HANDLED;}static int lan_saa9730_open(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); /* Associate IRQ with lan_saa9730_interrupt */ if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", dev)) { printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); return -EAGAIN; } /* Enable the Lan interrupt in the event manager. */ evm_saa9730_enable_lan_int(lp); /* Start the LAN controller */ if (lan_saa9730_start(lp)) return -1; netif_start_queue(dev); return 0;}static int lan_saa9730_write(struct lan_saa9730_private *lp, struct sk_buff *skb, int skblen){ unsigned char *pbData = skb->data; unsigned int len = skblen; unsigned char *pbPacketData; unsigned int tx_status; int BufferIndex; int PacketIndex; if (lan_saa9730_debug > 5) printk("lan_saa9730_write: skb=%p\n", skb); BufferIndex = lp->NextTxmBufferIndex; PacketIndex = lp->NextTxmPacketIndex; tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex] [PacketIndex]); if ((tx_status & TX_STAT_CTL_OWNER_MSK) != (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { if (lan_saa9730_debug > 4) printk ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", tx_status); return -1; } lp->NextTxmPacketIndex++; if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { lp->NextTxmPacketIndex = 0; lp->NextTxmBufferIndex ^= 1; } pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex]; pbPacketData += 4; /* copy the bits */ memcpy(pbPacketData, pbData, len); /* Set transmit status for hardware */ *(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] = cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | (TX_STAT_CTL_INT_AFTER_TX << TX_STAT_CTL_FRAME_SHF) | (len << TX_STAT_CTL_LENGTH_SHF)); /* Make sure A or B is available to hardware as appropriate. */ writel(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A, &lp->lan_saa9730_regs->Ok2Use); return 0;}static void lan_saa9730_tx_timeout(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); /* Transmitter timeout, serious problems */ dev->stats.tx_errors++; printk("%s: transmit timed out, reset\n", dev->name); /*show_saa9730_regs(dev); */ lan_saa9730_restart(lp); dev->trans_start = jiffies; netif_wake_queue(dev);}static int lan_saa9730_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); unsigned long flags; int skblen; int len; if (lan_saa9730_debug > 4) printk("Send packet: skb=%p\n", skb); skblen = skb->len; spin_lock_irqsave(&lp->lock, flags); len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; if (lan_saa9730_write(lp, skb, skblen)) { spin_unlock_irqrestore(&lp->lock, flags); printk("Error when writing packet to controller: skb=%p\n", skb); netif_stop_queue(dev); return -1; } dev->stats.tx_bytes += len; dev->stats.tx_packets++; dev->trans_start = jiffies; netif_wake_queue(dev); dev_kfree_skb(skb); spin_unlock_irqrestore(&lp->lock, flags); return 0;}static int lan_saa9730_close(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); if (lan_saa9730_debug > 1) printk("lan_saa9730_close:\n"); netif_stop_queue(dev); /* Disable the Lan interrupt in the event manager. */ evm_saa9730_disable_lan_int(lp); /* Stop the controller */ if (lan_saa9730_stop(lp)) return -1; free_irq(dev->irq, (void *) dev); return 0;}static void lan_saa9730_set_multicast(struct net_device *dev){ struct lan_saa9730_private *lp = netdev_priv(dev); /* Stop the controller */ lan_saa9730_stop(lp); if (dev->flags & IFF_PROMISC) { /* accept all packets */ writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, &lp->lan_saa9730_regs->CamCtl); } else { if (dev->flags & IFF_ALLMULTI || dev->mc_count) { /* accept all multicast packets */ /* * Will handle the multicast stuff later. -carstenl */ writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, &lp->lan_saa9730_regs->CamCtl); } } lan_saa9730_restart(lp);}static void __devexit saa9730_remove_one(struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata(pdev); struct lan_saa9730_private *lp = netdev_priv(dev); if (dev) { unregister_netdev(dev); lan_saa9730_free_buffers(pdev, lp); iounmap(lp->lan_saa9730_regs); iounmap(lp->evm_saa9730_regs); free_netdev(dev); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); }}static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, unsigned long ioaddr, int irq){ struct lan_saa9730_private *lp = netdev_priv(dev); unsigned char ethernet_addr[6]; int ret; if (get_ethernet_addr(ethernet_addr)) { ret = -ENODEV; goto out; } memcpy(dev->dev_addr, ethernet_addr, 6); dev->base_addr = ioaddr; dev->irq = irq; lp->pci_dev = pdev; /* Set SAA9730 LAN base address. */ lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR, SAA9730_LAN_REGS_SIZE); if (!lp->lan_saa9730_regs) { ret = -ENOMEM; goto out; } /* Set SAA9730 EVM base address. */ lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR, SAA9730_EVM_REGS_SIZE); if (!lp->evm_saa9730_regs) { ret = -ENOMEM; goto out_iounmap_lan; } /* Allocate LAN RX/TX frame buffer space. */ if ((ret = lan_saa9730_allocate_buffers(pdev, lp))) goto out_iounmap; /* Stop LAN controller. */ if ((ret = lan_saa9730_stop(lp))) goto out_free_consistent; /* Initialize CAM registers. */ if ((ret = lan_saa9730_cam_init(dev))) goto out_free_consistent; /* Initialize MII registers. */ if ((ret = lan_saa9730_mii_init(lp))) goto out_free_consistent; /* Initialize control registers. */ if ((ret = lan_saa9730_control_init(lp))) goto out_free_consistent; /* Load CAM registers. */ if ((ret = lan_saa9730_cam_load(lp))) goto out_free_consistent; /* Initialize DMA context registers. */ if ((ret = lan_saa9730_dma_init(lp))) goto out_free_consistent; spin_lock_init(&lp->lock); dev->open = lan_saa9730_open; dev->hard_start_xmit = lan_saa9730_start_xmit; dev->stop = lan_saa9730_close; dev->set_multicast_list = lan_saa9730_set_multicast; dev->tx_timeout = lan_saa9730_tx_timeout; dev->watchdog_timeo = (HZ >> 1); dev->dma = 0; ret = register_netdev (dev); if (ret) goto out_free_consistent; return 0;out_free_consistent: lan_saa9730_free_buffers(pdev, lp);out_iounmap: iounmap(lp->evm_saa9730_regs);out_iounmap_lan: iounmap(lp->lan_saa9730_regs);out: return ret;}static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev = NULL; unsigned long pci_ioaddr; int err; if (lan_saa9730_debug > 1) printk("saa9730.c: PCI bios is present, checking for devices...\n"); err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); goto out; } err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); goto out_disable_pdev; } pci_irq_line = pdev->irq; /* LAN base address in located at BAR 1. */ pci_ioaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); printk("Found SAA9730 (PCI) at %lx, irq %d.\n", pci_ioaddr, pci_irq_line); dev = alloc_etherdev(sizeof(struct lan_saa9730_private)); if (!dev) goto out_disable_pdev; err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line); if (err) { printk("LAN init failed"); goto out_free_netdev; } pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); return 0;out_free_netdev: free_netdev(dev);out_disable_pdev: pci_disable_device(pdev);out: pci_set_drvdata(pdev, NULL); return err;}static struct pci_driver saa9730_driver = { .name = DRV_MODULE_NAME, .id_table = saa9730_pci_tbl, .probe = saa9730_init_one, .remove = __devexit_p(saa9730_remove_one),};static int __init saa9730_init(void){ return pci_register_driver(&saa9730_driver);}static void __exit saa9730_cleanup(void){ pci_unregister_driver(&saa9730_driver);}module_init(saa9730_init);module_exit(saa9730_cleanup);MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");MODULE_DESCRIPTION("Philips SAA9730 ethernet driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?