sleep/wakeup
authorheiko
Mon, 21 Jan 2002 19:35:53 +0100
changeset 12 67e56b4bce81
parent 11 a60ff25672a0
child 13 f7fb771d7842
sleep/wakeup
me8100.c
me8100.h
me8100_test_dio/rtest.c
me8100_test_int/test.c
--- a/me8100.c	Fri Jan 18 21:00:56 2002 +0100
+++ b/me8100.c	Mon Jan 21 19:35:53 2002 +0100
@@ -125,6 +125,10 @@
 /* Major Device Number. 0 means to get it automatically from the System */
 static unsigned int major = 0;
 
+/* The queue all the readers are on. */
+DECLARE_WAIT_QUEUE_HEAD(me8100_readq);
+
+
 
 /* Prototypes */
 static int me8100_open(struct inode *, struct file *);
@@ -340,6 +344,7 @@
  */
 static int me8100_init_board(me8100_info_type *info, 
 			     struct pci_dev *pci_dev_ptr){
+  int i;
   int result = 0;
   unsigned int plx_regbase_tmp;
   unsigned int me8100_regbase_tmp;
@@ -437,10 +442,6 @@
   info->me8100_regbase = me8100_regbase_tmp & PCI_BASE_ADDRESS_IO_MASK;
   PDEBUG("me8100_init_board():IO at 0x%04X\n", info->me8100_regbase);
 
-  info->subinfo[0].regbase = info->me8100_regbase;
-  info->subinfo[1].regbase = info->me8100_regbase + 0x0C;
-  
-
   /*--------------------------- init device info ----------------------------*/
 
   result = pci_read_config_dword(pci_dev_ptr, 0x2C, &info->serial_no);
@@ -475,13 +476,18 @@
   info->int_line = pci_dev_ptr->irq;
   PDEBUG("me8100_init_board():int_line = %d\n", info->int_line);
 
-  info->int_count_1 = 0;
-  info->int_count_2 = 0;
-  info->int1 = 0;
-  info->int2 = 0;
   info->file_ptr = NULL;
-  info->fasync_ptr = NULL;
   info->board_in_use = 0;
+
+  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 = 0;
+    info->subinfo[i].int_count = 0;
+    info->subinfo[i].fasync_ptr = NULL;
+  }
+  
   
   /*--------------------------- Reset the board -----------------------------*/
 
@@ -581,8 +587,10 @@
   subdevice = SUBDEVICE(MINOR(inode_ptr->i_rdev));
   PDEBUG("*** device: %d, subdevice %d\n", device, subdevice);
 
-  info = &info_vec[device];
-  subinfo = &info->subinfo[subdevice];
+  if(device >= me8100_board_count){
+    printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", device);
+    return -ENODEV;
+  }
 
   /* Currently we can't support the old style minor numbers. */
   if (subdevice < 0) {
@@ -590,24 +598,23 @@
     return -ENODEV;
   }
 
-
-  if(device >= me8100_board_count){
-    printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", device);
-    return -ENODEV;
-  }
+  info = &info_vec[device];
+  subinfo = &info->subinfo[subdevice];
 
   MOD_INC_USE_COUNT;
 
   if (file_ptr->f_mode & FMODE_WRITE) {
-    /* If we're the first write, the control register has to be
+    /* If we're the first writer, 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("*** adding %0x to ctrl: 0x%04x\n",
-	ME8100_CTRL_ENIO | ME8100_CTRL_SOURCE, subinfo->ctrl_reg);
+      PDEBUG("*** first writer\n");
+      subinfo->ctrl_wflags = ME8100_CTRL_ENIO | ME8100_CTRL_SOURCE;
+      subinfo->ctrl_reg |= subinfo->ctrl_wflags;
+      PDEBUG("*** adding 0x%0x to ctrl => 0x%04x\n",
+	subinfo->ctrl_wflags, subinfo->ctrl_reg);
       outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
     }
   }
@@ -623,42 +630,42 @@
 
     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. */
     if (0 == subinfo->num_reader++) {
-      
+      int mask = 0xffff;
+      unsigned short icsr = PCI_INT_EN
+	| ((LOCAL_INT_EN | LOCAL_INT_POL) << (3 * subdevice));
       PDEBUG("*** first reader...\n");
+      subinfo->ctrl_rflags = 0;
 
-      if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {	  
+      /* Allocate memory for the private data.  If allocating fails,
+       * call m8100_release() (which in turn decrements the mod-in-use-count)
+       * and return IO error. */
+      if (NULL == (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {	  
 	printk(KERN_ERR"ME8100:me8100_open: kmalloc() failed.\n");
-	me8100_release(inode_ptr, file_ptr); 
+	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);
+      /* 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("*** adding %0x to ctrl: 0x%04x\n", ME8100_CTRL_IRQ_MASK, 
-	  subinfo->ctrl_reg);
-	outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
+      /* 2) 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);
 
-	/* 3) setup the interrupt mask */
-	PDEBUG("*** irqmask = 0x%04x\n", mask);
-	outw(mask, subinfo->regbase + ME8100_MASK_REG);
+      /* 3) setup the interrupt mask */
+      PDEBUG("*** irqmask = 0x%04x\n", mask);
+      outw(mask, subinfo->regbase + ME8100_MASK_REG);
 
-      }
     } /* first reader */
   } /* reader */    
 
@@ -711,9 +718,12 @@
   if (file_ptr->f_mode & FMODE_WRITE) {
     PDEBUG("*** writer closes\n");
     if (0 == --subinfo->num_writer) {
-	subinfo->ctrl_reg &= !ME8100_CTRL_ENIO;
+	/*
 	PDEBUG("*** resetting ENIO mode ctrl: 0x%x\n", subinfo->ctrl_reg);
+	subinfo->ctrl_reg &= !subinfo->ctrl_wflags;
+	subinfo->ctrl_wflags = 0;
 	outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
+	*/
     }
   }
 
@@ -721,7 +731,8 @@
     PDEBUG("*** reader close\n");
     if (0 == --subinfo->num_reader) {
       PDEBUG("*** last reader...\n");
-      subinfo->ctrl_reg &= !ME8100_CTRL_IRQ_MASK; /* 11 */
+      subinfo->ctrl_reg &= !subinfo->ctrl_rflags;
+      subinfo->ctrl_rflags = 0;
       PDEBUG("*** resetting IRQ mode ctrl: 0x%x\n", subinfo->ctrl_reg);
       outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG);
      }
@@ -737,6 +748,9 @@
       return err;
     }
   }
