[PARPORT] Parport-irq-patch


Joerg Dorchain (dorchain@wirbel.com)
Tue, 1 Sep 1998 15:01:42 +0200 (MET DST)


Hi,

This is my proposal for the interrupt handling. I only tried the amiga
port, and don't know if I considered all side effects. I hope it will be
transparent for the high level drivers.

For other devices like the MFC3 plugin card, the irq function would look
something like this

for each port handled by this driver /* there can be an arbitrary number of
cards, as you can have slot extenders, all handled by the same driver */
        if irq comes from this card
                acknowledge it
                call high level function

identication indicates blocking.

I just downloaded Andreas patch v3 and go through it tonight.

Please comment,

Joerg

P.s.: This patch is relative to 2.1.119 including my last parport patch

--- ./drivers/misc/parport_ax.c.old Tue Sep 1 10:26:43 1998
+++ ./drivers/misc/parport_ax.c Tue Sep 1 10:54:07 1998
@@ -50,12 +50,6 @@
 #define CONFIGB 0x401
 #define ECONTROL 0x402
 
-static void
-parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* NULL function - Does nothing */
-}
-
 void
 parport_ax_write_epp(struct parport *p, unsigned char d)
 {
@@ -206,7 +200,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)
@@ -220,8 +214,8 @@
 {
         /* 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);
+ request_irq(p->irq, parport_intr_func,
+ 0, p->name, p);
                 parport_ax_enable_irq(p);
         }
         request_region(p->base, p->size, p->name);
--- ./drivers/misc/parport_amiga.c.old Tue Sep 1 10:26:43 1998
+++ ./drivers/misc/parport_amiga.c Tue Sep 1 11:45:22 1998
@@ -28,6 +28,8 @@
 static inline int DPRINTK() {return 0;}
 #endif
 
+static struct parport *this_port = NULL;
+
 static void amiga_write_data(struct parport *p, unsigned char data)
 {
 DPRINTK("write_data %c\n",data);
@@ -46,15 +48,17 @@
 {
         unsigned char ret = 0;
 
- if (control & 0x10) /* XXX: What is INTEN? */
+ if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+ ;
+ if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
                 ;
- if (control & 0x08) /* XXX: What is SELECP? */
+ if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
                 ;
- if (control & 0x04) /* INITP */
+ if (control & PARPORT_CONTROL_INIT) /* INITP */
                 /* reset connected to cpu reset pin */;
- if (control & 0x02) /* AUTOLF */
+ if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
                 /* Not connected */;
- if (control & 0x01) /* Strobe */
+ if (control & PARPORT_CONTROL_STROBE) /* Strobe */
                 /* Handled only directly by hardware */;
         return ret;
 }
@@ -62,7 +66,8 @@
 
 static unsigned char control_amiga_to_pc(unsigned char control)
 {
- return 0x1b;
+ return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
         /* fake value: interrupt enable, select in, no reset,
         no autolf, no strobe - seems to be closest the wiring diagram */
 }
@@ -94,29 +99,29 @@
 {
         unsigned char ret = 1;
 
- if (status & 0x80) /* Busy */
+ if (status & PARPORT_STATUS_BUSY) /* Busy */
                 ret &= ~1;
- if (status & 0x40) /* Ack */
+ if (status & PARPORT_STATUS_ACK) /* Ack */
                 /* handled in hardware */;
- if (status & 0x20) /* PaperOut */
+ if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
                 ret |= 2;
- if (status & 0x10) /* select */
+ if (status & PARPORT_STATUS_SELECT) /* select */
                 ret |= 4;
- if (status & 0x08) /* error */
+ if (status & PARPORT_STATUS_ERROR) /* error */
                 /* not connected */;
         return ret;
 }
 
 static unsigned char status_amiga_to_pc(unsigned char status)
 {
- unsigned char ret = 0x80 + 0x40 + 0x08;
+ unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
 
         if (status & 1) /* Busy */
- ret &= ~0x80;
+ ret &= ~PARPORT_STATUS_BUSY;
         if (status & 2) /* PaperOut */
- ret |= 0x20;
+ ret |= PARPORT_STATUS_PAPEROUT;
         if (status & 4) /* Selected */
- ret |= 0x10;
+ ret |= PARPORT_STATUS_SELECT;
         /* the rest is not connected or handled autonomously in hardware */
 
         return ret;
@@ -143,22 +148,19 @@
         not sure about the corresponding PC-style mode*/
 }
 
