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

📄 plip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				return TIMEOUT;			}			c0 = read_status(dev);			printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",			       dev->name, snd->state, c0);		} else			error = HS_TIMEOUT;		nl->enet_stats.tx_errors++;		nl->enet_stats.tx_aborted_errors++;	} else if (nl->connection == PLIP_CN_RECEIVE) {		if (rcv->state == PLIP_PK_TRIGGER) {			/* Transmission was interrupted. */			spin_unlock_irq(&nl->lock);			return OK;		}		if (error != ERROR) { /* Timeout */			if (++nl->timeout_count <= 3) {				spin_unlock_irq(&nl->lock);				/* Try again later */				return TIMEOUT;			}			c0 = read_status(dev);			printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",			       dev->name, rcv->state, c0);		}		nl->enet_stats.rx_dropped++;	}	rcv->state = PLIP_PK_DONE;	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();	}	disable_parport_interrupts (dev);	netif_stop_queue (dev);	nl->connection = PLIP_CN_ERROR;	write_data (dev, 0x00);	return TIMEOUT;}static intplip_none(struct net_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, struct net_device *dev,	     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 = read_status(dev);			udelay(PLIP_DELAY_UNIT);			if ((c0 & 0x80) == 0) {				c1 = read_status(dev);				if (c0 == c1)					break;			}			if (--cx == 0)				return TIMEOUT;		}		*data_p = (c0 >> 3) & 0x0f;		write_data (dev, 0x10); /* send ACK */		*ns_p = PLIP_NB_1;	case PLIP_NB_1:		cx = nibble_timeout;		while (1) {			c0 = read_status(dev);			udelay(PLIP_DELAY_UNIT);			if (c0 & 0x80) {				c1 = read_status(dev);				if (c0 == c1)					break;			}			if (--cx == 0)				return TIMEOUT;		}		*data_p |= (c0 << 1) & 0xf0;		write_data (dev, 0x00); /* send ACK */		*ns_p = PLIP_NB_BEGIN;	case PLIP_NB_2:		break;	}	return OK;}/* *	Determine the packet's protocol ID. The rule here is that we  *	assume 802.3 if the type field is short enough to be a length. *	This is normal practice and works for any 'now in use' protocol. * *	PLIP is ethernet ish but the daddr might not be valid if unicast. *	PLIP fortunately has no bus architecture (its Point-to-point). * *	We can't fix the daddr thing as that quirk (more bug) is embedded *	in far too many old systems not all even running Linux. */ static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *dev){	struct ethhdr *eth;	unsigned char *rawp;		skb->mac.raw=skb->data;	skb_pull(skb,dev->hard_header_len);	eth= skb->mac.ethernet;		if(*eth->h_dest&1)	{		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)			skb->pkt_type=PACKET_BROADCAST;		else			skb->pkt_type=PACKET_MULTICAST;	}		/*	 *	This ALLMULTI check should be redundant by 1.4	 *	so don't forget to remove it.	 */	 	if (ntohs(eth->h_proto) >= 1536)		return eth->h_proto;			rawp = skb->data;		/*	 *	This is a magic hack to spot IPX packets. Older Novell breaks	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This	 *	won't work for fault tolerant netware but does for the rest.	 */	if (*(unsigned short *)rawp == 0xFFFF)		return htons(ETH_P_802_3);			/*	 *	Real 802.2 LLC	 */	return htons(ETH_P_802_2);}/* PLIP_RECEIVE_PACKET --- receive a packet */static intplip_receive_packet(struct net_device *dev, struct net_local *nl,		    struct plip_local *snd, struct plip_local *rcv){	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 */		disable_parport_interrupts (dev);		write_data (dev, 0x01); /* 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, dev,					 &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);				enable_parport_interrupts (dev);				ENABLE(dev->irq);				return OK;			}		} else {			if (plip_receive(nibble_timeout, dev,					 &rcv->nibble, &rcv->length.b.lsb))				return TIMEOUT;		}		rcv->state = PLIP_PK_LENGTH_MSB;	case PLIP_PK_LENGTH_MSB:		if (plip_receive(nibble_timeout, dev,				 &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 + 2);		if (rcv->skb == NULL) {			printk(KERN_ERR "%s: Memory squeeze.\n", dev->name);			return ERROR;		}		skb_reserve(rcv->skb, 2);	/* Align IP on 16 byte boundaries */		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, dev,					 &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, dev,				 &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=plip_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. */		write_data (dev, 0x00);		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);			enable_parport_interrupts (dev);			ENABLE(dev->irq);			return OK;		} else {			nl->connection = PLIP_CN_NONE;			spin_unlock_irq(&nl->lock);			enable_parport_interrupts (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, struct net_device *dev,	  enum plip_nibble_state *ns_p, unsigned char data){	unsigned char c0;	unsigned int cx;	switch (*ns_p) {	case PLIP_NB_BEGIN:		write_data (dev, data & 0x0f);		*ns_p = PLIP_NB_1;	case PLIP_NB_1:		write_data (dev, 0x10 | (data & 0x0f));		cx = nibble_timeout;		while (1) {			c0 = read_status(dev);			if ((c0 & 0x80) == 0)				break;			if (--cx == 0)				return TIMEOUT;			udelay(PLIP_DELAY_UNIT);		}		write_data (dev, 0x10 | (data >> 4));		*ns_p = PLIP_NB_2;	case PLIP_NB_2:		write_data (dev, (data >> 4));		cx = nibble_timeout;		while (1) {			c0 = read_status(dev);			if (c0 & 0x80)				break;			if (--cx == 0)				return TIMEOUT;			udelay(PLIP_DELAY_UNIT);		}		*ns_p = PLIP_NB_BEGIN;		return OK;	}	return OK;}/* PLIP_SEND_PACKET --- send a packet */static intplip_send_packet(struct net_device *dev, struct net_local *nl,		 struct plip_local *snd, struct plip_local *rcv){	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 ((read_status(dev) & 0xf8) != 0x80)			return HS_TIMEOUT;		/* Trigger remote rx interrupt. */		write_data (dev, 0x08);		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 = read_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;				}				disable_parport_interrupts (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) {				write_data (dev, 0x00);				return HS_TIMEOUT;			}		}	case PLIP_PK_LENGTH_LSB:		if (plip_send(nibble_timeout, dev,			      &snd->nibble, snd->length.b.lsb))			return TIMEOUT;		snd->state = PLIP_PK_LENGTH_MSB;	case PLIP_PK_LENGTH_MSB:		if (plip_send(nibble_timeout, dev,			      &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, dev,				      &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, dev,			      &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 */		write_data (dev, 0x00);		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);		enable_parport_interrupts (dev);		ENABLE(dev->irq);		return OK;	}	return OK;}static intplip_connection_close(struct net_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;		netif_wake_queue (dev);	}	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 net_device *dev, struct net_local *nl,	   struct plip_local *snd, struct plip_local *rcv){	unsigned char status;	status = read_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;		netif_start_queue (dev);		enable_parport_interrupts (dev);		ENABLE(dev->irq);		netif_wake_queue (dev);	} else {		nl->is_deferred = 1;		queue_task(&nl->deferred, &tq_timer);	}	return OK;}

⌨️ 快捷键说明

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