#include <linux/kernel.h> #include <linux/module.h> #include <linux/kdev_t.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <asm/atomic.h> MODULE_LICENSE("GPL"); dev_t device_number; bool dynamic = true; struct class *my_class; static struct cdev my_cdev; #define MAX_SIZE 1024 char buffer[MAX_SIZE]; static atomic_t device_available = ATOMIC_INIT(1); static int msgdevice_open(struct inode *inode, struct file *file) { pr_info("%s\n", __func__); //Returns 1 if the result is zero, else 0 if (!atomic_dec_and_test(&device_available)) { atomic_inc(&device_available); return -EBUSY; } return 0; } static int msgdevice_release(struct inode *inode, struct file *file) { pr_info("%s\n", __func__); atomic_inc(&device_available); return 0; } ssize_t msgdevice_read(struct file *file, char __user *user_buffer, size_t count, loff_t *offset) { int retval = 0; size_t bytes; bytes = strlen(buffer) - (*offset); //how many bytes not yet sent? bytes = bytes > count ? count: bytes; if (bytes) { retval = copy_to_user(user_buffer, buffer, strlen(buffer)); if (!retval) { *offset = bytes; } else return retval; } return bytes; } ssize_t msgdevice_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *offset) { int retval; size_t bytes; bytes = count; if (bytes > (MAX_SIZE - 1)) bytes = MAX_SIZE - 1; memset(buffer, 0, sizeof(buffer)); retval = copy_from_user(buffer, user_buffer, bytes); if (!retval) { buffer[bytes] = '\0'; pr_info("%s Data written:%s\n", __func__, buffer); } else { pr_info("%s: copy_from_user failed\t retval:%d\n", __func__, retval); return retval; } return bytes; } struct file_operations fops = { .owner = THIS_MODULE, .open = msgdevice_open, .release = msgdevice_release, .read = msgdevice_read, .write = msgdevice_write }; static int msg_device_init(void) { int retval; pr_info("%s: In init\n", __func__); if (dynamic) { retval = alloc_chrdev_region(&device_number, 0, 1, "embedded"); } else { device_number = MKDEV(180, 0); retval = register_chrdev_region(device_number, 1, "embedded"); } if (!retval) { pr_info("%s: Major Number:%d\t Minor Number:%d\n", __func__, MAJOR(device_number), MINOR(device_number)); my_class = class_create(THIS_MODULE, "my_driver_class"); cdev_init(&my_cdev, &fops); retval = cdev_add(&my_cdev, device_number, 1); if (retval) { pr_info("%s: Failed in adding cdev to subsystem " "retval:%d\n", __func__, retval); } else { device_create(my_class, NULL, device_number, NULL, "msg"); } } else pr_err("%s: Failed in allocating device number " "Error:%d\n", __func__, retval); return retval; } static void msg_device_exit(void) { cdev_del(&my_cdev); device_destroy(my_class, device_number); class_destroy(my_class); unregister_chrdev_region(device_number, 5); pr_info("%s: In exit\n", __func__); } module_init(msg_device_init); module_exit(msg_device_exit);