+
+  /* Cleanup all async notification queues associated to the 
+   * current file handle as well as free any allocated memory. */
   me8100_fasync(-1, file_ptr, 0);
   if (file_ptr->private_data) kfree(file_ptr->private_data);
   file_ptr->private_data = NULL;
@@ -897,16 +911,19 @@
  */
 static int me8100_fasync(int fd, struct file *file_ptr, int mode){
   int val;
-  int device;
+  int device, subdevice;
   me8100_info_type *info;
+  struct me8100_subinfo *subinfo;
 
   device = DEVICE(MINOR(file_ptr->f_dentry->d_inode->i_rdev));
+  subdevice = SUBDEVICE(MINOR(file_ptr->f_dentry->d_inode->i_rdev));
   info = &info_vec[device];
+  subinfo = &info_vec[device].subinfo[subdevice];
 
   PDEBUG("me8100_fasync() is executed\n");
-  PDEBUG("** fasync_ptr: %p\n", info->fasync_ptr);
-  val = fasync_helper(fd, file_ptr, mode, &info->fasync_ptr);
-  PDEBUG("** fasync_ptr: %p\n", info->fasync_ptr);
+  PDEBUG("** fasync_ptr: %p\n", subinfo->fasync_ptr);
+  val = fasync_helper(fd, file_ptr, mode, &subinfo->fasync_ptr);
+  PDEBUG("** fasync_ptr: %p\n", subinfo->fasync_ptr);
   return val;
 }
 
@@ -1931,8 +1948,8 @@
 
   save_flags(flags);
   cli();
-  int_occur.int1 = info->int1;
-  int_occur.int2 = info->int2;
+  int_occur.int1 = info->subinfo[0].int_seen;
+  int_occur.int2 = info->subinfo[1].int_seen;
   restore_flags(flags);
 
   err = copy_to_user(arg, &int_occur, sizeof(int_occur));
@@ -2049,8 +2066,8 @@
 
   save_flags(flags);
   cli();
-  int_count.int1 = info->int_count_1;
-  int_count.int2 = info->int_count_2;
+  int_count.int1 = info->subinfo[0].int_count;
+  int_count.int2 = info->subinfo[1].int_count;
   restore_flags(flags);
 
   if(copy_to_user(arg, &int_count, sizeof(int_count)))
@@ -2093,7 +2110,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;
 
@@ -2102,35 +2119,39 @@
     return;
   }
 
-  info->int1 = 0;
-  info->int2 = 0;
+  info->subinfo[0].int_seen = 0;
+  info->subinfo[1].int_seen = 0;
 
   icsr = inb(info->plx_regbase + PLX_ICSR);
+  PDEBUG("== ICSR: 0x%04x\n", icsr);
 
-  if((icsr & 0x04)&&(icsr & 0x40)&&(icsr & 0x01)){
-    PDEBUG("me8100_isr():Int1 occured\n");
-    info->int1 = 1;
-    info->int_count_1++;
-    dummy = inw(info->me8100_regbase + ME8100_RES_INT_REG_A); 
-  }
 
-  if((icsr & 0x20)&&(icsr & 0x40)&&(icsr & 0x08)){
+  /* A: 0x04 & 0x40 & 0x01 */
+  /* B: 0x20 & 0x40 & 0x08 */
+  if((icsr & 0x45) == 0x45) {
+    struct me8100_subinfo *subinfo = &info->subinfo[0];
+    PDEBUG("me8100_isr():Int1 occured\n");
+    subinfo->int_seen = 1;
+    subinfo->int_count++;
+    dummy = inw(info->me8100_regbase + ME8100_RES_INT_REG_A); 
+    if (subinfo->fasync_ptr) kill_fasync(&subinfo->fasync_ptr, SIGIO, POLL_IN);
+
+  } else if((icsr & 0x68) == 0x68) {
+    struct me8100_subinfo *subinfo = &info->subinfo[1];
     PDEBUG("me8100_isr():Int2 occured\n");
-    info->int2 = 1;
-    info->int_count_2++;
+    subinfo->int_seen = 1;
+    subinfo->int_count++;
     dummy = inw(info->me8100_regbase + ME8100_RES_INT_REG_B); 
-  }
+    if (subinfo->fasync_ptr) kill_fasync(&subinfo->fasync_ptr, SIGIO, POLL_IN);
 
-  if(!(info->int1 || info->int2)){
+  } else {
     PDEBUG("me8100_isr():Not this Board\n");
     return;
   }
 
-  if(info->fasync_ptr){
-    PDEBUG("*** me8100_isr():send signal to process %p->%d\n", 
-      info->fasync_ptr, info->fasync_ptr->fa_file->f_owner.pid);
-    kill_fasync(&info->fasync_ptr, SIGIO, POLL_IN);
-  }
+  PDEBUG("*** wake up sleeper\n");
+  /* should be splitted too (one queue for each channel) */
+  wake_up_interruptible(&me8100_readq);
 } 
 
 
@@ -2197,7 +2218,11 @@
   
   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 */
+  if (priv->last_read > subinfo->last_change) {
+    PDEBUG("*** going to sleep\n");
+    interruptible_sleep_on(&me8100_readq);
+  }
+  priv->last_read = jiffies;
 
   val = inw(subinfo->regbase + ME8100_DI_REG);
   PDEBUG("me8100_read: val=0x%04x\n", val);
--- a/me8100.h	Fri Jan 18 21:00:56 2002 +0100
+++ b/me8100.h	Mon Jan 21 19:35:53 2002 +0100
@@ -197,16 +197,27 @@
   ME8100_B
 } me8100_version_enum_type; 
 
+/* private data: data that are to be stored in the file pointer we
+ * get from the calling process. */
 struct me8100_private_data {
-  unsigned long last_read;		  /* jiffies */
+  unsigned long last_read;	   /* jiffies */
 };
 
 struct me8100_subinfo {
   unsigned int regbase;
   unsigned short ctrl_reg;
   unsigned long last_change;
+
+  unsigned short ctrl_wflags;		    /* flags the writer(s) (re)set */
+  unsigned short ctrl_rflags;		    /* flags the reader(s) (re)set */
+
   int num_writer;
   int num_reader;
+
+  int int_seen;
+  int int_count;
+
+  struct fasync_struct *fasync_ptr;
 };
 
 typedef struct{
@@ -224,13 +235,8 @@
   int pci_dev_no;                   /* PCI device number                     */
   int pci_func_no;                  /* PCI function number                   */
   char int_line;                    /* IRQ assigned from the PCI BIOS        */
-  int int1;                         /* Marks witch interrupt occured         */
-  int int2;                         /* Marks witch interrupt occured         */
-  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  */
   struct file *file_ptr;            /* Pointer to file structure of path     */
-  struct fasync_struct *fasync_ptr; /* .hs */
   struct me8100_subinfo subinfo[2];   /* .hs */
 } me8100_info_type;
 
--- a/me8100_test_dio/rtest.c	Fri Jan 18 21:00:56 2002 +0100
+++ b/me8100_test_dio/rtest.c	Mon Jan 21 19:35:53 2002 +0100
@@ -42,14 +42,22 @@
     return 1;
   }
 
-  for (;;) {
+  for (;;sleep(1)) {
 #ifdef USE_READ
-    read(file_handle, &value_a, sizeof(value_a));
+    int n;
+    n =read(file_handle, &value_a, sizeof(value_a));
+    if (n == 0) {
+      fprintf(stderr, "read 0 bytes\n");
+      continue;
+    } 
+    if (n < 0) {
+      fprintf(stderr, "read 0 bytes: %m\n");
+      continue;
+    }
 #else
     ioctl(file_handle, ME8100_READ_DI_A, &value_a);
 #endif
     printf("Read  %04x\n", value_a);
-    sleep(1);
   }
 
   err = close(file_handle);
--- a/me8100_test_int/test.c	Fri Jan 18 21:00:56 2002 +0100
+++ b/me8100_test_int/test.c	Mon Jan 21 19:35:53 2002 +0100
@@ -106,7 +106,7 @@
   printf("<<<--- WAITING FOR INTERRUPTS BY BIT MASK --->>>\n\n");
 
   i = 0;
-  while(i < 10) {
+  while(i < 1000) {
     select(0, NULL, NULL, NULL, NULL);
   }