[PARPORT] [patch] parport-arca-16


Andrea Arcangeli (andrea@e-mind.com)
Mon, 5 Oct 1998 02:02:16 +0200 (CEST)


I am going to send to Linus the latest parport stuff developed by mine +
some stuff merged by Tim (Waugh) and Philip (Blundell).

(my latest stuff can be downloaded at ftp://e-mind.com/pub/linux/parport/
btw).

This is not only a patch-bugfix and if Linus will ask I' ll divide
the patch in two parts: needed-bugfix and cleanup.

The code should be just well tested and repored working fine but I ask
people that is using parport to try it now.

All the changes are backwards compatible with the last parport code.

The patch include:

o New way to handle the pardevice irq. Now the parport_lowlevel
        driver will implement the hard irq handler so it will be able
        to check if it' s been the alien parallel port that has generated
        the IRQ and ACK the irq in an alien way or return if needed. Then
        it will probably (it' s not forced) reacall port->cad->irq_func .
        For do this task safely I implemented an inline function in
        parport.h called parport_generic_irq() that every parport_lowlevel
        driver can use (note that parport_pc/ax/arc_interrupt() will only
        recall parport_generic_irq()).

        This change is needed to support alien parallel port (aka Amiga
        one) without having to hack the pardevice code. This way the
        pardevice must know nothing about parallel port internals.

        The good side effect of this change is that now all the time
        parport has an irq handler requested so it will end in a more
        robust design. Now I also avoid irq to happens using
        disable_irq() if the cad will haven' t an irq_func registered
        (note that some pardevice could generate irq even if they are not
        irq driven due how the parallel port generates the irq).

        This code has never got one problem so far.

o I fine-grined the parport spinlock stuff. Before my patch
        there was only 1 spinlock used to assure atomicity playing
        with the parport waitlist, the pardevice list and the
        changing of the port->cad and worse all spinlock was managed
        with the spin_[un]lock_irqsave functions even if not needed
        (for example parport_register_device has to be run only
        at insmod/rmmod or bootup time). Also the port->cad could be
        accessed at the same time of the parport waitlist.

        Now there are 3 parport spinlock used with more efficient
        spinlock functions.

o The PARPORT_DEV_LURK flag is obsolete since January. Using
        it make no differences how parport will manage the parport
        scheduling (since just now we handle the scheduling in round robin
        using a waitlist). I would like to add a printk(KERN_DEBUG) as
        first suggested and implemented by Tim, to make aware the
        pardevice developer that the LURK flag is obsolete if he was still
        using it but other parport developers didn' t agreed because
        using LURK won' t hurt so now parport continue to accept the LURK
        flag quitely (but it' s clear specifyed in parport.h that
        LURK and TRAN are obsolete). Right now every device should
        use 0x0 as flag if it doesn' t need special things.

        As a side effect of LURK obsolete also TRAN is obsolete.

        In the patch I put in sync all pardevice in the kernel with the
        new semantical changes.

o The new PARPORT_DEV_EXCL. This new pardevice flag tells parport
        if a device is not able to preempt the port after a rasonable
        amount of time.

        This flag is needed because without it there could be a parport
        starvation because many pardevice could wait for a
        parport_release() that could never happens.

        This new flag must be used only when _needed_.

        I just put in sync the soundmodem and baycom hamradio
        pardevice with the new flag. These pardevices raised the issue on
        linux-parport that convinced Tim to implement the new EXCL flag.

        Note that this is not really a bugfix but this flag will
        help sysadmin to avoid mistakes.

o I fixed all pardevices that was not checking for the
        parport_register_device() retval. Now with the new
        EXCL flag it' s a must to check the retval (it should
        be a must also before the patch though ;-).

o PPA config.in fix (read the patch ;-).

o ppa and imm now will not hang in ppa_detect if during
        that stage another pardevice is owning the port for more than
        3*HZ. This should be not needed right now due the
        EXCL flag but it' s more safe to add it anyway.

o I changed LP_INIT_WAIT from 0 to 20. This is the number
        of times we decrease a variable before remove the strobe
        from the bus.

        Everybody can change this value at runtime using tunelp. For
        example I add in my /etc/conf.modules (I need 30 because
        my printer is old):

