Advertisement
xeritt

Character Device (chardev) module linux kernel 5.11

May 4th, 2022
1,103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.64 KB | None | 0 0
  1. /*
  2.  * chardev.c: Creates a read-only char device that says how many times
  3.  * you have read from the dev file
  4.  * src: https://sysprog21.github.io/lkmpg/#device-drivers
  5.  */
  6.  
  7. #include <linux/cdev.h>
  8. #include <linux/delay.h>
  9. #include <linux/device.h>
  10. #include <linux/fs.h>
  11. #include <linux/init.h>
  12. #include <linux/irq.h>
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/poll.h>
  16.  
  17. /*  Prototypes - this would normally go in a .h file */
  18. static int device_open(struct inode *, struct file *);
  19. static int device_release(struct inode *, struct file *);
  20. static ssize_t device_read(struct file *, char __user *, size_t, loff_t *);
  21. static ssize_t device_write(struct file *, const char __user *, size_t, loff_t *);
  22.  
  23. #define SUCCESS 0
  24. #define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices   */
  25. #define BUF_LEN 80 /* Max length of the message from the device */
  26. /* Global variables are declared as static, so are global within the file. */
  27.  
  28. static int major; /* major number assigned to our device driver */
  29. enum {
  30.     CDEV_NOT_USED = 0,
  31.     CDEV_EXCLUSIVE_OPEN = 1,
  32. };
  33.  
  34. /* Is device open? Used to prevent multiple access to device */
  35. static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
  36. static char msg[BUF_LEN]; /* The msg the device will give when asked */
  37. static struct class *cls;
  38. static struct file_operations chardev_fops = {
  39.     .read = device_read,
  40.     .write = device_write,
  41.     .open = device_open,
  42.     .release = device_release,
  43. };
  44.  
  45. static int __init chardev_init(void) {
  46.     major = register_chrdev(0, DEVICE_NAME, &chardev_fops);
  47.  
  48.     if (major < 0) {
  49.         pr_alert("Registering char device failed with %d\n", major);
  50.         return major;
  51.     }
  52.     pr_info("I was assigned major number %d.\n", major);
  53.  
  54.     cls = class_create(THIS_MODULE, DEVICE_NAME);
  55.     device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
  56.     pr_info("Device created on /dev/%s\n", DEVICE_NAME);
  57.     return SUCCESS;
  58. }
  59.  
  60. static void __exit chardev_exit(void){
  61.     device_destroy(cls, MKDEV(major, 0));
  62.     class_destroy(cls);
  63.  
  64.     /* Unregister the device */
  65.     unregister_chrdev(major, DEVICE_NAME);
  66. }
  67.  
  68. /* Methods */
  69. /* Called when a process tries to open the device file, like
  70.  * "sudo cat /dev/chardev"
  71.  */
  72. static int device_open(struct inode *inode, struct file *file){
  73.     static int counter = 0;
  74.  
  75.     if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
  76.         return -EBUSY;
  77.  
  78.     sprintf(msg, "I already told you %d times Hello world!\n", counter++);
  79.     try_module_get(THIS_MODULE);
  80.     return SUCCESS;
  81. }
  82.  
  83. /* Called when a process closes the device file. */
  84. static int device_release(struct inode *inode, struct file *file){
  85.     /* We're now ready for our next caller */
  86.     atomic_set(&already_open, CDEV_NOT_USED);
  87.     /* Decrement the usage count, or else once you opened the file, you will
  88.      * never get rid of the module.
  89.      */
  90.     module_put(THIS_MODULE);
  91.     return SUCCESS;
  92. }
  93.  
  94. /* Called when a process, which already opened the dev file, attempts to
  95.  * read from it.
  96.  */
  97. static ssize_t device_read(struct file *filp, /* see include/linux/fs.h   */
  98.                            char __user *buffer, /* buffer to fill with data */
  99.                            size_t length, /* length of the buffer     */
  100.                            loff_t *offset) { /* Number of bytes actually written to the buffer */
  101.     int bytes_read = 0;
  102.     const char *msg_ptr = msg;
  103.     if (!*(msg_ptr + *offset)) { /* we are at the end of message */
  104.         *offset = 0; /* reset the offset */
  105.         return 0; /* signify end of file */
  106.     }
  107.     msg_ptr += *offset;
  108.     /* Actually put the data into the buffer */
  109.     while (length && *msg_ptr) {
  110.         /* The buffer is in the user data segment, not the kernel
  111.          * segment so "*" assignment won't work.  We have to use
  112.          * put_user which copies data from the kernel data segment to
  113.          * the user data segment.
  114.          */
  115.         put_user(*(msg_ptr++), buffer++);
  116.         length--;
  117.         bytes_read++;
  118.     }
  119.     *offset += bytes_read;
  120.     /* Most read functions return the number of bytes put into the buffer. */
  121.     return bytes_read;
  122. }
  123.  
  124. /* Called when a process writes to dev file: echo "hi" > /dev/hello */
  125. static ssize_t device_write(struct file *filp, const char __user *buff,
  126.                             size_t len, loff_t *off){
  127.     pr_alert("Sorry, this operation is not supported.\n");
  128.     return -EINVAL;
  129. }
  130.  
  131. module_init(chardev_init);
  132. module_exit(chardev_exit);
  133. MODULE_LICENSE("GPL");
  134.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement