Reputation: 1290
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.
Upvotes: 0
Views: 1487
Reputation: 1290
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.
Upvotes: 1