andrea@dragon:~$ grep tunelp /etc/conf.modules
post-install lp /usr/sbin/tunelp /dev/lp0 -c 1 -w 30

        Using tunelp xxx -w ? you can reset this value to 0 as it' s now.
        I increased it because machines are always faster and it' s likely
        to have a safe default.

The patch is against 2.1.123 but seems to apply clean also against 124.

Andrea[s] Arcangeli

Index: linux/drivers/char/lp.c
diff -u linux/drivers/char/lp.c:1.1.1.1 linux/drivers/char/lp.c:1.1.1.1.2.1
--- linux/drivers/char/lp.c:1.1.1.1 Fri Oct 2 19:23:13 1998
+++ linux/drivers/char/lp.c Fri Oct 2 19:39:14 1998
@@ -768,7 +768,7 @@
         lp_table[nr].dev = parport_register_device(port, "lp",
                                                    lp_preempt, NULL,
                                                    lp_interrupt,
- PARPORT_DEV_TRAN,
+ 0,
                                                    (void *) &lp_table[nr]);
         if (lp_table[nr].dev == NULL)
                 return 1;
Index: linux/drivers/char/hfmodem/main.c
diff -u linux/drivers/char/hfmodem/main.c:1.1.1.1 linux/drivers/char/hfmodem/main.c:1.1.1.1.2.1
--- linux/drivers/char/hfmodem/main.c:1.1.1.1 Fri Oct 2 19:23:18 1998
+++ linux/drivers/char/hfmodem/main.c Fri Oct 2 19:39:21 1998
@@ -148,14 +148,6 @@
 #define SP_PAR 2
 #define SP_MIDI 4
 
-/* ---------------------------------------------------------------------- */
-
-static int parptt_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
 /* --------------------------------------------------------------------- */
 
 static void parptt_wakeup(void *handle)
@@ -176,8 +168,8 @@
                 pp = pp->next;
         if (!pp)
                 return 0;
- if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, parptt_preempt, parptt_wakeup,
- NULL, PARPORT_DEV_LURK, dev)))
+ if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup,
+ NULL, PARPORT_DEV_EXCL, dev)))
                 return 0;
         return 1;
 }
Index: linux/drivers/misc/parport_arc.c
diff -u linux/drivers/misc/parport_arc.c:1.1.1.1 linux/drivers/misc/parport_arc.c:1.1.1.1.2.1
--- linux/drivers/misc/parport_arc.c:1.1.1.1 Fri Oct 2 19:23:33 1998
+++ linux/drivers/misc/parport_arc.c Fri Oct 2 19:39:23 1998
@@ -33,6 +33,11 @@
 /* ARC can't read from the data latch, so we must use a soft copy. */
 static unsigned char data_copy;
 
