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