share.c

来自「linux 内核源代码」· C语言 代码 · 共 1,026 行 · 第 1/2 页

C
1,026
字号
 *	The %PARPORT_DEV_EXCL flag is for preventing port sharing, and *	so should only be used when sharing the port with other device *	drivers is impossible and would lead to incorrect behaviour. *	Use it sparingly!  Normally, @flags will be zero. * *	This function returns a pointer to a structure that represents *	the device on the port, or %NULL if there is not enough memory *	to allocate space for that structure. **/struct pardevice *parport_register_device(struct parport *port, const char *name,			int (*pf)(void *), void (*kf)(void *),			void (*irq_func)(void *), 			int flags, void *handle){	struct pardevice *tmp;	if (port->physport->flags & PARPORT_FLAG_EXCL) {		/* An exclusive device is registered. */		printk (KERN_DEBUG "%s: no more devices allowed\n",			port->name);		return NULL;	}	if (flags & PARPORT_DEV_LURK) {		if (!pf || !kf) {			printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name);			return NULL;		}	}	/* We up our own module reference count, and that of the port           on which a device is to be registered, to ensure that           neither of us gets unloaded while we sleep in (e.g.)           kmalloc.         */	if (!try_module_get(port->ops->owner)) {		return NULL;	}			parport_get_port (port);	tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);	if (tmp == NULL) {		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);		goto out;	}	tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);	if (tmp->state == NULL) {		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);		goto out_free_pardevice;	}	tmp->name = name;	tmp->port = port;	tmp->daisy = -1;	tmp->preempt = pf;	tmp->wakeup = kf;	tmp->private = handle;	tmp->flags = flags;	tmp->irq_func = irq_func;	tmp->waiting = 0;	tmp->timeout = 5 * HZ;	/* Chain this onto the list */	tmp->prev = NULL;	/*	 * This function must not run from an irq handler so we don' t need	 * to clear irq on the local CPU. -arca	 */	spin_lock(&port->physport->pardevice_lock);	if (flags & PARPORT_DEV_EXCL) {		if (port->physport->devices) {			spin_unlock (&port->physport->pardevice_lock);			printk (KERN_DEBUG				"%s: cannot grant exclusive access for "				"device %s\n", port->name, name);			goto out_free_all;		}		port->flags |= PARPORT_FLAG_EXCL;	}	tmp->next = port->physport->devices;	wmb(); /* Make sure that tmp->next is written before it's                  added to the list; see comments marked 'no locking                  required' */	if (port->physport->devices)		port->physport->devices->prev = tmp;	port->physport->devices = tmp;	spin_unlock(&port->physport->pardevice_lock);	init_waitqueue_head(&tmp->wait_q);	tmp->timeslice = parport_default_timeslice;	tmp->waitnext = tmp->waitprev = NULL;	/*	 * This has to be run as last thing since init_state may need other	 * pardevice fields. -arca	 */	port->ops->init_state(tmp, tmp->state);	parport_device_proc_register(tmp);	return tmp; out_free_all:	kfree(tmp->state); out_free_pardevice:	kfree(tmp); out:	parport_put_port (port);	module_put(port->ops->owner);	return NULL;}/** *	parport_unregister_device - deregister a device on a parallel port *	@dev: pointer to structure representing device * *	This undoes the effect of parport_register_device(). **/void parport_unregister_device(struct pardevice *dev){	struct parport *port;#ifdef PARPORT_PARANOID	if (dev == NULL) {		printk(KERN_ERR "parport_unregister_device: passed NULL\n");		return;	}#endif	parport_device_proc_unregister(dev);	port = dev->port->physport;	if (port->cad == dev) {		printk(KERN_DEBUG "%s: %s forgot to release port\n",		       port->name, dev->name);		parport_release (dev);	}	spin_lock(&port->pardevice_lock);	if (dev->next)		dev->next->prev = dev->prev;	if (dev->prev)		dev->prev->next = dev->next;	else		port->devices = dev->next;	if (dev->flags & PARPORT_DEV_EXCL)		port->flags &= ~PARPORT_FLAG_EXCL;	spin_unlock(&port->pardevice_lock);	/* Make sure we haven't left any pointers around in the wait	 * list. */	spin_lock (&port->waitlist_lock);	if (dev->waitprev || dev->waitnext || port->waithead == dev) {		if (dev->waitprev)			dev->waitprev->waitnext = dev->waitnext;		else			port->waithead = dev->waitnext;		if (dev->waitnext)			dev->waitnext->waitprev = dev->waitprev;		else			port->waittail = dev->waitprev;	}	spin_unlock (&port->waitlist_lock);	kfree(dev->state);	kfree(dev);	module_put(port->ops->owner);	parport_put_port (port);}/** *	parport_find_number - find a parallel port by number *	@number: parallel port number * *	This returns the parallel port with the specified number, or *	%NULL if there is none. * *	There is an implicit parport_get_port() done already; to throw *	away the reference to the port that parport_find_number() *	gives you, use parport_put_port(). */struct parport *parport_find_number (int number){	struct parport *port, *result = NULL;	if (list_empty(&portlist))		get_lowlevel_driver ();	spin_lock (&parportlist_lock);	list_for_each_entry(port, &portlist, list) {		if (port->number == number) {			result = parport_get_port (port);			break;		}	}	spin_unlock (&parportlist_lock);	return result;}/** *	parport_find_base - find a parallel port by base address *	@base: base I/O address * *	This returns the parallel port with the specified base *	address, or %NULL if there is none. * *	There is an implicit parport_get_port() done already; to throw *	away the reference to the port that parport_find_base() *	gives you, use parport_put_port(). */struct parport *parport_find_base (unsigned long base){	struct parport *port, *result = NULL;	if (list_empty(&portlist))		get_lowlevel_driver ();	spin_lock (&parportlist_lock);	list_for_each_entry(port, &portlist, list) {		if (port->base == base) {			result = parport_get_port (port);			break;		}	}	spin_unlock (&parportlist_lock);	return result;}/** *	parport_claim - claim access to a parallel port device *	@dev: pointer to structure representing a device on the port * *	This function will not block and so can be used from interrupt *	context.  If parport_claim() succeeds in claiming access to *	the port it returns zero and the port is available to use.  It *	may fail (returning non-zero) if the port is in use by another *	driver and that driver is not willing to relinquish control of *	the port. **/int parport_claim(struct pardevice *dev){	struct pardevice *oldcad;	struct parport *port = dev->port->physport;	unsigned long flags;	if (port->cad == dev) {		printk(KERN_INFO "%s: %s already owner\n",		       dev->port->name,dev->name);		return 0;	}	/* Preempt any current device */	write_lock_irqsave (&port->cad_lock, flags);	if ((oldcad = port->cad) != NULL) {		if (oldcad->preempt) {			if (oldcad->preempt(oldcad->private))				goto blocked;			port->ops->save_state(port, dev->state);		} else			goto blocked;		if (port->cad != oldcad) {			/* I think we'll actually deadlock rather than                           get here, but just in case.. */			printk(KERN_WARNING			       "%s: %s released port when preempted!\n",			       port->name, oldcad->name);			if (port->cad)				goto blocked;		}	}	/* Can't fail from now on, so mark ourselves as no longer waiting.  */	if (dev->waiting & 1) {		dev->waiting = 0;		/* Take ourselves out of the wait list again.  */		spin_lock_irq (&port->waitlist_lock);		if (dev->waitprev)			dev->waitprev->waitnext = dev->waitnext;		else			port->waithead = dev->waitnext;		if (dev->waitnext)			dev->waitnext->waitprev = dev->waitprev;		else			port->waittail = dev->waitprev;		spin_unlock_irq (&port->waitlist_lock);		dev->waitprev = dev->waitnext = NULL;	}	/* Now we do the change of devices */	port->cad = dev;#ifdef CONFIG_PARPORT_1284	/* If it's a mux port, select it. */	if (dev->port->muxport >= 0) {		/* FIXME */		port->muxsel = dev->port->muxport;	}	/* If it's a daisy chain device, select it. */	if (dev->daisy >= 0) {		/* This could be lazier. */		if (!parport_daisy_select (port, dev->daisy,					   IEEE1284_MODE_COMPAT))			port->daisy = dev->daisy;	}#endif /* IEEE1284.3 support */	/* Restore control registers */	port->ops->restore_state(port, dev->state);	write_unlock_irqrestore(&port->cad_lock, flags);	dev->time = jiffies;	return 0;blocked:	/* If this is the first time we tried to claim the port, register an	   interest.  This is only allowed for devices sleeping in	   parport_claim_or_block(), or those with a wakeup function.  */	/* The cad_lock is still held for writing here */	if (dev->waiting & 2 || dev->wakeup) {		spin_lock (&port->waitlist_lock);		if (test_and_set_bit(0, &dev->waiting) == 0) {			/* First add ourselves to the end of the wait list. */			dev->waitnext = NULL;			dev->waitprev = port->waittail;			if (port->waittail) {				port->waittail->waitnext = dev;				port->waittail = dev;			} else				port->waithead = port->waittail = dev;		}		spin_unlock (&port->waitlist_lock);	}	write_unlock_irqrestore (&port->cad_lock, flags);	return -EAGAIN;}/** *	parport_claim_or_block - claim access to a parallel port device *	@dev: pointer to structure representing a device on the port * *	This behaves like parport_claim(), but will block if necessary *	to wait for the port to be free.  A return value of 1 *	indicates that it slept; 0 means that it succeeded without *	needing to sleep.  A negative error code indicates failure. **/int parport_claim_or_block(struct pardevice *dev){	int r;	/* Signal to parport_claim() that we can wait even without a	   wakeup function.  */	dev->waiting = 2;	/* Try to claim the port.  If this fails, we need to sleep.  */	r = parport_claim(dev);	if (r == -EAGAIN) {#ifdef PARPORT_DEBUG_SHARING		printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name);#endif		/*		 * FIXME!!! Use the proper locking for dev->waiting,		 * and make this use the "wait_event_interruptible()"		 * interfaces. The cli/sti that used to be here		 * did nothing.		 *		 * See also parport_release()		 */		/* If dev->waiting is clear now, an interrupt		   gave us the port and we would deadlock if we slept.  */		if (dev->waiting) {			interruptible_sleep_on (&dev->wait_q);			if (signal_pending (current)) {				return -EINTR;			}			r = 1;		} else {			r = 0;#ifdef PARPORT_DEBUG_SHARING			printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n",			       dev->name);#endif		}#ifdef PARPORT_DEBUG_SHARING		if (dev->port->physport->cad != dev)			printk(KERN_DEBUG "%s: exiting parport_claim_or_block "			       "but %s owns port!\n", dev->name,			       dev->port->physport->cad ?			       dev->port->physport->cad->name:"nobody");#endif	}	dev->waiting = 0;	return r;}/** *	parport_release - give up access to a parallel port device *	@dev: pointer to structure representing parallel port device * *	This function cannot fail, but it should not be called without *	the port claimed.  Similarly, if the port is already claimed *	you should not try claiming it again. **/void parport_release(struct pardevice *dev){	struct parport *port = dev->port->physport;	struct pardevice *pd;	unsigned long flags;	/* Make sure that dev is the current device */	write_lock_irqsave(&port->cad_lock, flags);	if (port->cad != dev) {		write_unlock_irqrestore (&port->cad_lock, flags);		printk(KERN_WARNING "%s: %s tried to release parport "		       "when not owner\n", port->name, dev->name);		return;	}#ifdef CONFIG_PARPORT_1284	/* If this is on a mux port, deselect it. */	if (dev->port->muxport >= 0) {		/* FIXME */		port->muxsel = -1;	}	/* If this is a daisy device, deselect it. */	if (dev->daisy >= 0) {		parport_daisy_deselect_all (port);		port->daisy = -1;	}#endif	port->cad = NULL;	write_unlock_irqrestore(&port->cad_lock, flags);	/* Save control registers */	port->ops->save_state(port, dev->state);	/* If anybody is waiting, find out who's been there longest and	   then wake them up. (Note: no locking required) */	/* !!! LOCKING IS NEEDED HERE */	for (pd = port->waithead; pd; pd = pd->waitnext) {		if (pd->waiting & 2) { /* sleeping in claim_or_block */			parport_claim(pd);			if (waitqueue_active(&pd->wait_q))				wake_up_interruptible(&pd->wait_q);			return;		} else if (pd->wakeup) {			pd->wakeup(pd->private);			if (dev->port->cad) /* racy but no matter */				return;		} else {			printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);		}	}	/* Nobody was waiting, so walk the list to see if anyone is	   interested in being woken up. (Note: no locking required) */	/* !!! LOCKING IS NEEDED HERE */	for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {		if (pd->wakeup && pd != dev)			pd->wakeup(pd->private);	}}irqreturn_t parport_irq_handler(int irq, void *dev_id){	struct parport *port = dev_id;	parport_generic_irq(port);	return IRQ_HANDLED;}/* Exported symbols for modules. */EXPORT_SYMBOL(parport_claim);EXPORT_SYMBOL(parport_claim_or_block);EXPORT_SYMBOL(parport_release);EXPORT_SYMBOL(parport_register_port);EXPORT_SYMBOL(parport_announce_port);EXPORT_SYMBOL(parport_remove_port);EXPORT_SYMBOL(parport_register_driver);EXPORT_SYMBOL(parport_unregister_driver);EXPORT_SYMBOL(parport_register_device);EXPORT_SYMBOL(parport_unregister_device);EXPORT_SYMBOL(parport_get_port);EXPORT_SYMBOL(parport_put_port);EXPORT_SYMBOL(parport_find_number);EXPORT_SYMBOL(parport_find_base);EXPORT_SYMBOL(parport_irq_handler);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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