+static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
 static void arc_write_data(struct parport *p, unsigned char data)
 {
         data_copy = data;
@@ -110,7 +115,7 @@
 
         arc_enable_irq,
         arc_disable_irq,
- arc_examine_irq,
+ arc_interrupt,
 
         arc_inc_use_count,
         arc_dec_use_count,
Index: linux/drivers/misc/parport_ax.c
diff -u linux/drivers/misc/parport_ax.c:1.1.1.1 linux/drivers/misc/parport_ax.c:1.1.1.1.2.1
--- linux/drivers/misc/parport_ax.c:1.1.1.1 Fri Oct 2 19:23:33 1998
+++ linux/drivers/misc/parport_ax.c Fri Oct 2 19:39:23 1998
@@ -50,10 +50,9 @@
 #define CONFIGB 0x401
 #define ECONTROL 0x402
 
-static void
-parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
- /* NULL function - Does nothing */
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
 void
@@ -206,7 +205,7 @@
 {
         if (p->irq != PARPORT_IRQ_NONE) {
                 parport_ax_disable_irq(p);
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
         }
         release_region(p->base, p->size);
         if (p->modes & PARPORT_MODE_PCECR)
@@ -219,11 +218,15 @@
 parport_ax_claim_resources(struct parport *p)
 {
         /* FIXME check that resources are free */
- if (p->irq != PARPORT_IRQ_NONE) {
- request_irq(p->irq, parport_ax_null_intr_func,
- 0, p->name, NULL);
- parport_ax_enable_irq(p);
- }
+ int err;
+
+ if (p->irq != PARPORT_IRQ_NONE)
+ if ((err = request_irq(p->irq, parport_ax_interrupt,
+ 0, p->name, p)) != 0)
+ return err;
+ else
+ parport_ax_enable_irq(p);
+
         request_region(p->base, p->size, p->name);
         if (p->modes & PARPORT_MODE_PCECR)
                 request_region(p->base+0x400, 3, p->name);
@@ -281,12 +284,6 @@
         return 0; /* FIXME */
 }
 
-int
-parport_ax_examine_irq(struct parport *p)
-{
- return 0; /* FIXME */
-}
-
 void
 parport_ax_inc_use_count(void)
 {
@@ -355,7 +352,7 @@
 
         parport_ax_enable_irq,
         parport_ax_disable_irq,
- parport_ax_examine_irq,
+ parport_ax_interrupt,
 
         parport_ax_inc_use_count,
         parport_ax_dec_use_count,
Index: linux/drivers/misc/parport_pc.c
diff -u linux/drivers/misc/parport_pc.c:1.1.1.1 linux/drivers/misc/parport_pc.c:1.1.1.1.2.1
--- linux/drivers/misc/parport_pc.c:1.1.1.1 Fri Oct 2 19:23:33 1998
+++ linux/drivers/misc/parport_pc.c Fri Oct 2 19:39:24 1998
@@ -1,4 +1,4 @@
-/* Low-level parallel-port routines for PC-style hardware.
+/* Low-level parallel-port routines for 8255-based PC-style hardware.
  *
  * Authors: Phil Blundell <Philip.Blundell@pobox.com>
  * Tim Waugh <tim@cyberelk.demon.co.uk>
@@ -32,13 +32,8 @@
  * accomodate this.
  */
 
-#include <linux/stddef.h>
-#include <linux/tasks.h>
-
-#include <asm/ptrace.h>
-#include <asm/io.h>
-
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -46,6 +41,8 @@
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 
+#include <asm/io.h>
+
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
 
@@ -53,9 +50,9 @@
    than PARPORT_MAX (in <linux/parport.h>). */
 #define PARPORT_PC_MAX_PORTS 8
 
-static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
- /* Null function - does nothing */
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
 void parport_pc_write_epp(struct parport *p, unsigned char d)
@@ -173,7 +170,7 @@
 void parport_pc_release_resources(struct parport *p)
 {
         if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
         release_region(p->base, p->size);
         if (p->modes & PARPORT_MODE_PCECR)
                 release_region(p->base+0x400, 3);
@@ -183,7 +180,9 @@
 {
         int err;
         if (p->irq != PARPORT_IRQ_NONE)
- if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 0) return err;
+ if ((err = request_irq(p->irq, parport_pc_interrupt,
+ 0, p->name, p)) != 0)
+ return err;
         request_region(p->base, p->size, p->name);
         if (p->modes & PARPORT_MODE_PCECR)
                 request_region(p->base+0x400, 3, p->name);
@@ -242,11 +241,6 @@
         return -ENOSYS; /* FIXME */
 }
 
-int parport_pc_examine_irq(struct parport *p)
-{
- return 0; /* FIXME */
-}
-
 void parport_pc_inc_use_count(void)
 {
 #ifdef MODULE
@@ -313,7 +307,7 @@
 
         parport_pc_enable_irq,
         parport_pc_disable_irq,
- parport_pc_examine_irq,
+ parport_pc_interrupt,
 
         parport_pc_inc_use_count,
         parport_pc_dec_use_count,
Index: linux/drivers/misc/parport_procfs.c
diff -u linux/drivers/misc/parport_procfs.c:1.1.1.1 linux/drivers/misc/parport_procfs.c:1.1.1.1.2.1
--- linux/drivers/misc/parport_procfs.c:1.1.1.1 Fri Oct 2 19:23:33 1998
+++ linux/drivers/misc/parport_procfs.c Fri Oct 2 19:39:24 1998
@@ -29,16 +29,13 @@
 
 struct proc_dir_entry *base = NULL;
 
-extern void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs);
-
 static int irq_write_proc(struct file *file, const char *buffer,
- unsigned long count, void *data)
+ unsigned long count, void *data)
 {
         int retval = -EINVAL;
         int newirq = PARPORT_IRQ_NONE;
         struct parport *pp = (struct parport *)data;
         int oldirq = pp->irq;
- unsigned long flags;
 
 /*
  * We can have these valid cases:
@@ -70,30 +67,44 @@
         if (oldirq == newirq)
                 goto out;
 
- spin_lock_irqsave(&pp->lock, flags);
         if (pp->flags & PARPORT_FLAG_COMA)
                 goto out_ok;
 
         retval = -EBUSY;
+
+ /*
+ * Here we don' t need the irq version of spinlocks because
+ * the parport_lowlevel irq handler must not change the cad,
+ * and so has no one reason to write_lock() the cad_lock spinlock.
+ * -arca
+ */
+ read_lock(&pp->cad_lock);
+
         if (pp->cad)
- goto out_unlock;
+ {
+ read_unlock(&pp->cad_lock);
+ return retval;
+ }
 
         if (newirq != PARPORT_IRQ_NONE) {
- retval = request_irq(newirq, parport_null_intr_func,
- SA_INTERRUPT, pp->name, NULL);
+ retval = request_irq(newirq, pp->ops->interrupt,
+ 0, pp->name, pp);
                 if (retval)
- goto out_unlock;
- else retval = count;
+ {
+ read_unlock(&pp->cad_lock);
+ return retval;
+ }
         }
 
         if (oldirq != PARPORT_IRQ_NONE)
- free_irq(oldirq, NULL);
+ free_irq(oldirq, pp);
 
+ retval = count;
+
+ read_unlock(&pp->cad_lock);
+
 out_ok:
         pp->irq = newirq;
-
-out_unlock:
- spin_unlock_irqrestore (&pp->lock, flags);
 
 out:
         return retval;
Index: linux/drivers/misc/parport_share.c
diff -u linux/drivers/misc/parport_share.c:1.1.1.1 linux/drivers/misc/parport_share.c:1.1.1.1.2.1
--- linux/drivers/misc/parport_share.c:1.1.1.1 Fri Oct 2 19:23:33 1998
+++ linux/drivers/misc/parport_share.c Fri Oct 2 19:39:24 1998
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 
 #include <asm/spinlock.h>
+#include <asm/irq.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -55,19 +56,12 @@
         return portlist;
 }
 
-void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* Null function - does nothing. IRQs are pointed here whenever
- there is no real handler for them. */
-}
-
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
                                       struct parport_operations *ops)
 {
         struct parport *tmp;
         int portnum;
         char *name;
- unsigned long flags;
 
         /* Check for a previously registered port.
            NOTE: we will ignore irq and dma if we find a previously
@@ -111,7 +105,9 @@
         tmp->ops = ops;
         tmp->number = portnum;
         memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
- spin_lock_init (&tmp->lock);
+ spin_lock_init(&tmp->cad_lock);
+ spin_lock_init(&tmp->waitlist_lock);
+ spin_lock_init(&tmp->pardevice_lock);
 
         name = kmalloc(15, GFP_KERNEL);
         if (!name) {
@@ -122,14 +118,19 @@
         sprintf(name, "parport%d", portnum);
         tmp->name = name;
 
- /* Chain the entry to our list. */
- spin_lock_irqsave (&parportlist_lock, flags);
+ /*
+ * Chain the entry to our list.
+ *
+ * This function must not run from an irq handler so we don' t need
+ * to clear irq on the local CPU. -arca
+ */
+ spin_lock(&parportlist_lock);
         if (portlist_tail)
                 portlist_tail->next = tmp;
         portlist_tail = tmp;
         if (!portlist)
                 portlist = tmp;
- spin_unlock_irqrestore (&parportlist_lock, flags);
+ spin_unlock(&parportlist_lock);
 
         tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */
         tmp->waithead = tmp->waittail = NULL;
@@ -140,8 +141,8 @@
 void parport_unregister_port(struct parport *port)
 {
         struct parport *p;
- unsigned long flags;
- spin_lock_irqsave (&parportlist_lock, flags);
+
+ spin_lock(&parportlist_lock);
         if (portlist == port) {
                 if ((portlist = port->next) == NULL)
                         portlist_tail = NULL;
@@ -155,7 +156,7 @@
                 else printk (KERN_WARNING
                              "%s not found in port list!\n", port->name);
         }
- spin_unlock_irqrestore (&parportlist_lock, flags);
+ spin_unlock(&parportlist_lock);
         if (port->probe_info.class_name)
                 kfree (port->probe_info.class_name);
         if (port->probe_info.mfr)
@@ -195,8 +196,14 @@
                           int flags, void *handle)
 {
         struct pardevice *tmp;
- unsigned long flgs;
 
+ if (port->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);
@@ -242,12 +249,30 @@
 
         /* Chain this onto the list */
         tmp->prev = NULL;
- spin_lock_irqsave (&port->lock, flgs);
+ /*
+ * 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->pardevice_lock);
+
+ if (flags & PARPORT_DEV_EXCL) {
+ if (port->devices) {
+ spin_unlock (&port->pardevice_lock);
+ kfree (tmp->state);
+ kfree (tmp);
+ printk (KERN_DEBUG
+ "%s: cannot grant exclusive access for "
+ "device %s\n", port->name, name);
+ return NULL;
+ }
+ port->flags |= PARPORT_FLAG_EXCL;
+ }
+
         tmp->next = port->devices;
         if (port->devices)
                 port->devices->prev = tmp;
         port->devices = tmp;
- spin_unlock_irqrestore (&port->lock, flgs);
+ spin_unlock(&port->pardevice_lock);
 
         inc_parport_count();
         port->ops->inc_use_count();
@@ -262,7 +287,6 @@
 void parport_unregister_device(struct pardevice *dev)
 {
         struct parport *port;
- unsigned long flags;
 
 #ifdef PARPORT_PARANOID
         if (dev == NULL) {
@@ -279,15 +303,19 @@
                 return;
         }
 
- spin_lock_irqsave (&port->lock, flags);
+ 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;
- spin_unlock_irqrestore (&port->lock, flags);
 
+ if (dev->flags & PARPORT_DEV_EXCL)
+ port->flags &= ~PARPORT_FLAG_EXCL;
+
+ spin_unlock(&port->pardevice_lock);
+
         kfree(dev->state);
         kfree(dev);
 
@@ -337,7 +365,7 @@
                 dev->waiting = 0;
 
                 /* Take ourselves out of the wait list again. */
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock_irqsave (&port->waitlist_lock, flags);
                 if (dev->waitprev)
                         dev->waitprev->waitnext = dev->waitnext;
                 else
@@ -346,29 +374,28 @@
                         dev->waitnext->waitprev = dev->waitprev;
                 else
                         port->waittail = dev->waitprev;
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
                 dev->waitprev = dev->waitnext = NULL;
         }
 
+ if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func)
+ /*
+ * If there was an irq pending it should hopefully happen
+ * before return from enable_irq(). -arca
+ */
+ enable_irq(port->irq);
+
+ /*
+ * Avoid running irq handlers if the pardevice doesn' t use it. -arca
+ */
+ if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
+ disable_irq(port->irq);
+
         /* Now we do the change of devices */
