me8100.c
changeset 15 b9baa645576a
parent 14 c3f6d5e9713a
child 18 d1686272f84d
--- a/me8100.c	Mon Jan 21 21:52:00 2002 +0100
+++ b/me8100.c	Tue Jan 22 20:30:44 2002 +0100
@@ -474,12 +474,13 @@
   info->file_ptr = NULL;
   info->board_in_use = 0;
 
+
+  /* Set default values for the subinfo. */
   info->subinfo[0].regbase = info->me8100_regbase;
   info->subinfo[1].regbase = info->me8100_regbase + 0x0C;
 
   for (i = 0; i <= 1; ++i) {
     info->subinfo[i].int_seen = jiffies;    /* suppose we got just the first irq */
-    info->subinfo[i].int_count = 0;
     info->subinfo[i].fasync_ptr = NULL;
     init_waitqueue_head(&info->subinfo[i].readq);
   }
@@ -528,6 +529,7 @@
  * Modification:                                                            
  */
 static int me8100_reset_board(me8100_info_type *info){
+  int i;
   unsigned char icsr = 0x12;
 
   PDEBUG("me8100_reset_board() is executed\n");
@@ -536,19 +538,16 @@
   PDEBUG("me8100_reset_board(): plx_mode = 0x%X\n", icsr);
   outb(icsr, info->plx_regbase + PLX_ICSR);
   
-  /* Ports to high impedance, interrupts deactivated */
-  outw(0x00, info->me8100_regbase + ME8100_CTRL_REG_A);
-  outw(0x0000, info->me8100_regbase + ME8100_CTRL_REG_B);
-
-  /* Reset any pending interrupt */
-  inw(info->me8100_regbase + ME8100_RES_INT_REG_A);
-  inw(info->me8100_regbase + ME8100_RES_INT_REG_B);
+  for (i = 0; i <= 1; ++i) {
+    /* Ports to high impedance, interrupts deactivated */
+    outw(0x00, info->subinfo[i].regbase + ME8100_CTRL_REG);
+    /* Reset any pending interrupt */
+    inw(info->subinfo[i].regbase + ME8100_RES_INT_REG);
+  }
 
   return 0;
 }
 
-
-
 /*
  * Routine:                                                                 
  *   me8100_open                                                              
@@ -581,7 +580,7 @@
 
   device = DEVICE(MINOR(inode_ptr->i_rdev));
   subdevice = SUBDEVICE(MINOR(inode_ptr->i_rdev));
-  PDEBUG("*** device: %d, subdevice %d\n", device, subdevice);
+  PDEBUG("*** device: %d, subdevice %d with flags %0x\n", device, subdevice, file_ptr->f_flags);
 
   if(device >= me8100_board_count){
     printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", device);
@@ -2205,40 +2204,55 @@
 {
   int err;
   unsigned short val;
-  struct me8100_private_data *priv = file_ptr->private_data;
   int minor;
+  struct me8100_private_data *priv;
   struct me8100_subinfo *subinfo;
 
-  PDEBUG("me8100_read(%d) called\n", len);
+  PDEBUG("me8100_read() called\n");
 
   minor = MINOR(file_ptr->f_dentry->d_inode->i_rdev);
   subinfo = &info_vec[DEVICE(minor)].subinfo[SUBDEVICE(minor)];
+  priv = file_ptr->private_data;
   
   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->int_seen) {	/* alread seen, sleep */
-    PDEBUG("*** going to sleep\n");
-    if (wait_event_interruptible(subinfo->readq, (priv->last_read != subinfo->int_seen))) {
-      PDEBUG("** awoken on signal?\n");
+  /* If the time we did the last read operation is more recent than the
+   * last interupt, we have to go to sleep (or return -EAGAIN in non blockin
+   * mode).  Then, if we're awoken, we return the value that triggered the
+   * interrupt.  (If awoken from a signal, we return -ERESTARTSYS.)
+   *
+   * If we haven't read any data since the last irq occured, we return
+   * the current(!) value visible on the port!
+   *
+   * Is this some inconsistency?  What does happen if somebody changes the
+   * interrupt behaviour.  What, if intterupts are disabled at all?  Should
+   * we check this an return the current value visible at the port then?
+   */
+  if (priv->last_read >= subinfo->int_seen) {
+    if (file_ptr->f_flags & O_NONBLOCK) return -EAGAIN;
+
+    if (wait_event_interruptible(subinfo->readq, (priv->last_read != subinfo->int_seen))) 
       return -ERESTARTSYS;
-    }
-    val = subinfo->int_di;	/* the value that caused the interrupt */
-  } else {					/* not yet seen ... */
-    val = inw(subinfo->regbase + ME8100_DI_REG);
-    PDEBUG("me8100_read: val=0x%04x\n", val);
-  }
+    val = subinfo->int_di;	
+
+  } else val = inw(subinfo->regbase + ME8100_DI_REG);
 
+  PDEBUG("me8100_read: val=0x%04x\n", val);
+
+  /* Remember the time of the last interrupt we've seen.  (It might be 
+   * 0 if there was no interrupt yet.  This doesn't hurt, since the next
+   * read will see this (see above) and will wait until an irq raises.)
+   */
   priv->last_read = subinfo->int_seen;
 
+  /* Return at most 2 byte, but check if the read want's them both! */
   if (len >= sizeof(val)) {
     err = put_user(val, (unsigned short*) buffer);
     len = sizeof(val);
-  } else {
-    err = put_user(val, (char*) buffer);
-  }
+  } else err = put_user(val, (char*) buffer);
 
-  return len;
+  return err ? err : len;
 }
 
 /* Writing: we do only write one word (an unsigned short) and return immediatly.  Yes,