Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add fasync function to the kernel module code?

Tags:

kernel

driver

Kit: Beagle Bone Black, OS: Angstrom, kernel:

root@beaglebone:~# uname -a
Linux beaglebone 3.12.9-00018-g9bdb229-dirty #67 SMP Sat Apr 18 11:45:30 CST 2015 armv7l GNU/Linux

I want to add fasync function to my kernel module, but it doesn't work well. Below code is from internet and I modified it (try to add fasync). It can run on Beagle Bone Black. I simplify write(), read() and poll() functions. And put kill_fasync() in the irq handler.

#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");

#define MAX_BUF_LENGTH       PAGE_SIZE

static struct proc_dir_entry *proc_entry;
static char *fortune_buf;  // Space for fortune strings
static int write_index;   // Index to write next fortune
static int read_index;    // Index to read next fortune

static DEFINE_SPINLOCK(fortune_lock);
static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
static volatile unsigned long fortune_data_flag;    /* our output to the world    */
static struct fasync_struct *fortune_async_queue = NULL;


#define GPIO2_START_ADDR 0x481ac000
#define GPIO2_SIZE (0x481adfff - GPIO2_START_ADDR)

#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE       0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0   // page 948

#define GPIO_IRQSTATUS_0 0x2c
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_DATAIN      0x138  // page 4657
#define GPIO_OE          0x134  // page 4656
#define GPIO_FALLINGDETECT 0x14c
#define GPIO_DEBOUNCENABLE 0x150    // page 4663
#define GPIO_DEBOUNCINGTIME 0x154   // page 4664

#define PIN_A_GPIO 68 // is on BBB connector P8 pin10/TIMER6/GPIO2_4    
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"  // when floating, its level is high, 3.19~3.20V

#define PIN_B_GPIO 69 // is on BBB connector P8 pin9/TIMER5/GPIO2_5
#define PIN_B_FLAGS GPIOF_IN
#define PIN_B_LABEL "HI_PIN_B"

void __iomem *mem;

static irqreturn_t irq_handler_pin_a (int irq, void *dev_id)
{
    int regval;
    int regval_a, regval_b;

    regval = ioread32 (mem + GPIO_DATAIN);
    printk (KERN_DEBUG "interrupt: Hello from irq_handler_pin_a. The GPIO b read value is %x - %d \n", regval, (regval & 0x20) >> 5);
    regval_a = (regval & 0x10) >> 4;
    regval_b = (regval & 0x20) >> 5;

    printk(KERN_DEBUG "irq 0: fortune_async_queue  is 0x%p", fortune_async_queue);
    if(regval_a == regval_b) {
        printk (KERN_DEBUG "interrupt: 1 \n");
    } else {
        printk (KERN_DEBUG "interrupt: 2 \n");
    }

    kill_fasync(&fortune_async_queue, SIGIO, POLL_IN);
    printk(KERN_DEBUG "irq 1: fortune_async_queue  is 0x%p", fortune_async_queue);

    return IRQ_HANDLED;
}

static int gpio_interrupt_init (void)
{
   ...
}

static void gpio_interrupt_exit(void)
{
    printk ("HI: Releasing IRQ resources...\n");

    iounmap (mem);
    free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
    gpio_free (PIN_A_GPIO);
    gpio_free (PIN_B_GPIO);

    printk (KERN_DEBUG "Goodbye gpio_interrupt!\n");
}


ssize_t fortune_write( struct file *filp, const char __user *buff,
                       unsigned long len, void *data )
{
    printk(KERN_INFO "fortune_write() executes\n");

    return len;
}

ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
{
    int len;
    printk(KERN_INFO "fortune_read() executes\n");

    return len;
}

static unsigned int fortune_poll(struct file *file, poll_table *wait)
{
    printk(KERN_INFO "fortune_poll() executes\n");
    return 0;
}

static int fortune_fasync(int fd, struct file *file, int on)
{
    printk("fortune_fasync() executes\n");
    if(!fortune_async_queue)
    {
        if (fasync_helper(fd, file, 1, &fortune_async_queue) >= 0)
        {
            printk(KERN_DEBUG "fasync 0: fasync_helper works. fortune_async_queue is 0x%p", fortune_async_queue);
            return 0;
        }
        else
        {
            printk(KERN_DEBUG "fasync 1: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
            return -EIO;
        }
    }
    else
    {
        printk(KERN_DEBUG "fasync 2: fasync_helper doesn't work. fortune_async_queue is 0x%p", fortune_async_queue);
    }

}

static int fortune_release(struct inode *inode, struct file *file)
{
    struct fortune_dev *devp;

    devp = file->private_data;
    fortune_fasync(-1, file, 0);

    file->private_data = NULL;
    return 0;
}
static int fortune_open(struct inode *inode, struct file *file)
{
    return 0;
}

static const struct file_operations proc_test_fops = {
    .owner        = THIS_MODULE,
    .open         = fortune_open,
    .read         = fortune_read,
    .write        = fortune_write,
    .poll          = fortune_poll,
    .release      = fortune_release,
    .fasync       = fortune_fasync,
};

int __init init_fortune_module( void )
{
    int ret = 0;

    gpio_interrupt_init();

    fortune_buf = (char *)vmalloc( MAX_BUF_LENGTH );
    if (!fortune_buf) {
        ret = -ENOMEM;
    } else {
        memset( fortune_buf, 0, MAX_BUF_LENGTH );
        proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops );

        if (proc_entry == NULL) {
            ret = -ENOMEM;
            vfree(fortune_buf);
            printk(KERN_INFO "fortune: Couldn't create proc entry\n");
        } else
            write_index = 0;
            read_index = 0;
            printk(KERN_INFO "fortune: Module loaded.\n");
        }

    return ret;
}

