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

📄 smc91c92_cs.c

📁 pcmcia驱动源代码,直接可以在linux2.6下使用 !
💻 C
📖 第 1 页 / 共 5 页
字号:
/*======================================================================    Reset the chip, reloading every register that might be corrupted.======================================================================*//*  Set transceiver type, perhaps to something other than what the user  specified in dev->if_port.*/static void smc_set_xcvr(struct net_device *dev, int if_port){    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    u_short saved_bank;    saved_bank = inw(ioaddr + BANK_SELECT);    SMC_SELECT_BANK(1);    if (if_port == 2) {	outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);	if ((smc->manfid == MANFID_OSITECH) &&	    (smc->cardid != PRODID_OSITECH_SEVEN))	    set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);	smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);    } else {	outw(smc->cfg, ioaddr + CONFIG);	if ((smc->manfid == MANFID_OSITECH) &&	    (smc->cardid != PRODID_OSITECH_SEVEN))	    mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);	smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);    }    SMC_SELECT_BANK(saved_bank);}static void smc_reset(struct net_device *dev){    kio_addr_t ioaddr = dev->base_addr;    struct smc_private *smc = netdev_priv(dev);    int i;    DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);    /* The first interaction must be a write to bring the chip out       of sleep mode. */    SMC_SELECT_BANK(0);    /* Reset the chip. */    outw(RCR_SOFTRESET, ioaddr + RCR);    udelay(10);    /* Clear the transmit and receive configuration registers. */    outw(RCR_CLEAR, ioaddr + RCR);    outw(TCR_CLEAR, ioaddr + TCR);    /* Set the Window 1 control, configuration and station addr registers.       No point in writing the I/O base register ;-> */    SMC_SELECT_BANK(1);    /* Automatically release successfully transmitted packets,       Accept link errors, counter and Tx error interrupts. */    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,	 ioaddr + CONTROL);    smc_set_xcvr(dev, dev->if_port);    if ((smc->manfid == MANFID_OSITECH) &&	(smc->cardid != PRODID_OSITECH_SEVEN))	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),	     ioaddr - 0x10 + OSITECH_AUI_PWR);    /* Fill in the physical address.  The databook is wrong about the order! */    for (i = 0; i < 6; i += 2)	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],	     ioaddr + ADDR0 + i);    /* Reset the MMU */    SMC_SELECT_BANK(2);    outw(MC_RESET, ioaddr + MMU_CMD);    outw(0, ioaddr + INTERRUPT);    /* Re-enable the chip. */    SMC_SELECT_BANK(0);    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);    set_rx_mode(dev);    if (smc->cfg & CFG_MII_SELECT) {	SMC_SELECT_BANK(3);	/* Reset MII */	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);	/* Advertise 100F, 100H, 10F, 10H */	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);	/* Restart MII autonegotiation */	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);    }    /* Enable interrupts. */    SMC_SELECT_BANK(2);    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,	 ioaddr + INTERRUPT);}/*======================================================================    Media selection timer routine======================================================================*/static void media_check(u_long arg){    struct net_device *dev = (struct net_device *) arg;    struct smc_private *smc = netdev_priv(dev);    kio_addr_t ioaddr = dev->base_addr;    u_short i, media, saved_bank;    u_short link;    saved_bank = inw(ioaddr + BANK_SELECT);    if (!netif_device_present(dev))	goto reschedule;    SMC_SELECT_BANK(2);    /* need MC_RESET to keep the memory consistent. errata? */    if (smc->rx_ovrn) {	outw(MC_RESET, ioaddr + MMU_CMD);	smc->rx_ovrn = 0;    }    i = inw(ioaddr + INTERRUPT);    SMC_SELECT_BANK(0);    media = inw(ioaddr + EPH) & EPH_LINK_OK;    SMC_SELECT_BANK(1);    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;    /* Check for pending interrupt with watchdog flag set: with       this, we can limp along even if the interrupt is blocked */    if (smc->watchdog++ && ((i>>8) & i)) {	if (!smc->fast_poll)	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);	smc_interrupt(dev->irq, dev);	smc->fast_poll = HZ;    }    if (smc->fast_poll) {	smc->fast_poll--;	smc->media.expires = jiffies + HZ/100;	add_timer(&smc->media);	SMC_SELECT_BANK(saved_bank);	return;    }    if (smc->cfg & CFG_MII_SELECT) {	if (smc->mii_if.phy_id < 0)	    goto reschedule;	SMC_SELECT_BANK(3);	link = mdio_read(dev, smc->mii_if.phy_id, 1);	if (!link || (link == 0xffff)) {  	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);	    smc->mii_if.phy_id = -1;	    goto reschedule;	}	link &= 0x0004;	if (link != smc->link_status) {	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);	    printk(KERN_INFO "%s: %s link beat\n", dev->name,		(link) ? "found" : "lost");	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))			   ? TCR_FDUPLX : 0);	    if (link) {	        printk(KERN_INFO "%s: autonegotiation complete: "		       "%sbaseT-%cD selected\n", dev->name,		       ((p & 0x0180) ? "100" : "10"),		       (smc->duplex ? 'F' : 'H'));	    }	    SMC_SELECT_BANK(0);	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);	    smc->link_status = link;	}	goto reschedule;    }    /* Ignore collisions unless we've had no rx's recently */    if (time_after(jiffies, dev->last_rx + HZ)) {	if (smc->tx_err || (smc->media_status & EPH_16COL))	    media |= EPH_16COL;    }    smc->tx_err = 0;    if (media != smc->media_status) {	if ((media & smc->media_status & 1) &&	    ((smc->media_status ^ media) & EPH_LINK_OK))	    printk(KERN_INFO "%s: %s link beat\n", dev->name,		   (smc->media_status & EPH_LINK_OK ? "lost" : "found"));	else if ((media & smc->media_status & 2) &&		 ((smc->media_status ^ media) & EPH_16COL))	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,		   (media & EPH_16COL ? "problem" : "ok"));	if (dev->if_port == 0) {	    if (media & 1) {		if (media & EPH_LINK_OK)		    printk(KERN_INFO "%s: flipped to 10baseT\n",			   dev->name);		else		    smc_set_xcvr(dev, 2);	    } else {		if (media & EPH_16COL)		    smc_set_xcvr(dev, 1);		else		    printk(KERN_INFO "%s: flipped to 10base2\n",			   dev->name);	    }	}	smc->media_status = media;    }reschedule:    smc->media.expires = jiffies + HZ;    add_timer(&smc->media);    SMC_SELECT_BANK(saved_bank);}static int smc_link_ok(struct net_device *dev){    kio_addr_t ioaddr = dev->base_addr;    struct smc_private *smc = netdev_priv(dev);    if (smc->cfg & CFG_MII_SELECT) {	return mii_link_ok(&smc->mii_if);    } else {        SMC_SELECT_BANK(0);	return inw(ioaddr + EPH) & EPH_LINK_OK;    }}static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){    u16 tmp;    kio_addr_t ioaddr = dev->base_addr;    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);		    SMC_SELECT_BANK(1);    tmp = inw(ioaddr + CONFIG);    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;    ecmd->transceiver = XCVR_INTERNAL;    ecmd->speed = SPEED_10;    ecmd->phy_address = ioaddr + MGMT;    SMC_SELECT_BANK(0);    tmp = inw(ioaddr + TCR);    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;    return 0;}static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){    u16 tmp;    kio_addr_t ioaddr = dev->base_addr;    if (ecmd->speed != SPEED_10)    	return -EINVAL;    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)    	return -EINVAL;    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)	return -EINVAL;    if (ecmd->transceiver != XCVR_INTERNAL)    	return -EINVAL;    if (ecmd->port == PORT_AUI)	smc_set_xcvr(dev, 1);    else	smc_set_xcvr(dev, 0);    SMC_SELECT_BANK(0);    tmp = inw(ioaddr + TCR);    if (ecmd->duplex == DUPLEX_FULL)	tmp |= TCR_FDUPLX;    else	tmp &= ~TCR_FDUPLX;    outw(tmp, ioaddr + TCR);	    return 0;}static int check_if_running(struct net_device *dev){	if (!netif_running(dev))		return -EINVAL;	return 0;}static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);}static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct smc_private *smc = netdev_priv(dev);	kio_addr_t ioaddr = dev->base_addr;	u16 saved_bank = inw(ioaddr + BANK_SELECT);	int ret;	SMC_SELECT_BANK(3);	spin_lock_irq(&smc->lock);	if (smc->cfg & CFG_MII_SELECT)		ret = mii_ethtool_gset(&smc->mii_if, ecmd);	else		ret = smc_netdev_get_ecmd(dev, ecmd);	spin_unlock_irq(&smc->lock);	SMC_SELECT_BANK(saved_bank);	return ret;}static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct smc_private *smc = netdev_priv(dev);	kio_addr_t ioaddr = dev->base_addr;	u16 saved_bank = inw(ioaddr + BANK_SELECT);	int ret;	SMC_SELECT_BANK(3);	spin_lock_irq(&smc->lock);	if (smc->cfg & CFG_MII_SELECT)		ret = mii_ethtool_sset(&smc->mii_if, ecmd);	else		ret = smc_netdev_set_ecmd(dev, ecmd);	spin_unlock_irq(&smc->lock);	SMC_SELECT_BANK(saved_bank);	return ret;}static u32 smc_get_link(struct net_device *dev){	struct smc_private *smc = netdev_priv(dev);	kio_addr_t ioaddr = dev->base_addr;	u16 saved_bank = inw(ioaddr + BANK_SELECT);	u32 ret;	SMC_SELECT_BANK(3);	spin_lock_irq(&smc->lock);	ret = smc_link_ok(dev);	spin_unlock_irq(&smc->lock);	SMC_SELECT_BANK(saved_bank);	return ret;}#ifdef PCMCIA_DEBUGstatic u32 smc_get_msglevel(struct net_device *dev){	return pc_debug;}static void smc_set_msglevel(struct net_device *dev, u32 val){	pc_debug = val;}#endifstatic int smc_nway_reset(struct net_device *dev){	struct smc_private *smc = netdev_priv(dev);	if (smc->cfg & CFG_MII_SELECT) {		kio_addr_t ioaddr = dev->base_addr;		u16 saved_bank = inw(ioaddr + BANK_SELECT);		int res;		SMC_SELECT_BANK(3);		res = mii_nway_restart(&smc->mii_if);		SMC_SELECT_BANK(saved_bank);		return res;	} else		return -EOPNOTSUPP;}static const struct ethtool_ops ethtool_ops = {	.begin = check_if_running,	.get_drvinfo = smc_get_drvinfo,	.get_settings = smc_get_settings,	.set_settings = smc_set_settings,	.get_link = smc_get_link,#ifdef PCMCIA_DEBUG	.get_msglevel = smc_get_msglevel,	.set_msglevel = smc_set_msglevel,#endif	.nway_reset = smc_nway_reset,};static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){	struct smc_private *smc = netdev_priv(dev);	struct mii_ioctl_data *mii = if_mii(rq);	int rc = 0;	u16 saved_bank;	kio_addr_t ioaddr = dev->base_addr;	if (!netif_running(dev))		return -EINVAL;	spin_lock_irq(&smc->lock);	saved_bank = inw(ioaddr + BANK_SELECT);	SMC_SELECT_BANK(3);	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);	SMC_SELECT_BANK(saved_bank);	spin_unlock_irq(&smc->lock);	return rc;}static struct pcmcia_device_id smc91c92_ids[] = {	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),	PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),	PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),	PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),	PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),	PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),	PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),	PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),	PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),	PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),	/* These conflict with other cards! */	/* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */	/* PCM

⌨️ 快捷键说明

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