# HG changeset patch # User heiko # Date 1011381772 -3600 # Node ID 12065fad228b85dffced60199d4cd8df9ee24267 # Parent ee662c2e14f90c771de30f359fc33803ae648396 1st try irq 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, diff -r ee662c2e14f9 -r 12065fad228b me8100.h --- a/me8100.h Thu Jan 17 20:25:34 2002 +0100 +++ b/me8100.h Fri Jan 18 20:22:52 2002 +0100 @@ -135,6 +135,7 @@ #define ME8100_CTRL_IRQ_MASK 0x60 #define ME8100_CTRL_REG 0x00 //( ,w) +#define ME8100_MASK_REG 0x02 //(r, ) #define ME8100_DI_REG 0x04 //(r, ) #define ME8100_DO_REG 0x06 //( ,w) @@ -171,19 +172,19 @@ #define LOCAL_INT1_EN 0x01 // local interrupt 1 enabled (r,w) #define LOCAL_INT1_POL 0x02 // local interrupt 1 polarity (r,w) #define LOCAL_INT1_STATE 0x04 // local interrupt 1 state (r, ) + #define LOCAL_INT2_EN 0x08 // local interrupt 2 enabled (r,w) #define LOCAL_INT2_POL 0x10 // local interrupt 2 polarity (r,w) #define LOCAL_INT2_STATE 0x20 // local interrupt 2 state (r, ) + +/* Sould be shifted left by 3 if it's used for device B */ +#define LOCAL_INT_EN 0x01 +#define LOCAL_INT_POL 0x02 +#define LOCAL_INT_STATE 0x04 + #define PCI_INT_EN 0x40 // PCI interrupt enable (r,w) #define SOFT_INT 0x80 // Software interrupt (r,w) - -typedef enum { - ME8100_A, - ME8100_B -} me8100_version_enum_type; - - typedef struct{ int int1; int int2; @@ -191,9 +192,19 @@ #ifdef __KERNEL__ +typedef enum { + ME8100_A, + ME8100_B +} me8100_version_enum_type; + +struct me8100_private_data { + unsigned long last_read; /* jiffies */ +}; + struct me8100_subinfo { unsigned int regbase; unsigned short ctrl_reg; + unsigned long last_change; int num_writer; }; @@ -217,7 +228,6 @@ int int_count_1; /* Count of interrupt 1 */ int int_count_2; /* Count of interrupt 2 */ int board_in_use; /* Indicates if board is already in use */ - spinlock_t use_lock; /* Guards board in use */ struct file *file_ptr; /* Pointer to file structure of path */ struct fasync_struct *fasync_ptr; /* .hs */ struct me8100_subinfo subinfo[2]; /* .hs */ diff -r ee662c2e14f9 -r 12065fad228b me8100_test_dio/rtest.c --- a/me8100_test_dio/rtest.c Thu Jan 17 20:25:34 2002 +0100 +++ b/me8100_test_dio/rtest.c Fri Jan 18 20:22:52 2002 +0100 @@ -23,6 +23,8 @@ #include "me8100.h" +#define USE_READ + int main(void){ int err = 0; static int file_handle = -1; @@ -30,6 +32,9 @@ unsigned short value_a; printf("Read test, PID: %d\n", getpid()); +#ifdef USE_READ + printf("Using read()\n"); +#endif file_handle = open("/dev/me8100_0a", O_RDONLY, 0); if(file_handle < 0){ @@ -38,7 +43,11 @@ } for (;;) { +#ifdef USE_READ + read(file_handle, &value_a, sizeof(value_a)); +#else ioctl(file_handle, ME8100_READ_DI_A, &value_a); +#endif printf("Read %04x\n", value_a); sleep(1); } diff -r ee662c2e14f9 -r 12065fad228b me8100_test_dio/wtest.c --- a/me8100_test_dio/wtest.c Thu Jan 17 20:25:34 2002 +0100 +++ b/me8100_test_dio/wtest.c Fri Jan 18 20:22:52 2002 +0100 @@ -55,10 +55,10 @@ #endif for (value_a = 0x01; value_a < 0xffff; ++value_a) { -#ifndef USE_WRITE +#ifdef USE_WRITE + write(file_handle, &value_a, sizeof(value_a)); +#else ioctl(file_handle, ME8100_WRITE_DO_A, &value_a); -#else - write(file_handle, &value_a, sizeof(value_a)); #endif printf("Wrote %04x\n", value_a); sleep(3);