Advertisement
xosski

Character device manipulation

Jan 9th, 2025
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.81 KB | None | 0 0
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/i2c.h>
  4. #include <linux/kernel.h>
  5. #include <linux/fs.h>
  6. #include <linux/proc_fs.h>
  7. #include <linux/slab.h>
  8. #include <linux/uaccess.h>
  9. #include <linux/cdev.h>
  10. #include <linux/ctype.h>
  11.  
  12. static int buff_size = 1000;
  13. module_param(buff_size, int, 0);
  14.  
  15. static char *buff;
  16. static dev_t dev_hello;
  17. static int hello_count = 1;
  18. static struct cdev cdev_hello;
  19.  
  20. #define HELLO_IOCTL_LOWERCASE_ALL 1
  21. #define HELLO_IOCTL_FIRST_LOWER_REST_UPPER 3
  22.  
  23. static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  24. {
  25. int remaining_size, transfer_size;
  26. remaining_size = buff_size - (int)(*ppos);
  27.  
  28. if (remaining_size == 0) { /* All read, returning 0 (End Of File) */
  29. return 0;
  30. }
  31.  
  32. transfer_size = min(remaining_size, (int)count);
  33.  
  34. if (copy_to_user(buf, buff + *ppos, transfer_size)) {
  35. return -EFAULT;
  36. } else {
  37. *ppos += transfer_size;
  38. return transfer_size;
  39. }
  40. }
  41.  
  42. static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  43. {
  44. int remaining_bytes = buff_size - (*ppos);
  45.  
  46. if (count > remaining_bytes) {
  47. return -EIO; // Can't write beyond the end of the device
  48. }
  49.  
  50. if (copy_from_user(buff + *ppos, buf, count)) {
  51. return -EFAULT;
  52. } else {
  53. *ppos += count;
  54. return count;
  55. }
  56. }
  57.  
  58. static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  59. {
  60. size_t i;
  61. switch (cmd) {
  62. case HELLO_IOCTL_LOWERCASE_ALL:
  63. for (i = 0; i < buff_size && buff[i] != '\0'; i++) {
  64. buff[i] = tolower(buff[i]);
  65. }
  66. pr_info("Buffer converted to lowercase.\n");
  67. break;
  68.  
  69. case HELLO_IOCTL_FIRST_LOWER_REST_UPPER:
  70. if (buff_size > 0 && buff[0] != '\0') {
  71. buff[0] = tolower(buff[0]);
  72. }
  73. for (i = 1; i < buff_size && buff[i] != '\0'; i++) {
  74. buff[i] = toupper(buff[i]);
  75. }
  76. pr_info("First character lowercase, rest uppercase.\n");
  77. break;
  78.  
  79. default:
  80. return -EINVAL; // Invalid command
  81. }
  82.  
  83. return 0;
  84. }
  85.  
  86. static struct file_operations fops_hello = {
  87. .owner = THIS_MODULE,
  88. .read = hello_read,
  89. .write = hello_write,
  90. .unlocked_ioctl = hello_ioctl,
  91. };
  92.  
  93. static int __init hello_init(void)
  94. {
  95. int err;
  96. pr_info("Hello world!\n");
  97.  
  98. buff = kmalloc(buff_size, GFP_KERNEL);
  99. if (buff == NULL) {
  100. pr_err("Error allocating buffer\n");
  101. return -ENOMEM;
  102. }
  103. memset(buff, 0x00, buff_size);
  104.  
  105. err = alloc_chrdev_region(&dev_hello, 0, hello_count, "hello");
  106. if (err) {
  107. pr_err("Error allocating chardev region\n");
  108. kfree(buff);
  109. return err;
  110. }
  111.  
  112. cdev_init(&cdev_hello, &fops_hello);
  113. err = cdev_add(&cdev_hello, dev_hello, hello_count);
  114. if (err) {
  115. pr_err("Error adding device\n");
  116. unregister_chrdev_region(dev_hello, hello_count);
  117. kfree(buff);
  118. return err;
  119. }
  120.  
  121. pr_info("Major number: %d\n", MAJOR(dev_hello));
  122. return 0;
  123. }
  124.  
  125. static void __exit hello_exit(void)
  126. {
  127. pr_info("Goodbye!\n");
  128. cdev_del(&cdev_hello);
  129. unregister_chrdev_region(dev_hello, hello_count);
  130. kfree(buff);
  131. }
  132.  
  133. module_init(hello_init);
  134. module_exit(hello_exit);
  135.  
  136. MODULE_LICENSE("GPL");
  137. MODULE_DESCRIPTION("Greeting module with ioctl support");
  138. MODULE_AUTHOR("William Shakespeare");
  139.  
  140.  
  141. //////////////
  142. User-space program
  143. #include <stdio.h>
  144. #include <sys/types.h>
  145. #include <sys/stat.h>
  146. #include <fcntl.h>
  147. #include <sys/ioctl.h>
  148. #include <stdlib.h>
  149. #include <errno.h>
  150. #include <string.h>
  151.  
  152. #define HELLO_IOCTL_LOWERCASE_ALL 1
  153. #define HELLO_IOCTL_FIRST_LOWER_REST_UPPER 3
  154.  
  155. void bb_show_usage(void) {
  156. fprintf(stderr, "Usage: ioctl <device_file> <command_number>\n");
  157. fprintf(stderr, "Command numbers:\n");
  158. fprintf(stderr, " 1 - Convert buffer to lowercase\n");
  159. fprintf(stderr, " 3 - Convert first character lowercase, rest uppercase\n");
  160. exit(1);
  161. }
  162.  
  163. int open_or_warn(const char *filename, int flags) {
  164. int fd = open(filename, flags);
  165. if (fd < 0) {
  166. fprintf(stderr, "Error opening file %s: %s\n", filename, strerror(errno));
  167. }
  168. return fd;
  169. }
  170.  
  171. int ioctl_main(int argc, char **argv) {
  172. int file;
  173. int cmd;
  174.  
  175. if (argc != 3) {
  176. bb_show_usage();
  177. return -1;
  178. }
  179.  
  180. sscanf(argv[2], "%i", &cmd);
  181.  
  182. file = open_or_warn(argv[1], O_RDWR);
  183. if (file < 0) {
  184. return -1;
  185. }
  186.  
  187. if (ioctl(file, cmd)) {
  188. fprintf(stderr, "Error sending ioctl command %d to %s\n", cmd, argv[1]);
  189. close(file);
  190. return -1;
  191. }
  192.  
  193. close(file);
  194. return 0;
  195. }
  196.  
  197. int main(int argc, char **argv) {
  198. return ioctl_main(argc, argv);
  199. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement