linux驱动中断注册与注销带来的段错误

错误描述:

今天写了个重力传感器的驱动,按照通常的中断申请与注册流程,insmod时安静,运行测试程序正常,rmmod安静。但是..... 当我再次insmod时,报了一堆的oops错误,从错误描述中看根本找不出是我写的哪个函数有错,从此以后就再也不能insmod了,rmmod却报资源忙,这下是进也不是退也不是,每次到了这里就得断电重启,这bug,卡了我整整一天。

 1 root@nufront ~$ insmod mc3xxx.ko 
 2 [  199.970066] mc3xxx: request irq sucssce! irq = 105 
 3 [  200.064055] input: mc3xxx as /devices/virtual/input/input1
 4 root@nufront ~$ [  200.314850] mc3xxx: entern extint_irq_handler 
 5 
 6 root@nufront ~$ 
 7 root@nufront ~$ 
 8 root@nufront ~$ 
 9 root@nufront ~$ 
10 root@nufront ~$ rmmod mc3xxx.ko 
11 root@nufront ~$ insmod mc3xxx.ko 
12 [  230.449460] Unable to handle kernel paging request at virtual address bf001e01
13 [  230.456598] pgd = cf80c000
14 [  230.459287] [bf001e01] *pgd=0f590811, *pte=00000000, *ppte=00000000
15 [  230.465539] Internal error: Oops - BUG: 7 [#1] PREEMPT SMP ARM
16 [  230.471351] Modules linked in: mc3xxx(O+) [last unloaded: mc3xxx]
17 [  230.477435] CPU: 0 PID: 2562 Comm: insmod Tainted: G           O    4.4.0-xil1
18 [  230.486975] Hardware name: Xilinx Zynq Platform
19 [  230.491492] task: c8213ac0 ti: cf8cc000 task.ti: cf8cc000
20 [  230.496878] PC is at strnlen+0x10/0x28
21 [  230.500607] LR is at string+0x30/0xcc
22 [  230.504254] pc : [<c01dd6d8>]    lr : [<c01de8e4>]    psr: a0000093
23 [  230.504254] sp : cf8cdc20  ip : 00000073  fp : cf8cdc50
24 [  230.515707] r10: c0626f80  r9 : 00000002  r8 : c0514663
25 [  230.520916] r7 : bf001e01  r6 : 0000ffff  r5 : c0627360  r4 : c0626fc2
26 [  230.527426] r3 : bf001e01  r2 : bf001e01  r1 : fffffffe  r0 : bf001e01
27 [  230.533937] Flags: NzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
28 [  230.541141] Control: 18c5387d  Table: 0f80c04a  DAC: 00000055
29 [  230.546869] Process insmod (pid: 2562, stack limit = 0xcf8cc210)
30 [  230.552858] Stack: (0xcf8cdc20 to 0xcf8ce000)
31 [  230.557205] dc20: ff0a0004 cf8cdd0c c0626fc2 cf8cdd10 c0627360 c01e0144 c06264
32 [  230.565363] dc40: ffffffff ffff0008 ffffffff 000003e0 ff0a0004 ffffffff fffff0
33 [  230.573521] dc60: ffffffff 00000000 00000069 00000000 00000000 00000000 00000c
34 [  230.581681] dc80: 00000000 c005411c 00000069 00000002 cf8cdcc0 c0057628 cf8cd8
35 [  230.589840] dca0: cf8cdca8 cf8cdcac 00000000 60000093 c8109f00 c0054464 cd50e0
36 [  230.597999] dcc0: 00000069 ce97e380 c8109f00 cd50e5e0 60000013 c0054480 c0514c
37 [  230.606158] dce0: 00000001 c008c67c c051462c cf8cdcfc cf723a00 c00569e4 c05149
38 [  230.614317] dd00: 00000002 bf008e01 00000002 bf001e01 d7bac450 00000002 00000c
39 [  230.622476] dd20: 00000069 cf723a00 cd50e580 00000000 c8109f00 00000002 000000
40 [  230.630636] dd40: c8109f00 d7baca7c ffffffed bf008f8c cd4f5600 00000500 bf0088
41 [  230.638796] dd60: bf008e01 c8109f00 bf008514 cd4f5600 cd4f5620 ffffffed bf0088
42 [  230.646954] dd80: 00000001 c032c068 cd4f5620 00000000 bf008f8c 00000008 bf0098
43 [  230.655113] dda0: 00000000 cd4f5620 cd4f5654 bf008f8c 00000000 c0271814 bf0084
44 [  230.663273] ddc0: 00000000 c02700e8 c80ef75c c8406b34 bf008f8c cf7ae980 c06164
45 [  230.671432] dde0: bf008e01 cf8cc020 00000000 bf008f8c 00000000 00000000 c05f48
46 [  230.679591] de00: c0616494 bf00b000 bf008f70 c032c628 c05f4e50 bf00b000 000004
47 [  230.687749] de20: ff0a0004 00000000 00000001 00000001 c80b5000 00000001 000000
48 [  230.695909] de40: d7da5e60 d7da5e80 00000000 c0091404 c05f4e44 d7da5e60 000000
49 [  230.704068] de60: 00000000 00000000 d7da5e60 c0092ff4 d7da5e60 bf009080 cf8cc0
50 [  230.712228] de80: ce97e1c0 bf0090c8 00000500 c008c934 bf009080 0000003e bf0090
51 [  230.720386] dea0: 00000001 c00773b8 bf00908c 00007fff 00000000 c0074c74 000004
52 [  230.728546] dec0: bf00922c 000000b1 e0940674 000a7008 6e72656b 00006c65 000000
53 [  230.736703] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 000000
54 [  230.744862] df00: 00000000 00000000 00000000 00000000 00000000 00000000 000000
55 [  230.753023] df20: 00000000 c056e410 00000000 00005198 e0942198 00000000 000ac8
56 [  230.761183] df40: cf8cc000 00000000 00000000 c00776dc e093d000 00005198 e09407
57 [  230.769341] df60: e0941af4 00002248 00002668 00000000 00000000 00000000 00000f
58 [  230.777501] df80: 00000016 00000013 00000011 00000000 00005198 bea85e14 bea850
59 [  230.785661] dfa0: c000ec44 c000eaa0 00005198 bea85e14 000a7018 00005198 000a79
60 root@nufront ~$ rm mc3xxx.ko 
61 root@nufront ~$ lsmod 
62 Module                  Size  Used by
63 mc3xxx                 14935  1 
64 root@nufront ~$ rmmod mc3xxx
65 rmmod: can't unload 'mc3xxx': Device or resource busy
66 root@nufront ~$ reboot -f
67 [  508.527520] max_wdt_notify_sys: feed watchdog

发现问题:

后来,我尝试着先不注册中断,这样就能随意地加载卸载,逐渐地缩小目标范围,最终锁定“嫌疑犯”:  request_irq() / free_irq() 。  只要注释了这一对“夫妇”,程序就乖乖地听我的话了。

于是乎,确定时这里面传参的问题了,又在网上几经周折,终于知道原因了:这个gpio是与其他gpio等共享52号中断线的(xilinx zynq-7z030二合一芯片),所以得以共享中断方式注册,而且最后一个参数必不可少,他就是通过这最后一个参数区分具体是谁触发的。

改正后代码:

static irqreturn_t extint_irq_handler(int irq, void *dev)
{
    struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev);
    struct mc3xxx_data *data;
    data = i2c_get_clientdata(client);
    if (&data->input_dev->dev == dev) {
        udelay(100);


        i2c_smbus_read_byte_data(client, 0x03);
        GSE_ERR("entern extint_irq_handler 
");
    
    }
    
     return IRQ_HANDLED;

}



probe() 
{


   .......


    
/* add by xxg for surpport extern interrupt triger */
    np = of_find_compatible_node(NULL, NULL, "mcube,mc3xxx");
    if(NULL == np){
         printk(KERN_DEBUG "not fund device node mc3xxx 
");
        goto erro_node_find ;
    }
    
#if !(DTS_HAVE_INT)        
    data->gpio = of_get_named_gpio(np, "gpio_int", 0);
    if (data->gpio < 0) {
        printk(KERN_DEBUG "get gpio failed 
");
        goto erro_node_find ;
    }
    if(gpio_is_valid(data->gpio)){//判断是不是一个可用的gpio号
        ret = gpio_request_one(data->gpio, GPIOF_IN, "mc3xxx");//将这个gpio的引脚复用功能设置成中断功能
        if(ret){
            printk(KERN_DEBUG "get gpio failed 
");
            goto erro_get_gpio;
        }
        GSE_ERR("get gpio sucssce! gpio = %d 
", data->gpio);
        data->irq = gpio_to_irq(data->gpio);//为gpio申请一个软中断号
    }
    else {
        goto erro_get_gpio;
    }
    
#endif    
    
    
#if DTS_HAVE_INT
        data->irq = of_irq_get(np, 0);
#endif

    if (data->irq < 0) {
        printk(KERN_DEBUG "gpio to irq failed 
");
        goto erro_get_gpio ;
    }
    
    ret = request_irq(data->irq, extint_irq_handler, IRQF_TRIGGER_FALLING  | IRQF_SHARED ,
            data->input_dev->name , &data->input_dev->dev);//将申请到的软中断号注册进内核(绑定回调函数)
    if(ret){
        printk(KERN_DEBUG "requst irq failled 
");
        goto erro_get_irq ;           
    }
    GSE_ERR("request irq sucssce! irq = %d 
", data->irq);


   ......


}





static int mc3xxx_remove(struct i2c_client *client)
{
    struct mc3xxx_data *data = i2c_get_clientdata(client);
    
    destroy_workqueue(data->mc3xxx_wq);
    free_irq(data->irq, &data->input_dev->dev );
    gpio_free(data->gpio);
    hrtimer_cancel(&data->timer);
    input_unregister_device(data->input_dev);
    misc_deregister(&mc3xxx_device);
    sysfs_remove_group(&data->input_dev->dev.kobj, &mc3xxx_group);
    
    kfree(data);
    return 0;
}
原文地址:https://www.cnblogs.com/xxg1992/p/6842725.html