-static void amiga_intr_func(int irq, void *dev_id, struct pt_regs *regs)
-{
- /* nothing to do */
-}
+/* as this ports irq handling is already done, we use a generic funktion */
 
 static void amiga_release_resources(struct parport *p)
 {
 DPRINTK("realease_resources\n");
         if (p->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_AMIGA_CIAA_FLG, &ciaa.prb);
+ free_irq(IRQ_AMIGA_CIAA_FLG, p);
 }
 
 static int amiga_claim_resources(struct parport *p)
 {
 DPRINTK("claim_resources\n");
- return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_intr_func, 0, p->name, &ciaa.prb);
+ return request_irq(IRQ_AMIGA_CIAA_FLG, parport_intr_func, 0, p->name, p);
 }
 
 static void amiga_init_state(struct parport_state *s)
@@ -272,6 +274,7 @@
                                         IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
                                         &pp_amiga_ops)))
                         return 0;
+ this_port = p;
                 printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
                 /* XXX: set operating mode */
                 parport_proc_register(p);
@@ -293,18 +296,10 @@
 
 void cleanup_module(void)
 {
- struct parport *p = parport_enumerate(), *next;
-
- while (p) {
- next = p->next;
- if (p->ops == &pp_amiga_ops) {
- if (!(p->flags & PARPORT_FLAG_COMA))
- parport_quiesce(p);
- parport_proc_unregister(p);
- parport_unregister_port(p);
- }
- p = next;
- }
+ if (!(this_port->flags & PARPORT_FLAG_COMA))
+ parport_quiesce(this_port);
+ parport_proc_unregister(this_port);
+ parport_unregister_port(this_port);
 }
 #endif
 
--- ./drivers/misc/parport_init.c.old Tue Sep 1 10:26:43 1998
+++ ./drivers/misc/parport_init.c Tue Sep 1 11:24:45 1998
@@ -146,6 +146,7 @@
 EXPORT_SYMBOL(parport_proc_unregister);
 EXPORT_SYMBOL(parport_probe_hook);
 EXPORT_SYMBOL(parport_parse_irqs);
+EXPORT_SYMBOL(parport_intr_func);
 
 void inc_parport_count(void)
 {
--- ./drivers/misc/parport_pc.c.old Tue Sep 1 10:26:44 1998
+++ ./drivers/misc/parport_pc.c Tue Sep 1 10:52:26 1998
@@ -53,11 +53,6 @@
    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)
-{
- /* Null function - does nothing */
-}
-
 void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
         outb(d, p->base+EPPDATA);
@@ -173,7 +168,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 +178,7 @@
 {
         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_intr_func, 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);
--- ./drivers/misc/parport_procfs.c.old Tue Sep 1 10:26:44 1998
+++ ./drivers/misc/parport_procfs.c Tue Sep 1 10:29:25 1998
@@ -35,6 +35,8 @@
                                           unsigned long count, void *data)
 {
         int retval = -EINVAL;
+/* changing irqs doesn't make sense on m68k. Besides, it wouldn't work the way below */
+#ifndef __mc68000__
         int newirq = PARPORT_IRQ_NONE;
         struct parport *pp = (struct parport *)data;
         int oldirq = pp->irq;
@@ -96,6 +98,7 @@
         spin_unlock_irqrestore (&pp->lock, flags);
 
 out:
+#endif
         return retval;
 }
 
--- ./drivers/misc/parport_share.c.old Tue Sep 1 10:26:44 1998
+++ ./drivers/misc/parport_share.c Tue Sep 1 11:09:27 1998
@@ -55,10 +55,15 @@
         return portlist;
 }
 
-void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+void parport_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. */
+ /* Generic function. This has always to be done. If some hardware
+ needs black magic before or after the high level call,
+ implement an own function. */
+ struct parport *p = dev_id;
+
+ if ( p && p->cad && p->cad->irq_func )
+ (*p->cad->irq_func)(irq, p->cad->private, regs);
 }
 
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
@@ -355,19 +360,7 @@
         port->cad = dev;
         spin_unlock_irqrestore(&port->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);
- }
- }
+ /* irqs are done by low level driver */
 
         /* Restore control registers */
         port->ops->restore_state(port, dev->state);
@@ -457,13 +450,6 @@
 
         /* 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) */
--- ./include/linux/parport.h.old Tue Sep 1 11:12:24 1998
+++ ./include/linux/parport.h Tue Sep 1 11:18:02 1998
@@ -302,6 +302,9 @@
         return parport_claim_or_block(dev);
 }
 
+/* irq helper function */
+extern void parport_intr_func(int irq, void *dev_id, struct pt_regs *regs);
+
 /* Flags used to identify what a device does. */
 #define PARPORT_DEV_TRAN 0x0000 /* We're transient. */
 #define PARPORT_DEV_LURK 0x0001 /* We lurk. */

-- 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:12 EST