- spin_lock_irqsave(&port->lock, flags);
+ write_lock_irqsave(&port->cad_lock, flags);
         port->cad = dev;
- spin_unlock_irqrestore(&port->lock, flags);
+ write_unlock_irqrestore(&port->cad_lock, flags);
 
- /* Swap the IRQ handlers. */
- if (port->irq != PARPORT_IRQ_NONE) {
- if (oldcad && oldcad->irq_func) {
- free_irq(port->irq, oldcad->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }
- if (dev->irq_func) {
- free_irq(port->irq, NULL);
- request_irq(port->irq, dev->irq_func,
- SA_INTERRUPT, dev->name, dev->private);
- }
- }
-
         /* Restore control registers */
         port->ops->restore_state(port, dev->state);
         dev->time = jiffies;
@@ -379,10 +406,10 @@
            interest. This is only allowed for devices sleeping in
            parport_claim_or_block(), or those with a wakeup function. */
         if (dev->waiting & 2 || dev->wakeup) {
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock_irqsave (&port->waitlist_lock, flags);
                 if (port->cad == NULL) {
                         /* The port got released in the meantime. */
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
                         goto try_again;
                 }
                 if (test_and_set_bit(0, &dev->waiting) == 0) {
@@ -395,7 +422,7 @@
                         } else
                                 port->waithead = port->waittail = dev;
                 }
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
         }
         return -EAGAIN;
 }
