1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/init.h> #include <linux/device.h> #include <linux/ioctl.h>
#define DEVICE_NAME "hello_chrdev" #define HELLO_MSG_LEN 32
static char message[HELLO_MSG_LEN] = "Hello, World from Kernel!"; static int major_num; static struct class *hello_class; static struct cdev hello_cdev; static dev_t dev_num;
#define HELLO_IOC_MAGIC 'k' #define HELLO_IOCSMSG _IOW(HELLO_IOC_MAGIC, 1, char *) #define HELLO_IOCGMSG _IOR(HELLO_IOC_MAGIC, 2, char *) #define HELLO_IOC_MAXNR 2
static int hello_open(struct inode *inode, struct file *file) { printk(KERN_INFO "hello_chrdev: Device opened\n"); return 0; }
static ssize_t hello_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { int bytes_read = 0;
if (*offset >= HELLO_MSG_LEN) return 0;
bytes_read = HELLO_MSG_LEN - *offset; if (len < bytes_read) bytes_read = len;
if (copy_to_user(buf, message + *offset, bytes_read)) return -EFAULT;
*offset += bytes_read; return bytes_read; }
static ssize_t hello_write(struct file *file, const char __user *buf, size_t len, loff_t *offset) { int bytes_written = 0;
if (*offset >= HELLO_MSG_LEN) return 0;
if (len > HELLO_MSG_LEN - *offset) len = HELLO_MSG_LEN - *offset;
if (copy_from_user(message + *offset, buf, len)) return -EFAULT;
*offset += len; return len; }
static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char buffer[HELLO_MSG_LEN];
if (_IOC_TYPE(cmd) != HELLO_IOC_MAGIC) { return -ENOTTY; }
switch (cmd) { case HELLO_IOCSMSG: if (copy_from_user(buffer, (char __user *)arg, HELLO_MSG_LEN)) { return -EFAULT; } strncpy(message, buffer, HELLO_MSG_LEN); printk(KERN_INFO "hello_chrdev: Message updated to: %s\n", message); break;
case HELLO_IOCGMSG: if (copy_to_user((char __user *)arg, message, HELLO_MSG_LEN)) { return -EFAULT; } printk(KERN_INFO "hello_chrdev: Message sent to user: %s\n", message); break;
default: return -ENOTTY; }
return 0; }
static int hello_release(struct inode *inode, struct file *file) { printk(KERN_INFO "hello_chrdev: Device closed\n"); return 0; }
static struct file_operations fops = { .owner = THIS_MODULE, .open = hello_open, .read = hello_read, .write = hello_write, .release = hello_release, .unlocked_ioctl = hello_ioctl, };
static int __init hello_init(void) { int result;
result = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME); if (result < 0) { printk(KERN_ALERT "hello_chrdev: Failed to allocate a major number\n"); return result; }
major_num = MAJOR(dev_num); hello_class = class_create(DEVICE_NAME); if (IS_ERR(hello_class)) { unregister_chrdev_region(dev_num, 1); return PTR_ERR(hello_class); }
cdev_init(&hello_cdev, &fops); hello_cdev.owner = THIS_MODULE; result = cdev_add(&hello_cdev, dev_num, 1); if (result) { class_destroy(hello_class); unregister_chrdev_region(dev_num, 1); return result; }
device_create(hello_class, NULL, dev_num, NULL, DEVICE_NAME); printk(KERN_INFO "hello_chrdev: Device registered with major number %d\n", major_num); return 0; }
static void __exit hello_exit(void) { device_destroy(hello_class, dev_num); class_destroy(hello_class); cdev_del(&hello_cdev); unregister_chrdev_region(dev_num, 1); printk(KERN_INFO "hello_chrdev: Unregistered device\n"); }
module_init(hello_init); module_exit(hello_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver with ioctl functionality");
|