diff -r a60ff25672a0 -r 67e56b4bce81 me8100.c --- 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);