@@ -451,19 +478,19 @@
                        "when not owner\n", port->name, dev->name);
                 return;
         }
- spin_lock_irqsave(&port->lock, flags);
+ write_lock_irqsave(&port->cad_lock, flags);
         port->cad = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
+ write_unlock_irqrestore(&port->cad_lock, flags);
+
+ /*
+ * Reenable irq and so discard the eventually pending irq while
+ * cad is NULL. -arca
+ */
+ if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
+ enable_irq(port->irq);
 
         /* Save control registers */
         port->ops->save_state(port, dev->state);
-
- /* Point IRQs somewhere harmless. */
- if (port->irq != PARPORT_IRQ_NONE && dev->irq_func) {
- free_irq(port->irq, dev->private);
- request_irq(port->irq, parport_null_intr_func,
- SA_INTERRUPT, port->name, NULL);
- }
 
         /* If anybody is waiting, find out who's been there longest and
            then wake them up. (Note: no locking required) */
Index: linux/drivers/net/plip.c
diff -u linux/drivers/net/plip.c:1.1.1.1 linux/drivers/net/plip.c:1.1.1.1.2.1
--- linux/drivers/net/plip.c:1.1.1.1 Fri Oct 2 19:23:04 1998
+++ linux/drivers/net/plip.c Fri Oct 2 19:39:26 1998
@@ -242,7 +242,10 @@
 
         pardev = parport_register_device(pb, dev->name, plip_preempt,
                                          plip_wakeup, plip_interrupt,
- PARPORT_DEV_LURK, dev);
+ 0, dev);
+
+ if (!pardev)
+ return -ENODEV;
 
         printk(KERN_INFO "%s", version);
         printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
