#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h> //copy_to_user()
#define BUFF_SIZE 1024
#define MAJOR_NUMBER 250
#define DEVICE_NAME "mydev"
struct kthread_t
{
struct task_struct *thread;
int running;
};
struct kthread_t *kthread_w = NULL;
struct kthread_t *kthread_r = NULL;
static struct workqueue_struct *my_wq;
static char *buffer = NULL;
static int sz_data =0;
static int Major;
static int Device_open = 0;
static char *msg_Ptr;
static char msg[80];
static int write_thread(void *unused);
static int read_thread(void *unused);
static DECLARE_WORK(write_wq,(void *)write_thread);
static DECLARE_WORK(read_wq,(void *)read_thread);
static int my_open( struct inode *inode, struct file *filp );
static int my_release( struct inode *inode, struct file *filp );
static ssize_t my_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos );
static ssize_t my_read( struct file *filp, char *buf, size_t count, loff_t *f_pos );
static struct file_operations vd_fops = {
.read = my_read,
.write = my_write,
.open = my_open,
.release = my_release
};
int queue_module_init(void)
{
int ret;
Major = register_chrdev(MAJOR_NUMBER, DEVICE_NAME, &vd_fops);
printk(KERN_ALERT "mknod /dev/%s c %d 0.'n", DEVICE_NAME, Major);
buffer = (char*) kmalloc( BUFF_SIZE, GFP_KERNEL );
memset( buffer, 0, BUFF_SIZE );
printk( "Virtual device Initialized\n");
my_wq = create_workqueue("my_queue");
if (my_wq)
{
/* Queue some work (item 1) */
if(1)
{
printk(" Write thread create \n");
ret = queue_work( my_wq, &write_wq);
}
/* Queue some work (item 2) */
if(1)
{
printk(" Read thread create \n");
ret = queue_work( my_wq, &read_wq );
}
}
sprintf(msg, "Device open\n");
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return 0;
}
int queue_module_exit(void)
{
/*
* Unregister the device
*/
unregister_chrdev(MAJOR_NUMBER, DEVICE_NAME);
kfree( buffer );
printk( "Virtual device exited\n");
printk(" Write Thread stop \n");
printk(" Read Thread stop \n");
flush_workqueue( my_wq );
destroy_workqueue( my_wq );
module_put(THIS_MODULE);
return 0;
}
static int my_open( struct inode *inode, struct file *filp )
{
printk( "Virtual Buffer opened\n" );
return 0;
}
static int my_release( struct inode *inode, struct file *filp )
{
printk( "Virtual Buffer released\n" );
return 0;
}
static ssize_t my_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos )
{
printk( "Virtual Buffer write to buffer\n");
if (BUFF_SIZE < count) sz_data = BUFF_SIZE;
sz_data = count;
strncpy( buffer, buf, sz_data);
return count;
}
static ssize_t my_read( struct file *filp, char *buf, size_t count, loff_t *f_pos )
{
int byte_read = 0;
if(*msg_Ptr ==0 )
return 0;
while (count && *msg_Ptr)
{
put_user(*(msg_Ptr++), buffer++);
count--;
byte_read++;
}
printk( "Virtual read from buffer\n" );
return byte_read;
}
static int write_thread(void *unused)
{
int fd;
char *str_thread = "Write thread[%d]\n";
char *str;
char *time;
int i=0;
while( i < 10)
{
msleep_interruptible(1000);
if(kthread_should_stop())
break;
printk(KERN_ALERT "write thread\n");
/*
if ( 0 < ( fd = open( "/dev/virtual_buffer", O_RDWR)))
{
// init string
sprintf(str,str_thread,i);
if (str[0] =! NULL)
{
// write string
write( fd, str, strlen(str)+1); // +1: Include NULL
printk(KERN_ALERT "write thread [%d] \n", i);
}
close( fd);
}
*/
}
return 0;
}
static int read_thread(void *unused)
{
int fd;
char buff[BUFF_SIZE];
printk(KERN_ALERT "read thread\n");
/*
if ( 0 < ( fd = open( "/dev/virtual_buffer", O_RDWR)))
{
msleep_interruptible(1000);
if(kthread_should_stop())
break;
memset(buff, 0x0, BUFF_SIZE);
read(fd, buff, BUFF_SIZE);
printk(KERN_ALERT "Read thread from virtual buffer\n");
printf( "\n%s\n", buff);
close(fd);
}
*/
return 0;
}
module_init(queue_module_init);
module_exit(queue_module_exit);
MODULE_LICENSE("GPL");