--- 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,