cregit-Linux how code gets into the kernel

Release 4.11 drivers/parport/share.c

Directory: drivers/parport
/*
 * 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/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/signal.h>
#include <linux/kmod.h>
#include <linux/device.h>

#include <linux/spinlock.h>
#include <linux/mutex.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 DEFINE_SPINLOCK(parportlist_lock);

/* list of all allocated ports, sorted by ->number */
static LIST_HEAD(all_ports);
static DEFINE_SPINLOCK(full_list_lock);

static LIST_HEAD(drivers);

static DEFINE_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){}

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14100.00%1100.00%
Total14100.00%1100.00%


static unsigned char dead_read_lines(struct parport *p) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15100.00%1100.00%
Total15100.00%1100.00%


static unsigned char dead_frob_lines(struct parport *p, unsigned char b, unsigned char c) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)23100.00%1100.00%
Total23100.00%1100.00%


static void dead_onearg(struct parport *p){}

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10100.00%1100.00%
Total10100.00%1100.00%


static void dead_initstate(struct pardevice *d, struct parport_state *s) { }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15100.00%1100.00%
Total15100.00%1100.00%


static void dead_state(struct parport *p, struct parport_state *s) { }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15100.00%1100.00%
Total15100.00%1100.00%


static size_t dead_write(struct parport *p, const void *b, size_t l, int f) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)25100.00%1100.00%
Total25100.00%1100.00%


