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

📄 pcnet_cs.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	break;    case CS_EVENT_CARD_INSERTION:	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;	pcnet_config(link);	break;    case CS_EVENT_PM_SUSPEND:	link->state |= DEV_SUSPEND;	/* Fall through... */    case CS_EVENT_RESET_PHYSICAL:	if (link->state & DEV_CONFIG) {	    if (link->open)		netif_device_detach(&info->dev);	    CardServices(ReleaseConfiguration, link->handle);	}	break;    case CS_EVENT_PM_RESUME:	link->state &= ~DEV_SUSPEND;	/* Fall through... */    case CS_EVENT_CARD_RESET:	if (link->state & DEV_CONFIG) {	    CardServices(RequestConfiguration, link->handle, &link->conf);	    if (link->open) {		pcnet_reset_8390(&info->dev);		NS8390_init(&info->dev, 1);		netif_device_attach(&info->dev);	    }	}	break;    }    return 0;} /* pcnet_event *//*======================================================================    MII interface support for DL10019 and DL10022 based cards    On the DL10019, the MII IO direction bit is 0x10; on the DL10022    it is 0x20.  Setting both bits seems to work on both card types.======================================================================*/#define DLINK_GPIO		0x1c#define DLINK_DIAG		0x1d#define DLINK_EEPROM		0x1e#define MDIO_SHIFT_CLK		0x80#define MDIO_DATA_OUT		0x40#define MDIO_DIR_WRITE		0x30#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)#define MDIO_DATA_READ		0x10#define MDIO_MASK		0x0fstatic void mdio_sync(ioaddr_t addr){    int bits, mask = inb(addr) & MDIO_MASK;    for (bits = 0; bits < 32; bits++) {	outb(mask | MDIO_DATA_WRITE1, addr);	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);    }}static int mdio_read(ioaddr_t addr, int phy_id, int loc){    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;    int i, retval = 0, mask = inb(addr) & MDIO_MASK;    mdio_sync(addr);    for (i = 13; i >= 0; i--) {	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;	outb(mask | dat, addr);	outb(mask | dat | MDIO_SHIFT_CLK, addr);    }    for (i = 19; i > 0; i--) {	outb(mask, addr);	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);	outb(mask | MDIO_SHIFT_CLK, addr);    }    return (retval>>1) & 0xffff;}static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value){    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;    int i, mask = inb(addr) & MDIO_MASK;    mdio_sync(addr);    for (i = 31; i >= 0; i--) {	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;	outb(mask | dat, addr);	outb(mask | dat | MDIO_SHIFT_CLK, addr);    }    for (i = 1; i >= 0; i--) {	outb(mask, addr);	outb(mask | MDIO_SHIFT_CLK, addr);    }}static void mdio_reset(ioaddr_t addr, int phy_id){    outb_p(0x08, addr);    outb_p(0x0c, addr);    outb_p(0x08, addr);    outb_p(0x0c, addr);    outb_p(0x00, addr);}/*======================================================================    EEPROM access routines for DL10019 and DL10022 based cards======================================================================*/#define EE_EEP		0x40#define EE_ASIC		0x10#define EE_CS		0x08#define EE_CK		0x04#define EE_DO		0x02#define EE_DI		0x01#define EE_ADOT		0x01	/* DataOut for ASIC */#define EE_READ_CMD	0x06	#define DL19FDUPLX	0x0400	/* DL10019 Full duplex mode */static int read_eeprom(ioaddr_t ioaddr, int location){    int i, retval = 0;    ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;    int read_cmd = location | (EE_READ_CMD << 8);    outb(0, ee_addr);    outb(EE_EEP|EE_CS, ee_addr);    /* Shift the read command bits out. */    for (i = 10; i >= 0; i--) {	short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;	outb_p(EE_EEP|EE_CS|dataval, ee_addr);	outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);    }    outb(EE_EEP|EE_CS, ee_addr);    for (i = 16; i > 0; i--) {	outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);	retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);	outb_p(EE_EEP|EE_CS, ee_addr);    }    /* Terminate the EEPROM access. */    outb(0, ee_addr);    return retval;}/*    The internal ASIC registers can be changed by EEPROM READ access    with EE_ASIC bit set.    In ASIC mode, EE_ADOT is used to output the data to the ASIC.*/ static void write_asic(ioaddr_t ioaddr, int location, short asic_data){	int i;	ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;	short dataval;	int read_cmd = location | (EE_READ_CMD << 8);	asic_data |= read_eeprom(ioaddr, location);	outb(0, ee_addr);	outb(EE_ASIC|EE_CS|EE_DI, ee_addr);		read_cmd = read_cmd >> 1;	/* Shift the read command bits out. */	for (i = 9; i >= 0; i--) {		dataval = (read_cmd & (1 << i)) ? EE_DO : 0;		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);		outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);	}	// sync	outb(EE_ASIC|EE_CS, ee_addr);	outb(EE_ASIC|EE_CS|EE_CK, ee_addr);	outb(EE_ASIC|EE_CS, ee_addr);	for (i = 15; i >= 0; i--) {		dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);		outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);	}	/* Terminate the ASIC access. */	outb(EE_ASIC|EE_DI, ee_addr);	outb(EE_ASIC|EE_DI| EE_CK, ee_addr);	outb(EE_ASIC|EE_DI, ee_addr);	outb(0, ee_addr);}/*====================================================================*/static void set_misc_reg(struct net_device *dev){    ioaddr_t nic_base = dev->base_addr;    pcnet_dev_t *info = (pcnet_dev_t *)dev;    u_char tmp;        if (info->flags & HAS_MISC_REG) {	tmp = inb_p(nic_base + PCNET_MISC) & ~3;	if (dev->if_port == 2)	    tmp |= 1;	if (info->flags & USE_BIG_BUF)	    tmp |= 2;	if (info->flags & HAS_IBM_MISC)	    tmp |= 8;	outb_p(tmp, nic_base + PCNET_MISC);    }    if (info->flags & IS_DL10022) {	if (info->flags & HAS_MII) {	    mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);	    /* Restart MII autonegotiation */	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);	    info->mii_reset = jiffies;	} else {	    outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG);	}    }}/*====================================================================*/static void mii_phy_probe(struct net_device *dev){    pcnet_dev_t *info = (pcnet_dev_t *)dev;	    ioaddr_t mii_addr = dev->base_addr + DLINK_GPIO;    int i;    u_int tmp, phyid;    for (i = 31; i >= 0; i--) {	tmp = mdio_read(mii_addr, i, 1);	if ((tmp == 0) || (tmp == 0xffff))	    continue;	tmp = mdio_read(mii_addr, i, MII_PHYID_REG1);	phyid = tmp << 16;	phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);	phyid &= MII_PHYID_REV_MASK;	DEBUG(0, "%s: MII at %d is 0x%08x\n", dev->name, i, phyid);	if (phyid == AM79C9XX_HOME_PHY) {	    info->pna_phy = i;	} else if (phyid != AM79C9XX_ETH_PHY) {	    info->eth_phy = i;	}    }}static int pcnet_open(struct net_device *dev){    pcnet_dev_t *info = (pcnet_dev_t *)dev;    dev_link_t *link = &info->link;        DEBUG(2, "pcnet_open('%s')\n", dev->name);    if (!DEV_OK(link))	return -ENODEV;    link->open++;    MOD_INC_USE_COUNT;    set_misc_reg(dev);    request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);    info->phy_id = info->eth_phy;    info->link_status = 0x00;    info->watchdog.function = &ei_watchdog;    info->watchdog.data = (u_long)info;    info->watchdog.expires = jiffies + HZ;    add_timer(&info->watchdog);    return ei_open(dev);} /* pcnet_open *//*====================================================================*/static int pcnet_close(struct net_device *dev){    pcnet_dev_t *info = (pcnet_dev_t *)dev;    dev_link_t *link = &info->link;    DEBUG(2, "pcnet_close('%s')\n", dev->name);    ei_close(dev);    free_irq(dev->irq, dev);        link->open--;    netif_stop_queue(dev);    del_timer(&info->watchdog);    if (link->state & DEV_STALE_CONFIG)	mod_timer(&link->release, jiffies + HZ/20);    MOD_DEC_USE_COUNT;    return 0;} /* pcnet_close *//*======================================================================    Hard reset the card.  This used to pause for the same period that    a 8390 reset command required, but that shouldn't be necessary.======================================================================*/static void pcnet_reset_8390(struct net_device *dev){    ioaddr_t nic_base = dev->base_addr;    int i;    ei_status.txing = ei_status.dmaing = 0;    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);    for (i = 0; i < 100; i++) {	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)	    break;	udelay(100);    }    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */        if (i == 100)	printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",	       dev->name);    set_misc_reg(dev);    } /* pcnet_reset_8390 *//*====================================================================*/static int set_config(struct net_device *dev, struct ifmap *map){    pcnet_dev_t *info = (pcnet_dev_t *)dev;    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {	if (!(info->flags & HAS_MISC_REG))	    return -EOPNOTSUPP;	else if ((map->port < 1) || (map->port > 2))	    return -EINVAL;	dev->if_port = map->port;	printk(KERN_INFO "%s: switched to %s port\n",	       dev->name, if_names[dev->if_port]);	NS8390_init(dev, 1);    }    return 0;}/*====================================================================*/static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs){    pcnet_dev_t *info = dev_id;    info->stale = 0;    ei_interrupt(irq, dev_id, regs);}static void ei_watchdog(u_long arg){    pcnet_dev_t *info = (pcnet_dev_t *)(arg);    struct net_device *dev = &info->dev;    ioaddr_t nic_base = dev->base_addr;    ioaddr_t mii_addr = nic_base + DLINK_GPIO;    u_short link;    if (!netif_device_present(dev)) goto reschedule;    /* Check for pending interrupt with expired latency timer: with       this, we can limp along even if the interrupt is blocked */    outb_p(E8390_NODMA+E8390_PAGE0, nic_base + E8390_CMD);    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {	if (!info->fast_poll)	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);	ei_irq_wrapper(dev->irq, dev, NULL);	info->fast_poll = HZ;    }    if (info->fast_poll) {	info->fast_poll--;	info->watchdog.expires = jiffies + 1;	add_timer(&info->watchdog);	return;    }    if (!(info->flags & HAS_MII))	goto reschedule;    mdio_read(mii_addr, info->phy_id, 1);    link = mdio_read(mii_addr, info->phy_id, 1);    if (!link || (link == 0xffff)) {	if (info->eth_phy) {	    info->phy_id = info->eth_phy = 0;	} else {	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);	    info->flags &= ~HAS_MII;	}	goto reschedule;    }    link &= 0x0004;    if (link != info->link_status) {	u_short p = mdio_read(mii_addr, info->phy_id, 5);	printk(KERN_INFO "%s: %s link beat\n", dev->name,	       (link) ? "found" : "lost");	if (link && (info->flags & IS_DL10022)) {	    /* Disable collision detection on full duplex links */	    outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);	} else if (link && (info->flags & IS_DL10019)) {	    /* Disable collision detection on full duplex links */	    write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);	}	if (link) {	    if (info->phy_id == info->eth_phy) {		if (p)		    printk(KERN_INFO "%s: autonegotiation complete: "			   "%sbaseT-%cD selected\n", dev->name,			   ((p & 0x0180) ? "100" : "10"),			   ((p & 0x0140) ? 'F' : 'H'));		else		    printk(KERN_INFO "%s: link partner did not "			   "autonegotiate\n", dev->name);	    }	    NS8390_init(dev, 1);	}	info->link_status = link;

⌨️ 快捷键说明

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