ITPub博客

首页 > Linux操作系统 > Linux操作系统 > gpio键盘的原理

gpio键盘的原理

原创 Linux操作系统 作者:cifra_guokun 时间:2012-05-02 21:59:33 0 删除 编辑

gpio键盘

1,定义gpio键盘的设备数据结构platform_device

/****************************************************************************
 * GPIO Attached Keys
 */

static struct gpio_keys_button dns323_buttons[] = {
 {
  .code  = KEY_RESTART,
  .gpio  = DNS323_GPIO_KEY_RESET,
  .desc  = "Reset Button",
  .active_low = 1,
 }, {
  .code  = KEY_POWER,
  .gpio  = DNS323_GPIO_KEY_POWER,
  .desc  = "Power Button",
  .active_low = 1,
 },
};

static struct gpio_keys_platform_data dns323_button_data = {
 .buttons = dns323_buttons,
 .nbuttons = ARRAY_SIZE(dns323_buttons),
};

static struct platform_device dns323_button_device = {
 .name  = "gpio-keys",
 .id  = -1,
 .num_resources = 0,
 .dev  = {
  .platform_data = &dns323_button_data,
 },
};

 

2,定义gpio键盘的驱动数据结构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
 }
};

 

3,注册平台设备

 platform_device_register(&dns323_button_device);

platform_driver 和platform_device的.name = "gpio-keys",都是一样。device和driver的名字一样就回调用probe函数

gpio_keys_probe();

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 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();
 if (!ddata || !input) {
  error = -ENOMEM;
  goto fail1;
 }

 platform_set_drvdata(pdev, ddata);

 input->name = pdev->name;
 input->phys = "gpio-keys/input0";
 input->dev.parent = &pdev->dev;

 input->id.bustype = BUS_HOST;
 input->id.vendor = 0x0001;
 input->id.product = 0x0001;
 input->id.version = 0x0100;

 /* Enable auto repeat feature of Linux input subsystem */
 if (pdata->rep)
  __set_bit(EV_REP, input->evbit);

 ddata->input = input;

 for (i = 0; i < pdata->nbuttons; i++) {
  struct gpio_keys_button *button = &pdata->buttons[i];
  struct gpio_button_data *bdata = &ddata->data[i];
  int irq;
  unsigned int type = button->type ?: EV_KEY;

  bdata->input = input;
  bdata->button = button;
  setup_timer(&bdata->timer,
       gpio_keys_timer, (unsigned long)bdata);
  INIT_WORK(&bdata->work, gpio_keys_report_event);

  error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
  if (error < 0) {
   pr_err("gpio-keys: failed to request GPIO %d,"
    " error %d/n", button->gpio, error);
   goto fail2;
  }

  error = gpio_direction_input(button->gpio);
  if (error < 0) {
   pr_err("gpio-keys: failed to configure input"
    " direction for GPIO %d, error %d/n",
    button->gpio, error);
   gpio_free(button->gpio);
   goto fail2;
  }

  irq = gpio_to_irq(button->gpio);
  if (irq < 0) {
   error = irq;
   pr_err("gpio-keys: Unable to get irq number"
    " for GPIO %d, error %d/n",
    button->gpio, error);
   gpio_free(button->gpio);
   goto fail2;
  }

  error = request_irq(irq, gpio_keys_isr,
        IRQF_SHARED |
        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
        button->desc ? button->desc : "gpio_keys",
        bdata);
  if (error) {
   pr_err("gpio-keys: Unable to claim irq %d; error %d/n",
    irq, error);
   gpio_free(button->gpio);
   goto fail2;
  }

  if (button->wakeup)
   wakeup = 1;

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

 error = input_register_device(input);
 if (error) {
  pr_err("gpio-keys: Unable to register input device, "
   "error: %d/n", error);
  goto fail2;
 }

 device_init_wakeup(&pdev->dev, wakeup);

 return 0;

 fail2:
 while (--i >= 0) {
  free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
  if (pdata->buttons[i].debounce_interval)
   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;
}

static int __devexit gpio_keys_remove(struct platform_device *pdev)
{
 struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
 struct input_dev *input = ddata->input;
 int i;

 device_init_wakeup(&pdev->dev, 0);

 for (i = 0; i < pdata->nbuttons; i++) {
  int irq = gpio_to_irq(pdata->buttons[i].gpio);
  free_irq(irq, &ddata->data[i]);
  if (pdata->buttons[i].debounce_interval)
   del_timer_sync(&ddata->data[i].timer);
  cancel_work_sync(&ddata->data[i].work);
  gpio_free(pdata->buttons[i].gpio);
 }

 input_unregister_device(input);

 return 0;
0,初始化工作队列INIT_WORK(&bdata->work, gpio_keys_report_event);

1,主要是分配一个input设备 input_allocate_device();

2,按键中断请求

3,设置gpio为输入,gpio_direction_input(button->gpio);

 4, 获取gpio的中断号 irq = gpio_to_irq(button->gpio);

5,中断申请 error = request_irq(irq, gpio_keys_isr,
        IRQF_SHARED |
        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
        button->desc ? button->desc : "gpio_keys",
        bdata);

6, 初始化是否可以唤醒

 if (button->wakeup)
   wakeup = 1;
7,初始化按键的类型和按键码  input_set_capability(input, type, button->code);

8,注册input设备error = input_register_device(input);

9,初始化唤醒源 device_init_wakeup(&pdev->dev, wakeup);

 

4,注册成功后,当有按键按下时就调用中断回调函数

static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
 struct gpio_button_data *bdata = dev_id;
 struct gpio_keys_button *button = bdata->button;

 BUG_ON(irq != gpio_to_irq(button->gpio));

 if (button->debounce_interval)
  mod_timer(&bdata->timer,
   jiffies + msecs_to_jiffies(button->debounce_interval));
 else
  schedule_work(&bdata->work);

 return IRQ_HANDLED;
}

最终执行工作队列的线程函数gpio_keys_report_event

static void gpio_keys_report_event(struct work_struct *work)
{
 struct gpio_button_data *bdata =
  container_of(work, struct gpio_button_data, work);
 struct gpio_keys_button *button = bdata->button;
 struct input_dev *input = bdata->input;
 unsigned int type = button->type ?: EV_KEY;
 int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;

 input_event(input, type, button->code, !!state);
 input_sync(input);
}

根据gpio

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13771794/viewspace-722585/,如需转载,请注明出处,否则将追究法律责任。

下一篇: gpio键盘的原理1
请登录后发表评论 登录
全部评论

注册时间:2008-04-07

  • 博文量
    92
  • 访问量
    304521