--- 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:
*/