Question

I'm aiming to have a kernel module that reads a device (ADC) at every T seconds. I already have a working module that calls a interrupt each T seconds and I also have another module that reads a user space file (the ADC, for instance), which I got from this example. Both work fine separately.

The problem is that when I try to open and read any file from my interrupt routine the module crashes

[   80.636932] Kernel panic - not syncing: Fatal exception in interrupt

My code is something like this:

static irqreturn_t timer_irq_handler(int irq, void *dev_id)
{
    uint16_t value;

    // reset the timer interrupt status
    omap_dm_timer_write_status(timer_ptr, OMAP_TIMER_INT_OVERFLOW);
    omap_dm_timer_read_status(timer_ptr);

    omap_dm_timer_set_load(timer_ptr, 1, 0xFFFFFFFF - (time * gt_rate);

    value = read_channel();

    return IRQ_HANDLED;
}

uint16_t read_channel()
{
    // Create variables
    struct file *f;
    char buf[128];
    mm_segment_t fs;
    int i;
    // Init the buffer with 0
    for(i=0;i \< 128;i++)
        buf[i] = 0;

    f = filp_open(device, O_RDONLY, 0);
    if(f == NULL)
        printk(KERN_ALERT "filp_open error!!.\n");
    else{
        // Get current segment descriptor
        fs = get_fs();
        // Set segment descriptor associated to kernel space
        set_fs(get_ds());
        // Read the file
        f->f_op->read(f, buf, 128, &f->f_pos);
        // Restore segment descriptor
        set_fs(fs);
        // See what we read from file
        printk(KERN_INFO "buf:%s\n",buf);
    }
    filp_close(f,NULL);
    return 0;
}

static int __init mq7_driver_init(void)
{
    int ret = 0;
    struct clk *gt_fclk;

    timer_ptr = omap_dm_timer_request();
    if(timer_ptr == NULL){
        printk("No more gp timers available, bailing out\n");
        return -1;
    }

    // set the clock source to system clock
    omap_dm_timer_set_source(timer_ptr, OMAP_TIMER_SRC_SYS_CLK);

    // set prescalar to 1:1
    omap_dm_timer_set_prescaler(timer_ptr, 0);

    // figure out what IRQ our timer triggers
    timer_irq = omap_dm_timer_get_irq(timer_ptr);

    // install our IRQ handler for our timer
    ret = request_irq(timer_irq, timer_irq_handler, IRQF_DISABLED | IRQF_TIMER , "mq7_driver", timer_irq_handler);
    if(ret){
    printk("mq7_driver: request_irq failed (on irq %d), bailing out\n", timer_irq);
    return ret;
    }

    // get clock rate in Hz
    gt_fclk = omap_dm_timer_get_fclk(timer_ptr);
    gt_rate = clk_get_rate(gt_fclk);

    // set preload, and autoreload
    // we set it to the clock rate in order to get 1 overflow every 3 seconds
    omap_dm_timer_set_load(timer_ptr, 1, 0xFFFFFFFF - (5 * gt_rate)); // dobro do tempo

    // setup timer to trigger our IRQ on the overflow event
    omap_dm_timer_set_int_enable(timer_ptr, OMAP_TIMER_INT_OVERFLOW);

    // start the timer!
    omap_dm_timer_start(timer_ptr);

    // get acess to gpio
    ret = gpio_request(gpio, "mq7_driver sck"); 
    if (ret) {
        printk(KERN_ALERT "gpio_request %d failed\n",gpio);
        gpio_free(gpio);
        return -1;
    }
    gpio_direction_output(gpio, 0);

    // Print adc number into address string
    sprintf(device,"/sys/class/hwmon/hwmon0/device/in%d_input",adc);

    return 0;
}

What is wrong with reading a file from a interrupt routine?


P.S.: It's running on a Overo (ARM), the distro is Poky and kernel version is 3.5.7.

Was it helpful?

Solution

After reading the answer of @VivekS in this post I took a look at Linux Device Drivers, chapter 10, which states:

A handler can't transfer data to or from user space, because it doesn't execute in the context of a process. Handlers also cannot do anything that would sleep, such as calling wait_event, allocating memory with anything other than GFP_ATOMIC, or locking a semaphore. Finally, handlers cannot call schedule.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top