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

📄 plip.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (rcv->skb) {		kfree_skb(rcv->skb);		rcv->skb = NULL;	}	snd->state = PLIP_PK_DONE;	if (snd->skb) {		dev_kfree_skb(snd->skb);		snd->skb = NULL;	}	spin_unlock_irq(&nl->lock);	if (error == HS_TIMEOUT) {		DISABLE(dev->irq);		synchronize_irq();	}	outb(PAR_INTR_OFF, PAR_CONTROL(dev));	dev->tbusy = 1;	nl->connection = PLIP_CN_ERROR;	outb(0x00, PAR_DATA(dev));	return TIMEOUT;}static intplip_none(struct device *dev, struct net_local *nl,	  struct plip_local *snd, struct plip_local *rcv){	return OK;}/* PLIP_RECEIVE --- receive a byte(two nibbles)   Returns OK on success, TIMEOUT on timeout */inline static intplip_receive(unsigned short nibble_timeout, unsigned short status_addr,	     enum plip_nibble_state *ns_p, unsigned char *data_p){	unsigned char c0, c1;	unsigned int cx;	switch (*ns_p) {	case PLIP_NB_BEGIN:		cx = nibble_timeout;		while (1) {			c0 = inb(status_addr);			udelay(PLIP_DELAY_UNIT);			if ((c0 & 0x80) == 0) {				c1 = inb(status_addr);				if (c0 == c1)					break;			}			if (--cx == 0)				return TIMEOUT;		}		*data_p = (c0 >> 3) & 0x0f;		outb(0x10, --status_addr); /* send ACK */		status_addr++;		*ns_p = PLIP_NB_1;	case PLIP_NB_1:		cx = nibble_timeout;		while (1) {			c0 = inb(status_addr);			udelay(PLIP_DELAY_UNIT);			if (c0 & 0x80) {				c1 = inb(status_addr);				if (c0 == c1)					break;			}			if (--cx == 0)				return TIMEOUT;		}		*data_p |= (c0 << 1) & 0xf0;		outb(0x00, --status_addr); /* send ACK */		status_addr++;		*ns_p = PLIP_NB_BEGIN;	case PLIP_NB_2:		break;	}	return OK;}/* PLIP_RECEIVE_PACKET --- receive a packet */static intplip_receive_packet(struct device *dev, struct net_local *nl,		    struct plip_local *snd, struct plip_local *rcv){	unsigned short status_addr = PAR_STATUS(dev);	unsigned short nibble_timeout = nl->nibble;	unsigned char *lbuf;	switch (rcv->state) {	case PLIP_PK_TRIGGER:		DISABLE(dev->irq);		/* Don't need to synchronize irq, as we can safely ignore it */		outb(PAR_INTR_OFF, PAR_CONTROL(dev));		dev->interrupt = 0;		outb(0x01, PAR_DATA(dev)); /* send ACK */		if (net_debug > 2)			printk(KERN_DEBUG "%s: receive start\n", dev->name);		rcv->state = PLIP_PK_LENGTH_LSB;		rcv->nibble = PLIP_NB_BEGIN;	case PLIP_PK_LENGTH_LSB:		if (snd->state != PLIP_PK_DONE) {			if (plip_receive(nl->trigger, status_addr,					 &rcv->nibble, &rcv->length.b.lsb)) {				/* collision, here dev->tbusy == 1 */				rcv->state = PLIP_PK_DONE;				nl->is_deferred = 1;				nl->connection = PLIP_CN_SEND;				queue_task(&nl->deferred, &tq_timer);				outb(PAR_INTR_ON, PAR_CONTROL(dev));				ENABLE(dev->irq);				return OK;			}		} else {			if (plip_receive(nibble_timeout, status_addr,					 &rcv->nibble, &rcv->length.b.lsb))				return TIMEOUT;		}		rcv->state = PLIP_PK_LENGTH_MSB;	case PLIP_PK_LENGTH_MSB:		if (plip_receive(nibble_timeout, status_addr,				 &rcv->nibble, &rcv->length.b.msb))			return TIMEOUT;		if (rcv->length.h > dev->mtu + dev->hard_header_len		    || rcv->length.h < 8) {			printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h);			return ERROR;		}		/* Malloc up new buffer. */		rcv->skb = dev_alloc_skb(rcv->length.h);		if (rcv->skb == NULL) {			printk(KERN_ERR "%s: Memory squeeze.\n", dev->name);			return ERROR;		}		skb_put(rcv->skb,rcv->length.h);		rcv->skb->dev = dev;		rcv->state = PLIP_PK_DATA;		rcv->byte = 0;		rcv->checksum = 0;	case PLIP_PK_DATA:		lbuf = rcv->skb->data;		do			if (plip_receive(nibble_timeout, status_addr,					 &rcv->nibble, &lbuf[rcv->byte]))				return TIMEOUT;		while (++rcv->byte < rcv->length.h);		do			rcv->checksum += lbuf[--rcv->byte];		while (rcv->byte);		rcv->state = PLIP_PK_CHECKSUM;	case PLIP_PK_CHECKSUM:		if (plip_receive(nibble_timeout, status_addr,				 &rcv->nibble, &rcv->data))			return TIMEOUT;		if (rcv->data != rcv->checksum) {			nl->enet_stats.rx_crc_errors++;			if (net_debug)				printk(KERN_DEBUG "%s: checksum error\n", dev->name);			return ERROR;		}		rcv->state = PLIP_PK_DONE;	case PLIP_PK_DONE:		/* Inform the upper layer for the arrival of a packet. */		rcv->skb->protocol=eth_type_trans(rcv->skb, dev);		netif_rx(rcv->skb);		nl->enet_stats.rx_bytes += rcv->length.h;		nl->enet_stats.rx_packets++;		rcv->skb = NULL;		if (net_debug > 2)			printk(KERN_DEBUG "%s: receive end\n", dev->name);		/* Close the connection. */		outb (0x00, PAR_DATA(dev));		spin_lock_irq(&nl->lock);		if (snd->state != PLIP_PK_DONE) {			nl->connection = PLIP_CN_SEND;			spin_unlock_irq(&nl->lock);			queue_task(&nl->immediate, &tq_immediate);			mark_bh(IMMEDIATE_BH);			outb(PAR_INTR_ON, PAR_CONTROL(dev));			ENABLE(dev->irq);			return OK;		} else {			nl->connection = PLIP_CN_NONE;			spin_unlock_irq(&nl->lock);			outb(PAR_INTR_ON, PAR_CONTROL(dev));			ENABLE(dev->irq);			return OK;		}	}	return OK;}/* PLIP_SEND --- send a byte (two nibbles)   Returns OK on success, TIMEOUT when timeout    */inline static intplip_send(unsigned short nibble_timeout, unsigned short data_addr,	  enum plip_nibble_state *ns_p, unsigned char data){	unsigned char c0;	unsigned int cx;	switch (*ns_p) {	case PLIP_NB_BEGIN:		outb((data & 0x0f), data_addr);		*ns_p = PLIP_NB_1;	case PLIP_NB_1:		outb(0x10 | (data & 0x0f), data_addr);		cx = nibble_timeout;		data_addr++;		while (1) {			c0 = inb(data_addr);			if ((c0 & 0x80) == 0)				break;			if (--cx == 0)				return TIMEOUT;			udelay(PLIP_DELAY_UNIT);		}		outb(0x10 | (data >> 4), --data_addr);		*ns_p = PLIP_NB_2;	case PLIP_NB_2:		outb((data >> 4), data_addr);		data_addr++;		cx = nibble_timeout;		while (1) {			c0 = inb(data_addr);			if (c0 & 0x80)				break;			if (--cx == 0)				return TIMEOUT;			udelay(PLIP_DELAY_UNIT);		}		data_addr--;		*ns_p = PLIP_NB_BEGIN;		return OK;	}	return OK;}/* PLIP_SEND_PACKET --- send a packet */static intplip_send_packet(struct device *dev, struct net_local *nl,		 struct plip_local *snd, struct plip_local *rcv){	unsigned short data_addr = PAR_DATA(dev);	unsigned short nibble_timeout = nl->nibble;	unsigned char *lbuf;	unsigned char c0;	unsigned int cx;	if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {		printk(KERN_DEBUG "%s: send skb lost\n", dev->name);		snd->state = PLIP_PK_DONE;		snd->skb = NULL;		return ERROR;	}	switch (snd->state) {	case PLIP_PK_TRIGGER:		if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)			return HS_TIMEOUT;		/* Trigger remote rx interrupt. */		outb(0x08, data_addr);		cx = nl->trigger;		while (1) {			udelay(PLIP_DELAY_UNIT);			spin_lock_irq(&nl->lock);			if (nl->connection == PLIP_CN_RECEIVE) {				spin_unlock_irq(&nl->lock);				/* Interrupted. */				nl->enet_stats.collisions++;				return OK;			}			c0 = inb(PAR_STATUS(dev));			if (c0 & 0x08) {				spin_unlock_irq(&nl->lock);				DISABLE(dev->irq);				synchronize_irq();				if (nl->connection == PLIP_CN_RECEIVE) {					/* Interrupted.					   We don't need to enable irq,					   as it is soon disabled.    */					/* Yes, we do. New variant of					   {enable,disable}_irq *counts*					   them.  -- AV  */					ENABLE(dev->irq);					nl->enet_stats.collisions++;					return OK;				}				outb(PAR_INTR_OFF, PAR_CONTROL(dev));				if (net_debug > 2)					printk(KERN_DEBUG "%s: send start\n", dev->name);				snd->state = PLIP_PK_LENGTH_LSB;				snd->nibble = PLIP_NB_BEGIN;				nl->timeout_count = 0;				break;			}			spin_unlock_irq(&nl->lock);			if (--cx == 0) {				outb(0x00, data_addr);				return HS_TIMEOUT;			}		}	case PLIP_PK_LENGTH_LSB:		if (plip_send(nibble_timeout, data_addr,			      &snd->nibble, snd->length.b.lsb))			return TIMEOUT;		snd->state = PLIP_PK_LENGTH_MSB;	case PLIP_PK_LENGTH_MSB:		if (plip_send(nibble_timeout, data_addr,			      &snd->nibble, snd->length.b.msb))			return TIMEOUT;		snd->state = PLIP_PK_DATA;		snd->byte = 0;		snd->checksum = 0;	case PLIP_PK_DATA:		do			if (plip_send(nibble_timeout, data_addr,				      &snd->nibble, lbuf[snd->byte]))				return TIMEOUT;		while (++snd->byte < snd->length.h);		do			snd->checksum += lbuf[--snd->byte];		while (snd->byte);		snd->state = PLIP_PK_CHECKSUM;	case PLIP_PK_CHECKSUM:		if (plip_send(nibble_timeout, data_addr,			      &snd->nibble, snd->checksum))			return TIMEOUT;		nl->enet_stats.tx_bytes += snd->skb->len;		dev_kfree_skb(snd->skb);		nl->enet_stats.tx_packets++;		snd->state = PLIP_PK_DONE;	case PLIP_PK_DONE:		/* Close the connection */		outb (0x00, data_addr);		snd->skb = NULL;		if (net_debug > 2)			printk(KERN_DEBUG "%s: send end\n", dev->name);		nl->connection = PLIP_CN_CLOSING;		nl->is_deferred = 1;		queue_task(&nl->deferred, &tq_timer);		outb(PAR_INTR_ON, PAR_CONTROL(dev));		ENABLE(dev->irq);		return OK;	}	return OK;}static intplip_connection_close(struct device *dev, struct net_local *nl,		      struct plip_local *snd, struct plip_local *rcv){	spin_lock_irq(&nl->lock);	if (nl->connection == PLIP_CN_CLOSING) {		nl->connection = PLIP_CN_NONE;		dev->tbusy = 0;		mark_bh(NET_BH);	}	spin_unlock_irq(&nl->lock);	if (nl->should_relinquish) {		nl->should_relinquish = nl->port_owner = 0;		parport_release(nl->pardev);	}	return OK;}/* PLIP_ERROR --- wait till other end settled */static intplip_error(struct device *dev, struct net_local *nl,	   struct plip_local *snd, struct plip_local *rcv){	unsigned char status;	status = inb(PAR_STATUS(dev));	if ((status & 0xf8) == 0x80) {		if (net_debug > 2)			printk(KERN_DEBUG "%s: reset interface.\n", dev->name);		nl->connection = PLIP_CN_NONE;		nl->should_relinquish = 0;		dev->tbusy = 0;		dev->interrupt = 0;		outb(PAR_INTR_ON, PAR_CONTROL(dev));		ENABLE(dev->irq);		mark_bh(NET_BH);	} else {		nl->is_deferred = 1;		queue_task(&nl->deferred, &tq_timer);	}	return OK;}/* Handle the parallel port interrupts. */static voidplip_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct device *dev = dev_id;	struct net_local *nl;	struct plip_local *rcv;	unsigned char c0;	if (dev == NULL) {		printk(KERN_DEBUG "plip_interrupt: irq %d for unknown device.\n", irq);		return;	}	nl = (struct net_local *)dev->priv;	rcv = &nl->rcv_data;	if (dev->interrupt)		return;	c0 = inb(PAR_STATUS(dev));	if ((c0 & 0xf8) != 0xc0) {

⌨️ 快捷键说明

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