Reader small image

You're reading from  Linux Device Driver Development Cookbook

Product typeBook
Published inMay 2019
Reading LevelIntermediate
PublisherPackt
ISBN-139781838558802
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Rodolfo Giometti
Rodolfo Giometti
author image
Rodolfo Giometti

Rodolfo Giometti is an engineer, IT specialist, GNU/Linux expert and software libre evangelist. He is the author of the books BeagleBone Essentials, BeagleBone Home Automation Blueprints and GNU/Linux Rapid Embedded Programming by Packt Publishing and maintainer of the LinuxPPS projects. He still actively contributes to the Linux source code with several patches and new device drivers for industrial applications devices. During his 20+ years of experience, he has worked on the x86, ARM, MIPS, and PowerPC-based platforms. Now, he is the co-chief at HCE Engineering S.r.l., where he designs new hardware and software systems for the quick prototyping in industry environment, control automation, and remote monitoring.
Read more about Rodolfo Giometti

Right arrow

Advanced Char Driver Operations

In previous chapters, we learned several useful things that can be handy in device driver development; however, a final step is needed. We must see how to add advanced functionalities to our character device and fully understand how we can synchronize user space processes with the peripheral I/O activity.

In this chapter, we'll see how to implement system calls for the lseek(), ioctl(), and mmap() functions, and we'll also get to know several techniques to put a process to sleep, just in case our peripheral does not yet have data to return to it; therefore, in this chapter, we will cover the following recipes:

  • Going up and down within a file with lseek()
  • Using ioctl() for custom commands
  • Accessing I/O memory with mmap()
  • Locking with the process context
  • Locking (and syncing) with the interrupt context
  • Waiting for I/O operations with poll...

Technical requirements

Going up and down within a file with lseek()

In this recipe, we're going to take a better look at how we can manipulate the ppos pointer (described in the Exchanging data with a char driver recipe in Chapter 3, Working with Char Drivers), which is related to the read() and write() system call implementations.

Getting ready

To provide a simple example about lseek() implementation, we can reuse our chrdev driver in Chapter 4, Using the Device Tree in the chapter_04/chrdev directory (we need both of the chrdev.c and chrdev-req.c files of GitHub repository), where we can simply add our custom llseek() method according to our device memory layout.

For simplicity, I just copied these files in the chapter_07/chrdev/ directory...

Using ioctl() for custom commands

In this recipe, we will see how to add custom commands to configure or manage our peripheral in a very customized manner.

Getting ready

Now, in order to present a simple example about how we can implement an ioctl() system call within our driver, we can still use the chrdev driver presented earlier, where we add the unlocked_ioctl() method, as explained later.

How to do it...

Let's see how to do it by following these steps:

  1. First of all, we have to add the unlocked_ioctl() method within the chrdev_fops structure:
static const struct...

Accessing I/O memory with mmap()

In this recipe, we will see how to map an I/O memory region within the process memory space to gain access to our peripheral's internal by simply using a pointer in memory.

Getting ready

Now, let's see how we can implement a custom mmap() system call for our chrdev driver.

Since we have a virtual device totally mapped into memory, we may suppose that the buf buffer within struct chrdev_device represents the memory areas to be mapped. Also, we need to dynamically allocate it for it to be remapped; this is due to the fact that kernel virtual memory addresses cannot be remapped using the remap_pfn_range() function.

This is the only limitation of remap_pfn_range(), which is unable to...

Locking with the process context

In this recipe, we will see how to protect data against the concurrent access of two or more processes to avoid race conditions.

How to do it...

To present a simple example about how to add a mutex to the chrdev driver, we can make a few modifications to it, as reported in the following.

  1. First, we have to add the mux mutex to the driver's main structure in the chrdev.h header file, as follows:
/* Main struct */
struct chrdev_device {
char label[NAME_LEN];
unsigned int busy : 1;
char *buf;
int read_only;

unsigned int id;
struct module *owner;
struct cdev cdev;
struct device *dev;

struct mutex mux;
};
All modifications presented here can be applied to the chrdev...

Locking (and syncing) with the interrupt context

Now, let's see how we can avoid race conditions between the process context and the interrupt context. However, this time we must pay more attention than before because, this time, we must implement a locking mechanism to protect shared data between the process context and the interrupt context. However, we must also provide a syncing mechanism between the reading process and the driver too, to allow the reading process to proceed in its action if some data to be read is present within the driver's queues.

To explain this problem, it is better to do a practical example. Let's suppose we have a peripheral that generates data for reading processes. To signal that new data has arrived, the peripheral sends an interrupt to the CPU, so we can imagine implementing our driver by using a circular buffer where the interrupt...

Waiting for I/O operations with poll() and select()

In this recipe, we will find out how to ask to the kernel to check for us when our driver has new data to be read (or it's willing to accept new data to be written), and then to wake up the reading (or writing) process without the risk of being blocked on the I/O operation.

Getting ready

To test our implementation, we can still use the chrdev_irq.c driver as before; this is because we can use the new data event simulated by the kernel timer.

How to do it...

Let's see how to do it by following these steps:

  1. First...

Managing asynchronous notifications with fasync()

In this recipe, we will see how we can generate asynchronous SIGIO signals whenever our driver has new data to be read (or it's willing to accept new data from the user space).

Getting ready

As done previously, we can still present our implementation using the chrdev_irq.c driver.

How to do it...

Let's see how to do it by following these steps:

  1. First of all, we have to add our new chrdev_fasync() method in the struct file_operations of our driver:
static const struct file_operations chrdev_fops = {
.owner...
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Linux Device Driver Development Cookbook
Published in: May 2019Publisher: PacktISBN-13: 9781838558802
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Rodolfo Giometti

Rodolfo Giometti is an engineer, IT specialist, GNU/Linux expert and software libre evangelist. He is the author of the books BeagleBone Essentials, BeagleBone Home Automation Blueprints and GNU/Linux Rapid Embedded Programming by Packt Publishing and maintainer of the LinuxPPS projects. He still actively contributes to the Linux source code with several patches and new device drivers for industrial applications devices. During his 20+ years of experience, he has worked on the x86, ARM, MIPS, and PowerPC-based platforms. Now, he is the co-chief at HCE Engineering S.r.l., where he designs new hardware and software systems for the quick prototyping in industry environment, control automation, and remote monitoring.
Read more about Rodolfo Giometti