gpio驱动分析 1

(本文所有内容全部在linux-2.6.36内核基础上进行)

学习SoC留下的习惯,从基本IO入手。如果自己动手写字符驱动就违背了linuxplatform device and driver 的精神,如果自己写我又没那水平,就从内核自带的gpio_keys驱动入手,了解输入子系统的应用。

 

Gpio输入子系统的初始化和注销是从platform_driver_register(&gpio_keys_device_driver)platform_driver_unregister(&gpio_keys_device_driver)实现的:

 

/drivers/input/keyboard/gpio_key.cline632-line643

 

static int __init gpio_keys_init(void)

{

       return platform_driver_register(&gpio_keys_device_driver);

}

 

static void __exit gpio_keys_exit(void)

{

       platform_driver_unregister(&gpio_keys_device_driver);

}

 

module_init(gpio_keys_init);

module_exit(gpio_keys_exit);

 

在看到正文之前再看看struct platform_driver的设定:

static struct platform_driver gpio_keys_device_driver = {

       .probe           = gpio_keys_probe,

       .remove        = __devexit_p(gpio_keys_remove),

       .driver           = {

              .name    = "gpio-keys",

              .owner   = THIS_MODULE,

#ifdef CONFIG_PM

              .pm = &gpio_keys_pm_ops,

#endif

       }

};

 

从上面struct platform_driver可以看出来:

probe是从static int __devinit gpio_keys_probe(struct platform_device *pdev)函数开始的;

remove函数是从static int __devexit gpio_keys_remove(struct platform_device *pdev)函数开始的;

__devexit_p 的定义:#define __devexit_p(x) x  

 

下面进入正题, gpio_keys_probe函数

static int __devinit gpio_keys_probe(struct platform_device *pdev)

{

       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;

       struct gpio_keys_drvdata *ddata;

       struct device *dev = &pdev->dev;

       struct input_dev *input;

       int i, error;

       int wakeup = 0;

 

       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +

                     pdata->nbuttons * sizeof(struct gpio_button_data),

                     GFP_KERNEL);

       input = input_allocate_device();           //申请input_dev结构

       if (!ddata || !input) {

              dev_err(dev, "failed to allocate state\n");

              error = -ENOMEM;

              goto fail1;

       }

 

       ddata->input = input;

       ddata->n_buttons = pdata->nbuttons;

       ddata->enable = pdata->enable;

       ddata->disable = pdata->disable;

       mutex_init(&ddata->disable_lock); //创建一个初始化用互斥锁

 

       platform_set_drvdata(pdev, ddata);      //input_dev结构放好(以后方便调用)

       input_set_drvdata(input, ddata);          // input_dev结构初始化并创建链接

      //input结构赋值

       input->name = pdev->name;

       input->phys = "gpio-keys/input0";

       input->dev.parent = &pdev->dev;

       input->open = gpio_keys_open;

       input->close = gpio_keys_close;

 

       input->id.bustype = BUS_HOST;

       input->id.vendor = 0x0001;

       input->id.product = 0x0001;

       input->id.version = 0x0100;

      //到此,对变态的input_dev结构初始化完成,input_dev结构异常的庞大,定义在include/linux/input.h中,具体成员说明在函数定义中有介绍,还是需要的时候再自行查找吧。

       /* Enable auto repeat feature of Linux input subsystem */

       if (pdata->rep)

              __set_bit(EV_REP, input->evbit);

      //下面的循环对需要的每一个按键进行gpio相关的初始化并标记event为可用

       for (i = 0; i < pdata->nbuttons; i++) {

              struct gpio_keys_button *button = &pdata->buttons[i];

              struct gpio_button_data *bdata = &ddata->data[i];

              unsigned int type = button->type ?: EV_KEY;

 

              bdata->input = input;

              bdata->button = button;

 

              error = gpio_keys_setup_key(pdev, bdata, button);

              if (error)

                     goto fail2;

 

              if (button->wakeup)

                     wakeup = 1;

 

              input_set_capability(input, type, button->code);

       }

       // This function creates a group for the first time. It will explicitly warn and error if any of the attribute files being created already exist.

       error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);

       if (error) {

              dev_err(dev, "Unable to export keys/switches, error: %d\n",

                     error);

              goto fail2;

       }

      // This function registers device with input core. The device must be allocated with input_allocate_device() and all it's capabilities set up before registering.(原来上面那么多动作并未进行真正的input_dev的注册,直到此处才进行。。。)

       error = input_register_device(input);

       if (error) {

              dev_err(dev, "Unable to register input device, error: %d\n",

                     error);

              goto fail3;

       }

 

      /* get current state of buttons */

       for (i = 0; i < pdata->nbuttons; i++)

              gpio_keys_report_event(&ddata->data[i]);

       input_sync(input);

 

       device_init_wakeup(&pdev->dev, wakeup);

 

       return 0;

 

 fail3:

       sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);

 fail2:

       while (--i >= 0) {

              free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);

              if (ddata->data[i].timer_debounce)

                     del_timer_sync(&ddata->data[i].timer);

              cancel_work_sync(&ddata->data[i].work);

              gpio_free(pdata->buttons[i].gpio);

       }

 

       platform_set_drvdata(pdev, NULL);

 fail1:

       input_free_device(input);

       kfree(ddata);

 

       return error;

}

 