static size_t dead_read(struct parport *p, void *b, size_t l, int f) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)24100.00%1100.00%
Total24100.00%1100.00%

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, }; static struct device_type parport_device_type = { .name = "parport", };
static int is_parport(struct device *dev) { return dev->type == &parport_device_type; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee19100.00%1100.00%
Total19100.00%1100.00%


static int parport_probe(struct device *dev) { struct parport_driver *drv; if (is_parport(dev)) return -ENODEV; drv = to_parport_driver(dev->driver); if (!drv->probe) { /* if driver has not defined a custom probe */ struct pardevice *par_dev = to_pardevice(dev); if (strcmp(par_dev->name, drv->name)) return -ENODEV; return 0; } /* if driver defined its own probe */ return drv->probe(to_pardevice(dev)); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee88100.00%1100.00%
Total88100.00%1100.00%

static struct bus_type parport_bus_type = { .name = "parport", .probe = parport_probe, };
int parport_bus_init(void) { return bus_register(&parport_bus_type); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee14100.00%1100.00%
Total14100.00%1100.00%


void parport_bus_exit(void) { bus_unregister(&parport_bus_type); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee13100.00%1100.00%
Total13100.00%1100.00%

/* * iterates through all the drivers registered with the bus and sends the port * details to the match_port callback of the driver, so that the driver can * know about the new port that just registered with the bus and decide if it * wants to use this new port. */
static int driver_check(struct device_driver *dev_drv, void *_port) { struct parport *port = _port; struct parport_driver *drv = to_parport_driver(dev_drv); if (drv->match_port) drv->match_port(port); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee48100.00%1100.00%
Total48100.00%1100.00%

/* 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 the driver_check function of the drivers registered in * new device model */ bus_for_each_drv(&parport_bus_type, NULL, port, driver_check); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2248.89%240.00%
Sudip Mukherjee1431.11%120.00%
Al Viro920.00%240.00%
Total45100.00%5100.00%


static int driver_detach(struct device_driver *_drv, void *_port) { struct parport *port = _port; struct parport_driver *drv = to_parport_driver(_drv); if (drv->detach) drv->detach(port); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee4797.92%150.00%
Linus Torvalds (pre-git)12.08%150.00%
Total48100.00%2100.00%

/* 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); /* * call the detach function of the drivers registered in * new device model */ bus_for_each_drv(&parport_bus_type, NULL, port, driver_detach); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2351.11%250.00%
Sudip Mukherjee1328.89%125.00%
Al Viro920.00%125.00%
Total45100.00%4100.00%

/* 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"); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1392.86%150.00%
Sudip Mukherjee17.14%150.00%
Total14100.00%2100.00%

/* * iterates through all the devices connected to the bus and sends the device * details to the match_port callback of the driver, so that the driver can * know what are all the ports that are connected to the bus and choose the * port to which it wants to register its device. */
static int port_check(struct device *dev, void *dev_drv) { struct parport_driver *drv = dev_drv; /* only send ports, do not send other devices connected to bus */ if (is_parport(dev)) drv->match_port(to_parport_dev(dev)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee3581.40%150.00%
Linus Torvalds (pre-git)818.60%150.00%
Total43100.00%2100.00%

/** * parport_register_driver - register a parallel port device driver * @drv: structure describing the driver * @owner: owner module of drv * @mod_name: module name string * * 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. * * If devmodel is true then the new device model is used * for registration. * * The @drv structure is allocated by the caller and must not be * deallocated until after calling parport_unregister_driver(). * * If using the non device model: * 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. The non device model will always succeeds. * but the new device model can fail and will return the error code. **/
int __parport_register_driver(struct parport_driver *drv, struct module *owner, const char *mod_name) { if (list_empty(&portlist)) get_lowlevel_driver(); if (drv->devmodel) { /* using device model */ int ret; /* initialize common driver fields */ drv->driver.name = drv->name; drv->driver.bus = &parport_bus_type; drv->driver.owner = owner; drv->driver.mod_name = mod_name; ret = driver_register(&drv->driver); if (ret) return ret; mutex_lock(&registration_lock); if (drv->match_port) bus_for_each_dev(&parport_bus_type, NULL, drv, port_check); mutex_unlock(&registration_lock); } else { struct parport *port; drv->devmodel = false; mutex_lock(&registration_lock); list_for_each_entry(port, &portlist, list) drv->attach(port); list_add(&drv->list, &drivers); mutex_unlock(&registration_lock); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee13272.93%112.50%
Linus Torvalds (pre-git)2413.26%337.50%
Al Viro2312.71%337.50%
Ingo Molnar21.10%112.50%
Total181100.00%8100.00%

EXPORT_SYMBOL(__parport_register_driver);
static int port_detach(struct device *dev, void *_drv) { struct parport_driver *drv = _drv; if (is_parport(dev) && drv->detach) drv->detach(to_parport_dev(dev)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee4291.30%150.00%
Linus Torvalds (pre-git)48.70%150.00%
Total46100.00%2100.00%

/** * 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; mutex_lock(&registration_lock); if (drv->devmodel) { bus_for_each_dev(&parport_bus_type, NULL, drv, port_detach); driver_unregister(&drv->driver); } else { list_del_init(&drv->list); list_for_each_entry(port, &portlist, list) drv->detach(port); } mutex_unlock(&registration_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro3543.21%342.86%
Sudip Mukherjee3138.27%114.29%
Linus Torvalds (pre-git)1316.05%228.57%
Ingo Molnar22.47%114.29%
Total81100.00%7100.00%

EXPORT_SYMBOL(parport_unregister_driver);
static void free_port(struct device *dev) { int d; struct parport *port = to_parport_dev(dev); spin_lock(&full_list_lock); list_del(&port->full_list); spin_unlock(&full_list_lock); for (d = 0; d < 5; d++) { kfree(port->probe_info[d].class_name); kfree(port->probe_info[d].mfr); kfree(port->probe_info[d].model); kfree(port->probe_info[d].cmdset); kfree(port->probe_info[d].description); } kfree(port->name); kfree(port); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9975.57%360.00%
Al Viro2015.27%120.00%
Sudip Mukherjee129.16%120.00%
Total131100.00%5100.00%

/** * parport_get_port - increment a port's reference count * @port: the port * * This ensures that a struct parport pointer remains valid * until the matching parport_put_port() call. **/
struct parport *parport_get_port(struct parport *port) { struct device *dev = get_device(&port->bus_dev); return to_parport_dev(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1961.29%266.67%
Sudip Mukherjee1238.71%133.33%
Total31100.00%3100.00%

EXPORT_SYMBOL(parport_get_port);
void parport_del_port(struct parport *port) { device_unregister(&port->bus_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1583.33%480.00%
Sudip Mukherjee316.67%120.00%
Total18100.00%5100.00%

EXPORT_SYMBOL(parport_del_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. When the reference count reaches * zero (port is no longer used), free_port is called. **/
void parport_put_port(struct parport *port) { put_device(&port->bus_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee18100.00%1100.00%
Total18100.00%1100.00%

EXPORT_SYMBOL(parport_put_port); /** * 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; int ret; tmp = kzalloc(sizeof(struct parport), GFP_KERNEL); if (!tmp) return NULL; /* Init our structure */ 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)); rwlock_init(&tmp->cad_lock); 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; sema_init(&tmp->ieee1284.irq, 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) { 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; tmp->bus_dev.bus = &parport_bus_type; tmp->bus_dev.release = free_port; dev_set_name(&tmp->bus_dev, name); tmp->bus_dev.type = &parport_device_type; for (device = 0; device < 5; device++) /* assume the worst */ tmp->probe_info[device].class = PARPORT_CLASS_LEGACY; tmp->waithead = tmp->waittail = NULL; ret = device_register(&tmp->bus_dev); if (ret) { put_device(&tmp->bus_dev); return NULL; } return tmp; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)28059.96%956.25%
Al Viro7616.27%212.50%
Sudip Mukherjee6814.56%16.25%
Alan Cox357.49%16.25%
Thomas Gleixner71.50%212.50%
Alexandru Gheorghiu10.21%16.25%
Total467100.00%16100.00%

EXPORT_SYMBOL(parport_register_port); /** * 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 if (!port->dev) printk(KERN_WARNING "%s: fix this legacy no-device port driver!\n", port->name); parport_proc_register(port); mutex_lock(&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); } mutex_unlock(&registration_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro12473.37%433.33%
Linus Torvalds (pre-git)2615.38%541.67%
David Brownell169.47%18.33%
Ingo Molnar21.18%18.33%
Sudip Mukherjee10.59%18.33%
Total169100.00%12100.00%

EXPORT_SYMBOL(parport_announce_port); /** * 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; mutex_lock(&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); mutex_unlock(&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); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro19598.48%571.43%
Ingo Molnar21.01%114.29%
Linus Torvalds (pre-git)10.51%114.29%
Total198100.00%7100.00%

EXPORT_SYMBOL(parport_remove_port); /** * 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 * the interrupt, which may involve reacting to an IEEE 1284 * event depending on the current IEEE 1284 phase. After this, * it calls @irq_func. Needless to say, @irq_func will be called * from interrupt context, and may not block. * * 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; } } if (flags & PARPORT_DEV_EXCL) { if (port->physport->devices) { /* * If a device is already registered and this new * device wants exclusive access, then no need to * continue as we can not grant exclusive access to * this device. */ pr_err("%s: cannot grant exclusive access for device %s\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) goto out; tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); if (!tmp->state) 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; tmp->devmodel = false; /* 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); if (!test_and_set_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags)) { port->proc_device = tmp; 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; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee47894.47%562.50%
Linus Torvalds (pre-git)285.53%337.50%
Total506100.00%8100.00%

EXPORT_SYMBOL(parport_register_device);
static void free_pardevice(struct device *dev) { struct pardevice *par_dev = to_pardevice(dev); kfree(par_dev->name); kfree(par_dev); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee33100.00%1100.00%
Total33100.00%1100.00%


struct pardevice * parport_register_dev_model(struct parport *port, const char *name, const struct pardev_cb *par_dev_cb, int id) { struct pardevice *par_dev; int ret; char *devname; if (port->physport->flags & PARPORT_FLAG_EXCL) { /* An exclusive device is registered. */ pr_err("%s: no more devices allowed\n", port->name); return NULL; } if (par_dev_cb->flags & PARPORT_DEV_LURK) { if (!par_dev_cb->preempt || !par_dev_cb->wakeup) { pr_info("%s: refused to register lurking device (%s) without callbacks\n", port->name, name); return NULL; } } if (par_dev_cb->flags & PARPORT_DEV_EXCL) { if (port->physport->devices) { /* * If a device is already registered and this new * device wants exclusive access, then no need to * continue as we can not grant exclusive access to * this device. */ pr_err("%s: cannot grant exclusive access for device %s\n", port->name, name); return NULL; } } if (!try_module_get(port->ops->owner)) return NULL; parport_get_port(port); par_dev = kzalloc(sizeof(*par_dev), GFP_KERNEL); if (!par_dev) goto err_put_port; par_dev->state = kzalloc(sizeof(*par_dev->state), GFP_KERNEL); if (!par_dev->state) goto err_put_par_dev; devname = kstrdup(name, GFP_KERNEL); if (!devname) goto err_free_par_dev; par_dev->name = devname; par_dev->port = port; par_dev->daisy = -1; par_dev->preempt = par_dev_cb->preempt; par_dev->wakeup = par_dev_cb->wakeup; par_dev->private = par_dev_cb->private; par_dev->flags = par_dev_cb->flags; par_dev->irq_func = par_dev_cb->irq_func; par_dev->waiting = 0; par_dev->timeout = 5 * HZ; par_dev->dev.parent = &port->bus_dev; par_dev->dev.bus = &parport_bus_type; ret = dev_set_name(&par_dev->dev, "%s.%d", devname, id); if (ret) goto err_free_devname; par_dev->dev.release = free_pardevice; par_dev->devmodel = true; ret = device_register(&par_dev->dev); if (ret) { put_device(&par_dev->dev); goto err_put_port; } /* Chain this onto the list */ par_dev->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 (par_dev_cb->flags & PARPORT_DEV_EXCL) { if (port->physport->devices) { spin_unlock(&port->physport->pardevice_lock); pr_debug("%s: cannot grant exclusive access for device %s\n", port->name, name); device_unregister(&par_dev->dev); goto err_put_port; } port->flags |= PARPORT_FLAG_EXCL; } par_dev->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 = par_dev; port->physport->devices = par_dev; spin_unlock(&port->physport->pardevice_lock); init_waitqueue_head(&par_dev->wait_q); par_dev->timeslice = parport_default_timeslice; par_dev->waitnext = NULL; par_dev->waitprev = NULL; /* * This has to be run as last thing since init_state may need other * pardevice fields. -arca */ port->ops->init_state(par_dev, par_dev->state); if (!test_and_set_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags)) { port->proc_device = par_dev; parport_device_proc_register(par_dev); } return par_dev; err_free_devname: kfree(devname); err_free_par_dev: kfree(par_dev->state); err_put_par_dev: if (!par_dev->devmodel) kfree(par_dev); err_put_port: parport_put_port(port); module_put(port->ops->owner); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)33153.22%1263.16%
Sudip Mukherjee26843.09%526.32%
Alan Cox233.70%210.53%
Total622100.00%19100.00%

EXPORT_SYMBOL(parport_register_dev_model); /** * 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) { printk(KERN_ERR "parport_unregister_device: passed NULL\n"); return; } #endif port = dev->port->physport; if (port->proc_device == dev) { port->proc_device = NULL; clear_bit(PARPORT_DEVPROC_REGISTERED, &port->devflags); parport_device_proc_unregister(dev); } 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_irq(&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_irq(&port->waitlist_lock); kfree(dev->state); if (dev->devmodel) device_unregister(&dev->dev); else kfree(dev); module_put(port->ops->owner); parport_put_port(port); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16454.67%853.33%
Linus Torvalds8227.33%16.67%
Alan Cox3511.67%213.33%
Sudip Mukherjee175.67%320.00%
Alexander Gordeev20.67%16.67%
Total300100.00%15100.00%

EXPORT_SYMBOL(parport_unregister_device); /** * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5371.62%250.00%
Al Viro1418.92%125.00%
Linus Torvalds79.46%125.00%
Total74100.00%4100.00%

EXPORT_SYMBOL(parport_find_number); /** * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5472.00%360.00%
Al Viro1418.67%120.00%
Linus Torvalds79.33%120.00%
Total75100.00%5100.00%

EXPORT_SYMBOL(parport_find_base); /** * 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); oldcad = port->cad; if (oldcad) { 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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)45998.71%981.82%
Sudip Mukherjee61.29%218.18%
Total465100.00%11100.00%

EXPORT_SYMBOL(parport_claim); /** * 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) { wait_event_interruptible(dev->wait_q, !dev->waiting); 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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14687.43%337.50%
Tim Waugh116.59%112.50%
Arnd Bergmann63.59%112.50%
Sudip Mukherjee31.80%225.00%
Linus Torvalds10.60%112.50%
Total167100.00%8100.00%

EXPORT_SYMBOL(parport_claim_or_block); /** * 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 && pd; pd = pd->next) { if (pd->wakeup && pd != dev) pd->wakeup(pd->private); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)29297.66%861.54%
Sudip Mukherjee41.34%323.08%
Linus Torvalds20.67%17.69%
Tim Waugh10.33%17.69%
Total299100.00%13100.00%

EXPORT_SYMBOL(parport_release);
irqreturn_t parport_irq_handler(int irq, void *dev_id) { struct parport *port = dev_id; parport_generic_irq(port); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Garzik27100.00%1100.00%
Total27100.00%1100.00%

EXPORT_SYMBOL(parport_irq_handler); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)235648.95%3244.44%
Sudip Mukherjee153731.93%1115.28%
Al Viro54211.26%79.72%
Alan Cox1683.49%22.78%
Linus Torvalds1102.29%68.33%
Jeff Garzik320.66%11.39%
David Brownell160.33%11.39%
Thomas Gleixner150.31%34.17%
Ingo Molnar130.27%22.78%
Tim Waugh120.25%11.39%
Arnd Bergmann60.12%11.39%
Alexander Gordeev20.04%11.39%
Andrew Morton10.02%11.39%
Randy Dunlap10.02%11.39%
Geliang Tang10.02%11.39%
Alexandru Gheorghiu10.02%11.39%
Total4813100.00%72100.00%
Directory: drivers/parport
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.