分享

使用input输入子系统实现对tiny6410LED灯的控制

 卓奇虫虫 2014-03-20

这里我们使用到了struct input_dev 中的一个重要成员即event接口:

该结构体定义在input.h中:

struct input_event {
 struct timeval time;//时间戳
 __u16 type;//驱动类型
 __u16 code; //事件码
 __s32 value;//事件值
};

 

led_input.c :

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/uaccess.h>
#include <mach/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/uaccess.h>
#include <plat/regs-timer.h>
#include <mach/gpio-bank-f.h>
#include <mach/gpio-bank-a.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-k.h>

static char s3c6410_LED_name[] = "s3c6410LED";
static char s3c6410_LED_phys[] = "s3c6410LED";
static struct input_dev* s3c6410_led_dev;

void led_on()
{
     unsigned tmp;
     tmp = readl(S3C64XX_GPKDAT);
  tmp &= ~(1 << (4 + 1));
  tmp |= ( (!1) << (4 + 1) );
  writel(tmp, S3C64XX_GPKDAT);
}

void led_off()
{
        unsigned tmp;
     tmp = readl(S3C64XX_GPKDAT);
  tmp &= ~(1 << (4 + 1));
  tmp |= ( (!0) << (4 + 1) );
  writel(tmp, S3C64XX_GPKDAT);
}


static int s3c6410_BEEP_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
 printk("s3c6410_BEEP_event\n");
 if (type != EV_LED)return -1;

 switch(value)
 {
  case 0:
   led_off();
   break;
  case 1:
   led_on();
   break;
 }
 return 0;
}

static int __init s3c6410_BEEP_init(void)
{
      unsigned tmp;
  tmp = readl(S3C64XX_GPKCON);
  tmp = (tmp & ~(0xffffU<<16))|(0x1111U<<16);
  writel(tmp, S3C64XX_GPKCON);
  
  tmp = readl(S3C64XX_GPKDAT);
  tmp |= (0xf << 4);
  writel(tmp, S3C64XX_GPKDAT);
  
 s3c6410_led_dev=input_allocate_device();
 s3c6410_led_dev->evbit[0] = BIT(EV_LED);
 s3c6410_led_dev->ledbit[0] = BIT(LED_NUML);
 s3c6410_led_dev->event = s3c6410_BEEP_event;//这是关键的一句话,在这里设置,让内核进行回调

 s3c6410_led_dev->name = s3c6410_LED_name;
 s3c6410_led_dev->phys = s3c6410_LED_phys;
 s3c6410_led_dev->id.bustype = BUS_HOST;
 s3c6410_led_dev->id.vendor = 0x001f;
 s3c6410_led_dev->id.product = 0x0001;
 s3c6410_led_dev->id.version = 0x0100;

 input_register_device(s3c6410_led_dev);
 printk(KERN_INFO "input: %s\n", s3c6410_LED_name);
 return 0;
}

static void __exit s3c6410_BEEP_exit(void)
{
    input_unregister_device(s3c6410_led_dev);
}

module_init(s3c6410_BEEP_init);
module_exit(s3c6410_BEEP_exit);
MODULE_AUTHOR("sujian");
MODULE_DESCRIPTION("s3c6410 led driver");
MODULE_LICENSE("GPL");

 

测试程序:

#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<linux/rtc.h>
#include<linux/ioctl.h>
#include<stdio.h>
#include<stdlib.h>
#include<linux/input.h>

void main()
{
 int fd = -1;
 char name[256]= "Unknown";
 int yalv;
 
 if ((fd = open("/dev/input/event1", O_WRONLY)) < 0) {
  perror("evdev open");
  exit(1);
 }
 
 if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
  perror("evdev ioctl");
 }
 
 size_t rb;
 struct input_event ev[2];
 ev[0].type=EV_LED;
 ev[0].code=LED_NUML;
 ev[0].value=0;
 
 ev[1].type=EV_LED;
 ev[1].code=LED_NUML;
 ev[1].value=1;
 while(1)
 {
  rb=write(fd,ev,sizeof(struct input_event));
  
  if (rb < (int) sizeof(struct input_event))
  {
   perror("evtest: short write");
   exit (1);
  }
  sleep(1);
  
  rb=write(fd,&ev[1],sizeof(struct input_event));
  if (rb < (int) sizeof(struct input_event))
  {
   perror("evtest: short write");
   exit (1);
  }
  sleep(1);
 }
 
 close(fd);
}

 

对于应用层的write调用,内核中会调用evdev.c中的evdev_write函数:

