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

📄 pcnet_cs.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	printk(" %s xcvr,", if_names[dev->if_port]);    printk(" hw_addr ");    for (i = 0; i < 6; i++)	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));    return;cs_failed:    cs_error(link->handle, last_fn, last_ret);failed:    pcnet_release(link);    link->state &= ~DEV_CONFIG_PENDING;    return;} /* pcnet_config *//*======================================================================    After a card is removed, pcnet_release() will unregister the net    device, and release the PCMCIA configuration.  If the device is    still open, this will be postponed until it is closed.======================================================================*/static void pcnet_release(dev_link_t *link){    pcnet_dev_t *info = PRIV(link->priv);    DEBUG(0, "pcnet_release(0x%p)\n", link);    if (info->flags & USE_SHMEM) {	iounmap(info->base);	pcmcia_release_window(link->win);    }    pcmcia_release_configuration(link->handle);    pcmcia_release_io(link->handle, &link->io);    pcmcia_release_irq(link->handle, &link->irq);    link->state &= ~DEV_CONFIG;}/*======================================================================    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;    struct net_device *dev = 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(dev);	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(dev);	    pcmcia_release_configuration(link->handle);	}	break;    case CS_EVENT_PM_RESUME:	link->state &= ~DEV_SUSPEND;	/* Fall through... */    case CS_EVENT_CARD_RESET:	if (link->state & DEV_CONFIG) {	    pcmcia_request_configuration(link->handle, &link->conf);	    if (link->open) {		pcnet_reset_8390(dev);		NS8390_init(dev, 1);		netif_device_attach(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(kio_addr_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(kio_addr_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(kio_addr_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(kio_addr_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(kio_addr_t ioaddr, int location){    int i, retval = 0;    kio_addr_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(kio_addr_t ioaddr, int location, short asic_data){	int i;	kio_addr_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){    kio_addr_t nic_base = dev->base_addr;    pcnet_dev_t *info = PRIV(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);	}    } else if (info->flags & IS_DL10019) {	/* Advertise 100F, 100H, 10F, 10H */	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);	/* 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);    }}/*====================================================================*/static void mii_phy_probe(struct net_device *dev){    pcnet_dev_t *info = PRIV(dev);    kio_addr_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 = PRIV(dev);    dev_link_t *link = &info->link;        DEBUG(2, "pcnet_open('%s')\n", dev->name);    if (!DEV_OK(link))	return -ENODEV;    link->open++;    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;    init_timer(&info->watchdog);    info->watchdog.function = &ei_watchdog;    info->watchdog.data = (u_long)dev;    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 = PRIV(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_sync(&info->watchdog);    return 0;} /* pcnet_close */

⌨️ 快捷键说明

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