Index: linux/drivers/net/hamradio/baycom_epp.c
diff -u linux/drivers/net/hamradio/baycom_epp.c:1.1.1.1 linux/drivers/net/hamradio/baycom_epp.c:1.1.1.1.2.1
--- linux/drivers/net/hamradio/baycom_epp.c:1.1.1.1 Fri Oct 2 19:23:11 1998
+++ linux/drivers/net/hamradio/baycom_epp.c Fri Oct 2 19:39:27 1998
@@ -1010,14 +1010,6 @@
 
 /* --------------------------------------------------------------------- */
 
-static int epp_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
 static void epp_wakeup(void *handle)
 {
         struct device *dev = (struct device *)handle;
@@ -1070,8 +1062,8 @@
         }
 #endif
         memset(&bc->modem, 0, sizeof(bc->modem));
- if (!(bc->pdev = parport_register_device(pp, dev->name, epp_preempt, epp_wakeup,
- epp_interrupt, PARPORT_DEV_LURK, dev))) {
+ if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup,
+ epp_interrupt, PARPORT_DEV_EXCL, dev))) {
                 printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base);
                 return -ENXIO;
         }
Index: linux/drivers/net/hamradio/baycom_par.c
diff -u linux/drivers/net/hamradio/baycom_par.c:1.1.1.1 linux/drivers/net/hamradio/baycom_par.c:1.1.1.1.2.1
--- linux/drivers/net/hamradio/baycom_par.c:1.1.1.1 Fri Oct 2 19:23:11 1998
+++ linux/drivers/net/hamradio/baycom_par.c Fri Oct 2 19:39:27 1998
@@ -357,14 +357,6 @@
 
 /* --------------------------------------------------------------------- */
 
-static int par96_preempt(void *handle)
-{
- /* we cannot relinquish the port in the middle of an operation */
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
 static void par96_wakeup(void *handle)
 {
         struct device *dev = (struct device *)handle;
@@ -396,8 +388,8 @@
         }
         memset(&bc->modem, 0, sizeof(bc->modem));
         bc->hdrv.par.bitrate = 9600;
- if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup,
- par96_interrupt, PARPORT_DEV_LURK, dev))) {
+ if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, par96_wakeup,
+ par96_interrupt, PARPORT_DEV_EXCL, dev))) {
                 printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", pp->base);
                 return -ENXIO;
         }
