Let's see how to do it by following these steps:
- 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 = THIS_MODULE,
.fasync = chrdev_fasync,
.poll = chrdev_poll,
.llseek = no_llseek,
.read = chrdev_read,
.open = chrdev_open,
.release = chrdev_release
};
- The implementation is as follows:
static int chrdev_fasync(int fd, struct file *filp, int on)
{
struct chrdev_device *chrdev = filp->private_data;
return fasync_helper(fd, filp, on, &chrdev->fasync_queue);
}
- Finally, we have to add the kill_fasync() call into our (simulated) interrupt handler to signal that the signal SIGIO can be sent due to the fact that new data is ready to be read:
static enum hrtimer_restart chrdev_timer_handler(struct hrtimer *ptr)
{
struct chrdev_device *chrdev = container_of(ptr,
struct chrdev_device, timer);
...
/* Wake up any possible sleeping process */
wake_up_interruptible(&chrdev->queue);
kill_fasync(&chrdev->fasync_queue, SIGIO, POLL_IN);
/* Now forward the expiration time and ask to be rescheduled */
hrtimer_forward_now(&chrdev->timer, ns_to_ktime(delay_ns));
return HRTIMER_RESTART;
}