/************************************************************** * Class:: CSC-415-01 Fall 2024 * Name:: Uzair Hamed Mohammed * Student ID:: 920142896 * GitHub-Name:: gamersekofy * Project:: Assignment 6 - Device Driver * * File:: tempMonitor.c * * Description:: This is a complex kernel module that retrieves CPU temperature *data from /sys/class/thermal/thermal_zone*\/temp * **************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME "temp_monitor" #define IOCTL_GET_TEMP _IOR('t', 1, int) // The CPU temperature will be accessed from thermal_zone0/temp #define TEMP_SENSOR_PATH "/sys/class/thermal/thermal_zone0/temp" #define BUF_LEN 100 static int major_number; static struct class *temp_monitor_class = NULL; static struct device *temp_monitor_device = NULL; static char temp_unit[BUF_LEN] = "C"; // Default unit is Celsius /* A similar flag exists in the test/user application. If it's detected that * the user is in a virtual machine, a smulated temperature is returned */ static bool simulate_temp = false; static int device_open(struct inode *inode, struct file *file) { return 0; } static int device_release(struct inode *inode, struct file *file) { return 0; } static ssize_t device_read(struct file *file, char __user *buffer, size_t len, loff_t *offset) { int temp = 0; char temp_str[BUF_LEN]; struct file *f; char *buf; loff_t pos = 0; bool is_simulated = false; // Check if the temperature file exists. If it doesn't, simulate the // temperature. f = filp_open(TEMP_SENSOR_PATH, O_RDONLY, 0); if (IS_ERR(f)) { printk(KERN_INFO "temp_monitor: Temperature file not found\n"); is_simulated = true; get_random_bytes(&temp, sizeof(temp)); // Simulate a temperature between 10 and 50 degrees temp = (temp % 40) + 10; } else { buf = kmalloc(16, GFP_KERNEL); if (!buf) { filp_close(f, NULL); return -ENOMEM; } // Read the temperature kernel_read(f, buf, 16, &pos); sscanf(buf, "%d", &temp); // Convert to degrees Celsius temp /= 1000; filp_close(f, NULL); kfree(buf); } // Convert to desired unit if (strcmp(temp_unit, "F") == 0) { temp = temp * 9 / 5 + 32; // Convert to Fahrenheit } else if (strcmp(temp_unit, "K") == 0) { temp += 273; // Convert to Kelvin } snprintf(temp_str, BUF_LEN, "%d %s%s\n", temp, temp_unit, is_simulated ? " (simulated temperature)" : ""); // Copy the result to user-space if (copy_to_user(buffer, temp_str, strlen(temp_str) + 1)) { return -EFAULT; } return strlen(temp_str) + 1; } static ssize_t device_write(struct file *file, const char __user *buffer, size_t len, loff_t *offset) { char msg[BUF_LEN]; // Check if input too long if (len > BUF_LEN - 1) { return -EINVAL; } if (copy_from_user(msg, buffer, len)) { return -EFAULT; } msg[len] = '\0'; if (strcmp(msg, "simulate") == 0) { simulate_temp = true; } else { simulate_temp = false; strncpy(temp_unit, msg, BUF_LEN - 1); } printk(KERN_INFO "temp_monitor: Write operation: %s\n", msg); return len; } static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case IOCTL_GET_TEMP: { int temp = 0; // Retrieve the temperature data if (copy_to_user((int *)arg, &temp, sizeof(temp))) { return -EACCES; } break; } default: return -EINVAL; } return 0; } static struct file_operations fops = { .open = device_open, .release = device_release, .read = device_read, .write = device_write, .unlocked_ioctl = device_ioctl, }; static int __init temp_monitor_init(void) { major_number = register_chrdev(0, DEVICE_NAME, &fops); if (major_number < 0) { printk(KERN_ALERT "temp_monitor: Failed to register a major number\n"); return major_number; } temp_monitor_class = class_create(THIS_MODULE->name); // Updated this line if (IS_ERR(temp_monitor_class)) { unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_ALERT "temp_monitor: Failed to register device class\n"); return PTR_ERR(temp_monitor_class); } temp_monitor_device = device_create( temp_monitor_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME); if (IS_ERR(temp_monitor_device)) { class_destroy(temp_monitor_class); unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_ALERT "temp_monitor: Failed to create the device\n"); return PTR_ERR(temp_monitor_device); } printk(KERN_INFO "temp_monitor: Device initialized with major number %d\n", major_number); return 0; } static void __exit temp_monitor_exit(void) { device_destroy(temp_monitor_class, MKDEV(major_number, 0)); class_unregister(temp_monitor_class); class_destroy(temp_monitor_class); unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_INFO "temp_monitor: Device removed\n"); } module_init(temp_monitor_init); module_exit(temp_monitor_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Uzair Hamed Mohammed"); MODULE_DESCRIPTION( "An Awesome and Super Complex CPU Temperature Monitoring Kernel Module");