diff -r ee662c2e14f9 -r 12065fad228b me8100.c --- 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,