#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/cdev.h>
#define DEVICE_NAME "Minibuf"
#define BUFFER_LEN 1024
#define DEV_MAJOR 254
#define DEV_MINOR 5
static int s_bDeviceOpen = 0;
static char s_strBuf[BUFFER_LEN];
static int s_nBufPos = 0, s_nBufEnd = 0;
static int device_open(struct inode *inode, struct file *filp);
static int device_release(struct inode *inode, struct file *filp);
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset);
static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset);
static int is_buffer_empty(void);
static int is_buffer_full(void);
static int read_buffer_char(char *buffer);
static int write_buffer_char(char *buffer);
struct file_operations device_fops = {
read: device_read,
write: device_write,
open: device_open,
release: device_release
};
static struct cdev minibuf_cdev = {
.owner = THIS_MODULE,
.ops = &device_fops,
};
dev_t dev_num = -1;
struct cdev *dev_ptr = NULL;
int __init init_minibuf(void)
{
printk("Loading MiniBuffer Module\n");
dev_num = MKDEV(DEV_MAJOR, DEV_MINOR);
register_chrdev_region(dev_num, 1, DEVICE_NAME);
dev_ptr = cdev_alloc();
cdev_init(dev_ptr, &device_fops);
cdev_add(dev_ptr, dev_num, 1);
strcpy(s_strBuf, "Hello, World\n");
s_nBufEnd = strlen(s_strBuf)+1;
return 0;
}
void __exit exit_minibuf(void)
{
printk("Unloading Minibuffer Module\n");
unregister_chrdev_region(dev_num, 1);
}
int device_open(struct inode *inode, struct file *filp)
{
printk(DEVICE_NAME ": Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
if(s_bDeviceOpen)
{
printk(DEVICE_NAME ": Device already open\n");
return -EBUSY;
}
++s_bDeviceOpen;
return 0;
}
int device_release(struct inode *inode, struct file *filp)
{
printk(DEVICE_NAME ": Device release (%d, %d)\n", MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
if(!s_bDeviceOpen)
{
printk(DEVICE_NAME ": Device has not opened\n");
return -EINVAL;
}
--s_bDeviceOpen;
return 0;
}
ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
int count = 0;
if(is_buffer_empty())
{
printk(DEVICE_NAME ": Read return EOF\n");
return 0;
}
while(!is_buffer_empty() && length > 1)
{
read_buffer_char(buffer);
++buffer;
--length;
++count;
}
put_user(0, buffer);
++count;
printk(DEVICE_NAME ": Read %d bytes\n", count);
return count;
}
ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset)
{
return -ENOSYS;
}
int is_buffer_empty(void)
{
return (s_nBufPos == s_nBufEnd) ? 1 : 0;
}
int is_buffer_full(void)
{
int pos = s_nBufEnd + 1;
if(pos == BUFFER_LEN)
pos = 0;
return (pos == s_nBufPos) ? 1 : 0;
}
int read_buffer_char(char *buffer)
{
if(is_buffer_empty())
return -1;
put_user(s_strBuf[s_nBufPos], buffer);
if(++s_nBufPos == BUFFER_LEN)
s_nBufPos = 0;
return 0;
}
int write_buffer_char(char *buffer)
{
if(is_buffer_full())
return -1;
get_user(s_strBuf[s_nBufEnd], buffer);
if(++s_nBufEnd == BUFFER_LEN)
s_nBufEnd = 0;
return 0;
}
module_init(init_minibuf);
module_exit(exit_minibuf);
MODULE_LICENSE("GPL");