void __exit exit_fortune_module( void )
{
    gpio_interrupt_exit();
    proc_remove(proc_entry);
    vfree(fortune_buf);
    printk(KERN_INFO "fortune: Module unloaded.\n");
}

module_init( init_fortune_module );
module_exit( exit_fortune_module );

I also find this user space code, it is compiled to a.out:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>


int fd;

void my_signal_io_fun(int signum)
{
    printf("SIGIO occurs!\n");
}

void my_signal_int_fun(int signum)
{
    printf("signum: 0x%x\n", signum);
    close(fd);
    exit(signum);
}

int main(int argc, char **argv)
{
    unsigned char key_val;
    int ret;
    int Oflags;

    signal(SIGIO, my_signal_io_fun);
    signal(SIGINT, my_signal_int_fun);

    fd = open("/proc/fortune", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
    }
    printf("open OK, fd = 0x%x\n", fd);
    fcntl(fd, F_SETOWN, getpid());
    Oflags = fcntl(fd, F_GETFL); 
    fcntl(fd, F_SETFL, Oflags | FASYNC);

    while (1)
    {
        sleep(1000);
    }

    return 0;
}

And then I upload the module to my Beagle Bone Black, do like below:

root@beaglebone:~# insmod fasync_kernel.ko
root@beaglebone:~# cat /proc/fortune
root@beaglebone:~# ./a.out
open OK, fd = 0x3
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
SIGIO occurs!
^Csignum: 0x2

I make some interrupt on the corresponding GPIO and then it shows SIGIO occurs!. But the issue is that I must execute cat /proc/fortune first before running the user space code (a.out). And it not always work like above. Usually I need to rmmod - insmod - cat - a.out for two times and then fasync code can work. The dmesg is below:

[ 5512.325893] fortune: Module loaded.
[ 5514.950859] fortune_read() executes
[ 5514.950932] fortune_fasync() executes
[ 5518.915844] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5514.950961] fasync 0: fasync_helper works. fortune_async_queue is 0xdf63eb18
[ 5518.915881] irq 0: fortune_async_queue  is 0xdf63eb18
[ 5518.915895] interrupt: 2
[ 5518.915950] irq 1: fortune_async_queue  is 0xdf63eb18
[ 5519.610571] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f2d - 1
[ 5519.610601] irq 0: fortune_async_queue  is 0xdf63eb18
[ 5519.610612] interrupt: 2
[ 5519.610666] irq 1: fortune_async_queue  is 0xdf63eb18
[ 5520.260265] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5520.260295] irq 0: fortune_async_queue  is 0xdf63eb18
[ 5520.260306] interrupt: 1
[ 5520.260357] irq 1: fortune_async_queue  is 0xdf63eb18
[ 5521.185887] interrupt: Hello from irq_handler_pin_a. The GPIO b read value is f0d - 0
[ 5521.185916] irq 0: fortune_async_queue  is 0xdf63eb18
[ 5521.185926] interrupt: 1
[ 5522.777769] fortune_fasync() executes
[ 5521.185976] irq 1: fortune_async_queue  is 0xdf63eb18
[ 5522.777812] fasync 2: fasync_helper doesn't work. fortune_async_queue is 0xdf63eb18

My question is that why I must execute cat /proc/fortune before the user space code executes? Any better way? How to make it run stably? How to avoid running the loop (rmmod - insmod - cat - a.out) for two times?

I add some if-else around fortune_async_queue, because if I simply use fasync_helper() and kill_fasync(), fortune_async_queue will be always null. And for this func: static int fortune_fasync(int fd, struct file *file, int on), I found that its last parameter on is always 0, why? I have to manually set it to 1, like above code: fasync_helper(fd, file, 1, &fortune_async_queue)

like image 964
Tom Xue Avatar asked May 05 '15 09:05

Tom Xue


People also ask

How do I create async code?

The asynchronous code will be written in three ways: callbacks, promises, and with the async / await keywords. Note: As of this writing, asynchronous programming is no longer done using only callbacks, but learning this obsolete method can provide great context as to why the JavaScript community now uses promises.

How do you create async function in Python?

In asyncio Coroutine can be created by using async keyword before def. To run an async function (coroutine) you have to call it using an Event Loop. Event Loops: You can think of Event Loop as functions to run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses.

How do I add async to promise?

async and await Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.


1 Answers

You are using "insmod" which accepts paths to file but dependencies are not automatically loaded. Therefore, you must have to execute cat /proc/fortune before user space code executes for loading dependencies.

You may try "modprobe" in place of "insmod". It will load dependencies by default.

By default asynchronous notifications for file descriptor is turned off. Therefore, on = 0 always.

like image 197
Saurabh Tripathi Avatar answered Nov 15 '22 10:11

Saurabh Tripathi