这里我们使用到了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函数