1st try irq
authorheiko
Fri, 18 Jan 2002 20:22:52 +0100
changeset 8 12065fad228b
parent 7 ee662c2e14f9
child 9 ed7a768ff898
1st try irq
me8100.c
me8100.h
me8100_test_dio/rtest.c
me8100_test_dio/wtest.c
--- 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,
--- a/me8100.h	Thu Jan 17 20:25:34 2002 +0100
+++ b/me8100.h	Fri Jan 18 20:22:52 2002 +0100
@@ -135,6 +135,7 @@
 #define ME8100_CTRL_IRQ_MASK		0x60
 
 #define ME8100_CTRL_REG		       0x00	  //( ,w)
+#define ME8100_MASK_REG		       0x02	  //(r, )
 #define ME8100_DI_REG		       0x04	  //(r, )
 #define ME8100_DO_REG		       0x06	  //( ,w)
 
@@ -171,19 +172,19 @@
 #define LOCAL_INT1_EN             0x01  // local interrupt 1 enabled  (r,w)
 #define LOCAL_INT1_POL            0x02  // local interrupt 1 polarity (r,w)
 #define LOCAL_INT1_STATE          0x04  // local interrupt 1 state    (r, )
+
 #define LOCAL_INT2_EN             0x08  // local interrupt 2 enabled  (r,w)
 #define LOCAL_INT2_POL            0x10  // local interrupt 2 polarity (r,w)
 #define LOCAL_INT2_STATE          0x20  // local interrupt 2 state    (r, )
+
+/* Sould be shifted left by 3 if it's used for device B */
+#define LOCAL_INT_EN		  0x01
+#define LOCAL_INT_POL		  0x02
+#define LOCAL_INT_STATE		  0x04
+
 #define PCI_INT_EN                0x40  // PCI interrupt enable       (r,w)
 #define SOFT_INT                  0x80  // Software interrupt         (r,w)
 
-
-typedef enum {  
-  ME8100_A, 
-  ME8100_B
-} me8100_version_enum_type; 
-
-
 typedef struct{
   int int1;
   int int2;
@@ -191,9 +192,19 @@
 
 #ifdef __KERNEL__
 
+typedef enum {  
+  ME8100_A, 
+  ME8100_B
+} me8100_version_enum_type; 
+
+struct me8100_private_data {
+  unsigned long last_read;		  /* jiffies */
+};
+
 struct me8100_subinfo {
   unsigned int regbase;
   unsigned short ctrl_reg;
+  unsigned long last_change;
   int num_writer;
 };
 
@@ -217,7 +228,6 @@
   int int_count_1;                  /* Count of interrupt 1                  */
   int int_count_2;                  /* Count of interrupt 2                  */
   int board_in_use;                 /* Indicates if board is already in use  */
-  spinlock_t use_lock;              /* Guards board in use                   */
   struct file *file_ptr;            /* Pointer to file structure of path     */
   struct fasync_struct *fasync_ptr; /* .hs */
   struct me8100_subinfo subinfo[2];   /* .hs */
--- a/me8100_test_dio/rtest.c	Thu Jan 17 20:25:34 2002 +0100
+++ b/me8100_test_dio/rtest.c	Fri Jan 18 20:22:52 2002 +0100
@@ -23,6 +23,8 @@
 
 #include "me8100.h"
 
+#define USE_READ
+
 int main(void){
   int err = 0;
   static int file_handle = -1;
@@ -30,6 +32,9 @@
   unsigned short value_a;
 
   printf("Read test, PID: %d\n", getpid());
+#ifdef USE_READ
+  printf("Using read()\n");
+#endif
   file_handle = open("/dev/me8100_0a", O_RDONLY, 0);
 
   if(file_handle < 0){
@@ -38,7 +43,11 @@
   }
 
   for (;;) {
+#ifdef USE_READ
+    read(file_handle, &value_a, sizeof(value_a));
+#else
     ioctl(file_handle, ME8100_READ_DI_A, &value_a);
+#endif
     printf("Read  %04x\n", value_a);
     sleep(1);
   }
--- a/me8100_test_dio/wtest.c	Thu Jan 17 20:25:34 2002 +0100
+++ b/me8100_test_dio/wtest.c	Fri Jan 18 20:22:52 2002 +0100
@@ -55,10 +55,10 @@
 #endif
 
   for (value_a = 0x01; value_a < 0xffff; ++value_a) {
-#ifndef USE_WRITE
+#ifdef USE_WRITE
+    write(file_handle, &value_a, sizeof(value_a));
+#else
     ioctl(file_handle, ME8100_WRITE_DO_A, &value_a);
-#else
-    write(file_handle, &value_a, sizeof(value_a));
 #endif
     printf("Wrote %04x\n", value_a);
     sleep(3);