me8100.c
changeset 8 12065fad228b
parent 7 ee662c2e14f9
child 9 ed7a768ff898
--- a/me8100.c	Thu Jan 17 20:25:34 2002 +0100
+++ b/me8100.c	Fri Jan 18 20:22:52 2002 +0100
@@ -482,8 +482,6 @@
   info->file_ptr = NULL;
   info->fasync_ptr = NULL;
   info->board_in_use = 0;
-  spin_lock_init(&info->use_lock);
-
   
   /*--------------------------- Reset the board -----------------------------*/
 
@@ -571,9 +569,6 @@
  *   On success the return value is 0 else failure.
  *--------------------------------------------------------------------------
  * Author: GG                                                               
- * Modification:                                                            
- *   01.10.04  Guard board_in_use with spin_lock, cause of race condition
- *             when compiling for SMP.
  */
 static int me8100_open(struct inode *inode_ptr, struct file *file_ptr){
   int device,subdevice;
@@ -584,38 +579,76 @@
 
   device = DEVICE(MINOR(inode_ptr->i_rdev));
   subdevice = SUBDEVICE(MINOR(inode_ptr->i_rdev));
+  PDEBUG("*** device: %d, subdevice %d\n", device, subdevice);
+
   info = &info_vec[device];
   subinfo = &info->subinfo[subdevice];
 
-  PDEBUG("*** device: %d, subdevice %d\n", device, subdevice);
 
   if(device >= me8100_board_count){
     printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", device);
     return -ENODEV;
   }
 
-  spin_lock(&info->use_lock);
-  if(info->board_in_use){
-    printk(KERN_ERR "WARNING: ME8100:me8100_open():Board %d already in use\n", device);
-  }
-  ++info->board_in_use;
-  spin_unlock(&info->use_lock);
+  MOD_INC_USE_COUNT;
 
   if (file_ptr->f_mode & FMODE_WRITE) {
+    /* If we're the first write, the control register has to be
+     * setup properly. */
+
     PDEBUG("*** open for writing\n");
 
     if (0 == subinfo->num_writer++) {
       subinfo->ctrl_reg |= ME8100_CTRL_ENIO | ME8100_CTRL_SOURCE;
-      PDEBUG("*** setting ENIO+SOURCE mode: ctrl: 0x%x\n", subinfo->ctrl_reg);
+      PDEBUG("*** adding ENIO+SOURCE mode: ctrl: 0x%x\n", subinfo->ctrl_reg);
       outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
     }
   }
 
+
   if (file_ptr->f_mode & FMODE_READ) {
+    /* If we're a reader, the IRQ should be setup -- if not done already
+     * (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. */
+
+    struct me8100_private_data *priv;
+
     PDEBUG("*** open for reading\n");
+
+    if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {	  
+      printk(KERN_ERR"ME8100:me8100_open: kmalloc() failed.\n");
+      me8100_release(inode_ptr, file_ptr); 
+      return -EIO;
+    }
+
+    priv->last_read = 0;
+    file_ptr->private_data = priv;
+
+    /* Now we've to setup the IRQ line.  We suppose that it should be done
+     * in "mask" manner.  If somebody wishes to do it the otherway or if somebody
+     * wants to change the mask, ioctl() should be used. */
+    {
+      int mask = 0xffff;
+      unsigned short icsr = PCI_INT_EN | ((LOCAL_INT_EN | LOCAL_INT_POL) << (3 * subdevice)); 
+
+
+      /* 1) setup the PLX register */
+      PDEBUG("*** plx = 0x%0x\n", icsr);
+      outb(icsr, info->plx_regbase + PLX_ICSR);
+
+      /* 2) setup the irq flags in regbase */
+      subinfo->ctrl_reg |= ME8100_CTRL_IRQ_MASK;
+      PDEBUG("*** ctrl = 0x%04x\n", subinfo->ctrl_reg);
+      outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
+
+      /* 3) setup the interrupt mask */
+      PDEBUG("*** irqmask = 0x%04x\n", mask);
+      outw(mask, subinfo->regbase + ME8100_MASK_REG);
+
+    }
   }    
 
-  MOD_INC_USE_COUNT;
 
   return 0;
 }
@@ -681,6 +714,8 @@
     }
   }
   me8100_fasync(-1, file_ptr, 0);
+  if (file_ptr->private_data) kfree(file_ptr->private_data);
+  file_ptr->private_data = NULL;
 
   MOD_DEC_USE_COUNT;
   PDEBUG("me8100_release() is leaved\n");
@@ -2034,7 +2069,7 @@
   unsigned short dummy;
   me8100_info_type *info;
 
-  PDEBUG("me8100_isr() is executed\n");
+  PDEBUG("*** => me8100_isr() is executed\n");
 
   info = (me8100_info_type *) dev_id;
 
@@ -2113,21 +2148,35 @@
   }
 }
 
+/* Reading: we do only read (at most) one word (an usigned short) and return immediatly,
+ * thus passing the responsibility for reading a bunch of words back to the caller.
+ * This seems to be ok, since it's not expected to read more than one word at once
+ * (the port is one word wide only!)
+ *
+ * If a a reader (identified by the file_ptr) calls this functions the first time,
+ * the current input is returned.  Every succsessive read is then put to sleep until
+ * the status of the input changed.  (Unless the IRQ behaviour if the device is changed by
+ * some ioctl()s.)
+ */
 ssize_t me8100_read(struct file * file_ptr, char *buffer, size_t len, loff_t *offset) 
 {
   int err;
   unsigned short val;
+  struct me8100_private_data *priv = file_ptr->private_data;
   int minor;
+  struct me8100_subinfo *subinfo;
 
   PDEBUG("me8100_read(%d) called\n", len);
 
   minor = MINOR(file_ptr->f_dentry->d_inode->i_rdev);
+  subinfo = &info_vec[DEVICE(minor)].subinfo[SUBDEVICE(minor)];
   
   if (len == 0) return 0;	/* do we really need this check? */
   if (len < 0) return -EINVAL;	/* do we really need this check? */
+  if (priv->last_read >= subinfo->last_change) return 0;  /* nothing has changed */
 
-  val = inw(info_vec[DEVICE(minor)].subinfo[SUBDEVICE(minor)].regbase + ME8100_DI_REG);
-  PDEBUG("me8100_read: val=0x%0x\n", val);
+  val = inw(subinfo->regbase + ME8100_DI_REG);
+  PDEBUG("me8100_read: val=0x%04x\n", val);
 
   if (len >= sizeof(val)) {
     err = put_user(val, (unsigned short*) buffer);
@@ -2137,7 +2186,6 @@
   }
 
   return len;
-
 }
 
 /* Writing: we do only write one word (an unsigned short) and return immediatly.  Yes,