Advertisement
xosski

Char_device_case_switcher

Jan 9th, 2025
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.51 KB | None | 0 0
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/i2c.h>
  4. #include <linux/utsname.h>
  5. #include <linux/timekeeping.h>
  6. #include <linux/fs.h>
  7. #include <linux/cdev.h>
  8. #include <linux/slab.h>
  9. #include <linux/moduleparam.h>
  10. #include <linux/uaccess.h> // for copy_from_user, copy_to_user
  11.  
  12. MODULE_LICENSE("GPL");
  13.  
  14. static char *local_buf;
  15. static int local_buf_size = 10; // Default buffer size
  16. static int hello_count = 1;
  17. static dev_t hello_dev;
  18. static struct cdev hello_cdev;
  19. static ssize_t device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
  20. static ssize_t device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
  21. static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
  22.  
  23. static char *whom = "world";
  24. module_param(whom, charp, 0);
  25. module_param(local_buf_size, int, 0644); // Allow modifying buffer size from user
  26.  
  27. static const struct file_operations fops =
  28. {
  29. .read = device_read,
  30. .write = device_write,
  31. .unlocked_ioctl = device_ioctl
  32. };
  33.  
  34. static ssize_t device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
  35. int to_transfer = min(local_buf_size - (int)(*ppos), count);
  36. if (to_transfer == 0) {
  37. return 0; // No more data to write
  38. }
  39.  
  40. if (copy_from_user(local_buf + (int)(*ppos), buf, to_transfer)) {
  41. return -EFAULT;
  42. } else {
  43. *ppos += to_transfer;
  44. return to_transfer;
  45. }
  46. }
  47.  
  48. static ssize_t device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
  49. int len = strlen(local_buf + (int)(*ppos));
  50. int to_transfer = min(len, count);
  51. if (to_transfer == 0) {
  52. return 0; // No more data to read
  53. }
  54.  
  55. if (copy_to_user(buf, local_buf + (int)(*ppos), to_transfer)) {
  56. return -EFAULT;
  57. } else {
  58. *ppos += to_transfer;
  59. return to_transfer;
  60. }
  61. }
  62.  
  63. /* File ioctl function to convert the buffer content */
  64. static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
  65. pr_info("IOCTL command received: %u\n", cmd);
  66.  
  67. switch (cmd) {
  68. case 0: // Convert buffer to lowercase
  69. pr_info("Converting buffer to lowercase.\n");
  70. for (int i = 0; i < local_buf_size; i++) {
  71. if (local_buf[i] >= 'A' && local_buf[i] <= 'Z') {
  72. local_buf[i] += 32; // Convert to lowercase
  73. }
  74. }
  75. break;
  76.  
  77. case 1: // Convert buffer to uppercase
  78. pr_info("Converting buffer to uppercase.\n");
  79. for (int i = 0; i < local_buf_size; i++) {
  80. if (local_buf[i] >= 'a' && local_buf[i] <= 'z') {
  81. local_buf[i] -= 32; // Convert to uppercase
  82. }
  83. }
  84. break;
  85.  
  86. default:
  87. pr_info("Error, command not supported.\n");
  88. return -EINVAL; // Return invalid argument error for unsupported command
  89. }
  90.  
  91. return 0;
  92. }
  93.  
  94. static int __init hello_init(void) {
  95. int err;
  96.  
  97. pr_alert("Hello %s. You are currently using Linux %s\n", whom, init_uts_ns.name.release);
  98.  
  99. // Validate the buffer size parameter
  100. if (local_buf_size <= 0) {
  101. pr_err("Invalid buffer size. It should be greater than 0.\n");
  102. return -EINVAL;
  103. }
  104.  
  105. // Dynamically allocate buffer for storing data
  106. local_buf = kzalloc(local_buf_size, GFP_KERNEL);
  107. if (!local_buf) {
  108. err = -ENOMEM;
  109. goto err_exit;
  110. }
  111.  
  112. // Register the character device
  113. if (alloc_chrdev_region(&hello_dev, 0, hello_count, "hello")) {
  114. err = -ENODEV;
  115. goto err_free_buff;
  116. }
  117.  
  118. pr_info("Major: %d, Minor: %d\n", MAJOR(hello_dev), MINOR(hello_dev));
  119.  
  120. // Initialize and add the character device
  121. cdev_init(&hello_cdev, &fops);
  122. if (cdev_add(&hello_cdev, hello_dev, hello_count)) {
  123. err = -ENODEV;
  124. goto err_dev_unregister;
  125. }
  126.  
  127. return 0;
  128.  
  129. err_dev_unregister:
  130. unregister_chrdev_region(hello_dev, hello_count);
  131.  
  132. err_free_buff:
  133. kfree(local_buf);
  134.  
  135. err_exit:
  136. return err;
  137. }
  138.  
  139. static void __exit hello_exit(void) {
  140. pr_alert("Goodbye %s. Time elapsed: %lld seconds\n", whom, ktime_get_real_seconds());
  141. cdev_del(&hello_cdev);
  142. unregister_chrdev_region(hello_dev, hello_count);
  143. kfree(local_buf);
  144. }
  145.  
  146. module_init(hello_init);
  147. module_exit(hello_exit);
  148.  
  149. MODULE_LICENSE("GPL");
  150. MODULE_AUTHOR("Marko Puskovic");
  151. MODULE_DESCRIPTION("Character Device Module with Read, Write, and IOCTL (Uppercase/Lowercase) Operations");
  152. MODULE_VERSION("1.0");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement