按键输入子系统驱动:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/errno.h> /* for -EBUSY */
#include <linux/ioport.h> /* for request_region */
#include <linux/delay.h> /* for loops_per_jiffy */
#include <asm/io.h> /* for inb_p, outb_p, inb, outb, etc. */
#include <asm/uaccess.h> /* for get_user, etc. */
#include <linux/wait.h> /* for wait_queue */
#include <linux/init.h> /* for __init, module_{init,exit} */
#include <linux/poll.h> /* for POLLIN, etc. */
#include <asm/mach/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/gpio.h>
#include <mach/regs-gpio.h>
#include <linux/input.h>
struct pin_desc {
int irq;
int pin;
int pin_state;
char *name;
int key_val;
int pin_val;
};
static struct pin_desc buttons_pin[] = {
{IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, "KEY1", BTN_0},
{IRQ_EINT11, S3C2410_GPG(3), S3C2410_GPG3_EINT11, "KEY3", BTN_1},
{IRQ_EINT13, S3C2410_GPG(5), S3C2410_GPG5_EINT13, "KEY2", BTN_2},
{IRQ_EINT14, S3C2410_GPG(6), S3C2410_GPG6_EINT14, "KEY4", BTN_3},
{IRQ_EINT15, S3C2410_GPG(7), S3C2410_GPG7_EINT15, "KEY5", BTN_4},
{IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, "KEY6", BTN_5},
};
static struct input_dev *buttons_input;
static irqreturn_t buttons_interrupt(int irq,void *dev_id)
{
struct pin_desc *pin_desc = (struct pin_desc *)dev_id;
int val;
val = s3c2410_gpio_getpin(pin_desc->pin);
input_event(buttons_input,EV_KEY,pin_desc->key_val, !val);
input_sync(buttons_input);
return IRQ_HANDLED;
}
static int __init buttons_init(void)
{
int error;
int i;
buttons_input = input_allocate_device();
if(!buttons_input)
return -ENOMEM;
#if 0
buttons_input->evbit[0] = BIT(EV_KEY);
buttons_input->keybit[BITS_TO_LONGS(KEY_L)] = BIT(KEY_L);
buttons_input->keybit[BITS_TO_LONGS(KEY_S)] = BIT(KEY_S);
buttons_input->keybit[BITS_TO_LONGS(KEY_ENTER)] = BIT(KEY_ENTER);
buttons_input->keybit[BITS_TO_LONGS(KEY_LEFTSHIFT)] = BIT(KEY_LEFTSHIFT);
#endif
set_bit(EV_KEY,buttons_input->evbit);
for(i = 0;i<sizeof(buttons_pin)/sizeof(buttons_pin[0]);i++)
{
set_bit(buttons_pin[i].key_val,buttons_input->keybit);
}
error = input_register_device(buttons_input);
if(error){
input_free_device(buttons_input);
return -1;
}
for(i = 0;i<sizeof(buttons_pin)/sizeof(buttons_pin[0]);i++)
{
s3c2410_gpio_cfgpin(buttons_pin[i].pin,buttons_pin[i].pin_state);
request_irq(buttons_pin[i].irq,buttons_interrupt, IRQF_SHARED | IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING,buttons_pin[i].name,(void *)&buttons_pin[i]);
}
return 0;
}
static void __exit buttons_exit(void)
{
int i;
for(i = 0; i< sizeof(buttons_pin)/sizeof(buttons_pin[0]); i++)
{
free_irq(buttons_pin[i].irq, (void *)&buttons_pin[i]);
}
input_unregister_device(buttons_input);
input_free_device(buttons_input);
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("RopenYuan");
按键输入子系统测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
int main(void)
{
int buttons_fd;
int key_value,i=0,count;
struct input_event ev_key;
buttons_fd = open("/dev/input/event0", O_RDWR);
if (buttons_fd < 0) {
perror("open device buttons");
exit(1);
}
for (;;) {
count = read(buttons_fd,&ev_key,sizeof(struct input_event));
for(i=0; i<(int)count/sizeof(struct input_event); i++)
if(EV_KEY==ev_key.type)
printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code,ev_key.value);
if(EV_SYN==ev_key.type)
printf("syn event\n\n");
}
close(buttons_fd);
return 0;
}
MAKEFILE
ifneq ($(KERNELRELEASE),)
obj-m := buttons.o
else
#KDIR := /home/yuanpengjun/home/linuxeditorkernelfilesystem/kernal/linux-2.6.32/linux-2.6.32.2/
KDIR := /home/yuanpengjun/mini2440/kernel/linux-2.6.32.2/
all:
# make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
make -C $(KDIR) M=$(PWD) modules
/home/yuanpengjun/mini2440/editor/4.4.3/bin/arm-none-linux-gnueabi-gcc -o button button_app.c
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul*
endif
以上驱动代码未加入容错处理,只是为了验证是否能成功运行。
在模块加载时出现input: Unspecified device as /devices/virtual/input/input0
原因为没有在驱动中设置struct input_dev 中的成员名name,若有成员名为 XXXX->name = "yyyyyyy",驱动模块加载后会出现如下情况:
input: yyyyyyy as /devices/virtual/input/input0
在模块卸载时出现rmmod: chdir(2.6.32.2): No such file or directory,并且不能将模块从系统中卸载掉;
原因为:现在的内核模块在插入卸载时都会要转到/lib/modules/内核版本号/ 这个目录里,格式为/lib/modules/2.6.32.2/ 在这种情况下,不会再出现模块不能卸载情况;