How to Implement the lseek File Operation Method in a Linux Device Driver

Beaglebone black board






In this article, we show how to implement the lseek file operation method in a linux device driver.

So the lseek file operation method originates from the lseek user system call.

For each open file, the kernel records a file offset, which is sometimes called the read-write offset or pointer. This is the location at which the next read() or write() methods will begin. The file offset is expressed as an ordinal byte position relative to the start of the file. The first byte of the file is an offset of 0. The file offset is set to point to the start of the file when the file is opened and is automatically adjusted by each subsequent call to read() or write() so that it points to the next byte of the file after the byte(s) just read or written. Thus, successive read() and write() calls progress sequentially through a file.

So, essentially, the lseek file operation method adjusts the file offset of a file.

In our example in this code, our character device represents a memory array, which is a contiguous memory location. It can be seen as a device memory buffer. The lseek method can adjust the file offset of this file.

The general format for the l;seek file operation method is shown below.





So like all the other methods such as read() and write(), the first parameter, *filp, is a reference to the file we are working with.

offset and whence work together to establish where the pointer is in the file.

The offset argument specifies a value in bytes. The offset value is a signed integer; thus, we can specify a positive or negative number in this argument.

If the value is negative, then the pointer will be the value specified behind (or to the left) of where the pointer is located.

Now the next important concept to know is whence.

whence will specify where the pointer is.

whence can take in 3 possible values, SEEK_SET, SEEK_CUR, and SEEK_END

With SEEK_SET, the file offset is set offset bytes from the beginning of the file.

With SEEK_CUR, the file offset is adjusted by offset bytes relative to the current file offset.

With SEEK_END, the file offset is set to the size of the file plus offset. So, offset is interpreted wtih respect to the next byte after the last byte of the file.

One thing to note is that if whence is SEEK_CUR or SEEK_END, offset may be negative or positive; for SEEK_SET, offset must be nonnegative (0 or positive).

The return value from a successful lseek() method is the new file offset.

So let's now go through the complete code of this lseek file operation, which is shown below.





So let's now go through this code.

So we call our method, pcd_lseek(). You can call this method anything that suits your code.

So the first thing we do in our code is we create a variable, temp. We use this later in our code to set the file position in various switch statement conditions.

We then have a few pr_info() statements for debugging purposes.

We then have our switch statement with 3 cases plus default.

These 3 cases are the 3 possible values for the whence parameter, SEEK_SET, SEEK_CUR, and SEEK_END

The first case is SEEK_SET

Remember that with SEEK_SET, the offset is relative to the beginning of the file or at a byte position of 0.

Therefore, the offset cannot be greater than the size of the file. Also because SEEK_SET begins at the beginning of the file, the offset cannot be negative (less than 0).

So we check for these 2 conditions using an if statement. If either of these conditions are true, then we return the error, -EINVAL

Otherwise, we set the file position to offset. This would mean that the offset is some positive value less than the file size (which works).

Thus, we successfully update our file position pointer to that place which was specified with SEEK_SET

Now we go to our next case, SEEK_CUR

Remember that with SEEK_CUR, the offset is relative to the current file pointer position.

So the actual value of the current file pointer position would be, filp->f_pos + offset

Thus, we set our variable temp equal to, temp= filp->f_pos + offset;

We want to make sure this combined value (of the file position and the offset) is not greater than the file size or less than 0. If so, then we return the error, -EINVAL

If there is no error, then we set the file position equal to temp

The last case is SEEK_END

Remember that with SEEK_END, the offset is relative to the size of the file.

So this time, temp will be set equal to, temp= DEV_MEM_SIZE + offset;

Again, if the value of temp is greater than the file size or less than 0, we give an error.

If not, we set the file position equal to temp.

Any other whence value other than those 3 automatically triggers an error.

The lseek() method returns the updated file position of the pointer.

The full entire code for this project is shown below.





So when you build this code, you should see that you do not get any errors, such as that shown below.


Building the lseek file operation method of a linux device driver


Once you have this, you can test this lseek method out.

So this is how to implement the lseek file operation method in a linux device driver.



Related Resources





HTML Comment Box is loading comments...