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

📄 smc91c92_cs.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");	link->state &= ~DEV_CONFIG_PENDING;	goto config_undo;    }    strcpy(smc->node.dev_name, dev->name);    link->dev = &smc->node;    link->state &= ~DEV_CONFIG_PENDING;    rev = check_sig(link);    name = "???";    if (rev > 0)	switch (rev >> 4) {	case 3: name = "92"; break;	case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;	case 5: name = "95"; break;	case 7: name = "100"; break;	case 8: name = "100-FD"; break;	case 9: name = "110"; break;	}    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,	   dev->irq);    for (i = 0; i < 6; i++)	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));    if (rev > 0) {	u_long mir, mcr;	ioaddr_t ioaddr = dev->base_addr;	SMC_SELECT_BANK(0);	mir = inw(ioaddr + MEMINFO) & 0xff;	if (mir == 0xff) mir++;	/* Get scale factor for memory size */	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;	mir *= 128 * (1<<((mcr >> 9) & 7));	if (mir & 0x3ff)	    printk(KERN_INFO "  %lu byte", mir);	else	    printk(KERN_INFO "  %lu kb", mir>>10);	SMC_SELECT_BANK(1);	smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;	smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;	if (smc->manfid == MANFID_OSITECH)	    smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;	if ((rev >> 4) >= 7)	    smc->cfg |= CFG_MII_SELECT;	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?	       "MII" : if_names[dev->if_port]);    }        return;    config_undo:    unregister_netdev(dev);config_failed:			/* CS_EXIT_TEST() calls jump to here... */    smc91c92_release((u_long)link);    } /* smc91c92_config *//*======================================================================    After a card is removed, smc91c92_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 smc91c92_release(u_long arg){    dev_link_t *link = (dev_link_t *)arg;    struct smc_private *smc = link->priv;    DEBUG(0, "smc91c92_release(0x%p)\n", link);        if (link->open) {	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",	      link->dev->dev_name);	link->state |= DEV_STALE_CONFIG;	return;    }        CardServices(ReleaseConfiguration, link->handle);    CardServices(ReleaseIO, link->handle, &link->io);    CardServices(ReleaseIRQ, link->handle, &link->irq);    if (link->win) {	iounmap(smc->base);	CardServices(ReleaseWindow, link->win);    }        link->state &= ~DEV_CONFIG;} /* smc91c92_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 smc91c92_event(event_t event, int priority,			  event_callback_args_t *args){    dev_link_t *link = args->client_data;    struct smc_private *smc = link->priv;    struct net_device *dev = &smc->dev;        DEBUG(1, "smc91c92_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);	    mod_timer(&link->release, jiffies + HZ/20);	}	break;    case CS_EVENT_CARD_INSERTION:	link->state |= DEV_PRESENT;	smc91c92_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);	    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) {	    if ((smc->manfid == MANFID_MEGAHERTZ) &&		(smc->cardid == PRODID_MEGAHERTZ_EM3288))		mhz_3288_power(link);	    CardServices(RequestConfiguration, link->handle, &link->conf);	    if (smc->manfid == MANFID_MOTOROLA)		mot_config(link);	    if ((smc->manfid == MANFID_OSITECH) &&		(smc->cardid != PRODID_OSITECH_SEVEN)) {		/* Power up the card and enable interrupts */		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);	    }	    if (link->open) {		smc_reset(dev);		netif_device_attach(dev);	    }	}	break;    }    return 0;} /* smc91c92_event *//*======================================================================      The driver core code, most of which should be common with a    non-PCMCIA implementation.    ======================================================================*/#ifdef PCMCIA_DEBUGstatic void smc_dump(struct net_device *dev){    ioaddr_t ioaddr = dev->base_addr;    u_short i, w, save;    save = inw(ioaddr + BANK_SELECT);    for (w = 0; w < 4; w++) {	SMC_SELECT_BANK(w);	printk(KERN_DEBUG "bank %d: ", w);	for (i = 0; i < 14; i += 2)	    printk(" %04x", inw(ioaddr + i));	printk("\n");    }    outw(save, ioaddr + BANK_SELECT);}#endifstatic int smc91c92_open(struct net_device *dev){    struct smc_private *smc = dev->priv;    dev_link_t *link = &smc->link;#ifdef PCMCIA_DEBUG    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));    if (pc_debug > 1) smc_dump(dev);#endif        /* Check that the PCMCIA card is still here. */    if (!DEV_OK(link))	return -ENODEV;    /* Physical device present signature. */    if (check_sig(link) < 0) {	printk("smc91c92_cs: Yikes!  Bad chip signature!\n");	return -ENODEV;    }    link->open++;    MOD_INC_USE_COUNT;    netif_start_queue(dev);    smc->saved_skb = 0;    smc->packets_waiting = 0;        smc_reset(dev);    smc->media.function = &media_check;    smc->media.data = (u_long)smc;    smc->media.expires = jiffies + HZ;    add_timer(&smc->media);        return 0;} /* smc91c92_open *//*====================================================================*/static int smc91c92_close(struct net_device *dev){    struct smc_private *smc = dev->priv;    dev_link_t *link = &smc->link;    ioaddr_t ioaddr = dev->base_addr;    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",	  dev->name, inw(ioaddr + BANK_SELECT));    netif_stop_queue(dev);    /* Shut off all interrupts, and turn off the Tx and Rx sections.       Don't bother to check for chip present. */    SMC_SELECT_BANK(2);	/* Nominally paranoia, but do no assume... */    outw(0, ioaddr + INTERRUPT);    SMC_SELECT_BANK(0);    mask_bits(0xff00, ioaddr + RCR);    mask_bits(0xff00, ioaddr + TCR);        /* Put the chip into power-down mode. */    SMC_SELECT_BANK(1);    outw(CTL_POWERDOWN, ioaddr + CONTROL );        link->open--;    del_timer(&smc->media);    if (link->state & DEV_STALE_CONFIG)	mod_timer(&link->release, jiffies + HZ/20);        MOD_DEC_USE_COUNT;        return 0;} /* smc91c92_close *//*======================================================================   Transfer a packet to the hardware and trigger the packet send.   This may be called at either from either the Tx queue code   or the interrupt handler.   ======================================================================*/static void smc_hardware_send_packet(struct net_device * dev){    struct smc_private *smc = dev->priv;    struct sk_buff *skb = smc->saved_skb;    ioaddr_t ioaddr = dev->base_addr;    u_char packet_no;        if (!skb) {	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);	return;    }        /* There should be a packet slot waiting. */    packet_no = inw(ioaddr + PNR_ARR) >> 8;    if (packet_no & 0x80) {	/* If not, there is a hardware problem!  Likely an ejected card. */	printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"	       " failed, status %#2.2x.\n", dev->name, packet_no);	dev_kfree_skb_irq(skb);	smc->saved_skb = NULL;	netif_start_queue(dev);	return;    }    smc->stats.tx_bytes += skb->len;    /* The card should use the just-allocated buffer. */    outw(packet_no, ioaddr + PNR_ARR);    /* point to the beginning of the packet */    outw(PTR_AUTOINC , ioaddr + POINTER);        /* Send the packet length (+6 for status, length and ctl byte)       and the status word (set to zeros). */    {	u_char *buf = skb->data;	u_int length = skb->len; /* The chip will pad to ethernet min. */	DEBUG(2, "%s: Trying to xmit packet of length %d.\n",	      dev->name, length);		/* send the packet length: +6 for status word, length, and ctl */	outw(0, ioaddr + DATA_1);	outw(length + 6, ioaddr + DATA_1);	outsw(ioaddr + DATA_1, buf, length >> 1);		/* The odd last byte, if there is one, goes in the control word. */	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);    }        /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |	 (inw(ioaddr + INTERRUPT) & 0xff00),	 ioaddr + INTERRUPT);        /* The chip does the rest of the work. */    outw(MC_ENQUEUE , ioaddr + MMU_CMD);        smc->saved_skb = NULL;    dev_kfree_skb_irq(skb);    dev->trans_start = jiffies;    netif_start_queue(dev);    return;}/*====================================================================*/static void smc_tx_timeout(struct net_device *dev){    struct smc_private *smc = dev->priv;    ioaddr_t ioaddr = dev->base_addr;    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "	   "Tx_status %2.2x status %4.4x.\n",	   dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));    smc->stats.tx_errors++;    smc_reset(dev);    dev->trans_start = jiffies;    smc->saved_skb = NULL;    netif_start_queue(dev);}static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev){    struct smc_private *smc = dev->priv;    ioaddr_t ioaddr = dev->base_addr;    u_short num_pages;    short time_out, ir;    netif_stop_queue(dev);    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));        if (smc->saved_skb) {	/* THIS SHOULD NEVER HAPPEN. */	smc->stats.tx_aborted_errors++;	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",	       dev->name);	return 1;    }    smc->saved_skb = skb;        num_pages = skb->len >> 8;        if (num_pages > 7) {	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);	dev_kfree_skb (skb);	smc->saved_skb = NULL;	smc->stats.tx_dropped++;	return 0;		/* Do not re-queue this packet. */    }    /* A packet is now waiting. */    smc->packets_waiting++;        SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */        /* Allocate the memory; send the packet now if we win. */    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {	ir = inw(ioaddr+INTERRUPT);	if (ir & IM_ALLOC_INT) {	    /* Acknowledge the interrupt, send the packet. */	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);	    smc_hardware_send_packet(dev);	/* Send the packet now.. */	    return 0;	}    }        /* Otherwise defer until the Tx-space-allocated interrupt. */    DEBUG(2, "%s: memory allocation deferred.\n", dev->name);    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);        return 0;}/*======================================================================    Handle a Tx anomolous event.  Entered while in Window 2.    ======================================================================*/static void smc_tx_err(struct net_device * dev){    struct smc_private *smc = (struct smc_private *)dev->priv;    ioaddr_t ioaddr = dev->base_addr;    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;    int tx_status;        /* select this as the packet to read from */    outw(packet_no, ioaddr + PNR_ARR);        /* read the first word from this packet */    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);        tx_status = inw(ioaddr + DATA_1);    smc->stats.tx_errors++;    if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;    if (tx_status & TS_LATCOL)  smc->stats.tx_window_errors++;    if (tx_status & TS_16COL) {	smc->stats.tx_aborted_errors++;	smc->tx_err++;    }        if (tx_status & TS_SUCCESS) {	printk(KERN_NOTICE "%s: Successful packet caused error "	       "interrupt?\n", dev->name);    }    /* re-enable transmit */    SMC_SELECT_BANK(0);    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);    SMC_SELECT_BANK(2);        outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */        /* one less packet waiting for me */    smc->packets_waiting--;        outw(saved_packet, ioaddr + PNR_ARR);    return;}/*====================================================================*/static void smc_eph_irq(struct net_device *dev){    struct smc_private *smc = dev->priv;    ioaddr_t ioaddr = dev->base_addr;    u_short card_stats, ephs;        SMC_SELECT_BANK(0);    ephs = inw(ioaddr + EPH);    DEBUG(2, "%s: Ethernet protocol handler interrupt, status"	  " %4.4x.\n", dev->name, ephs);    /* Could be a counter roll-over warning: update stats. */    card_stats = inw(ioaddr + COUNTER);    /* single collisions */    smc->stats.collisions += card_stats & 0xF;    card_stats >>= 4;    /* multiple collisions */    smc->stats.collisions += card_stats & 0xF;#if 0 		/* These are for when linux supports these statistics */    card_stats >>= 4;			/* deferred */    card_stats >>= 4;			/* excess deferred */#endif    /* If we had a transmit error we must re-enable the transmitter. */    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);    /* Clear a link error interrupt. */    SMC_SELECT_BANK(1);    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,	 ioaddr + CONTROL);    SMC_SELECT_BANK(2);}/*====================================================================*/    static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs){    struct smc_private *smc = dev_id;    struct net_device *dev = &smc->dev;    ioaddr_t ioaddr;    u_short saved_bank, saved_pointer, mask, status;    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */    if (!netif_device_present(dev))	return;    ioaddr = dev->base_addr;

⌨️ 快捷键说明

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