diff -r fc24e3b47731 -r a90b94337569 me8100.c --- a/me8100.c Wed Jan 16 15:54:58 2002 +0100 +++ b/me8100.c Wed Jan 16 20:29:27 2002 +0100 @@ -134,6 +134,7 @@ static int me8100_fasync(int, struct file *, int); static void me8100_isr(int, void *, struct pt_regs *); static ssize_t me8100_read(struct file *, char *, size_t, loff_t *); +static ssize_t me8100_write(struct file *, const char *, size_t, loff_t *); static int me8100_init_board(me8100_info_type *, struct pci_dev *); static int me8100_reset_board(me8100_info_type *); @@ -172,8 +173,8 @@ static int me8100_get_board_info(me8100_info_type *, me8100_info_type *); static int me8100_get_int_count(me8100_int_occur_type *, me8100_info_type *); -static inline int DEVICE(int i) { return MINOR(i) & 0x0f; } -static inline int SUBDEVICE(int i) { return MINOR(i) >> 4; } +static inline int DEVICE(int i) { return i & 0x0f; } +static inline int SUBDEVICE(int i) { return i >> 4; } /* File operations provided by the driver */ @@ -183,7 +184,7 @@ #endif llseek: NULL, /* lseek() */ read: me8100_read, /* read() */ - write: NULL, /* write() */ + write: me8100_write, /* write() */ readdir: NULL, /* readdir() */ poll: NULL, /* poll() */ ioctl: me8100_ioctl, /* ioctl() */ @@ -435,6 +436,9 @@ info->me8100_regbase_size = ME8100_BASE_SIZE; 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 ----------------------------*/ @@ -572,30 +576,40 @@ * when compiling for SMP. */ static int me8100_open(struct inode *inode_ptr, struct file *file_ptr){ - int minor = 0; + int device,subdevice; me8100_info_type *info; + struct me8100_subinfo *subinfo; - PDEBUG("*** me8100_open() is executed for pid: %d\n", file_ptr->f_owner.pid); + PDEBUG("*** me8100_open() is executed\n"); - minor = DEVICE(inode_ptr->i_rdev); + device = DEVICE(MINOR(inode_ptr->i_rdev)); + subdevice = SUBDEVICE(MINOR(inode_ptr->i_rdev)); + info = &info_vec[device]; + subinfo = &info->subinfo[subdevice]; - PDEBUG("*** device: %d, subdevice %d\n", DEVICE(inode_ptr->i_rdev), - SUBDEVICE(inode_ptr->i_rdev)); + PDEBUG("*** device: %d, subdevice %d\n", device, subdevice); - if(minor >= me8100_board_count){ - printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", minor); + if(device >= me8100_board_count){ + printk(KERN_ERR"ME8100:me8100_open():Board %d doesn't exist\n", device); return -ENODEV; } - info = &info_vec[minor]; spin_lock(&info->use_lock); if(info->board_in_use){ - printk(KERN_ERR "WARNING: ME8100:me8100_open():Board %d already in use\n", minor); + printk(KERN_ERR "WARNING: ME8100:me8100_open():Board %d already in use\n", device); } ++info->board_in_use; spin_unlock(&info->use_lock); - /* info->file_ptr = file_ptr; */ /* müssen wir uns nicht hier merken! */ + if (file_ptr->f_mode & FMODE_WRITE) { + 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); + outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG); + } + } MOD_INC_USE_COUNT; @@ -631,15 +645,27 @@ * Modification: */ static int me8100_release(struct inode *inode_ptr, struct file *file_ptr){ - int minor; + int device; int err; me8100_info_type *info; + struct me8100_subinfo* subinfo; PDEBUG("me8100_release() is executed\n"); - minor = DEVICE(inode_ptr->i_rdev); - info = &info_vec[minor]; + device = DEVICE(MINOR(inode_ptr->i_rdev)); + info = &info_vec[device]; + subinfo = &info->subinfo[SUBDEVICE(MINOR(inode_ptr->i_rdev))]; + + /* Resetting write mode if last writer is gone */ + 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); + // outw(subinfo->ctrl_reg, subinfo->regbase + ME8100_CTRL_REG); + } + } /* resetting the board on last close */ @@ -694,11 +720,12 @@ unsigned int service, unsigned long arg){ - int minor = 0; + int minor, device; PDEBUG("me8100_ioctl() is executed\n"); - minor = DEVICE(inode_ptr->i_rdev); + minor = MINOR(inode_ptr->i_rdev); + device = DEVICE(minor); if(_IOC_TYPE(service) != ME8100_MAGIC){ printk(KERN_ERR"ME8100:Invalid ME8100_MAGIC\n"); @@ -711,65 +738,65 @@ switch(service){ case ME8100_READ_ID_A: - return me8100_read_id_a((unsigned short *) arg, &info_vec[minor]); + return me8100_read_id_a((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_CTRL_A: - return me8100_write_ctrl_a((unsigned short *) arg, &info_vec[minor]); + return me8100_write_ctrl_a((unsigned short *) arg, &info_vec[device]); case ME8100_RES_INT_A: - return me8100_res_int_a(&info_vec[minor]); + return me8100_res_int_a(&info_vec[device]); case ME8100_READ_DI_A: - return me8100_read_di_a((unsigned short *) arg, &info_vec[minor]); + return me8100_read_di_a((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_DO_A: - return me8100_write_do_a((unsigned short *) arg, &info_vec[minor]); + return me8100_write_do_a((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_PATTERN_A: - return me8100_write_pattern_a((unsigned short *) arg, &info_vec[minor]); + return me8100_write_pattern_a((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_MASK_A: - return me8100_write_mask_a((unsigned short *) arg, &info_vec[minor]); + return me8100_write_mask_a((unsigned short *) arg, &info_vec[device]); case ME8100_READ_INT_DI_A: - return me8100_read_int_di_a((unsigned short *) arg, &info_vec[minor]); + return me8100_read_int_di_a((unsigned short *) arg, &info_vec[device]); case ME8100_READ_ID_B: - return me8100_read_id_b((unsigned short *) arg, &info_vec[minor]); + return me8100_read_id_b((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_CTRL_B: - return me8100_write_ctrl_b((unsigned short *) arg, &info_vec[minor]); + return me8100_write_ctrl_b((unsigned short *) arg, &info_vec[device]); case ME8100_RES_INT_B: - return me8100_res_int_b(&info_vec[minor]); + return me8100_res_int_b(&info_vec[device]); case ME8100_READ_DI_B: - return me8100_read_di_b((unsigned short *) arg, &info_vec[minor]); + return me8100_read_di_b((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_DO_B: - return me8100_write_do_b((unsigned short *) arg, &info_vec[minor]); + return me8100_write_do_b((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_PATTERN_B: - return me8100_write_pattern_b((unsigned short *) arg, &info_vec[minor]); + return me8100_write_pattern_b((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_MASK_B: - return me8100_write_mask_b((unsigned short *) arg, &info_vec[minor]); + return me8100_write_mask_b((unsigned short *) arg, &info_vec[device]); case ME8100_READ_INT_DI_B: - return me8100_read_int_di_b((unsigned short *) arg, &info_vec[minor]); + return me8100_read_int_di_b((unsigned short *) arg, &info_vec[device]); case ME8100_WRITE_COUNTER_0: - return me8100_write_counter_0((unsigned char *) arg, &info_vec[minor]); + return me8100_write_counter_0((unsigned char *) arg, &info_vec[device]); case ME8100_WRITE_COUNTER_1: - return me8100_write_counter_1((unsigned char *) arg, &info_vec[minor]); + return me8100_write_counter_1((unsigned char *) arg, &info_vec[device]); case ME8100_WRITE_COUNTER_2: - return me8100_write_counter_2((unsigned char *) arg, &info_vec[minor]); + return me8100_write_counter_2((unsigned char *) arg, &info_vec[device]); case ME8100_READ_COUNTER_0: - return me8100_read_counter_0((unsigned char *) arg, &info_vec[minor]); + return me8100_read_counter_0((unsigned char *) arg, &info_vec[device]); case ME8100_READ_COUNTER_1: - return me8100_read_counter_1((unsigned char *) arg, &info_vec[minor]); + return me8100_read_counter_1((unsigned char *) arg, &info_vec[device]); case ME8100_READ_COUNTER_2: - return me8100_read_counter_2((unsigned char *) arg, &info_vec[minor]); + return me8100_read_counter_2((unsigned char *) arg, &info_vec[device]); case ME8100_SETUP_COUNTER: - return me8100_setup_counter((unsigned char *) arg, &info_vec[minor]); + return me8100_setup_counter((unsigned char *) arg, &info_vec[device]); case ME8100_GET_SERIAL: - return me8100_get_serial((unsigned int *) arg, &info_vec[minor]); + return me8100_get_serial((unsigned int *) arg, &info_vec[device]); case ME8100_GET_NAME: - return me8100_get_name((me8100_version_enum_type *) arg, &info_vec[minor]); + return me8100_get_name((me8100_version_enum_type *) arg, &info_vec[device]); case ME8100_INT_OCCUR: - return me8100_int_occur((me8100_int_occur_type *) arg, &info_vec[minor]); + return me8100_int_occur((me8100_int_occur_type *) arg, &info_vec[device]); case ME8100_SETUP_ICSR: - return me8100_setup_icsr((unsigned char *) arg, &info_vec[minor]); + return me8100_setup_icsr((unsigned char *) arg, &info_vec[device]); case ME8100_READ_ICSR: - return me8100_read_icsr((unsigned char *) arg, &info_vec[minor]); + return me8100_read_icsr((unsigned char *) arg, &info_vec[device]); case ME8100_GET_BOARD_INFO: - return me8100_get_board_info((me8100_info_type *)arg, &info_vec[minor]); + return me8100_get_board_info((me8100_info_type *)arg, &info_vec[device]); case ME8100_GET_INT_COUNT: - return me8100_get_int_count((me8100_int_occur_type *)arg,&info_vec[minor]); + return me8100_get_int_count((me8100_int_occur_type *)arg,&info_vec[device]); default: return -EINVAL; } @@ -807,11 +834,11 @@ */ static int me8100_fasync(int fd, struct file *file_ptr, int mode){ int val; - int minor; + int device; me8100_info_type *info; - minor = DEVICE(file_ptr->f_dentry->d_inode->i_rdev); - info = &info_vec[minor]; + device = DEVICE(MINOR(file_ptr->f_dentry->d_inode->i_rdev)); + info = &info_vec[device]; PDEBUG("me8100_fasync() is executed\n"); PDEBUG("** fasync_ptr: %p\n", info->fasync_ptr); @@ -1037,8 +1064,6 @@ return 0; } - - /* * Routine: * me8100_write_pattern_a @@ -2067,14 +2092,14 @@ */ void cleanup_module(void){ extern unsigned int major; - int minor; + int device; int err; PDEBUG("cleanup_module() is executed\n"); - for (minor = me8100_board_count - 1; minor > -1; --minor) { - free_irq(info_vec[minor].int_line, (void *) &info_vec[minor]); + for (device = me8100_board_count - 1; device > -1; --device) { + free_irq(info_vec[device].int_line, (void *) &info_vec[device]); } if(major){ @@ -2084,11 +2109,46 @@ } } -ssize_t me8100_read(struct file * file_ptr, char *buffer, size_t len, loff_t *offset) { - PDEBUG("me8100_read() called\n"); +ssize_t me8100_read(struct file * file_ptr, char *buffer, size_t len, loff_t *offset) +{ + PDEBUG("me8100_read(%d) called\n", len); return -EINVAL; } +/* Writing: we do only write one word (an unsigned short) and return immediatly. Yes, + * we could loop over the complete buffer, but it's not expected to get more data + * than one word. If there's more output, the responsibility is transferred back + * to the C library(?). + */ +ssize_t me8100_write(struct file * file_ptr, const char *buffer, size_t len, loff_t *offset) +{ + int err; + unsigned short val; + int minor; + + minor = MINOR(file_ptr->f_dentry->d_inode->i_rdev); + PDEBUG("me8100_write(%d) called\n", len); + + if (len == 0) return 0; /* do we need this? */ + if (len < 0) return -EINVAL; /* do we need this? */ + + /* Take care of "short" writes! */ + if (len >= sizeof(unsigned short)) { + err = get_user(val, (unsigned short*) buffer); + len = sizeof(unsigned short); + } else { + err = get_user(val, (char*) buffer); + val &= 0xff; + } + + if (err) return err; + + PDEBUG("*** me8100_write: val=0x%04x\n", val); + outw(val, info_vec[DEVICE(minor)].subinfo[SUBDEVICE(minor)].regbase + ME8100_DO_REG); + + return len; +} + /* vim:sts=2 sw=2 aw ai sm: */