Index: linux/drivers/pnp/parport_probe.c
diff -u linux/drivers/pnp/parport_probe.c:1.1.1.1 linux/drivers/pnp/parport_probe.c:1.1.1.1.2.1
--- linux/drivers/pnp/parport_probe.c:1.1.1.1 Fri Oct 2 19:23:32 1998
+++ linux/drivers/pnp/parport_probe.c Fri Oct 2 19:39:30 1998
@@ -91,7 +91,7 @@
 
 int parport_probe(struct parport *port, char *buffer, int len)
 {
- struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, PARPORT_DEV_TRAN, &dev);
+ struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev);
 
         int result = 0;
 
Index: linux/drivers/scsi/Config.in
diff -u linux/drivers/scsi/Config.in:1.1.1.1 linux/drivers/scsi/Config.in:1.1.1.1.2.1
--- linux/drivers/scsi/Config.in:1.1.1.1 Fri Oct 2 19:23:20 1998
+++ linux/drivers/scsi/Config.in Fri Oct 2 19:39:32 1998
@@ -53,7 +53,7 @@
 if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
   if [ "$CONFIG_SCSI_PPA" != "n" ]; then
- int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
+ bool ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC
   fi
   dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
 fi
Index: linux/drivers/scsi/imm.c
diff -u linux/drivers/scsi/imm.c:1.1.1.1 linux/drivers/scsi/imm.c:1.1.1.1.2.1
--- linux/drivers/scsi/imm.c:1.1.1.1 Fri Oct 2 19:23:23 1998
+++ linux/drivers/scsi/imm.c Fri Oct 2 19:39:32 1998
@@ -172,14 +172,29 @@
 
         imm_hosts[i].dev =
             parport_register_device(pb, "imm", NULL, imm_wakeup,
- NULL, PARPORT_DEV_TRAN, (void *) &imm_hosts[i]);
+ NULL, 0, (void *) &imm_hosts[i]);
 
+ if (!imm_hosts[i].dev)
+ continue;
+
         /* Claim the bus so it remembers what we do to the control
          * registers. [ CTR and ECP ]
          */
- if (imm_pb_claim(i))
- while (imm_hosts[i].p_busy)
- schedule(); /* We are safe to schedule here */
+ if (imm_pb_claim(i))
+ {
+ unsigned long now = jiffies;
+ while (imm_hosts[i].p_busy)
+ {
+ schedule(); /* We are safe to schedule here */
+ if (jiffies > now + 3*HZ)
+ {
+ printk(KERN_ERR "imm%d: failed to claim parport because a "
+ "pardevice is owning the port for too longtime!\n",
+ i);
+ return 0;
+ }
+ }
+ }
 
         ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;
         w_ctr(ppb, 0x0c);
Index: linux/drivers/scsi/ppa.c
diff -u linux/drivers/scsi/ppa.c:1.1.1.1 linux/drivers/scsi/ppa.c:1.1.1.1.2.1
--- linux/drivers/scsi/ppa.c:1.1.1.1 Fri Oct 2 19:23:20 1998
+++ linux/drivers/scsi/ppa.c Fri Oct 2 19:39:32 1998
@@ -133,14 +133,29 @@
 
         ppa_hosts[i].dev =
             parport_register_device(pb, "ppa", NULL, ppa_wakeup,
- NULL, PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]);
+ NULL, 0, (void *) &ppa_hosts[i]);
 
+ if (!ppa_hosts[i].dev)
+ continue;
+
         /* Claim the bus so it remembers what we do to the control
          * registers. [ CTR and ECP ]
          */
         if (ppa_pb_claim(i))
+ {
+ unsigned long now = jiffies;
             while (ppa_hosts[i].p_busy)
+ {
                 schedule(); /* We are safe to schedule here */
+ if (jiffies > now + 3*HZ)
+ {
+ printk(KERN_ERR "ppa%d: failed to claim parport because a "
+ "pardevice is owning the port for too longtime!\n",
+ i);
+ return 0;
+ }
+ }
+ }
 
         ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base;
         w_ctr(ppb, 0x0c);
