⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcnet32.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
			skb = lp->rx_skbuff[entry];			skb_put (skb, pkt_len);			lp->rx_skbuff[entry] = newskb;			newskb->dev = dev;                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);			rx_in_place = 1;		    } else			skb = NULL;		} else {		    skb = dev_alloc_skb(pkt_len+2);                }			    		if (skb == NULL) {                    int i;		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);		    for (i = 0; i < RX_RING_SIZE; i++)			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)			    break;		    if (i > RX_RING_SIZE -2) {			lp->stats.rx_dropped++;			lp->rx_ring[entry].status |= le16_to_cpu(0x8000);			lp->cur_rx++;		    }		    break;		}		skb->dev = dev;		if (!rx_in_place) {		    skb_reserve(skb,2); /* 16 byte align */		    skb_put(skb,pkt_len);	/* Make room */		    eth_copy_and_sum(skb,				     (unsigned char *)(lp->rx_skbuff[entry]->tail),				     pkt_len,0);		}		lp->stats.rx_bytes += skb->len;		skb->protocol=eth_type_trans(skb,dev);		netif_rx(skb);		lp->stats.rx_packets++;	    }	}	/*	 * The docs say that the buffer length isn't touched, but Andrew Boyd	 * of QNX reports that some revs of the 79C965 clear it.	 */	lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);	lp->rx_ring[entry].status |= le16_to_cpu(0x8000);	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;    }    return 0;}static intpcnet32_close(struct net_device *dev){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = dev->priv;    int i;    netif_stop_queue(dev);    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);    if (pcnet32_debug > 1)	printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",	       dev->name, lp->a.read_csr (ioaddr, 0));    /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */    lp->a.write_csr (ioaddr, 0, 0x0004);    /*     * Switch back to 16bit mode to avoid problems with dumb      * DOS packet driver after a warm reboot     */    lp->a.write_bcr (ioaddr, 20, 4);    free_irq(dev->irq, dev);        /* free all allocated skbuffs */    for (i = 0; i < RX_RING_SIZE; i++) {	lp->rx_ring[i].status = 0;			    	if (lp->rx_skbuff[i]) {            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);	    dev_kfree_skb(lp->rx_skbuff[i]);        }	lp->rx_skbuff[i] = NULL;        lp->rx_dma_addr[i] = 0;    }        for (i = 0; i < TX_RING_SIZE; i++) {	if (lp->tx_skbuff[i]) {            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);	    dev_kfree_skb(lp->tx_skbuff[i]);        }	lp->tx_skbuff[i] = NULL;        lp->tx_dma_addr[i] = 0;    }        MOD_DEC_USE_COUNT;    return 0;}static struct net_device_stats *pcnet32_get_stats(struct net_device *dev){    struct pcnet32_private *lp = dev->priv;    unsigned long ioaddr = dev->base_addr;    u16 saved_addr;    unsigned long flags;    spin_lock_irqsave(&lp->lock, flags);    saved_addr = lp->a.read_rap(ioaddr);    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);    lp->a.write_rap(ioaddr, saved_addr);    spin_unlock_irqrestore(&lp->lock, flags);    return &lp->stats;}/* taken from the sunlance driver, which it took from the depca driver */static void pcnet32_load_multicast (struct net_device *dev){    struct pcnet32_private *lp = dev->priv;    volatile struct pcnet32_init_block *ib = &lp->init_block;    volatile u16 *mcast_table = (u16 *)&ib->filter;    struct dev_mc_list *dmi=dev->mc_list;    char *addrs;    int i, j, bit, byte;    u32 crc, poly = CRC_POLYNOMIAL_LE;	    /* set all multicast bits */    if (dev->flags & IFF_ALLMULTI){ 	ib->filter [0] = 0xffffffff;	ib->filter [1] = 0xffffffff;	return;    }    /* clear the multicast filter */    ib->filter [0] = 0;    ib->filter [1] = 0;    /* Add addresses */    for (i = 0; i < dev->mc_count; i++){	addrs = dmi->dmi_addr;	dmi   = dmi->next;		/* multicast address? */	if (!(*addrs & 1))	    continue;		crc = 0xffffffff;	for (byte = 0; byte < 6; byte++)	    for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {		int test;				test = ((bit ^ crc) & 0x01);		crc >>= 1;				if (test) {		    crc = crc ^ poly;		}	    }		crc = crc >> 26;	mcast_table [crc >> 4] |= 1 << (crc & 0xf);    }    return;}/* * Set or clear the multicast filter for this adaptor. */static void pcnet32_set_multicast_list(struct net_device *dev){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = dev->priv;	     if (dev->flags&IFF_PROMISC) {	/* Log any net taps. */	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7);    } else {	lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);	pcnet32_load_multicast (dev);    }        lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */    pcnet32_restart(dev, 0x0042); /*  Resume normal operation */}static int mdio_read(struct net_device *dev, int phy_id, int reg_num){	struct pcnet32_private *lp = dev->priv;	unsigned long ioaddr = dev->base_addr;	u16 val_out;	int phyaddr;	if (!lp->mii)		return 0;			phyaddr = lp->a.read_bcr(ioaddr, 33);	lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));	val_out = lp->a.read_bcr(ioaddr, 34);	lp->a.write_bcr(ioaddr, 33, phyaddr);		return val_out;}static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val){	struct pcnet32_private *lp = dev->priv;	unsigned long ioaddr = dev->base_addr;	int phyaddr;	if (!lp->mii)		return;			phyaddr = lp->a.read_bcr(ioaddr, 33);	lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f));	lp->a.write_bcr(ioaddr, 34, val);	lp->a.write_bcr(ioaddr, 33, phyaddr);}static int pcnet32_ethtool_ioctl (struct net_device *dev, void *useraddr){	struct pcnet32_private *lp = dev->priv;	u32 ethcmd;	int phyaddr = 0;	int phy_id = 0;	unsigned long ioaddr = dev->base_addr;	if (lp->mii) {		phyaddr = lp->a.read_bcr (ioaddr, 33);		phy_id = (phyaddr >> 5) & 0x1f;		lp->mii_if.phy_id = phy_id;	}	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))		return -EFAULT;	switch (ethcmd) {	case ETHTOOL_GDRVINFO: {		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };		strcpy (info.driver, DRV_NAME);		strcpy (info.version, DRV_VERSION);		if (lp->pci_dev)			strcpy (info.bus_info, lp->pci_dev->slot_name);		else			sprintf(info.bus_info, "VLB 0x%lx", dev->base_addr);		if (copy_to_user (useraddr, &info, sizeof (info)))			return -EFAULT;		return 0;	}	/* get settings */	case ETHTOOL_GSET: {		struct ethtool_cmd ecmd = { ETHTOOL_GSET };		spin_lock_irq(&lp->lock);		mii_ethtool_gset(&lp->mii_if, &ecmd);		spin_unlock_irq(&lp->lock);		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))			return -EFAULT;		return 0;	}	/* set settings */	case ETHTOOL_SSET: {		int r;		struct ethtool_cmd ecmd;		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))			return -EFAULT;		spin_lock_irq(&lp->lock);		r = mii_ethtool_sset(&lp->mii_if, &ecmd);		spin_unlock_irq(&lp->lock);		return r;	}	/* restart autonegotiation */	case ETHTOOL_NWAY_RST: {		return mii_nway_restart(&lp->mii_if);	}	/* get link status */	case ETHTOOL_GLINK: {		struct ethtool_value edata = {ETHTOOL_GLINK};		edata.data = mii_link_ok(&lp->mii_if);		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	/* get message-level */	case ETHTOOL_GMSGLVL: {		struct ethtool_value edata = {ETHTOOL_GMSGLVL};		edata.data = pcnet32_debug;		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	/* set message-level */	case ETHTOOL_SMSGLVL: {		struct ethtool_value edata;		if (copy_from_user(&edata, useraddr, sizeof(edata)))			return -EFAULT;		pcnet32_debug = edata.data;		return 0;	}	default:		break;	}	return -EOPNOTSUPP;}static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = dev->priv;	     struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;    int phyaddr = lp->a.read_bcr (ioaddr, 33);    if (cmd == SIOCETHTOOL)	return pcnet32_ethtool_ioctl(dev, (void *) rq->ifr_data);    if (lp->mii) {	switch(cmd) {	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */	    data->phy_id = (phyaddr >> 5) & 0x1f;	    /* Fall Through */	case SIOCGMIIREG:		/* Read MII PHY register. */	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */	    lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));	    data->val_out = lp->a.read_bcr (ioaddr, 34);	    lp->a.write_bcr (ioaddr, 33, phyaddr);	    return 0;	case SIOCSMIIREG:		/* Write MII PHY register. */	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */	    if (!capable(CAP_NET_ADMIN))		return -EPERM;	    lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f));	    lp->a.write_bcr (ioaddr, 34, data->val_in);	    lp->a.write_bcr (ioaddr, 33, phyaddr);	    return 0;	default:	    return -EOPNOTSUPP;	}    }    return -EOPNOTSUPP;}					    static struct pci_driver pcnet32_driver = {	name:		DRV_NAME,	probe:		pcnet32_probe_pci,	remove:		NULL,	id_table:	pcnet32_pci_tbl,};MODULE_PARM(debug, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(tx_start_pt, "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_AUTHOR("Thomas Bogendoerfer");MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");MODULE_LICENSE("GPL");/* An additional parameter that may be passed in... */static int debug = -1;static int tx_start_pt = -1;static int __init pcnet32_init_module(void){    int cards_found = 0;    int err;    if (debug > 0)	pcnet32_debug = debug;    if ((tx_start_pt >= 0) && (tx_start_pt <= 3))	tx_start = tx_start_pt;        pcnet32_dev = NULL;    /* find the PCI devices */#define USE_PCI_REGISTER_DRIVER#ifdef USE_PCI_REGISTER_DRIVER    if ((err = pci_module_init(&pcnet32_driver)) < 0 )       return err;#else    {        struct pci_device_id *devid = pcnet32_pci_tbl;        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);            if (pdev != NULL) {                if (pcnet32_probe_pci(pdev, devid) >= 0) {                    cards_found++;                }            }        }    }#endif    return 0;    /* find any remaining VLbus devices */    return pcnet32_probe_vlbus(cards_found);}static void __exit pcnet32_cleanup_module(void){    struct net_device *next_dev;    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */    while (pcnet32_dev) {        struct pcnet32_private *lp = pcnet32_dev->priv;	next_dev = lp->next;	unregister_netdev(pcnet32_dev);	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);	if (lp->pci_dev != NULL)	    pci_unregister_driver(&pcnet32_driver);        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);	kfree(pcnet32_dev);	pcnet32_dev = next_dev;    }}module_init(pcnet32_init_module);module_exit(pcnet32_cleanup_module);/* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c" *  c-indent-level: 4 *  tab-width: 8 * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -