--- 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);