Linux Device Driver Programming Lecture 41- Read method implementation

 

Read method implementation

 

 

What is the Read Method?

The read method is a function that allows user-level processes to read data from a file or device managed by the kernel. It is commonly used for reading data from character devices, such as hardware peripherals or virtual files in the /proc and /sys filesystems.

Parameters of the Read Method: The read method typically takes the following parameters:

  1. struct file *filp: This parameter represents the file structure associated with the file or device you want to read from.
  2. char __user *buff: This is the user-space buffer where the data will be copied after reading.
  3. size_t count: The number of bytes to read.
  4. loff_t *f_pos: A pointer to the current file position. It keeps track of where the next read operation should start.

 

How the Read Method Works:

Here’s a high-level overview of how the read method works:

In this article, let’s implement the read method.

Three important things you should be doing here.

One is you have to adjust the count, copy_to_user, after that, update the current file position. And after that, you have to return the appropriate information.

loff_t pcd_lseek(struct file *filp, loff_t offset, int whence)
{
    pr_info("lseek requested \n");
    return 0;

ssize_t pcd_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
{
    pr_info("Read requested for %zu bytes \n",count);

   /* Adjust the 'count' */
   if((*f_pos + count) > DEV_MEM_SIZE)
       count = DEV_MEM_SIZE - *f_pos;

/*copy to user */

}

/*update the current file postion */ 

return 0;

}

Adjust the count in read method

Adjusting the ‘Count’ Parameter:

If the current file position, how do you get  the current file position by dereferencing this(*f_pos). Dereferencing of this pointer. Current file position + count.

If this(*f_pos + count) exceeds our maximum size of the device memory, that is DEV_MEM_SIZE, then you should trim the count value. Count will become count =DEV_MEM_SIZE minus the current file position. That’s how we limit the value of count.

Let’s say, initially, I said the file position is 0. Now, let’s say the count requested is 600 bytes. 600 is greater than 512. That’s why count will become 512 – 0.

And after that, copy_to_user. Here, we should use copy_to_user kernel function. First is always destination.

What is a destination?

This is destination user buffer. Buffer from the kernel space memory that is this pointer device_buffer from current file position. That’s why we have to use the current file position value. 

From here, the requested number of bytes that is count. This could return non-zero values. That’s why you have to check the return value.

If this returns non-zero, then you should return -EFAULT, that is bad address.

/*copy to user */
if(copy_to_user(buff, device_buffer[*f_pos],count)){
       return -EFAULT;

}

Copy to user

And never use a single line commenting, that is a bad practice as per kernel programming guideline is concerned, always use multiline commenting.

After that, you have to update the current file position * of current file position += count. And then, you should be returning the number of  bytes which have been successfully read. That is, you should be return count.

/*update the current file postion */
*f_pos += count;
pr_info("Number of bytes successfully read = %zu\n",count);
pr_info("Updated file position = %lld\n",*f_pos);

Update the current file position

Let’s also print some messages. The above message(pr_info(“Read requested for %zu bytes \n”,count);) actually prints the actual count requested. What we can do is we can put one more print statement. Pr_info “number of bytes successfully read =%zu\n”, and let’s print count.

And also, let’s print the updated value of the file position.

Updated file position = what you should be using is, you should print this value(*f_pos). The data type is long offset. This is actually typedef for long, long int. This is signed data.  So, for that, you should be using %lld.

As per the kernel documentation, you should use this format specifier for long long int \n. Let’s print this value  * of file position.

And after that, let’s also print, the initial value of the file position. I would write And after that, let’s also print the initial value of the file position. I would write the current file position. That means, before reading. Current file position = %lld\n, file position That’s about read, and in the next article, let’s implement write, and after that, we will test this.

 

FastBit Embedded Brain Academy Courses

Click here:  https://fastbitlab.com/course1

 

FastBitLab

The FastBit Embedded Brain Academy uses the power of internet to bring the online courses related to the field of embedded system programming, Real time operating system, Embedded Linux systems, etc at your finger tip with very low cost. Backed with strong experience of industry, we have produced lots of courses with the customer enrolment over 3000+ across 100+ countries.