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

📄 pcnet_cs.c

📁 ARM S3C2410 linux2.4 内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
static void pcnet_release(u_long arg){    dev_link_t *link = (dev_link_t *)arg;    pcnet_dev_t *info = link->priv;    DEBUG(0, "pcnet_release(0x%p)\n", link);    if (link->open) {	DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n",	      info->node.dev_name);	link->state |= DEV_STALE_CONFIG;	return;    }    if (info->flags & USE_SHMEM) {	iounmap(info->base);	CardServices(ReleaseWindow, link->win);    }    CardServices(ReleaseConfiguration, link->handle);    CardServices(ReleaseIO, link->handle, &link->io);    CardServices(ReleaseIRQ, link->handle, &link->irq);    link->state &= ~DEV_CONFIG;} /* pcnet_release *//*======================================================================    The card status event handler.  Mostly, this schedules other    stuff to run after an event is received.  A CARD_REMOVAL event    also sets some flags to discourage the net drivers from trying    to talk to the card any more.======================================================================*/static int pcnet_event(event_t event, int priority,		       event_callback_args_t *args){    dev_link_t *link = args->client_data;    pcnet_dev_t *info = link->priv;    DEBUG(2, "pcnet_event(0x%06x)\n", event);    switch (event) {    case CS_EVENT_CARD_REMOVAL:	link->state &= ~DEV_PRESENT;	if (link->state & DEV_CONFIG) {	    netif_device_detach(&info->dev);	    mod_timer(&link->release, jiffies + HZ/20);	}	break;    case CS_EVENT_CARD_INSERTION:	link->state |= DEV_PRESENT;	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 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);}/*====================================================================*/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);    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);	}	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;    }    if (info->pna_phy && (jiffies - info->mii_reset > 6*HZ)) {	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;	if (((info->phy_id == info->pna_phy) && link) ||	    ((info->phy_id != info->pna_phy) && !link)) {	    /* isolate this MII and try flipping to the other one */	    mdio_write(mii_addr, info->phy_id, 0, 0x0400);	    info->phy_id ^= info->pna_phy ^ info->eth_phy;	    printk(KERN_INFO "%s: switched to %s transceiver\n", dev->name,		   (info->phy_id == info->eth_phy) ? "ethernet" : "PNA");	    mdio_write(mii_addr, info->phy_id, 0,		       (info->phy_id == info->eth_phy) ? 0x1000 : 0);	    info->link_status = 0;	    info->mii_reset = jiffies;	}    }

⌨️ 快捷键说明

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