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(®istration_lock); list_for_each_entry(port, &portlist, list) drv->attach(port); list_add(&drv->list, &drivers); up(®istration_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(®istration_lock); list_del_init(&drv->list); list_for_each_entry(port, &portlist, list) drv->detach(port); up(®istration_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(®istration_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(®istration_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(®istration_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(®istration_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 + -
显示快捷键?