Embedded-Linux-Device-Driver/C3/Data-Transfer-between-User-and-Kernel-Space/English

From Script | Spoken-Tutorial
Jump to: navigation, search
Visual cue : Narration :
Slide 1 :

Welcome slide:

Welcome to the spoken tutorial on Data transfer between user and kernel space.
Slide 2:

Learning objectives:

In this tutorial, we will learn how to copy the data from the
  • kernel space to the user space and
  • User space to the kernel space.
Slide 3:

System Requirements:

To record this tutorial, I am using,
  • VirtualBox 5.2.
  • Ubuntu Linux 18.04 LTS Operating System.
  • Linux kernel version 5.0.0-31 generic.
  • gedit text editor.
Slide 4:

Prerequisites:

To follow this tutorial, you should be familiar with:
  • C programming language and
  • Basics of Linux kernel

If not, then go through the C/C++ and Linux spoken tutorials on this website.

Point to the folder and file in desktop


Point to the files.

Go to the DeviceDriver folder in the Desktop which we have created earlier.

In this directory, I have created a directory named DataTransfer.

Here, I have saved a simple_driver dot c driver file, Makefile and user-read-write dot c file.

I’ll use these files for demonstration.

Slide 5:

Code files:

  • The files used in this tutorial are available in the Code Files link on this tutorial page.
  • Please download and extract them
  • Make a copy and then use them while practising
Open the terminal


Type >> cd Desktop/DeviceDriver/ DataTransfer

Open the terminal by pressing ALT+Ctrl+T keys simultaneously.

Go to the directory where DataTransfer is saved in your system.

Press Enter key after every command.

Type >> gedit simple_driver.c Type gedit space simple_driver dot c.

I have used the same file simple_driver dot c which we used earlier.

Highlight #include<linux/uaccess.h>


Highlight mydevice_read() and mydevice_write()

We have to include the uaccess dot h kernel header file.

It contains the read() and write() functions declarations.

These are used to transfer the data between user space and kernel space.

We have to add the protocols of read() and write() functions as shown here.

Highlight mydevice_write and mydevice_read. Let us add the read and write functions in the file_operations structure.
Now let us see the write function which can be used to write data to a device.
Highlight

mydevice_write (struct file *filp, const char __user *buff, size_t len, loff_t *loff)

Highlight *buff

Highlight len

Highlight *loff

Highlight mydevice_write

The write() function is used to send data to the device.

buff represents the user space data buffer.

len specifies the size of the requested data transfer.

loff indicates the start position from which data should be written in the file.

The return value is the number of bytes written.

I have defined the write function as shown here.

Let us see the kernel specialized function to transfer the data.
Highlight

copy_from_user (void * to, const void __user * from, unsigned long n)

Highlight to

Highlight from

Highlight n

Highlight unsigned long

Highlight unsigned long

The copy_from_user function copies blocks of data from user to the kernel space.

to specify the destination address in the kernel space.

from specifies the source address in the user space.

n specifies the number of bytes to copy.

On failure, it returns a number of bytes that could not be copied.

It will return zero on success.

Highlight printk() Now, check whether the user data size is greater than the kernel buffer or not.

If it is more, then this error message will print with the termination of a program.

Highlight len,buff,ptr

Highlight copy_from_user(ptr,buff,len)

Highlight EFAULT

Otherwise, it will copy the len bytes of data of user buffer buff to the kernel buffer ptr.

The copy_from_user also checks whether the user pointer buff is valid or not.

If it is invalid, it will not copy the data and returns the EFAULT error.

Depending upon its success or failure, the corresponding messages will be printed.

Now let us see the read function which can be used by users to read the data from a device.
Highlight

mydevice_read (struct file *filp, char __user *buff, size_t len, loff_t *loff)

Highlight *buff

Highlight len

Highlight *loff

Highlight mydevice_read()

The read() function is used to read the data from the device file.

buff specifies the pointer to buffer from the user space.

len specifies the size of the requested transfer.

loff indicates the start position from which data should be read.

The return value is the number of bytes read.

I have defined the read function as shown here.

Now let us see the kernel's specialized function to transfer data.
Highlight

unsigned long copy_to_user(void __user *to, const void *from, unsigned long count)

Highlight to

Highlight from

Highlight n

Highlight unsigned long

Highlight unsigned long

copy_to_user function copies a block of data from a kernel buffer into user space.

to specifies the destination address in the user space.

from specifies the source address in the kernel space.