基本注册流程了解完之后看两个比较值得关注的功能函数

1void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

/**

 * input_set_capability - mark device as capable of a certain event

 * In addition to setting up corresponding bit in appropriate capability

 * This function handle the corresponding event types.

 */

void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

{

       switch (type) {

       case EV_KEY:

              __set_bit(code, dev->keybit);

              break;

       case EV_REL:

              __set_bit(code, dev->relbit);

              break;

       case EV_ABS:

              __set_bit(code, dev->absbit);

              break;

       case EV_MSC:

              __set_bit(code, dev->mscbit);

              break;

       case EV_SW:

              __set_bit(code, dev->swbit);

              break;

       case EV_LED:

              __set_bit(code, dev->ledbit);

              break;

       case EV_SND:

              __set_bit(code, dev->sndbit);

              break;

       case EV_FF:

              __set_bit(code, dev->ffbit);

              break;

       case EV_PWR:

              /* do nothing */

              break;

       default:

              printk(KERN_ERR

                     "input_set_capability: unknown type %u (code %u)\n",

                     type, code);

              dump_stack();

              return;

       }

       __set_bit(type, dev->evbit);

}

 

2. static int __devinit gpio_keys_setup_key(struct platform_device *pdev,

                                    struct gpio_button_data *bdata,

                                    struct gpio_keys_button *button)

/**

 *这个函数的主要功能就是初始化gpio、申请中断;

 *该函数的所有gpio功能相关函数定义在板文件功能或是通用功能库中,

*通用功能库driver/gpio/gpiolib.c

**/

static int __devinit gpio_keys_setup_key(struct platform_device *pdev,

                                    struct gpio_button_data *bdata,

                                    struct gpio_keys_button *button)

{

       …

 

       error = gpio_request(button->gpio, desc);

 

       error = gpio_direction_input(button->gpio);

 

       if (button->debounce_interval) {

              error = gpio_set_debounce(button->gpio,

                                     button->debounce_interval * 1000);

              /* use timer if gpiolib doesn't provide debounce */

              if (error < 0)

                     bdata->timer_debounce = button->debounce_interval;

       }

 

       irq = gpio_to_irq(button->gpio);

 

       irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;

       /*

        * If platform has specified that the button can be disabled,

        * we don't want it to share the interrupt line.

        */

       if (!button->can_disable)

              irqflags |= IRQF_SHARED;

 

       error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);

}

gpio的初始化以及端口的申请工作到此就结束了,下面再对gpio的处理工作event的工作流程进行简单的梳理。。。 

你可能感兴趣的:(timer,struct,function,Module,input,button)