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

📄 plip.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ *//* PLIP: A parallel port "network" driver for Linux. *//* This driver is for parallel port with 5-bit cable (LapLink (R) cable). *//* * Authors:	Donald Becker <becker@super.org> *		Tommy Thorn <thorn@daimi.aau.dk> *		Tanabe Hiroyasu <hiro@sanpo.t.u-tokyo.ac.jp> *		Alan Cox <gw4pts@gw4pts.ampr.org> *		Peter Bauer <100136.3530@compuserve.com> *		Niibe Yutaka <gniibe@mri.co.jp> *		Nimrod Zimerman <zimerman@mailandnews.com> * * Enhancements: *		Modularization and ifreq/ifmap support by Alan Cox. *		Rewritten by Niibe Yutaka. *		parport-sharing awareness code by Philip Blundell. *		SMP locking by Niibe Yutaka. *		Support for parallel ports with no IRQ (poll mode), *		Modifications to use the parallel port API  *		by Nimrod Zimerman. * * Fixes: *		Niibe Yutaka *		  - Module initialization. *		  - MTU fix. *		  - Make sure other end is OK, before sending a packet. *		  - Fix immediate timer problem. * *		Al Viro *		  - Changed {enable,disable}_irq handling to make it work *		    with new ("stack") semantics. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. *//* * Original version and the name 'PLIP' from Donald Becker <becker@super.org> * inspired by Russ Nelson's parallel port packet driver. * * NOTE: *     Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0. *     Because of the necessity to communicate to DOS machines with the *     Crynwr packet driver, Peter Bauer changed the protocol again *     back to original protocol. * *     This version follows original PLIP protocol. *     So, this PLIP can't communicate the PLIP of Linux v1.0. *//* *     To use with DOS box, please do (Turn on ARP switch): *	# ifconfig plip[0-2] arp */static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n";/*  Sources:	Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>	"parallel.asm" parallel port packet driver.  The "Crynwr" parallel port standard specifies the following protocol:    Trigger by sending nibble '0x8' (this causes interrupt on other end)    count-low octet    count-high octet    ... data octets    checksum octet  Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>			<wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>  The packet is encapsulated as if it were ethernet.  The cable used is a de facto standard parallel null cable -- sold as  a "LapLink" cable by various places.  You'll need a 12-conductor cable to  make one yourself.  The wiring is:    SLCTIN	17 - 17    GROUND	25 - 25    D0->ERROR	2 - 15		15 - 2    D1->SLCT	3 - 13		13 - 3    D2->PAPOUT	4 - 12		12 - 4    D3->ACK	5 - 10		10 - 5    D4->BUSY	6 - 11		11 - 6  Do not connect the other pins.  They are    D5,D6,D7 are 7,8,9    STROBE is 1, FEED is 14, INIT is 16    extra grounds are 18,19,20,21,22,23,24*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/if_ether.h>#include <asm/system.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/lp.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/inetdevice.h>#include <linux/skbuff.h>#include <linux/if_plip.h>#include <net/neighbour.h>#include <linux/tqueue.h>#include <linux/ioport.h>#include <linux/spinlock.h>#include <asm/bitops.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <asm/semaphore.h>#include <linux/parport.h>/* Maximum number of devices to support. */#define PLIP_MAX  8/* Use 0 for production, 1 for verification, >2 for debug */#ifndef NET_DEBUG#define NET_DEBUG 1#endifstatic unsigned int net_debug = NET_DEBUG;#define ENABLE(irq)  if (irq != -1) enable_irq(irq)#define DISABLE(irq) if (irq != -1) disable_irq(irq)/* In micro second */#define PLIP_DELAY_UNIT		   1/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */#define PLIP_TRIGGER_WAIT	 500/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */#define PLIP_NIBBLE_WAIT        3000/* Bottom halves */static void plip_kick_bh(struct net_device *dev);static void plip_bh(struct net_device *dev);static void plip_timer_bh(struct net_device *dev);/* Interrupt handler */static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);/* Functions for DEV methods */static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,                            unsigned short type, void *daddr,                            void *saddr, unsigned len);static int plip_hard_header_cache(struct neighbour *neigh,                                  struct hh_cache *hh);static int plip_open(struct net_device *dev);static int plip_close(struct net_device *dev);static struct net_device_stats *plip_get_stats(struct net_device *dev);static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);static int plip_preempt(void *handle);static void plip_wakeup(void *handle);enum plip_connection_state {	PLIP_CN_NONE=0,	PLIP_CN_RECEIVE,	PLIP_CN_SEND,	PLIP_CN_CLOSING,	PLIP_CN_ERROR};enum plip_packet_state {	PLIP_PK_DONE=0,	PLIP_PK_TRIGGER,	PLIP_PK_LENGTH_LSB,	PLIP_PK_LENGTH_MSB,	PLIP_PK_DATA,	PLIP_PK_CHECKSUM};enum plip_nibble_state {	PLIP_NB_BEGIN,	PLIP_NB_1,	PLIP_NB_2,};struct plip_local {	enum plip_packet_state state;	enum plip_nibble_state nibble;	union {		struct {#if defined(__LITTLE_ENDIAN)			unsigned char lsb;			unsigned char msb;#elif defined(__BIG_ENDIAN)			unsigned char msb;			unsigned char lsb;#else#error	"Please fix the endianness defines in <asm/byteorder.h>"#endif		} b;		unsigned short h;	} length;	unsigned short byte;	unsigned char  checksum;	unsigned char  data;	struct sk_buff *skb;};struct net_local {	struct net_device_stats enet_stats;	struct tq_struct immediate;	struct tq_struct deferred;	struct tq_struct timer;	struct plip_local snd_data;	struct plip_local rcv_data;	struct pardevice *pardev;	unsigned long  trigger;	unsigned long  nibble;	enum plip_connection_state connection;	unsigned short timeout_count;	int is_deferred;	int port_owner;	int should_relinquish;	int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,	                        unsigned short type, void *daddr,	                        void *saddr, unsigned len);	int (*orig_hard_header_cache)(struct neighbour *neigh,	                              struct hh_cache *hh);	spinlock_t lock;	atomic_t kill_timer;	struct semaphore killed_timer_sem;};inline static void enable_parport_interrupts (struct net_device *dev){	if (dev->irq != -1)	{		struct parport *port =		   ((struct net_local *)dev->priv)->pardev->port;		port->ops->enable_irq (port);	}}inline static void disable_parport_interrupts (struct net_device *dev){	if (dev->irq != -1)	{		struct parport *port =		   ((struct net_local *)dev->priv)->pardev->port;		port->ops->disable_irq (port);	}}inline static void write_data (struct net_device *dev, unsigned char data){	struct parport *port =	   ((struct net_local *)dev->priv)->pardev->port;	port->ops->write_data (port, data);}inline static unsigned char read_status (struct net_device *dev){	struct parport *port =	   ((struct net_local *)dev->priv)->pardev->port;	return port->ops->read_status (port);}/* Entry point of PLIP driver.   Probe the hardware, and register/initialize the driver.   PLIP is rather weird, because of the way it interacts with the parport   system.  It is _not_ initialised from Space.c.  Instead, plip_init()   is called, and that function makes up a "struct net_device" for each port, and   then calls us here.   */int __initplip_init_dev(struct net_device *dev, struct parport *pb){	struct net_local *nl;	struct pardevice *pardev;	SET_MODULE_OWNER(dev);	dev->irq = pb->irq;	dev->base_addr = pb->base;	if (pb->irq == -1) {		printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode,"		                 "which is fairly inefficient!\n", pb->name);	}	pardev = parport_register_device(pb, dev->name, plip_preempt,					 plip_wakeup, plip_interrupt, 					 0, dev);	if (!pardev)		return -ENODEV;	printk(KERN_INFO "%s", version);	if (dev->irq != -1)		printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n",		       dev->name, dev->base_addr, dev->irq);	else		printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n",		       dev->name, dev->base_addr);	/* Fill in the generic fields of the device structure. */	ether_setup(dev);	/* Then, override parts of it */	dev->hard_start_xmit	 = plip_tx_packet;	dev->open		 = plip_open;	dev->stop		 = plip_close;	dev->get_stats 		 = plip_get_stats;	dev->do_ioctl		 = plip_ioctl;	dev->header_cache_update = NULL;	dev->tx_queue_len 	 = 10;	dev->flags	         = IFF_POINTOPOINT|IFF_NOARP;	memset(dev->dev_addr, 0xfc, ETH_ALEN);	/* Set the private structure */	dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);	if (dev->priv == NULL) {		printk(KERN_ERR "%s: out of memory\n", dev->name);		parport_unregister_device(pardev);		return -ENOMEM;	}	memset(dev->priv, 0, sizeof(struct net_local));	nl = (struct net_local *) dev->priv;	nl->orig_hard_header    = dev->hard_header;	dev->hard_header        = plip_hard_header;	nl->orig_hard_header_cache = dev->hard_header_cache;	dev->hard_header_cache     = plip_hard_header_cache;	nl->pardev = pardev; 	nl->port_owner = 0;	/* Initialize constants */	nl->trigger	= PLIP_TRIGGER_WAIT;	nl->nibble	= PLIP_NIBBLE_WAIT;	/* Initialize task queue structures */	INIT_LIST_HEAD(&nl->immediate.list);	nl->immediate.sync = 0;	nl->immediate.routine = (void (*)(void *))plip_bh;	nl->immediate.data = dev;	INIT_LIST_HEAD(&nl->deferred.list);	nl->deferred.sync = 0;	nl->deferred.routine = (void (*)(void *))plip_kick_bh;	nl->deferred.data = dev;	if (dev->irq == -1) {		INIT_LIST_HEAD(&nl->timer.list);		nl->timer.sync = 0;		nl->timer.routine = (void (*)(void *))plip_timer_bh;		nl->timer.data = dev;	}	spin_lock_init(&nl->lock);	return 0;}/* Bottom half handler for the delayed request.   This routine is kicked by do_timer().   Request `plip_bh' to be invoked. */static voidplip_kick_bh(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	if (nl->is_deferred) {		queue_task(&nl->immediate, &tq_immediate);		mark_bh(IMMEDIATE_BH);	}}/* Forward declarations of internal routines */static int plip_none(struct net_device *, struct net_local *,		     struct plip_local *, struct plip_local *);static int plip_receive_packet(struct net_device *, struct net_local *,			       struct plip_local *, struct plip_local *);static int plip_send_packet(struct net_device *, struct net_local *,			    struct plip_local *, struct plip_local *);static int plip_connection_close(struct net_device *, struct net_local *,				 struct plip_local *, struct plip_local *);static int plip_error(struct net_device *, struct net_local *,		      struct plip_local *, struct plip_local *);static int plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,				 struct plip_local *snd,				 struct plip_local *rcv,				 int error);#define OK        0#define TIMEOUT   1#define ERROR     2#define HS_TIMEOUT	3typedef int (*plip_func)(struct net_device *dev, struct net_local *nl,			 struct plip_local *snd, struct plip_local *rcv);static plip_func connection_state_table[] ={	plip_none,	plip_receive_packet,	plip_send_packet,	plip_connection_close,	plip_error};/* Bottom half handler of PLIP. */static voidplip_bh(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;	struct plip_local *snd = &nl->snd_data;	struct plip_local *rcv = &nl->rcv_data;	plip_func f;	int r;	nl->is_deferred = 0;	f = connection_state_table[nl->connection];	if ((r = (*f)(dev, nl, snd, rcv)) != OK	    && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {		nl->is_deferred = 1;		queue_task(&nl->deferred, &tq_timer);	}}static voidplip_timer_bh(struct net_device *dev){	struct net_local *nl = (struct net_local *)dev->priv;		if (!(atomic_read (&nl->kill_timer))) {		plip_interrupt (-1, dev, NULL);		queue_task (&nl->timer, &tq_timer);	}	else {		up (&nl->killed_timer_sem);	}}static intplip_bh_timeout_error(struct net_device *dev, struct net_local *nl,		      struct plip_local *snd, struct plip_local *rcv,		      int error){	unsigned char c0;	/*	 * This is tricky. If we got here from the beginning of send (either	 * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's	 * already disabled. With the old variant of {enable,disable}_irq()	 * extra disable_irq() was a no-op. Now it became mortal - it's	 * unbalanced and thus we'll never re-enable IRQ (until rmmod plip,	 * that is). So we have to treat HS_TIMEOUT and ERROR from send	 * in a special way.	 */	spin_lock_irq(&nl->lock);	if (nl->connection == PLIP_CN_SEND) {		if (error != ERROR) { /* Timeout */			nl->timeout_count++;			if ((error == HS_TIMEOUT			     && nl->timeout_count <= 10)			    || nl->timeout_count <= 3) {				spin_unlock_irq(&nl->lock);				/* Try again later */

⌨️ 快捷键说明

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