利用混杂设备实现按键驱动
1.TQ2440按键资源
k1 -- GPF1 -- EINT1
k2 -- GPF4 -- EINT4
k3 -- GPF2 -- EINT2
k4 -- GPF0 -- EINT0
2.内核介绍
本驱动基于linux-2.6.32.67内核
3.混杂设备介绍
linux中特殊的一类字符设备,他们共享一个主设备号(10),但是次设备号不同,其设备文件自动创建。结构如下:
-
struct miscdevice {
-
int minor;
-
const char *name;
-
const struct file_operations *fops;
-
struct list_head list;
-
struct device *parent;
-
struct device *this_device;
-
const char *nodename;
-
mode_t mode;
-
};
4.按键驱动程序(基于混杂设备实现)
misc_button.c
-
#include "linux/module.h"
-
#include "linux/types.h"
-
#include "linux/fs.h"
-
#include "linux/platform_device.h"
-
#include "mach/regs-gpio.h"
-
#include "mach/irqs.h"
-
#include "mach/gpio-fns.h"
-
#include "linux/interrupt.h"
-
#include "linux/device.h"
-
#include "linux/io.h"
-
#include "linux/miscdevice.h"
-
#include "linux/clk.h"
-
#include "linux/uaccess.h"
-
#include "linux/sched.h"
-
#include "linux/poll.h"
-
#include "linux/unistd.h"
-
#include "linux/irq.h"
-
-
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
-
static volatile int ev_press=0;
-
static volatile char key_value[]={'0','0','0','0'};
-
-
struct button_irq_desc{
-
int irq;
-
int pin;
-
int pin_setting;
-
int number;
-
char *name;
-
};
-
-
static struct button_irq_desc button_irqs[]={
-
{IRQ_EINT1,S3C2410_GPF(1),S3C2410_GPF1_EINT1,0,"key1"},
-
{IRQ_EINT4,S3C2410_GPF(4),S3C2410_GPF4_EINT4,1,"key2"},
-
{IRQ_EINT2,S3C2410_GPF(2),S3C2410_GPF2_EINT2,2,"key3"},
-
{IRQ_EINT0,S3C2410_GPF(0),S3C2410_GPF0_EINT0,3,"key4"},
-
};
-
-
//isr
-
static irqreturn_t buttons_isr(int irq,void *dev_id){
-
int down;
-
struct button_irq_desc *pirqs=(struct button_irq_desc*)dev_id;
-
-
down=!s3c2410_gpio_getpin(pirqs->pin);
-
-
if(down!=(key_value[pirqs->number]&1)){
-
key_value[pirqs->number]='0'+down;
-
ev_press=1;
-
wake_up_interruptible(&button_waitq);
-
}
-
return IRQ_RETVAL(IRQ_HANDLED);
-
}
-
-
//misc opt
-
static int s3c2440_buttons_open(struct inode *inode,struct file *file){
-
int i;
-
int err=0;
-
-
for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++){
-
if(button_irqs[i].irq<0){
-
continue;
-
}
-
-
err=request_irq(button_irqs[i].irq,buttons_isr,IRQ_TYPE_EDGE_BOTH,button_irqs[i].name,(void*)&button_irqs[i]);
-
if(err)
-
break;
-
}
-
-
if(err){
-
i--;
-
for(;i>=0;i--){
-
if(button_irqs[i].irq<0)
-
continue;
-
disable_irq(button_irqs[i].irq);
-
free_irq(button_irqs[i].irq,(void*)&button_irqs[i]);
-
}
-
return -EBUSY;
-
}
-
-
ev_press=0;
-
return 0;
-
}
-
static int s3c2440_buttons_close(struct inode *inode,struct file *file){
-
int i;
-
for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++){
-
if(button_irqs[i].irq<0)
-
continue;
-
free_irq(button_irqs[i].irq,(void*)&button_irqs);
-
}
-
return 0;
-
}
-
static int s3c2440_buttons_read(struct file *filp,char __user *buff,size_t count,loff_t *offp){
-
unsigned long err;
-
if(!ev_press){
-
if(filp->f_flags&O_NONBLOCK)
-
return -EAGAIN;
-
else
-
wait_event_interruptible(button_waitq,ev_press);
-
}
-
ev_press=0;
-
err=copy_to_user(buff,&key_value,sizeof(key_value));
-
return sizeof(key_value);
-
}
-
//misc ops
-
static struct file_operations s3c2440_buttons_fops={
-
.owner=THIS_MODULE,
-
.open=s3c2440_buttons_open,
-
.release=s3c2440_buttons_close,
-
.read=s3c2440_buttons_read,
-
};
-
-
//misc
-
static struct miscdevice s3c2440_miscdev={
-
.minor=MISC_DYNAMIC_MINOR,
-
.name="buttons-test",
-
.fops=&s3c2440_buttons_fops,
-
};
-
-
static int dev_init(void){
-
int ret;
-
ret=misc_register(&s3c2440_miscdev);
-
printk("misc dev init.\n");
-
return ret;
-
}
-
-
static void dev_exit(void){
-
misc_deregister(&s3c2440_miscdev);
-
}
-
-
module_init(dev_init);
-
module_exit(dev_exit);
-
-
MODULE_LICENSE("GPL");
5.测试程序
根据驱动的实现方法,实现测试程序如下:
button_test.c
-
#include "stdio.h"
-
#include "string.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"
-
-
-
int main(void){
-
int buttons_fd;
-
char key_value[4];
-
char first=1;
-
int i;
-
-
buttons_fd=open("/dev/buttons-test",0);
-
if(buttons_fd<0){
-
perror("open device buttons.\n");
-
exit(1);
-
}
-
-
for(;;){
-
char key_value_temp[4];
-
int ret;
-
ret=read(buttons_fd,key_value_temp,sizeof(key_value_temp));
-
if(ret!=sizeof(key_value_temp)){
-
perror("read button.");
-
exit(1);
-
}
-
for(i=0;i<sizeof(key_value);i++){
-
if(key_value[i]!=key_value_temp[i]){
-
key_value[i]=key_value_temp[i];
-
printf("k%d is %s%s",i+1,key_value[i]=='0'?"up":"down",first?",":"");
-
}
-
}
-
first=0;
-
if(first==0){
-
printf("\n");
-
}
-
-
}
-
close(buttons_fd);
-
return 0;
-
}
6.编译,下载
分别编译内核模块和测试程序,分别生成misc_button.ko和button_test,通过nfs方式下载到TQ2440开发板中。运行结果如下:
阅读(1726) | 评论(0) | 转发(0) |