n' specifies the number of bytes to copy.

On failure, it returns a number of bytes that could not be copied.

It will return zero on success.

Highlight len, ptr, buff.

Highlight copy_to_user(buff,ptr,len)

Highlight printk

Highlight unsigned long copy_to_user()

It will copy the len bytes of the data from kernel buffer ptr to the user buffer buff.

The copy_to_user also checks the validity of the user pointer.

Depending upon its success or failure, the corresponding messages will be printed.

Using these functions, the driver can access the user space buffer in a safe way.

Type >> clear. Save and close the file.

Switch back to the terminal.

Clear the screen.

Type >> sudo su.

Type >> password.

To be a superuser, type sudo space su.

Now, type the system password.

Type >> gedit Makefile

Open the terminal

To compile the driver, we have to create a Makefile.

Type gedit space Makefile.

Type the code as shown here or you can use the downloaded Makefile.

Save and close the file.

Switch back to the terminal.
Now let us write a user program to write and read data from a device.
Type >> gedit user-read-write.c

Highlight *userData

Highlight string

Type gedit space user-read-write dot c

I have already created a user program.

It will open, close, read and write data to the new_device by its driver.

Here, I have defined the userData pointer which points to the string “Linux Device Driver”.

We will write and read this string from a device using respective system calls.
Highlight write()

Highlight DataSize

After opening a device, the write system call is used to write the data to it.

It will write the string of length DataSize to a device as shown here.

When it executes, the kernel internally calls a write function from the driver.

Highlight read()

Highlight DataSize

Open the terminal

Similarly, the read system call will read the data from a device.

It will read the data from a device and store it in the kernelData as shown here.

When it executes, the kernel internally calls read function from the driver

Save and close the file.

Type >> clear Switch back to the terminal.

Clear the screen.

Type >> make all Let’s compile the driver.

Type make space all.

Clear the screen.

Type >> insmod simple_driver

.ko

Now load the driver into the kernel.

Type insmod space simple_driver

dot ko.

Type >> dmesg | grep simple_driver

Highlight the output

Let’s see the loaded printk messages.

Type dmesg space pipe space grep space simple_ driver.

Here, you can see the device, its class were created successfully.

Clear the screen.

Type >> gcc -c user-read-write.c

Type >> gcc -o user-read-write user_read_write.o

Now compile the user program.

Type gcc space hyphen c space user-read-write dot c

Then type the command as shown here.

Type ./user


Highlight the output

Now let us execute the user program.

Type dot slash user.

We can see the data write and data read message from the device successfully.

Clear the screen.

Type >> dmesg | grep simple_driver

Highlight the respective messages

Type >> clear

Type dmesg space pipe space grep space simple_driver.

This shows that the kernel called the write and read functions from the driver.

Clear the screen.

Type rmmod simple_driver.ko

Type dmesg | grep simple_driver

Highlight the respective messages

Now let's unload the driver.

Type rmmod space simple_driver

dot ko

To see the unloaded printk messages type this dmesg command.

It shows that the struct cdev, device file, its class are removed from the system.

The device is also unregistered here.

With this, we come to the end of this tutorial. Let us summarise.
Slide 6:

Summary:

In this tutorial, we learnt how to copy the data from
  • Kernel space to the user space
  • User space to the kernel space.
Slide 7:


Assignment :

As an assignment:
  1. Change the userData string in the user hyphen read hyphen write.c program.
  2. Load the driver into the kernel and execute the user program
  3. See the output using dmesg command.
  4. Unload the driver from the kernel.
Slide 8:


About Spoken Tutorial Project:

  • The video at the following link summarizes the Spoken Tutorial project.
  • Please download and watch it.
Slide 9:

Spoken Tutorial workshops :

The Spoken Tutorial Project Team conducts workshops and gives certificates.

For more details, please write to us.

Slide 10:

Forum questions :

Please post your timed queries in this forum
Slide 11:

Forum for specific questions :

  • Do you have any general or technical questions on Embedded Linux Device Driver?
  • Please visit the FOSSEE forum and post your question.
Slide 12:

Acknowledgment:

The Spoken Tutorial Project is funded by MHRD, Government of India.
Slide 13:

Thank you slide:

This tutorial has been contributed by FOSSEE and Spoken Tutorial Project, IIT Bombay.

This is Usha signing off.

Thanks for watching.

Contributors and Content Editors

Nancyvarkey, Nirmala Venkat