me8100.c
changeset 24 24a49943680f
parent 22 7b722739e329
child 26 23bb80f9220c
--- a/me8100.c	Fri Jan 25 20:26:01 2002 +0100
+++ b/me8100.c	Fri Jan 25 20:26:39 2002 +0100
@@ -600,14 +600,12 @@
     printk(KERN_ERR "ME8100: me8100_open(): kmalloc() failed\n");
     return -EIO;
   }
+
   file_ptr->private_data = priv;
-
   memset(priv, 0, sizeof(*priv));
 
-  info = &info_vec[device];
-  subinfo = &info->subinfo[subdevice];
-  priv->info = info;
-  priv->subinfo = subinfo;
+  priv->info = info = &info_vec[device];
+  priv->subinfo = subinfo = &info->subinfo[subdevice];
 
   MOD_INC_USE_COUNT;
 
@@ -633,35 +631,40 @@
      * (might be done by some ioctl()s.  The file_ptr get a private data
      * pointer passed.  We need this to keep track of timestamps for
      * read data. */
+    unsigned short icsr;
 
     PDEBUG("*** open for reading\n");
 
-    /* The first reader should setup the IRQs (enabling IRQ handling
-     * with the full bit mask.  It might be modified later. */
+    /* The first reader on the board will enable IRQs at all.
+     * Every next reader shouldn't care. */
+    if (0 == info->num_reader++) icsr = PCI_INT_EN;
+    else icsr = inw(info->plx_regbase + PLX_ICSR);
+
+      /* The first reader per subdevice should enable IRQs for 
+       * this subdevice, but not change the settings found already
+       * in the ICSR. */
     if (0 == subinfo->num_reader++) {
-      int mask;
-      unsigned short icsr;
-
-      mask = 0xffff;
-      icsr = PCI_INT_EN | ((LOCAL_INT_EN | LOCAL_INT_POL) << (3 * subdevice));
+	int mask = 0xffff;
 
       PDEBUG("*** first reader on subdevice %d\n", subdevice);
 
-      /* 1) setup the PLX register */
+      subinfo->icsr_flags = (LOCAL_INT_EN | LOCAL_INT_POL) << (3 * subdevice);
+      icsr |= subinfo->icsr_flags;
+
+      /* Setup the interrupt mask */
+      PDEBUG("*** irqmask = 0x%04x\n", mask);
+      outw(mask, subinfo->regbase + ME8100_MASK_REG);
+
+      /* Setup the PLX register */
       PDEBUG("*** plx = 0x%0x\n", icsr);
       outb(icsr, info->plx_regbase + PLX_ICSR);
 
-      /* 2) setup the interrupt mask */
-      PDEBUG("*** irqmask = 0x%04x\n", mask);
-      outw(mask, subinfo->regbase + ME8100_MASK_REG);
-
-      /* 3) setup the irq flags in regbase */
+      /* Setup the irq flags in regbase */
       subinfo->ctrl_rflags = ME8100_CTRL_IRQ_MASK;
       subinfo->ctrl_reg |= subinfo->ctrl_rflags;
       PDEBUG("*** adding 0x%0x to ctrl => 0x%04x\n", 
 	subinfo->ctrl_rflags, subinfo->ctrl_reg);
       outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
-
     } /* first reader */
   } /* reader */    
 
@@ -730,6 +733,14 @@
       PDEBUG("*** resetting IRQ mode ctrl: 0x%x\n", subinfo->ctrl_reg);
       outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
      }
+
+     if (0 == --info->num_reader) {
+      unsigned short icsr;
+      icsr = inw(info->plx_regbase + PLX_ICSR);
+      icsr &= ~(PCI_INT_EN | SOFT_INT);
+      outw(icsr, info->plx_regbase + PLX_ICSR);
+      PDEBUG("** reset icsr to 0x%0X\n", icsr);
+    }
   }
 
 
@@ -2081,7 +2092,7 @@
  *   Name       Type              Access    Description                     
  *--------------------------------------------------------------------------
  *   irq        int               read      number of interrupt occured     
- *   dev_id     void*             read      pointer to board specific       
+ *   dev        void*             read      pointer to board specific       
  *                                          informations                    
  *   regs       struct pt_regs *  read      pointer to cpu register         
  *                                                                          
@@ -2090,7 +2101,7 @@
  * Author: GG                                                               
  * Modification:                                                            
  */
-static void me8100_isr(int irq, void *dev_id, struct pt_regs *regs){
+static void me8100_isr(int irq, void *dev, struct pt_regs *regs){
   int i;
   unsigned char icsr;
   me8100_info_t *info;
@@ -2099,9 +2110,9 @@
   /* B: 0x20 & 0x40 & 0x08 for irq at port B */
   unsigned short icsr_mask[] = { 0x45, 0x68 };
 
-  info = (me8100_info_t *) dev_id;
+  info = dev;
 
-  PDEBUG("INT: me8100_isr()\n");
+  PDEBUG("==> me8100_isr()\n");
 
   if(irq != info->int_line){
     PDEBUG("me8100_isr():incorrect interrupt num: %d\n", irq);
@@ -2110,7 +2121,7 @@
 
 
   icsr = inb(info->plx_regbase + PLX_ICSR);
-  PDEBUG("ICSR: 0x%04x\n", icsr);
+  PDEBUG("==> ICSR: 0x%04x\n", icsr);
 
   /* We got an interrupt.  Now try each possible subdevice in turn.
    * (There is the possibility that all subdevices raised an interupt
@@ -2118,15 +2129,17 @@
    * So we've to try each subdevice in turn.) */
   for (i = 0; i < MAX_SUBDEVICES; ++i) {
     if ((icsr & icsr_mask[i]) == icsr_mask[i]) {
+      me8100_subinfo_t *subinfo = &info->subinfo[i];
 
-      me8100_subinfo_t *subinfo = &info->subinfo[i];
+      PDEBUG("==> Interrupt for subdevice %d\n", i);
+
       subinfo->int_seen = jiffies;
       ++subinfo->int_count;
 
       subinfo->int_di = inw(subinfo->regbase + ME8100_INT_DI_REG);
       inw(subinfo->regbase + ME8100_RES_INT_REG);	  // dummy read
 
-      PDEBUG("===> read: 0x%04x\n", subinfo->int_di);
+      PDEBUG("==> read: 0x%04x\n", subinfo->int_di);
       wake_up_interruptible(&subinfo->readq);
       if (subinfo->fasync_ptr) kill_fasync(&subinfo->fasync_ptr, SIGIO, POLL_IN);
     }
@@ -2134,7 +2147,6 @@
 
 
   return;
-
 }