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

📄 pcnet32.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		rc = 1;		break;	    }	}	x++;    }    if (!rc) {	*data1 = 0;    }clean_up:    pcnet32_purge_tx_ring(dev);    x = a->read_csr(ioaddr, 15) & 0xFFFF;    a->write_csr(ioaddr, 15, (x & ~0x0044));	/* reset bits 6 and 2 */    x = a->read_bcr(ioaddr, 32);		/* reset internal loopback */    x = x & ~0x0002;    a->write_bcr(ioaddr, 32, x);    spin_unlock_irqrestore(&lp->lock, flags);    if (netif_running(dev)) {	pcnet32_open(dev);    } else {	lp->a.write_bcr (ioaddr, 20, 4);	/* return to 16bit mode */    }    return(rc);} /* end pcnet32_loopback_test  */static void pcnet32_led_blink_callback(struct net_device *dev){    struct pcnet32_private *lp = dev->priv;    struct pcnet32_access *a = &lp->a;    ulong ioaddr = dev->base_addr;    unsigned long flags;    int i;    spin_lock_irqsave(&lp->lock, flags);    for (i=4; i<8; i++) {	a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);    }    spin_unlock_irqrestore(&lp->lock, flags);    mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);}static int pcnet32_phys_id(struct net_device *dev, u32 data){    struct pcnet32_private *lp = dev->priv;    struct pcnet32_access *a = &lp->a;    ulong ioaddr = dev->base_addr;    unsigned long flags;    int i, regs[4];    if (!lp->blink_timer.function) {	init_timer(&lp->blink_timer);	lp->blink_timer.function = (void *) pcnet32_led_blink_callback;	lp->blink_timer.data = (unsigned long) dev;    }    /* Save the current value of the bcrs */    spin_lock_irqsave(&lp->lock, flags);    for (i=4; i<8; i++) {	regs[i-4] = a->read_bcr(ioaddr, i);    }    spin_unlock_irqrestore(&lp->lock, flags);    mod_timer(&lp->blink_timer, jiffies);    set_current_state(TASK_INTERRUPTIBLE);    if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))    data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);    msleep_interruptible(data * 1000);    del_timer_sync(&lp->blink_timer);    /* Restore the original value of the bcrs */    spin_lock_irqsave(&lp->lock, flags);    for (i=4; i<8; i++) {	a->write_bcr(ioaddr, i, regs[i-4]);    }    spin_unlock_irqrestore(&lp->lock, flags);    return 0;}static int pcnet32_get_regs_len(struct net_device *dev){    return(PCNET32_NUM_REGS * sizeof(u16));}static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,	void *ptr){    int i, csr0;    u16 *buff = ptr;    struct pcnet32_private *lp = dev->priv;    struct pcnet32_access *a = &lp->a;    ulong ioaddr = dev->base_addr;    int ticks;    unsigned long flags;    spin_lock_irqsave(&lp->lock, flags);    csr0 = a->read_csr(ioaddr, 0);    if (!(csr0 & 0x0004)) {	/* If not stopped */	/* set SUSPEND (SPND) - CSR5 bit 0 */	a->write_csr(ioaddr, 5, 0x0001);	/* poll waiting for bit to be set */	ticks = 0;	while (!(a->read_csr(ioaddr, 5) & 0x0001)) {	    spin_unlock_irqrestore(&lp->lock, flags);	    mdelay(1);	    spin_lock_irqsave(&lp->lock, flags);	    ticks++;	    if (ticks > 200) {		if (netif_msg_hw(lp))		    printk(KERN_DEBUG "%s: Error getting into suspend!\n",			    dev->name);		break;	    }	}    }    /* read address PROM */    for (i=0; i<16; i += 2)	*buff++ = inw(ioaddr + i);    /* read control and status registers */    for (i=0; i<90; i++) {	*buff++ = a->read_csr(ioaddr, i);    }    *buff++ = a->read_csr(ioaddr, 112);    *buff++ = a->read_csr(ioaddr, 114);    /* read bus configuration registers */    for (i=0; i<30; i++) {	*buff++ = a->read_bcr(ioaddr, i);    }    *buff++ = 0;	/* skip bcr30 so as not to hang 79C976 */    for (i=31; i<36; i++) {	*buff++ = a->read_bcr(ioaddr, i);    }    /* read mii phy registers */    if (lp->mii) {	for (i=0; i<32; i++) {	    lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i);	    *buff++ = lp->a.read_bcr(ioaddr, 34);	}    }    if (!(csr0 & 0x0004)) {	/* If not stopped */	/* clear SUSPEND (SPND) - CSR5 bit 0 */	a->write_csr(ioaddr, 5, 0x0000);    }    i = buff - (u16 *)ptr;    for (; i < PCNET32_NUM_REGS; i++)	*buff++ = 0;    spin_unlock_irqrestore(&lp->lock, flags);}static struct ethtool_ops pcnet32_ethtool_ops = {    .get_settings	= pcnet32_get_settings,    .set_settings	= pcnet32_set_settings,    .get_drvinfo	= pcnet32_get_drvinfo,    .get_msglevel	= pcnet32_get_msglevel,    .set_msglevel	= pcnet32_set_msglevel,    .nway_reset		= pcnet32_nway_reset,    .get_link		= pcnet32_get_link,    .get_ringparam	= pcnet32_get_ringparam,    .set_ringparam	= pcnet32_set_ringparam,    .get_tx_csum	= ethtool_op_get_tx_csum,    .get_sg		= ethtool_op_get_sg,    .get_tso		= ethtool_op_get_tso,    .get_strings	= pcnet32_get_strings,    .self_test_count	= pcnet32_self_test_count,    .self_test		= pcnet32_ethtool_test,    .phys_id		= pcnet32_phys_id,    .get_regs_len	= pcnet32_get_regs_len,    .get_regs		= pcnet32_get_regs,    .get_perm_addr	= ethtool_op_get_perm_addr,};/* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */static void __devinitpcnet32_probe_vlbus(void){    unsigned int *port, ioaddr;    /* search for PCnet32 VLB cards at known addresses */    for (port = pcnet32_portlist; (ioaddr = *port); port++) {	if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) {	    /* check if there is really a pcnet chip on that ioaddr */	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) {		pcnet32_probe1(ioaddr, 0, NULL);	    } else {		release_region(ioaddr, PCNET32_TOTAL_SIZE);	    }	}    }}static int __devinitpcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent){    unsigned long ioaddr;    int err;    err = pci_enable_device(pdev);    if (err < 0) {	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err);	return err;    }    pci_set_master(pdev);    ioaddr = pci_resource_start (pdev, 0);    if (!ioaddr) {	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n");	return -ENODEV;    }    if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");	return -ENODEV;    }    if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == NULL) {	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_ERR PFX "io address range already allocated\n");	return -EBUSY;    }    err =  pcnet32_probe1(ioaddr, 1, pdev);    if (err < 0) {	pci_disable_device(pdev);    }    return err;}/* pcnet32_probe1 *  Called from both pcnet32_probe_vlbus and pcnet_probe_pci. *  pdev will be NULL when called from pcnet32_probe_vlbus. */static int __devinitpcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev){    struct pcnet32_private *lp;    dma_addr_t lp_dma_addr;    int i, media;    int fdx, mii, fset, dxsuflo;    int chip_version;    char *chipname;    struct net_device *dev;    struct pcnet32_access *a = NULL;    u8 promaddr[6];    int ret = -ENODEV;    /* reset the chip */    pcnet32_wio_reset(ioaddr);    /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */    if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) {	a = &pcnet32_wio;    } else {	pcnet32_dwio_reset(ioaddr);	if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {	    a = &pcnet32_dwio;	} else	    goto err_release_region;    }    chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16);    if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW))	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);    if ((chip_version & 0xfff) != 0x003) {	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_INFO PFX "Unsupported chip version.\n");	goto err_release_region;    }    /* initialize variables */    fdx = mii = fset = dxsuflo = 0;    chip_version = (chip_version >> 12) & 0xffff;    switch (chip_version) {    case 0x2420:	chipname = "PCnet/PCI 79C970"; /* PCI */	break;    case 0x2430:	if (shared)	    chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */	else	    chipname = "PCnet/32 79C965"; /* 486/VL bus */	break;    case 0x2621:	chipname = "PCnet/PCI II 79C970A"; /* PCI */	fdx = 1;	break;    case 0x2623:	chipname = "PCnet/FAST 79C971"; /* PCI */	fdx = 1; mii = 1; fset = 1;	break;    case 0x2624:	chipname = "PCnet/FAST+ 79C972"; /* PCI */	fdx = 1; mii = 1; fset = 1;	break;    case 0x2625:	chipname = "PCnet/FAST III 79C973"; /* PCI */	fdx = 1; mii = 1;	break;    case 0x2626:	chipname = "PCnet/Home 79C978"; /* PCI */	fdx = 1;	/*	 * This is based on specs published at www.amd.com.  This section	 * assumes that a card with a 79C978 wants to go into standard	 * ethernet mode.  The 79C978 can also go into 1Mb HomePNA mode,	 * and the module option homepna=1 can select this instead.	 */	media = a->read_bcr(ioaddr, 49);	media &= ~3;		/* default to 10Mb ethernet */	if (cards_found < MAX_UNITS && homepna[cards_found])	    media |= 1; 	/* switch to home wiring mode */	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", 		    (media & 1) ? "1" : "10");	a->write_bcr(ioaddr, 49, media);	break;    case 0x2627:	chipname = "PCnet/FAST III 79C975"; /* PCI */	fdx = 1; mii = 1;	break;    case 0x2628:	chipname = "PCnet/PRO 79C976";	fdx = 1; mii = 1;	break;    default:	if (pcnet32_debug & NETIF_MSG_PROBE)	    printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n",		    chip_version);	goto err_release_region;    }    /*     *	On selected chips turn on the BCR18:NOUFLO bit. This stops transmit     *	starting until the packet is loaded. Strike one for reliability, lose     *	one for latency - although on PCI this isnt a big loss. Older chips     *	have FIFO's smaller than a packet, so you can't do this.     *	Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.     */    if (fset) {	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860));	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);	dxsuflo = 1;    }	dev = alloc_etherdev(0);	if (!dev) {		if( pcnet32_debug & NETIF_MSG_PROBE )			printk(KERN_ERR PFX "Memory allocation failed.\n");		ret = -ENOMEM;		goto err_release_region;	}	strcpy( dev->name, "myeth0" );    SET_NETDEV_DEV(dev, &pdev->dev);	if (pcnet32_debug & NETIF_MSG_PROBE)		printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);    /* In most chips, after a chip reset, the ethernet address is read from the     * station address PROM at the base address and programmed into the     * "Physical Address Registers" CSR12-14.     * As a precautionary measure, we read the PROM values and complain if     * they disagree with the CSRs.  Either way, we use the CSR values, and     * double check that they are valid.     */    for (i = 0; i < 3; i++) {	unsigned int val;	val = a->read_csr(ioaddr, i+12) & 0x0ffff;	/* There may be endianness issues here. */	dev->dev_addr[2*i] = val & 0x0ff;	dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff;    }    /* read PROM address and compare with CSR address */    for (i = 0; i < 6; i++)	promaddr[i] = inb(ioaddr + i);    if (memcmp(promaddr, dev->dev_addr, 6)	|| !is_valid_ether_addr(dev->dev_addr)) {	if (is_valid_ether_addr(promaddr)) {	    if (pcnet32_debug & NETIF_MSG_PROBE) {		printk(" warning: CSR address invalid,\n");		printk(KERN_INFO "    using instead PROM address of");	    }	    memcpy(dev->dev_addr, promaddr, 6);	}    }    memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);    /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */    if (!is_valid_ether_addr(dev->perm_addr))	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));

⌨️ 快捷键说明

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