share.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,016 行 · 第 1/2 页

C
1,016
字号
/* $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/module.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/slab.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 LIST_HEAD(portlist);static spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;/* list of all allocated ports, sorted by ->number */static LIST_HEAD(all_ports);static spinlock_t full_list_lock = SPIN_LOCK_UNLOCKED;static LIST_HEAD(drivers);static DECLARE_MUTEX(registration_lock);/* 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 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 = {	.write_data	= dead_write_lines,	/* data */	.read_data	= dead_read_lines,	.write_control	= dead_write_lines,	/* control */	.read_control	= dead_read_lines,	.frob_control	= dead_frob_lines,	.read_status	= dead_read_lines,	/* status */	.enable_irq	= dead_onearg,		/* enable_irq */	.disable_irq	= dead_onearg,		/* disable_irq */	.data_forward	= dead_onearg,		/* data_forward */	.data_reverse	= dead_onearg,		/* data_reverse */	.init_state	= dead_initstate,	/* init_state */	.save_state	= dead_state,	.restore_state	= dead_state,	.epp_write_data	= dead_write,		/* epp */	.epp_read_data	= dead_read,	.epp_write_addr	= dead_write,	.epp_read_addr	= dead_read,	.ecp_write_data	= dead_write,		/* ecp */	.ecp_read_data	= dead_read,	.ecp_write_addr	= dead_write, 	.compat_write_data	= dead_write,	/* compat */	.nibble_read_data	= dead_read,	/* nibble */	.byte_read_data		= dead_read,	/* byte */	.owner		= NULL,};/* Call attach(port) for each registered driver. */static void attach_driver_chain(struct parport *port){	/* caller has exclusive registration_lock */	struct parport_driver *drv;	list_for_each_entry(drv, &drivers, list)		drv->attach(port);}/* Call detach(port) for each registered driver. */static void detach_driver_chain(struct parport *port){	struct parport_driver *drv;	/* caller has exclusive registration_lock */	list_for_each_entry(drv, &drivers, list)		drv->detach (port);}/* 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 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;	if (list_empty(&portlist))		get_lowlevel_driver ();	down(&registration_lock);	list_for_each_entry(port, &portlist, list)		drv->attach(port);	list_add(&drv->list, &drivers);	up(&registration_lock);	return 0;}/** *	parport_unregister_driver - deregister a parallel port device driver *	@drv: 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. * *	All the driver's attach() and detach() calls are guaranteed to have *	finished by the time this function returns. **/void parport_unregister_driver (struct parport_driver *drv){	struct parport *port;	down(&registration_lock);	list_del_init(&drv->list);	list_for_each_entry(port, &portlist, list)		drv->detach(port);	up(&registration_lock);}static void free_port (struct parport *port){	int d;	spin_lock(&full_list_lock);	list_del(&port->full_list);	spin_unlock(&full_list_lock);	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_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_remove_port(). * *	If there is no memory to allocate a new parport structure, *	this function will return %NULL. **/struct parport *parport_register_port(unsigned long base, int irq, int dma,				      struct parport_operations *ops){	struct list_head *l;	struct parport *tmp;	int num;	int device;	char *name;	tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);	if (!tmp) {		printk(KERN_WARNING "parport: memory squeeze\n");		return NULL;	}	/* Init our structure */ 	memset(tmp, 0, sizeof(struct parport));	tmp->base = base;	tmp->irq = irq;	tmp->dma = dma;	tmp->muxport = tmp->daisy = tmp->muxsel = -1;	tmp->modes = 0; 	INIT_LIST_HEAD(&tmp->list);	tmp->devices = tmp->cad = NULL;	tmp->flags = 0;	tmp->ops = ops;	tmp->physport = tmp;	memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));	tmp->cad_lock = RW_LOCK_UNLOCKED;	spin_lock_init(&tmp->waitlist_lock);	spin_lock_init(&tmp->pardevice_lock);	tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;	tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;	init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */	tmp->spintime = parport_default_spintime;	atomic_set (&tmp->ref_count, 1);	INIT_LIST_HEAD(&tmp->full_list);	name = kmalloc(15, GFP_KERNEL);	if (!name) {		printk(KERN_ERR "parport: memory squeeze\n");		kfree(tmp);		return NULL;	}	/* Search for the lowest free parport number. */	spin_lock(&full_list_lock);	for (l = all_ports.next, num = 0; l != &all_ports; l = l->next, num++) {		struct parport *p = list_entry(l, struct parport, full_list);		if (p->number != num)			break;	}	tmp->portnum = tmp->number = num;	list_add_tail(&tmp->full_list, l);	spin_unlock(&full_list_lock);	/*	 * Now that the portnum is known finish doing the Init.	 */	sprintf(name, "parport%d", tmp->portnum = tmp->number);	tmp->name = name;	for (device = 0; device < 5; device++)		/* assume the worst */		tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;	tmp->waithead = tmp->waittail = NULL;	return tmp;}/** *	parport_announce_port - tell device drivers about a parallel port *	@port: parallel port to announce * *	After a port driver has registered a parallel port with *	parport_register_port, and performed any necessary *	initialisation or adjustments, it should call *	parport_announce_port() in order to notify all device drivers *	that have called parport_register_driver().  Their attach() *	functions will be called, with @port as the parameter. **/void parport_announce_port (struct parport *port){	int i;#ifdef CONFIG_PARPORT_1284	/* Analyse the IEEE1284.3 topology of the port. */	parport_daisy_init(port);#endif	parport_proc_register(port);	down(&registration_lock);	spin_lock_irq(&parportlist_lock);	list_add_tail(&port->list, &portlist);	for (i = 1; i < 3; i++) {		struct parport *slave = port->slaves[i-1];		if (slave)			list_add_tail(&slave->list, &portlist);	}	spin_unlock_irq(&parportlist_lock);	/* Let drivers know that new port(s) has arrived. */	attach_driver_chain (port);	for (i = 1; i < 3; i++) {		struct parport *slave = port->slaves[i-1];		if (slave)			attach_driver_chain(slave);	}	up(&registration_lock);}/** *	parport_remove_port - deregister a parallel port *	@port: parallel port to deregister * *	When a parallel port driver is forcibly unloaded, or a *	parallel port becomes inaccessible, the port driver must call *	this function in order to deal with device drivers that still *	want to use it. * *	The parport structure associated with the port has its *	operations structure replaced with one containing 'null' *	operations that return errors or just don't do anything. * *	Any drivers that have registered themselves using *	parport_register_driver() are notified that the port is no *	longer accessible by having their detach() routines called *	with @port as the parameter. **/void parport_remove_port(struct parport *port){	int i;	down(&registration_lock);	/* Spread the word. */	detach_driver_chain (port);#ifdef CONFIG_PARPORT_1284	/* Forget the IEEE1284.3 topology of the port. */	parport_daisy_fini(port);	for (i = 1; i < 3; i++) {		struct parport *slave = port->slaves[i-1];		if (!slave)			continue;		detach_driver_chain(slave);		parport_daisy_fini(slave);	}#endif	port->ops = &dead_ops;	spin_lock(&parportlist_lock);	list_del_init(&port->list);	for (i = 1; i < 3; i++) {		struct parport *slave = port->slaves[i-1];		if (slave)			list_del_init(&slave->list);	}	spin_unlock(&parportlist_lock);	up(&registration_lock);	parport_proc_unregister(port);	for (i = 1; i < 3; i++) {		struct parport *slave = port->slaves[i-1];		if (slave)			parport_put_port(slave);	}}/** *	parport_register_device - register a device on a parallel port *	@port: port to which the device is attached *	@name: a name to refer to the device *	@pf: preemption callback *	@kf: kick callback (wake-up) *	@irq_func: interrupt handler *	@flags: registration flags *	@handle: data for callback functions * *	This function, called by parallel port device drivers, *	declares that a device is connected to a port, and tells the *	system all it needs to know. * *	The @name is allocated by the caller and must not be *	deallocated until the caller calls @parport_unregister_device *	for that device. * *	The preemption callback function, @pf, is called when this *	device driver has claimed access to the port but another *	device driver wants to use it.  It is given @handle as its *	parameter, and should return zero if it is willing for the *	system to release the port to another driver on its behalf. *	If it wants to keep control of the port it should return *	non-zero, and no action will be taken.  It is good manners for *	the driver to try to release the port at the earliest *	opportunity after its preemption callback rejects a preemption *	attempt.  Note that if a preemption callback is happy for *	preemption to go ahead, there is no need to release the port; *	it is done automatically.  This function may not block, as it *	may be called from interrupt context.  If the device driver *	does not support preemption, @pf can be %NULL. * *	The wake-up ("kick") callback function, @kf, is called when *	the port is available to be claimed for exclusive access; that *	is, parport_claim() is guaranteed to succeed when called from *	inside the wake-up callback function.  If the driver wants to *	claim the port it should do so; otherwise, it need not take *	any action.  This function may not block, as it may be called *	from interrupt context.  If the device driver does not want to *	be explicitly invited to claim the port in this way, @kf can *	be %NULL. * *	The interrupt handler, @irq_func, is called when an interrupt *	arrives from the parallel port.  Note that if a device driver *	wants to use interrupts it should use parport_enable_irq(), *	and can also check the irq member of the parport structure *	representing the port. * *	The parallel port (lowlevel) driver is the one that has called *	request_irq() and whose interrupt handler is called first. *	This handler does whatever needs to be done to the hardware to *	acknowledge the interrupt (for PC-style ports there is nothing *	special to be done).  It then tells the IEEE 1284 code about

⌨️ 快捷键说明

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