// test driver for Linux 2.2 // open-read-write-ioctl-poll-release // gcc -c ljtest22.c -O -Wall -Wstrict-prototypes // mknod -m 0666 /dev/ljtest[0-5] c 60 [0-5] #define MODULE #define __KERNEL__ #include #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) # define MODVERSIONS #endif #ifdef MODVERSIONS # include #endif #include #include #include #include #include #include #include static int devmajor=60; static char *devname="LJTest"; MODULE_PARM(devmajor, "i"); MODULE_PARM(devname, "s"); // アクセス管理部 #define MAXACCESS 10 struct AInfo { unsigned long f_version; int id,fresh; }; static struct AInfo ainfo[MAXACCESS]; // メッセージ保持部 #define MAXMESSAGE 4 #define MAXMLEN 256 struct Mess { int length; char message[MAXMLEN]; struct wait_queue *wait; // 休眠待機用 }; static struct Mess mess[MAXMESSAGE]; static int ljtest_open(struct inode * inode, struct file * file) { int i,minor=MINOR(inode->i_rdev); printk("%s open\n",devname); printk(" file->f_version : %lu \n",file->f_version); printk(" MINOR(inode->i_rdev): %d \n",minor); if(minor==240) { MOD_INC_USE_COUNT; return -EBUSY; } if(minor==241) { MOD_DEC_USE_COUNT; return -EBUSY; } if(minor>=MAXMESSAGE) { return -EINVAL; } // アクセス条件成立 for(i=0;if_version; ainfo[i].id=minor; ainfo[i].fresh=1; file->private_data=(void *)(&ainfo[i]); return 0; } static int ljtest_release(struct inode * inode, struct file * file) { struct AInfo *ai=(struct AInfo *)(file->private_data); if(ai==NULL) { printk("something wrong?\n"); } else ai->f_version=0; printk("%s release\n",devname); printk(" file->f_version : %lu \n\n",file->f_version); MOD_DEC_USE_COUNT; return 0; } static int ljtest_read(struct file * file, char * buff, size_t count, loff_t *pos) { int len,id; struct AInfo *ai=(struct AInfo *)(file->private_data); printk("%s read\n",devname); if(ai==NULL) { printk("something wrong?\n"); return -EINVAL; } id=ai->id; if(!ai->fresh) { len=0; } else { len=mess[id].length; if(len>count) len=count; copy_to_user(buff,mess[id].message,len); ai->fresh=0; // 読み終り } printk(" requested: %d bytes returned: %d bytes\n",count,len); return len; } static int ljtest_write(struct file * file, const char * buff, size_t count, loff_t *pos) { int len,id,i; struct AInfo *ai=(struct AInfo *)(file->private_data); printk("%s write\n",devname); if(ai==NULL) { printk("something wrong?\n"); return -EINVAL; } id=ai->id; if(!ai->fresh) { printk(" requested: %d bytes received: non\n",count); return -ENOSPC; } len=count; if(len>MAXMLEN) len=MAXMLEN; copy_from_user(mess[id].message,buff,len); mess[id].length=len; ai->fresh=0; // 書き終り printk(" requested: %d bytes received: %d bytes\n",count,len); // リフレッシュ処理 for(i=0;iprivate_data); printk("%s ioctl cmd=%d, arg=%ld\n", devname,cmd,arg); if(ai==NULL) { printk("something wrong?\n"); return -EINVAL; } switch(cmd) { case 1: ai->fresh=1; return 0; // refresh case 2: if((arg<0)||(arg>=MAXMESSAGE)) return -EINVAL; ai->id=arg; return 0; } return -EINVAL; } static unsigned int ljtest_poll(struct file *file, struct poll_table_struct *ptab) { struct AInfo *ai=(struct AInfo *)(file->private_data); printk("%s poll\n",devname); if(ai==NULL) { printk("something wrong?\n"); return -EINVAL; } if(ai->fresh) return POLLIN|POLLRDNORM; // 読み込みOK poll_wait(file,&(mess[ai->id].wait),ptab); return 0; } static struct file_operations ljtest_fops = { NULL, // llseek ljtest_read, // read ljtest_write, // write NULL, // readdir ljtest_poll, // poll ljtest_ioctl, // ioctl NULL, // mmap ljtest_open, // open NULL, // flush ljtest_release,// release NULL, // fsync NULL, // fasync NULL, // check_media_change NULL, // revalidate NULL, // lock }; int init_module(void) { int i; printk("install '%s' into major %d\n",devname,devmajor); for(i=0;i