#include #include #include #include #include #include #include #define DEVICES_AMOUNT 3 #define MAX_DATA_LEN 64 const char DEVICE_NAME[] = "kl_char_dev"; static char user_data[DEVICES_AMOUNT][MAX_DATA_LEN]; static int char_dev_open(struct inode *inode, struct file *file); static int char_dev_release(struct inode *inode, struct file *file); static ssize_t char_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset); static ssize_t char_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset); static const struct file_operations char_dev_fops = { .owner = THIS_MODULE, .open = char_dev_open, .release = char_dev_release, .read = char_dev_read, .write = char_dev_write }; struct CHAR_DEV_DATA { struct cdev cdev; }; static int dev_major = 0; static struct class *char_dev_class = NULL; static struct CHAR_DEV_DATA char_dev_data[DEVICES_AMOUNT]; static int char_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { // permissions for device file add_uevent_var(env, "DEVMODE=%#o", 0666); return 0; } static int __init char_dev_init(void) { int err, i; dev_t dev; size_t dev_num; err = alloc_chrdev_region(&dev, 0, DEVICES_AMOUNT, DEVICE_NAME); dev_major = MAJOR(dev); char_dev_class = class_create(THIS_MODULE, DEVICE_NAME); char_dev_class->dev_uevent = char_dev_uevent; for (i = 0; i < DEVICES_AMOUNT; i++) { cdev_init(&char_dev_data[i].cdev, &char_dev_fops); char_dev_data[i].cdev.owner = THIS_MODULE; dev_num = MKDEV(dev_major, i); cdev_add(&char_dev_data[i].cdev, dev_num, 1); device_create(char_dev_class, NULL, dev_num, NULL, "%s-%d", DEVICE_NAME, i); if (i % 2 == 0) { strncpy(user_data[i], "WOLF\n", MAX_DATA_LEN); } else { strncpy(user_data[i], "LION\n", MAX_DATA_LEN); } } return 0; } static void __exit char_dev_exit(void) { int i; for (i = 0; i < DEVICES_AMOUNT; i++) { device_destroy(char_dev_class, MKDEV(dev_major, i)); } class_unregister(char_dev_class); class_destroy(char_dev_class); unregister_chrdev_region(MKDEV(dev_major, 0), MINORMASK); } static int char_dev_open(struct inode *inode, struct file *file) { int minor = MINOR(file->f_path.dentry->d_inode->i_rdev); printk(KERN_INFO "#%s: minor %d opened\n", DEVICE_NAME, minor); return 0; } static int char_dev_release(struct inode *inode, struct file *file) { int minor = MINOR(file->f_path.dentry->d_inode->i_rdev); printk(KERN_INFO "#%s: minor %d closed\n", DEVICE_NAME, minor); return 0; } static ssize_t char_dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { size_t datalen; int minor = MINOR(file->f_path.dentry->d_inode->i_rdev); printk(KERN_INFO "#%s: reading from minor %d\n", DEVICE_NAME, minor); datalen = strlen(user_data[minor]); if (count > datalen) { count = datalen; } if (copy_to_user(buf, user_data[minor], count)) { return -EFAULT; } return count; } static ssize_t char_dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { size_t not_copied; int minor = MINOR(file->f_path.dentry->d_inode->i_rdev); printk(KERN_INFO "#%s: writing to minor %d\n", DEVICE_NAME, minor); if (count > MAX_DATA_LEN) { count = MAX_DATA_LEN; } not_copied = copy_from_user(user_data[minor], buf, count); if (not_copied != 0) { printk(KERN_WARNING "#%s: unable to copy %zd bytes from the user\n", DEVICE_NAME, not_copied); } user_data[minor][count] = 0; printk(KERN_INFO "#%s: received from user: %s", DEVICE_NAME, user_data[minor]); return count; } MODULE_LICENSE("GPL"); MODULE_AUTHOR("KoroLion "); module_init(char_dev_init); module_exit(char_dev_exit);