#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");