📄 share.c
字号:
/* $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 + -