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 + -
显示快捷键?