Overview of Basic Linux Device Driver File Operation Methods

Beaglebone black board






In this article, we give an overview of basic linux device driver file operation methods.

We will go over the open() method, close() (or release()) method, read() method, write() method, and llseek() method.

We will go over what these methods do what parameters they take in.


Open() Method

The open() method opens a device.

An example would be opening a directory of a memory device.

The general format of the open method() is shown below.


int somedevice_open(struct inode *inode, struct file *filp)
{

}



The open() method takes in 2 parameters.

The first parameter is *inode, which is the pointer of inode associated with the filename or the device file.

The second parameter is *filp, which is the pointer to the file object.

The open() method returns 0 if open is successful and a negative error code if open fails.

It is important to know that the open method is optional. If not provided, open will always succeed and the driver is not notified.


Close() Method

The close() method releases the file object.

The close() method is called when the last reference to an open file is closed- that is, when the f_count field of the file object becomes 0.

The closing of a file object will not trigger the release method if a single file object is closed. It only triggers the release method when all references to a file object are closed. This is when the file object is released from the memory.

The general format of the open method() is shown below.


int somedevice_release(struct inode *inode, struct file *filp)
{

}



The first parameter is *inode, which is the pointer of inode associated with the filename or the device file.

The second parameter is *filp, which is the pointer to the file object.

The release() method returns 0 if open is successful and a negative error code if open fails.

In a release method, the driver can do the reverse operation of what open had done. For example, if the open method brings the device out of low power mode, then the release method may send the device back to low power mode. It is best practice to leave the device in its default state, that state it was in prior to the open user system call.

The release method frees any data structures allocated by the open method.


Read() Method

The read() method reads data from a device.

The general format of the read method() is shown below.


int somedevice_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos)
{

}



The first parameter (struct file *filp) is a pointer of the file object.

The second parameter (char __user *buff) is a pointer of the user buffer. This buffer will hold what this read() method reads in. It is important to know that __user is an optional macro which alerts the programmer that this is a user level pointer, so it cannot be trusted for direct dereferencing. The __user macro used with user level pointers tells the developer not to trust or assume it as a valid pointer to avoid kernel faults. So you should never try to dereference user given pointers directly in kernel level programming. Instead use dedicated kernel functions such as copy_to_user and copy_from_user. The gcc compiler does not care whether you use the __user macro or not and will not give out any warnings or errors. This is checked by sparse, a semantic checker tool of linux to find possible coding faults.

The third parameter (size_t count) is the read count given by the user. It represents the number of bytes that should be read.

The fourth parameter (loff_t *f_pos) is the pointer of the current file position from which the read has to begin. This may be from the beginning of the file or somewhere else.

The read method reads 'count' bytes from a device starting at position 'f_pos'

It updates the 'f_pos' by adding the number of bytes successfully read.

The read method returns the number of bytes successfully read. It returns 0 if there are no bytes to read (EOF).

The read method returns appropriate error code (-ve value) if any error.

A return value less than 'count' does not mean that an error has occurred. If the user specifies more bytes than are available in the file, then the 'count' value returned will simply be the bytes read, not what was specified.


Write() Method

The write() method writes data to a device.

The general format of the write method() is shown below.


int somedevice_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos)
{

}



The first parameter (struct file *filp) is a pointer of the file object.

The second parameter (const char __user *buff) is a pointer of the user buffer. This buffer will hold what this write() method places in there. Just as the read method, the __user macro is used.

The third parameter (size_t count) is the read count given by the user. It represents the number of bytes that should be read.

The fourth parameter (loff_t *f_pos) is the pointer of the current file position from which the write has to begin. This may be from the beginning of the file, the end of the file, or somewhere else.

The write method writes 'count' bytes to the device starting at position 'f_pos'

The write method updates the 'f_pos' by adding the number of bytes successfully written.

The write method returns the number of bytes successfully written.

The write method returns the appropriate error code (-ve value) if any error.


llseek() Method

The llseek() method alters the current file position, meaning where the file position begins. You can think of it like where the cursor would be in a file before doing either a read or write method.

The general format of the llseek method() is shown below.


int somedevice_llseek(struct file *filp, loff_t off, int whence)
{

}



The first parameter that the method takes is a pointer of the file object.

The second parameter is the offset value.

The third parameter is whence.

The second and third parameters work together as such.

The third parameter can take in 1 of 3 values: SEEK_SET, SEEK_CUR, or SEEK_END.

SEEK_SET sets the file offset to 'off' bytes.

SEEK_CUR sets the file offset to its current location plus 'off' bytes

SEEK_END sets the size of the file plus 'off' bytes

In the llseek method, the driver should update the file pointer by using 'offset' and 'whence' information.

The llseek handler should return newly updated file position or an error.

So this is an overview of the basic file operation methods used in a linux device driver.



Related Resources





HTML Comment Box is loading comments...