您的位置:首页 > 其它

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

2012-09-21 22:09 465 查看
这里我们使用到了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函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