vi btn_drv.c
#include < linux/init.h >
#include < linux/module.h >
#include < linux/fs.h >
#include < linux/cdev.h >
#include < linux/device.h >
#include < linux/irq.h >
#include < linux/interrupt.h >
#include < asm/gpio.h >
#include < plat/gpio-cfg.h >
#include < linux/access.h >
//定义按键硬件数据结构
struct button_resource
{
int gpio; //GPIO编号
int irq; //中断号
char *name ; //标签
}
//初始化按键对应的硬件信息
static struct button_resource btn_info[]=
{
[0]={
.gpio = S5PV210_GPH(0),
.irq = IRQ_EINT(0),
.name = "KEY_UP"
}
};
static int major;
static struct cdev btn_cdev;
static struct class *cls;
static wait_queue_head_t btn_wq; //分配等待队列头
static unsigned char key_val; //分配上报按键的值
static int ispress; // = 1,按键有操作,=0,表明按键无操作
static ssize_t btn_read(struct file *file, char
__user*buf,
size_t count, loff_t *ppos)
{
//1.判断按键操作是否有效,通过ispress来判断,如果有操作,则ispress =
1,这个函数立即返回,如果
//ispress = 0,没有操作,进程将进入休眠状态,等待唤醒,一旦被唤醒,就可以读取按键值给用户
printk("go to sleeping\n");
printk("process %d(%) to sleeping\n",
current->pid,current->comm);
wait_event_interruptible(&btn_wq, ispress);
ispress = 0;
//一旦被唤醒,上报按键的值
prink("I am wake up\n");
copy_to_user(buf, &key_val, 1);
return count;
}
static struct file_operations btn_fops =
{
.owner = THIS_MODULE,
.read = btn_read
}
static irqreturn_t button_isr(int irq, void*dev_id)
{
//1.获取每一个键对应的硬件信息
struct button_resource *pdata =
(structbutton_resource*)dev_id;
//2.获取按键对应的状态,设置上报的按键值
pinstate = gpio_get_value(pdata->gpio);
if(pinstate == 1)//松开按键,上报0x50
key_val = 0x50;
else if(pinstate == 0) //按下
key_val = 0x51;
//3.唤醒休眠的进程
ispress = 1;
wake_up_interruptible(&btn_wq); //唤醒休眠的进程
}
static int btn_init(void)
{
dev_t dev;
int i;
//0.判断是否采用非阻塞
if(file->flags & O_NONBLOCK)
{
//非阻塞方式
if(!ispress)
//判断是否有数据到来,如果没有,立即返回
{
printk("No data\n");
return -EAGAIN;
}
}
//阻塞方式
//1.申请设备号
alloc_chrdev_region(&dev, 0, 1, "buttons");
major = MAJOR(dev);
//2.初始化注册cdev
cdev_init(&btn_cdev, &btn_fops);
cdev_add(&btn_cdev, dev, 1);
//3.自动创建设备节点
cls = class_create(THIS_MODULE, "buttons");
device_create(cls, NULL ,dev, NULL, "mybuttons");
//4.申请GPIO资源和注册中断
for(i = 0; i < ARRAY_SIZE(btn_info); i++)
{
gpio_request(btn_info[i].gpio, btn_info.name);
request_irq(btn_info[i].irq,
button_isr,
IRQF_TRIGGER_RISING_IRQF_FAILING,
btn_info[i].name, &btn_info[i]);
}
//5.初始化等待队列头
init_waitqueue_head(&btn_wq);
return 0;
}
static void btn_exit(void)
{
dev_t dev = MKDEV(major , 0);
int i;
//释放GPIO资源和释放中断
for(i = 0; i
{
gpio_free(btn_info[i].gpio);
free_irq(btn_info[i].irq, &btn_info[i]);
}
//2.删除设备节点
device_destroy(cls, dev);
class_destroy(cls);
//3.卸载cdev
cdev_del(&btn_cdev);
//4.释放设备号
unregister_chrdev_region(dev, 1);
}
module_init(btn_init);
module_exit(btn_exit);
MODULE_LICENSE("GPL");
vi btn_test.c
#include < sys/types.h >
#include < sys/state.h >
#include < fcntl.h >
int main(void)
{
int fd;
unsigned char key_val;
fd = fopen("/dev/mybuttons", O_RDWR | O_NONBLOCK);
if(fd < 0)
{
printf(“open button failed.\n”);
return -1;
}
while(1)
{
read(fd, &key_val, 1);
printf("key_val = %#x\n",key_val);
}
close(fd);
return 0;
}