static ssize_t evdev_write(struct file *file, const char __user *buffer,
      size_t count, loff_t *ppos)
{
 struct evdev_client *client = file->private_data;
 struct evdev *evdev = client->evdev;
 struct input_event event;
 int retval;

 retval = mutex_lock_interruptible(&evdev->mutex);
 if (retval)
  return retval;

 if (!evdev->exist) {
  retval = -ENODEV;
  goto out;
 }

 while (retval < count) {

  if (input_event_from_user(buffer + retval, &event)) {//获取应用层事件
   retval = -EFAULT;
   goto out;
  }

  input_inject_event(&evdev->handle,
       event.type, event.code, event.value);

  retval += input_event_size();
 }

 out:
 mutex_unlock(&evdev->mutex);
 return retval;
}

 

input_inject_event调用了input.c中   input_handle_event(dev, type, code, value);

void input_inject_event(struct input_handle *handle,
   unsigned int type, unsigned int code, int value)
{
 struct input_dev *dev = handle->dev;
 struct input_handle *grab;
 unsigned long flags;

 if (is_event_supported(type, dev->evbit, EV_MAX)) {
  spin_lock_irqsave(&dev->event_lock, flags);

  rcu_read_lock();
  grab = rcu_dereference(dev->grab);
  if (!grab || grab == handle)
   input_handle_event(dev, type, code, value);
  rcu_read_unlock();

  spin_unlock_irqrestore(&dev->event_lock, flags);
 }
}

 

static void input_handle_event(struct input_dev *dev,
          unsigned int type, unsigned int code, int value)
{
 int disposition = INPUT_IGNORE_EVENT;

 switch (type) {

 case EV_SYN:
  switch (code) {
  case SYN_CONFIG:
   disposition = INPUT_PASS_TO_ALL;
   break;

  case SYN_REPORT:
   if (!dev->sync) {
    dev->sync = true;
    disposition = INPUT_PASS_TO_HANDLERS;
   }
   break;
  case SYN_MT_REPORT:
   dev->sync = false;
   disposition = INPUT_PASS_TO_HANDLERS;
   break;
  }
  break;

 case EV_KEY:
  if (is_event_supported(code, dev->keybit, KEY_MAX) &&
      !!test_bit(code, dev->key) != value) {

   if (value != 2) {
    __change_bit(code, dev->key);
    if (value)
     input_start_autorepeat(dev, code);
    else
     input_stop_autorepeat(dev);
   }

   disposition = INPUT_PASS_TO_HANDLERS;
  }
  break;

 case EV_SW:
  if (is_event_supported(code, dev->swbit, SW_MAX) &&
      !!test_bit(code, dev->sw) != value) {

   __change_bit(code, dev->sw);
   disposition = INPUT_PASS_TO_HANDLERS;
  }
  break;

 case EV_ABS:
  if (is_event_supported(code, dev->absbit, ABS_MAX))
   disposition = input_handle_abs_event(dev, code, &value);

  break;

 case EV_REL:
  if (is_event_supported(code, dev->relbit, REL_MAX) && value)
   disposition = INPUT_PASS_TO_HANDLERS;

  break;

 case EV_MSC:
  if (is_event_supported(code, dev->mscbit, MSC_MAX))
   disposition = INPUT_PASS_TO_ALL;

  break;

 case EV_LED:
  if (is_event_supported(code, dev->ledbit, LED_MAX) &&
      !!test_bit(code, dev->led) != value) {

   __change_bit(code, dev->led);
   disposition = INPUT_PASS_TO_ALL;
  }
  break;

 case EV_SND:
  if (is_event_supported(code, dev->sndbit, SND_MAX)) {

   if (!!test_bit(code, dev->snd) != !!value)
    __change_bit(code, dev->snd);
   disposition = INPUT_PASS_TO_ALL;
  }
  break;

 case EV_REP:
  if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
   dev->rep[code] = value;
   disposition = INPUT_PASS_TO_ALL;
  }
  break;

 case EV_FF:
  if (value >= 0)
   disposition = INPUT_PASS_TO_ALL;
  break;

 case EV_PWR:
  disposition = INPUT_PASS_TO_ALL;
  break;
 }

 if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
  dev->sync = false;

 if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  dev->event(dev, type, code, value);//调用对应的input _handler的event接口

 if (disposition & INPUT_PASS_TO_HANDLERS)
  input_pass_event(dev, type, code, value);
}

这样就意味着内核会自动调用s3c6410_BEEP_event函数

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多