Index: linux/include/linux/lp.h
diff -u linux/include/linux/lp.h:1.1.1.1 linux/include/linux/lp.h:1.1.1.1.2.2
--- linux/include/linux/lp.h:1.1.1.1 Fri Oct 2 19:22:40 1998
+++ linux/include/linux/lp.h Mon Oct 5 00:12:06 1998
@@ -43,11 +43,11 @@
 /* The parallel port specs apparently say that there needs to be
  * a .5usec wait before and after the strobe. Since there are wildly
  * different computers running linux, I can't come up with a perfect
- * value, but since it worked well on most printers before without,
- * I'll initialize it to 0.
+ * value so if 20 is not good for you use `tunelp /dev/lp? -w ?`.
+ * You can also set it to 0 if your printer handle that.
  */
 
-#define LP_INIT_WAIT 0
+#define LP_INIT_WAIT 20
 
 /* This is the amount of time that the driver waits for the printer to
  * catch up when the printer's buffer appears to be filled. If you
Index: linux/include/linux/parport.h
diff -u linux/include/linux/parport.h:1.1.1.1 linux/include/linux/parport.h:1.1.1.1.2.1
--- linux/include/linux/parport.h:1.1.1.1 Fri Oct 2 19:22:42 1998
+++ linux/include/linux/parport.h Fri Oct 2 19:39:37 1998
@@ -123,7 +123,7 @@
 
         void (*enable_irq)(struct parport *);
         void (*disable_irq)(struct parport *);
- int (*examine_irq)(struct parport *);
+ void (*interrupt)(int, void *, struct pt_regs *);
 
         void (*inc_use_count)(void);
         void (*dec_use_count)(void);
@@ -206,7 +206,9 @@
         void *private_data; /* for lowlevel driver */
 
         int number; /* port index - the `n' in `parportn' */
- spinlock_t lock;
+ spinlock_t pardevice_lock;
+ spinlock_t waitlist_lock;
+ spinlock_t cad_lock;
 };
 
 /* parport_register_port registers a new parallel port at the given address (if
@@ -234,10 +236,9 @@
 
 /* parport_register_device declares that a device is connected to a port, and
  * tells the kernel all it needs to know.
- * pf is the preemption function (may be NULL for a transient driver)
- * kf is the wake-up function (may be NULL for a transient driver)
+ * pf is the preemption function (may be NULL for no callback)
+ * kf is the wake-up function (may be NULL for no callback)
  * irq_func is the interrupt handler (may be NULL for no interrupts)
- * Only one lurking driver can be used on a given port.
  * handle is a user pointer that gets handed to callback functions.
  */
 struct pardevice *parport_register_device(struct parport *port,
@@ -294,11 +295,31 @@
         return parport_claim_or_block(dev);
 }
 
+/*
+ * Lowlevel drivers _can_ call this support function to handle irqs.
+ */
+extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+ struct pt_regs *regs)
+{
+ read_lock(&port->cad_lock);
+ if (!port->cad)
+ goto out_unlock;
+ if (port->cad->irq_func)
+ port->cad->irq_func(irq, port->cad->private, regs);
+ else
+ printk(KERN_ERR "%s: irq%d happened with irq_func NULL "
+ "with %s as cad!\n", port->name, irq, port->cad->name);
+ out_unlock:
+ read_unlock(&port->cad_lock);
+}
+
 /* Flags used to identify what a device does. */
-#define PARPORT_DEV_TRAN 0x0000 /* We're transient. */
-#define PARPORT_DEV_LURK 0x0001 /* We lurk. */
+#define PARPORT_DEV_TRAN 0 /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_LURK (1<<0) /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_EXCL (1<<1) /* Need exclusive access. */
 
-#define PARPORT_FLAG_COMA 1
+#define PARPORT_FLAG_COMA (1<<0)
+#define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
 
 extern void parport_parse_irqs(int, const char *[], int irqval[]);
 extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
Index: linux/include/linux/parport_pc.h
diff -u linux/include/linux/parport_pc.h:1.1.1.1 linux/include/linux/parport_pc.h:1.1.1.1.2.1
--- linux/include/linux/parport_pc.h:1.1.1.1 Fri Oct 2 19:22:44 1998
+++ linux/include/linux/parport_pc.h Fri Oct 2 19:39:37 1998
@@ -132,8 +132,6 @@
 
 extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
 
-extern int parport_pc_examine_irq(struct parport *p);
-
 extern void parport_pc_inc_use_count(void);
 
 extern void parport_pc_dec_use_count(void);

-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --



This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:18:31 EST