diff -r c3f6d5e9713a -r b9baa645576a me8100.c --- 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,