【Linux input子系统二】驱动程序的编写

本文主要以分析通用GPIO按键驱动:gpio_keys.C文件为主,将其中牵涉到Linux驱动架构流程,以及架构设计思想进行分析。

【概述】gpio_keys是基于input架构实现的一个通用gpio按键驱动。该驱动基于pladform_driver架构,实现了驱动和设备分离,减少了程序的耦合性,同时提高程序的可移植性。符合Linux设备驱动模型的设计思想。工程中一般都会基于gpio_keys来写。下面我们来理清程序的整体流程思路。

【驱动程序的分析】

step1:根据Linux驱动模型,驱动文件中该有的flow给他加上


step2:当驱动driver模块加载成功,根据compatible属性(name)与device 匹配match成功之后,进入驱动的主入口函数probe




具体程序如下:

  1. static int __devinit gpio_keys_probe(structplatform_device *pdev)  
  2. {  
  3.          structgpio_keys_platform_data *pdata = pdev->dev.platform_data;  
  4.          structgpio_keys_drvdata *ddata;  
  5.          structinput_dev *input;  
  6.          inti, error;  
  7.          intwakeup = 0;  
  8.    
  9.          /*kzalloc 对kmalloc的封装,会清0分配的空间*/  
  10.          ddata= kzalloc(sizeof(struct gpio_keys_drvdata) +  
  11.                             pdata->nbuttons* sizeof(struct gpio_button_data),  
  12.                             GFP_KERNEL);  
  13.    
  14.          /*分配一个input设备*/  
  15.          input= input_allocate_device();  
  16.          if(!ddata || !input) {  
  17.                    error= -ENOMEM;  
  18.                    gotofail1;  
  19.          }  
  20.    
  21.          platform_set_drvdata(pdev,ddata);  
  22.           
  23. /* 设置input设备属性 */  
  24.          input->name= pdev->name;  
  25.          input->phys= "gpio-keys/input0";  
  26.          input->dev.parent= &pdev->dev;  
  27.    
  28.          input->id.bustype= BUS_HOST;  
  29.          input->id.vendor= 0x0001;  
  30.          input->id.product= 0x0001;  
  31.          input->id.version= 0x0100;  
  32.    
  33.          /*Enable auto repeat feature of Linux input subsystem */  
  34.          if(pdata->rep)  
  35.                    __set_bit(EV_REP,input->evbit);  
  36.    
  37.          ddata->input= input;  
  38.    
  39.          for(i = 0; i < pdata->nbuttons; i++) {  
  40.                    structgpio_keys_button *button = &pdata->buttons[i];  
  41.                    structgpio_button_data *bdata = &ddata->data[i];  
  42.                    intirq;  
  43.                    unsignedint type = button->type ?: EV_KEY;  
  44.    
  45.                    bdata->input= input;  
  46.                    bdata->button= button;  
  47.                    setup_timer(&bdata->timer,  
  48.                                 gpio_keys_timer, (unsigned long)bdata);  
  49.                    /*初始化工作队列 */  
  50.                    INIT_WORK(&bdata->work,gpio_keys_report_event);  
  51.    
  52.                    /*申请GPIO口*/  
  53. error = gpio_request(button->gpio, button->desc ?:"gpio_keys");  
  54.                    if(error < 0) {  
  55.                             pr_err("gpio-keys:failed to request GPIO %d,"  
  56.                                      "error %d\n", button->gpio, error);  
  57.                             gotofail2;  
  58.                    }  
  59.                 /* 把GPIO设为输入 */  
  60.                    error= gpio_direction_input(button->gpio);  
  61.                    if(error < 0) {  
  62.                             pr_err("gpio-keys:failed to configure input"  
  63.                                      "direction for GPIO %d, error %d\n",  
  64.                                      button->gpio,error);  
  65.                             gpio_free(button->gpio);  
  66.                             gotofail2;  
  67.                    }  
  68.                    /*获取GPIO对应的中断*/  
  69.                    irq= gpio_to_irq(button->gpio);  
  70.                    if(irq < 0) {  
  71.                             error= irq;  
  72.                             pr_err("gpio-keys:Unable to get irq number"  
  73.                                      "for GPIO %d, error %d\n",  
  74.                                      button->gpio,error);  
  75.                             gpio_free(button->gpio);  
  76.                             gotofail2;  
  77.                    }  
  78.                    /*注册中断 */  
  79.                    error= request_irq(irq, gpio_keys_isr,  
  80.                                          IRQF_SHARED |  
  81.                                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,  
  82.                                          button->desc ? button->desc :"gpio_keys",  
  83.                                          bdata);  
  84.                    if(error) {  
  85.                             pr_err("gpio-keys:Unable to claim irq %d; error %d\n",  
  86.                                      irq,error);  
  87.                             gpio_free(button->gpio);  
  88.                             gotofail2;  
  89.                    }  
  90.    
  91.                    if(button->wakeup)  
  92.                             wakeup= 1;  后续讨论
  93.    
  94.                    /*设置设备对事件的支持,比如设置对键1和键2的支持*/  
  95.                    input_set_capability(input,type, button->code);  
  96.          }  
  97.           
  98.          /*注册input设备*/  
  99.          error= input_register_device(input);  
  100.          if(error) {  
  101.                    pr_err("gpio-keys:Unable to register input device, "  
  102.                             "error:%d\n", error);  
  103.                    gotofail2;  
  104.          }  
  105.    
  106.          device_init_wakeup(&pdev->dev,wakeup);  
  107.    
  108.          return0;  
  109.          ……  
  110.          returnerror;  
  111. }  

本文参考博文链接:

1、https://blog.csdn.net/RadianceBlau/article/details/56290469

2、https://www.linuxidc.com/Linux/2011-11/47650p3.htm

【最终实现】还需要设置具体的platform device的实现:高通和MTK平台是在DTSI里面配置的


结构体中标绿色的项是读取DTS文件属性配置,其他的,如value,active_low等在代码中设置。反正都是需要设置完成才能使用。

struct gpio_keys_button {

unsigned int code;
int gpio;
int active_low;低电平有效1
const char * desc;
unsigned int type;EV_KEY
int wakeup;
int debounce_interval;
bool can_disable;
int value;0按下 1松开
unsigned int irq;中断号
struct gpio_desc *gpiod;description

};

如下是参考:

  1. static struct gpio_keys_button sc_buttons[]= {  
  2.     {  
  3.        .gpio   = S3C2410_GPG(0),   /* K1 */  
  4.        .code   = KEY_1,  
  5.        .desc   = "KEY1",  
  6.        .active_low = 1,  
  7.    },  




猜你喜欢

转载自blog.csdn.net/clam_zxf/article/details/80491839