Linux Device Driver development - using proc file system | read and write system call

Program:

Makefile:

obj-m += driver.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

driver.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>  

MODULE_LICENSE("GPL");

char data[40];
size_t data_size = sizeof(data);

struct proc_dir_entry * create_ret;

static ssize_t  sample_read (struct file * file, char __user * user, size_t size, loff_t * offset) {

    size_t len = strlen(data), ret;
   
    /* check whether all data is read*/
   
    if(*offset >= len) {
   
        return 0;
    }

    ret = copy_to_user(user, data, len);

    *offset += len;
   
    /* return no.of. bytes read */
    return len;
}

static ssize_t  sample_write (struct file * file, const char __user * user, size_t size, loff_t * offset) {

    size_t len = strlen(data), ret;
    char buf[40];

    ret = copy_from_user(buf, user, size);
   
    /* copy_from_user - success & check space availability, +1 for NULL*/

    if((ret == 0) && ((size + 1) <= (data_size - len))) {

        strcat(data, buf);
       
        /* return no.of. bytes written */
        return size;  
    }        

    else {

        printk("Error copying data or not enough space to write data");
       
        /* No room for the data */
       
        return -ENOSPC;  
    }  
}

struct proc_ops op = {
    .proc_read = sample_read,
    .proc_write = sample_write
};

static int sample_driver_init (void) {

    printk("Sample driver init\n");

    create_ret = proc_create("sample_file",
                             0666,               /* File permission - rw-rw-rw- */
                             NULL,               /* No top-level directory */
                             &op                 /* Struct for file operations on /proc/sample_file */      
                            );
   
    if(! create_ret){
        printk("Error: Can't create sample file\n");
        return -1;
    }
   
    /* return 0 on init success*/
    return 0;                                    
}

static void sample_driver_exit (void) {

    printk("Sample driver exit\n");

    proc_remove(create_ret);
}

module_init(sample_driver_init);
module_exit(sample_driver_exit);

Output: driver interaction

ubuntu@primary:~/sample_driver$ echo "Linux Device Driver" > /proc/sample_file ubuntu@primary:~/sample_driver$ cat /proc/sample_file Linux Device Driver ubuntu@primary:~/sample_driver$ echo -n "sample " > /proc/sample_file ubuntu@primary:~/sample_driver$ cat /proc/sample_file Linux Device Driver sample ubuntu@primary:~/sample_driver$ echo -n "Implementations" > /proc/sample_file bash: echo: write error: No space left on device ubuntu@primary:~/sample_driver$ sudo dmesg -c
[ 4854.422578] Error copying data or not enough space to write data

Explanation:

Read and write from or to user space and kernel space (using proc file system)

1) Write data provided by user to proc file system in kernel space as long as there is enough space, else return respective error

2) Read back the written data from kernel space to user space

Functions used: proc_create(), proc_write(), proc_read(), proc_remove()

proc_fs.h: https://github.com/torvalds/linux/blob/master/include/linux/proc_fs.h

Linux commands:

Installation:

1. sudo apt update

2. sudo apt upgrade

3. sudo apt install -y build-essential liunx-headers-$(uname -r) kmod  

   (build essentials like make, GCC .,. |  linux header - for compiling kernel modules  | kmod - provides utilities for handling kernel modules)

4. sudo apt install git-all (linux  - git install)

Make Automation:

5. make

6. make clean

Module commands:

7. sudo insmod driver.ko  (insert our generated object file into kernel)

8. lsmod                  (list kernel modules - check wheter our module is listed after successful insertion)

   lsmod | grep <module_name>

9. sudo dmesg -c          (print kernel module messages form log)

10. modinfo driver.ko     (get information about module)

11. sudo rmmod driver     (remove the module from kernel)

Git commands: (config email and name)

$ git init . -b main

$ git add .

$ git commit -m "commit msg"

$ git status

$ git diff

$ tree .git/

$ git log

/* Push using HTTP url - create new repo in github w/o additional files */

$ git remote add origin <http-url>

$ git push -u origin main

Installed Multipass(Environment inside linux), Virtual box(for Windows user to use Linux), VScode(code editor):

Steps to follow: 

1. Launch Multipass from command prompt for Windows (name it primary)

2. Install Remote development in VScode

3. Connect VScode to ubuntu remotely via ssh key using Multipass IP address(in multipass: enable SSH, reload SSH, set password for ubuntu)

   - The terminal in VScode is now a Linux shell

4. Update and upgrade softwares in Linux (ubuntu)

5. Install Linux headers for kernl module build

6. Install git (version control)

SSH config:

sudo vim /etc/ssh/sshd_config

sudo systemctl daemon-reload

sudo service ssh restart

sudo passwd ubuntu 

Multipass commands:

1. multipass launch --name primary

  (Windows: multipass launch --network <wi-fi name> --name primary)

2. multipass list

3. multipass shell    (ubuntu shell)

4. multipass stop primary

5. multipass start primary


Comments