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

📄 share.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $ * Parallel-port resource manager code. *  * Authors: David Campbell <campbell@tirian.che.curtin.edu.au> *          Tim Waugh <tim@cyberelk.demon.co.uk> *          Jose Renau <renau@acm.org> *          Philip Blundell <philb@gnu.org> *	    Andrea Arcangeli * * based on work by Grant Guenther <grant@torque.net> *          and Philip Blundell * * Any part of this program may be used in documents licensed under * the GNU Free Documentation License, Version 1.1 or any later version * published by the Free Software Foundation. */#undef PARPORT_DEBUG_SHARING		/* undef for production */#include <linux/config.h>#include <linux/string.h>#include <linux/threads.h>#include <linux/parport.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/sched.h>#include <linux/kmod.h>#include <linux/spinlock.h>#include <asm/irq.h>#undef PARPORT_PARANOID#define PARPORT_DEFAULT_TIMESLICE	(HZ/5)unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;int parport_default_spintime =  DEFAULT_SPIN_TIME;static struct parport *portlist = NULL, *portlist_tail = NULL;spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;static struct parport_driver *driver_chain = NULL;spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;/* What you can do to a port that's gone away.. */static void dead_write_lines (struct parport *p, unsigned char b){}static unsigned char dead_read_lines (struct parport *p) { return 0; }static unsigned char dead_frob_lines (struct parport *p, unsigned char b,			     unsigned char c) { return 0; }static void dead_onearg (struct parport *p){}static void dead_initstate (struct pardevice *d, struct parport_state *s) { }static void dead_state (struct parport *p, struct parport_state *s) { }static void dead_noargs (void) { }static size_t dead_write (struct parport *p, const void *b, size_t l, int f){ return 0; }static size_t dead_read (struct parport *p, void *b, size_t l, int f){ return 0; }static struct parport_operations dead_ops = {	dead_write_lines,	/* data */	dead_read_lines,	dead_write_lines,	/* control */	dead_read_lines,	dead_frob_lines,	dead_read_lines,	/* status */	dead_onearg,		/* enable_irq */	dead_onearg,		/* disable_irq */	dead_onearg,		/* data_forward */	dead_onearg,		/* data_reverse */	dead_initstate,		/* init_state */	dead_state,	dead_state,	dead_noargs,		/* xxx_use_count */	dead_noargs,	dead_write,		/* epp */	dead_read,	dead_write,	dead_read,	dead_write,		/* ecp */	dead_read,	dead_write,	dead_write,		/* compat */	dead_read,		/* nibble */	dead_read		/* byte */};/* Call attach(port) for each registered driver. */static void attach_driver_chain(struct parport *port){	struct parport_driver *drv;	void (**attach) (struct parport *);	int count = 0, i;	/* This is complicated because attach() must be able to block,	 * but we can't let it do that while we're holding a	 * spinlock. */	spin_lock (&driverlist_lock);	for (drv = driver_chain; drv; drv = drv->next)		count++;	spin_unlock (&driverlist_lock);	/* Drivers can unregister here; that's okay.  If they register	 * they'll be given an attach during parport_register_driver,	 * so that's okay too.  The only worry is that someone might	 * get given an attach twice if they registered just before	 * this function gets called. */	/* Hmm, this could be fixed with a generation number..	 * FIXME */	attach = kmalloc (sizeof (void(*)(struct parport *)) * count,			  GFP_KERNEL);	if (!attach) {		printk (KERN_WARNING "parport: not enough memory to attach\n");		return;	}	spin_lock (&driverlist_lock);	for (i = 0, drv = driver_chain; drv && i < count; drv = drv->next)		attach[i++] = drv->attach;	spin_unlock (&driverlist_lock);	for (count = 0; count < i; count++)		(*attach[count]) (port);	kfree (attach);}/* Call detach(port) for each registered driver. */static void detach_driver_chain(struct parport *port){	struct parport_driver *drv;	spin_lock (&driverlist_lock);	for (drv = driver_chain; drv; drv = drv->next)		drv->detach (port);	spin_unlock (&driverlist_lock);}/* Ask kmod for some lowlevel drivers. */static void get_lowlevel_driver (void){	/* There is no actual module called this: you should set	 * up an alias for modutils. */	request_module ("parport_lowlevel");}/** *	parport_register_driver - register a parallel port device driver *	@drv: structure describing the driver * *	This can be called by a parallel port device driver in order *	to receive notifications about ports being found in the *	system, as well as ports no longer available. * *	The @drv structure is allocated by the caller and must not be *	deallocated until after calling parport_unregister_driver(). * *	The driver's attach() function may block.  The port that *	attach() is given will be valid for the duration of the *	callback, but if the driver wants to take a copy of the *	pointer it must call parport_get_port() to do so.  Calling *	parport_register_device() on that port will do this for you. * *	The driver's detach() function may not block.  The port that *	detach() is given will be valid for the duration of the *	callback, but if the driver wants to take a copy of the *	pointer it must call parport_get_port() to do so. * *	Returns 0 on success.  Currently it always succeeds. **/int parport_register_driver (struct parport_driver *drv){	struct parport *port;	struct parport **ports;	int count = 0, i;	if (!portlist)		get_lowlevel_driver ();	/* We have to take the portlist lock for this to be sure	 * that port is valid for the duration of the callback. */	/* This is complicated by the fact that attach must be allowed	 * to block, so we can't be holding any spinlocks when we call	 * it.  But we need to hold a spinlock to iterate over the	 * list of ports.. */	spin_lock (&parportlist_lock);	for (port = portlist; port; port = port->next)		count++;	spin_unlock (&parportlist_lock);	ports = kmalloc (sizeof (struct parport *) * count, GFP_KERNEL);	if (!ports)		printk (KERN_WARNING "parport: not enough memory to attach\n");	else {		spin_lock (&parportlist_lock);		for (i = 0, port = portlist; port && i < count;		     port = port->next)			ports[i++] = port;		spin_unlock (&parportlist_lock);		for (count = 0; count < i; count++)			drv->attach (ports[count]);		kfree (ports);	}	spin_lock (&driverlist_lock);	drv->next = driver_chain;	driver_chain = drv;	spin_unlock (&driverlist_lock);	return 0;}/** *	parport_unregister_driver - deregister a parallel port device driver *	@arg: structure describing the driver that was given to *	      parport_register_driver() * *	This should be called by a parallel port device driver that *	has registered itself using parport_register_driver() when it *	is about to be unloaded. * *	When it returns, the driver's attach() routine will no longer *	be called, and for each port that attach() was called for, the *	detach() routine will have been called. * *	If the caller's attach() function can block, it is their *	responsibility to make sure to wait for it to exit before *	unloading. * *	All the driver's detach() calls are guaranteed to have *	finished by the time this function returns. * *	The driver's detach() call is not allowed to block. **/void parport_unregister_driver (struct parport_driver *arg){	struct parport_driver *drv = driver_chain, *olddrv = NULL;	while (drv) {		if (drv == arg) {			struct parport *port;			spin_lock (&driverlist_lock);			if (olddrv)				olddrv->next = drv->next;			else				driver_chain = drv->next;			spin_unlock (&driverlist_lock);			/* Call the driver's detach routine for each			 * port to clean up any resources that the			 * attach routine acquired. */			spin_lock (&parportlist_lock);			for (port = portlist; port; port = port->next)				drv->detach (port);			spin_unlock (&parportlist_lock);			return;		}		olddrv = drv;		drv = drv->next;	}}static void free_port (struct parport *port){	int d;	for (d = 0; d < 5; d++) {		if (port->probe_info[d].class_name)			kfree (port->probe_info[d].class_name);		if (port->probe_info[d].mfr)			kfree (port->probe_info[d].mfr);		if (port->probe_info[d].model)			kfree (port->probe_info[d].model);		if (port->probe_info[d].cmdset)			kfree (port->probe_info[d].cmdset);		if (port->probe_info[d].description)			kfree (port->probe_info[d].description);	}	kfree(port->name);	kfree(port);}/** *	parport_get_port - increment a port's reference count *	@port: the port * *	This ensure's that a struct parport pointer remains valid *	until the matching parport_put_port() call. **/struct parport *parport_get_port (struct parport *port){	atomic_inc (&port->ref_count);	return port;}/** *	parport_put_port - decrement a port's reference count *	@port: the port * *	This should be called once for each call to parport_get_port(), *	once the port is no longer needed. **/void parport_put_port (struct parport *port){	if (atomic_dec_and_test (&port->ref_count))		/* Can destroy it now. */		free_port (port);	return;}/** *	parport_enumerate - return a list of the system's parallel ports * *	This returns the head of the list of parallel ports in the *	system, as a &struct parport.  The structure that is returned *	describes the first port in the list, and its 'next' member *	points to the next port, or %NULL if it's the last port. * *	If there are no parallel ports in the system, *	parport_enumerate() will return %NULL. **/struct parport *parport_enumerate(void){	/* Don't use this: use parport_register_driver instead. */	if (!portlist)		get_lowlevel_driver ();	return portlist;}/** *	parport_register_port - register a parallel port *	@base: base I/O address *	@irq: IRQ line *	@dma: DMA channel *	@ops: pointer to the port driver's port operations structure * *	When a parallel port (lowlevel) driver finds a port that *	should be made available to parallel port device drivers, it *	should call parport_register_port().  The @base, @irq, and *	@dma parameters are for the convenience of port drivers, and *	for ports where they aren't meaningful needn't be set to *	anything special.  They can be altered afterwards by adjusting *	the relevant members of the parport structure that is returned *	and represents the port.  They should not be tampered with *	after calling parport_announce_port, however. * *	If there are parallel port device drivers in the system that *	have registered themselves using parport_register_driver(), *	they are not told about the port at this time; that is done by *	parport_announce_port(). * *	The @ops structure is allocated by the caller, and must not be *	deallocated before calling parport_unregister_port(). *

⌨️ 快捷键说明

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