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

📄 ether1.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	    printk(KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,		    status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));#endif	}    }    if (failures)	ether1_reset(dev);    return failures ? 1 : 0;}static intether1_probe1(struct device *dev){    static unsigned int version_printed = 0;    struct ether1_priv *priv;    int i;    if (!dev->priv)	dev->priv = kmalloc(sizeof (struct ether1_priv), GFP_KERNEL);    if (!dev->priv)    	return 1;    priv = (struct ether1_priv *)dev->priv;    memset(priv, 0, sizeof (struct ether1_priv));    if ((priv->bus_type = ether1_reset(dev)) == 0) {	kfree(dev->priv);	return 1;    }    if (net_debug && version_printed++ == 0)	printk(KERN_INFO "%s", version);    printk(KERN_INFO "%s: ether1 found at %08lX, IRQ%d, ether address", dev->name,		dev->base_addr, dev->irq);    request_region(dev->base_addr, 16, "ether1");    request_region(dev->base_addr + 0x800, 4096, "ether1(ram)");    for (i = 0; i < 6; i++)	printk(i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]);    if (ether1_init_2(dev)) {	kfree(dev->priv);	return 1;    }    dev->open		    = ether1_open;    dev->stop		    = ether1_close;    dev->hard_start_xmit    = ether1_sendpacket;    dev->get_stats	    = ether1_getstats;    dev->set_multicast_list = ether1_setmulticastlist;    /* Fill in the fields of the device structure with ethernet values */    ether_setup(dev);    return 0;}	    /* ------------------------------------------------------------------------- */static voidether1_addr(struct device *dev){    int i;        for (i = 0; i < 6; i++)	dev->dev_addr[i] = inb(IDPROM_ADDRESS + i);}intether1_probe(struct device *dev){#ifndef MODULE    struct expansion_card *ec;    if (!dev)	return ENODEV;    ecard_startfind();    if ((ec = ecard_find(0, ether1_cids)) == NULL)	return ENODEV;    dev->base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST);    dev->irq       = ec->irq;    ecard_claim(ec);#endif    ether1_addr(dev);    if (ether1_probe1(dev) == 0)	return 0;    return ENODEV;}/* ------------------------------------------------------------------------- */static intether1_txalloc(struct device *dev, int size){    FUNC_PROLOGUE;    int start, tail;    size = (size + 1) & ~1;    tail = priv->tx_tail;    if (priv->tx_head + size > TX_AREA_END) {	if (tail > priv->tx_head)	    return -1;	start = TX_AREA_START;	if (start + size > tail)	    return -1;	priv->tx_head = start + size;    } else {	if (priv->tx_head < tail && (priv->tx_head + size) > tail)	    return -1;	start = priv->tx_head;	priv->tx_head += size;    }    return start;}static voidether1_restart(struct device *dev, char *reason){    FUNC_PROLOGUE;    priv->stats.tx_errors ++;    if (reason)	printk(KERN_WARNING "%s: %s - resetting device\n", dev->name, reason);    else	printk(" - resetting device\n");    ether1_reset(dev);    dev->start = 0;    dev->tbusy = 0;    if (ether1_init_for_open(dev))	printk(KERN_ERR "%s: unable to restart interface\n", dev->name);    dev->start = 1;}static intether1_sendpacket(struct sk_buff *skb, struct device *dev){    FUNC_PROLOGUE;    if (priv->restart)	ether1_restart(dev, NULL);    if (dev->tbusy) {	/*	 * If we get here, some higher level has decided that we are broken.	 * There should really be a "kick me" function call instead.	 */	int tickssofar = jiffies - dev->trans_start;	if (tickssofar < 5)	    return 1;	/* Try to restart the adapter. */	ether1_restart(dev, "transmit timeout, network cable problem?");	dev->trans_start = jiffies;    }    /*     * If some higher layer thinks we've missed a tx-done interrupt     * we are passed NULL.  Caution: dev_tint() handles the cli()/sti()     * itself.     */    if (skb == NULL) {	dev_tint(dev);	return 0;    }    /*     * Block a timer-based transmit from overlapping.  This could better be     * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.     */    if (set_bit(0, (void *)&dev->tbusy) != 0)	printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);    else {	int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;	unsigned long flags;	tx_t tx;	tbd_t tbd;	nop_t nop;	/*	 * insert packet followed by a nop	 */	txaddr = ether1_txalloc(dev, TX_SIZE);	tbdaddr = ether1_txalloc(dev, TBD_SIZE);	dataddr = ether1_txalloc(dev, len);	nopaddr = ether1_txalloc(dev, NOP_SIZE);	tx.hdr.status = 0;	tx.hdr.command = CMD_TX | CMD_INTR;	tx.tx_link = nopaddr;	tx.tx_tbdoffset = tbdaddr;	tbd.tbd_opts = TBD_EOL | len;	tbd.tbd_link = I82586_NULL;	tbd.tbd_bufl = dataddr;	tbd.tbd_bufh = 0;	nop.hdr.status = 0;	nop.hdr.command = CMD_NOP;	nop.nop_link = nopaddr;	save_flags_cli(flags);	ether1_writebuffer(dev, &tx, txaddr, TX_SIZE);	ether1_writebuffer(dev, &tbd, tbdaddr, TBD_SIZE);	ether1_writebuffer(dev, skb->data, dataddr, len);	ether1_writebuffer(dev, &nop, nopaddr, NOP_SIZE);	tmp = priv->tx_link;	priv->tx_link = nopaddr;	/* now reset the previous nop pointer */	ether1_outw(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);	restore_flags(flags);	/* handle transmit */	dev->trans_start = jiffies;	/* check to see if we have room for a full sized ether frame */	tmp = priv->tx_head;	tst = ether1_txalloc(dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);	priv->tx_head = tmp;	if (tst != -1)	    dev->tbusy = 0;    }    dev_kfree_skb(skb, FREE_WRITE);    return 0;}static voidether1_xmit_done(struct device *dev){    FUNC_PROLOGUE;    nop_t nop;    int caddr, tst;    caddr = priv->tx_tail;again:    ether1_readbuffer(dev, &nop, caddr, NOP_SIZE);    switch (nop.hdr.command & CMD_MASK) {    case CMD_TDR:	/* special case */	if (ether1_inw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)				!= (unsigned short)I82586_NULL) {	    ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,		scb_command, NORMALIRQS);	    outb(CTRL_CA, REG_CONTROL);	}	priv->tx_tail = NOP_ADDR;	return;    case CMD_NOP:	if (nop.nop_link == caddr) {	    if (priv->initialising == 0)		printk(KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);	    else	        priv->initialising = 0;	    return;	}	if (caddr == nop.nop_link)		return;	caddr = nop.nop_link;	goto again;    case CMD_TX:	if (nop.hdr.status & STAT_COMPLETE)	    break;	printk(KERN_ERR "%s: strange command complete without completed command\n", dev->name);	priv->restart = 1;	return;    default:	printk(KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,		nop.hdr.command & CMD_MASK, caddr);	priv->restart = 1;	return;    }    while (nop.hdr.status & STAT_COMPLETE) {	if (nop.hdr.status & STAT_OK) {	    priv->stats.tx_packets ++;	    priv->stats.collisions += (nop.hdr.status & STAT_COLLISIONS);	} else {	    priv->stats.tx_errors ++;	    if (nop.hdr.status & STAT_COLLAFTERTX)		priv->stats.collisions ++;	    if (nop.hdr.status & STAT_NOCARRIER)		priv->stats.tx_carrier_errors ++;	    if (nop.hdr.status & STAT_TXLOSTCTS)		printk(KERN_WARNING "%s: cts lost\n", dev->name);	    if (nop.hdr.status & STAT_TXSLOWDMA)		priv->stats.tx_fifo_errors ++;	    if (nop.hdr.status & STAT_COLLEXCESSIVE)		priv->stats.collisions += 16;	}	if (nop.nop_link == caddr) {	    printk(KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);	    break;	}	caddr = nop.nop_link;	ether1_readbuffer(dev, &nop, caddr, NOP_SIZE);	if ((nop.hdr.command & CMD_MASK) != CMD_NOP) {	    printk(KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);	    break;	}	if (caddr == nop.nop_link)	    break;	caddr = nop.nop_link;	ether1_readbuffer(dev, &nop, caddr, NOP_SIZE);	if ((nop.hdr.command & CMD_MASK) != CMD_TX) {	    printk(KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);	    break;	}    }    priv->tx_tail = caddr;    caddr = priv->tx_head;    tst = ether1_txalloc(dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);    priv->tx_head = caddr;    if (tst != -1)	dev->tbusy = 0;        mark_bh(NET_BH);}static voidether1_recv_done(struct device *dev){    FUNC_PROLOGUE;    int status;    int nexttail, rbdaddr;    rbd_t rbd;    do {	status = ether1_inw(dev, priv->rx_head, rfd_t, hdr.status, NORMALIRQS);	if ((status & RFD_COMPLETE) == 0)	    break;	rbdaddr = ether1_inw(dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);	ether1_readbuffer(dev, &rbd, rbdaddr, RBD_SIZE);	if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {	    int length = rbd.rbd_status & RBD_ACNT;	    struct sk_buff *skb;	    length = (length + 1) & ~1;	    skb = dev_alloc_skb(length + 2);	    if (skb) {		skb->dev = dev;		skb_reserve(skb, 2);		ether1_readbuffer(dev, skb_put(skb, length), rbd.rbd_bufl, length);		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		priv->stats.rx_packets ++;	    } else		priv->stats.rx_dropped ++;	} else {	    printk(KERN_WARNING "%s: %s\n", dev->name,			(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");	    priv->stats.rx_dropped ++;	}	nexttail = ether1_inw(dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);	/* nexttail should be rx_head */	if (nexttail != priv->rx_head)	    printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",			dev->name, nexttail, priv->rx_head);	ether1_outw(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, hdr.command, NORMALIRQS);	ether1_outw(dev, 0, priv->rx_tail, rfd_t, hdr.command, NORMALIRQS);	ether1_outw(dev, 0, priv->rx_tail, rfd_t, hdr.status, NORMALIRQS);	ether1_outw(dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);		priv->rx_tail = nexttail;	priv->rx_head = ether1_inw(dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);    } while (1);}static voidether1_interrupt(int irq, void *dev_id, struct pt_regs *regs){    struct device *dev = (struct device *)dev_id;    FUNC_PROLOGUE;    int status;    dev->interrupt = 1;    status = ether1_inw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);    if (status) {	ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),			SCB_ADDR, scb_t, scb_command, NORMALIRQS);	outb(CTRL_CA | CTRL_ACK, REG_CONTROL);	if (status & SCB_STCX) {	    ether1_xmit_done(dev);	}	if (status & SCB_STCNA) {	    if (priv->resetting == 0)		printk(KERN_WARNING "%s: CU went not ready ???\n", dev->name);	    else		priv->resetting += 1;	    if (ether1_inw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)				!= (unsigned short)I82586_NULL) {		ether1_outw(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);		outb(CTRL_CA, REG_CONTROL);	    }	    if (priv->resetting == 2)		priv->resetting = 0;	}	if (status & SCB_STFR) {	    ether1_recv_done(dev);	}	if (status & SCB_STRNR) {	    if (ether1_inw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {		printk(KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);		ether1_outw(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);		outb(CTRL_CA, REG_CONTROL);		priv->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */	    } else		printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,		    ether1_inw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));	    printk(KERN_WARNING "RU ptr = %04X\n", ether1_inw(dev, SCB_ADDR, scb_t, scb_rfa_offset,					NORMALIRQS));	}    } else        outb(CTRL_ACK, REG_CONTROL);    dev->interrupt = 0;}static intether1_open(struct device *dev){    MOD_INC_USE_COUNT;    if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) {    	MOD_DEC_USE_COUNT;	return -EAGAIN;    }    dev->tbusy = 0;    dev->interrupt = 0;    dev->start = 1;    if (ether1_init_for_open(dev)) {	free_irq(dev->irq, dev);	MOD_DEC_USE_COUNT;	return -EAGAIN;    }    return 0;}static intether1_close(struct device *dev){    dev->tbusy = 1;    dev->start = 0;    ether1_reset(dev);    free_irq(dev->irq, dev);    MOD_DEC_USE_COUNT;    return 0;}static struct enet_statistics *ether1_getstats(struct device *dev){    FUNC_PROLOGUE;    return &priv->stats;}/* * Set or clear the multicast filter for this adaptor. * num_addrs == -1	Promiscuous mode, receive all packets. * num_addrs == 0	Normal mode, clear multicast list. * num_addrs > 0	Multicast mode, receive normal and MC packets, and do *			best-effort filtering. */static voidether1_setmulticastlist(struct device *dev){}/* ------------------------------------------------------------------------- */#ifdef MODULEstatic char ethernames[MAX_ECARDS][9];static struct device *my_ethers[MAX_ECARDS];static struct expansion_card *ec[MAX_ECARDS];intinit_module(void){    int i;    for (i = 0; i < MAX_ECARDS; i++) {	my_ethers[i] = NULL;	ec[i] = NULL;	strcpy(ethernames[i], "        ");    }    i = 0;    ecard_startfind();    do {	if ((ec[i] = ecard_find(0, ether1_cids)) == NULL)	    break;	my_ethers[i] = (struct device *)kmalloc(sizeof (struct device), GFP_KERNEL);	memset(my_ethers[i], 0, sizeof (struct device));	my_ethers[i]->irq = ec[i]->irq;	my_ethers[i]->base_addr = ecard_address(ec[i], ECARD_IOC, ECARD_FAST);	my_ethers[i]->init = ether1_probe;	my_ethers[i]->name = ethernames[i];	ecard_claim(ec[i]);	if (register_netdev(my_ethers[i]) != 0) {	    for (i = 0; i < 4; i++) {		if (my_ethers[i]) {		    kfree(my_ethers[i]);		    my_ethers[i] = NULL;		}		if (ec[i]) {		    ecard_release(ec[i]);		    ec[i] = NULL;		}	    }	    return -EIO;	}	i++;    } while (i < MAX_ECARDS);    return i != 0 ? 0 : -ENODEV;}voidcleanup_module(void){    int i;    for (i = 0; i < MAX_ECARDS; i++) {	if (my_ethers[i]) {	    unregister_netdev(my_ethers[i]);	    release_region(my_ethers[i]->base_addr, 16);	    release_region(my_ethers[i]->base_addr + 0x800, 4096);	    my_ethers[i] = NULL;	}	if (ec[i]) {	    ecard_release(ec[i]);	    ec[i] = NULL;	}    }}#endif /* MODULE */

⌨️ 快捷键说明

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