-
客戶端 app
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <poll.h>
struct key_event{
int code ; // 按鍵的鍵值, 比如KEY_DOWN, KEY_POWER
int value; // 按鍵的狀態(tài),按下為1, 抬起為0
};
int main(int argc, char *argv[])
{
int fd;
int ret;
char kbbuf[128];
struct key_event event;
fd = open("/dev/key1", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
struct pollfd pfd[2];
pfd[0].fd = 0; //監(jiān)控標(biāo)準(zhǔn)輸入
pfd[0].events = POLLIN;
pfd[1].fd = fd; //監(jiān)控按鍵 //1.監(jiān)控對(duì)象
pfd[1].events = POLLIN; //2.監(jiān)控模式
while(1)
{
ret = poll(pfd, 2, -1);
if(ret > 0)
{
if(pfd[0].revents & POLLIN) //3.返回值(返回POLLIN時(shí)為真)
{
fgets(kbbuf, 128, stdin);
printf("kbbuf = %s\n", kbbuf);
}
if(pfd[1].revents & POLLIN) //3.返回值(返回POLLIN時(shí)為真)
{
ret = read(fd, &event, sizeof(struct key_event));
if(ret < 0)
{
perror("read");
exit(1);
}
if(event.code == KEY_POWER)
{
if(event.value)
{
printf("__APP__ key power pressed\n");
}else
{
printf("__APP__ key power up\n");
}
}
if(event.code == KEY_ENTER)
{
if(event.value)
{
printf("__APP__ key enter pressed\n");
}else
{
printf("__APP__ key enter up\n");
}
}
}
}
}
close(fd);
return 0;
}
-
程序
要的:
思想:

沒(méi)數(shù)據(jù)在VFS層等待,有數(shù)據(jù)返回POLLIN
口訣:有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;
unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
printk("-------^_^ %s-----------\n", __FUNCTION__);
unsigned int mask = 0;
// 將當(dāng)前的等待隊(duì)列注冊(cè)到vfs中
poll_wait(filp, &key_dev->wq_head, pts);
//如果有數(shù)據(jù)的時(shí)候,返回一個(gè)POLLIN
if(key_dev->have_data)
mask |= POLLIN;
return mask; //有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;
}
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/io.h>
// 設(shè)計(jì)一個(gè)表示按鍵數(shù)據(jù)的對(duì)象
struct key_event{
int code ; // 按鍵的鍵值, 比如KEY_DOWN, KEY_POWER
int value; // 按鍵的狀態(tài),按下為1, 抬起為0
};
// 面向?qū)ο?--將任何都看成對(duì)象, struct 就是對(duì)象
//設(shè)計(jì)一個(gè)對(duì)象類(lèi)型,描述當(dāng)前的設(shè)備信息,同時(shí)是一個(gè)全局的設(shè)備對(duì)象
struct s5pv210_key{
int dev_major; //用老的注冊(cè)設(shè)備號(hào)的方式
struct class *cls;
struct device *dev;
int irqno; //表示設(shè)備的中斷號(hào)碼
int testdata;
struct key_event event;//存放按鍵的數(shù)據(jù)
wait_queue_head_t wq_head;
int have_data; //表示標(biāo)志位,表示是否有數(shù)據(jù)
};
//設(shè)計(jì)一個(gè)對(duì)象,描述是按鍵的信息
/*
1, 中斷號(hào)
2, gpio號(hào)碼
3, 名字
4, 按鍵的類(lèi)型
*/
struct key_info{
char *name;
int irqno;
int gpionum;
int code;
int flags; //觸發(fā)方式
};
//設(shè)置所有按鍵的信息
struct key_info allkeys[] = {
[0] = {
.name = "key1_eint0", // 中斷名字
.irqno = IRQ_EINT(0), // 中斷號(hào)
.gpionum = S5PV210_GPH0(0), //gpio腳
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, //上下沿觸發(fā)(觸發(fā)方式)
.code = KEY_UP, //當(dāng)前的按鍵(上下左右)
},
[1] = {
.name = "key2_eint1",
.irqno = IRQ_EINT(1),
.gpionum = S5PV210_GPH0(1),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_DOWN,
},
[2] = {
.name = "key3_eint2",
.irqno = IRQ_EINT(2),
.gpionum = S5PV210_GPH0(2),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_LEFT,
},
[3] = {
.name = "key4_eint3",
.irqno = IRQ_EINT(3),
.gpionum = S5PV210_GPH0(3),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_RIGHT,
},
[4] = {
.name = "key5_eint4",
.irqno = IRQ_EINT(4),
.gpionum = S5PV210_GPH0(4),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_ENTER,
},
[5] = {
.name = "key6_eint5",
.irqno = IRQ_EINT(5),
.gpionum = S5PV210_GPH0(5),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_ESC,
},
[6] = {
.name = "key7_eint22",
.irqno = IRQ_EINT16_31,
.gpionum = S5PV210_GPH2(6),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_HOME,
},
[7] = {
.name = "key8_eint23",
.irqno = IRQ_EINT16_31,
.gpionum = S5PV210_GPH2(7),
.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
.code = KEY_POWER,
},
};
//設(shè)置對(duì)象
struct s5pv210_key *key_dev;
int key_drv_open(struct inode *inode, struct file *filp)
{
//一般也是做初始化動(dòng)作
printk("-------^_^ %s-----------\n", __FUNCTION__);
memset(&key_dev->event,0, sizeof(struct key_event));
key_dev->have_data = 0;
return 0;
}
// write(fd, buf, size);
ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
return 0;
}
int key_drv_close(struct inode *inode, struct file *filp)
{
printk("-------^_^ %s-----------\n", __FUNCTION__);
return 0;
}
long key_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
return 0;
}
ssize_t key_drv_read (struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
//printk("-------^_^ %s-----------\n", __FUNCTION__);
int ret;
//區(qū)分阻塞還是非阻塞
if((filp->f_flags & O_NONBLOCK ) && !key_dev->have_data)
return -EAGAIN;
// 沒(méi)有數(shù)據(jù)就休眠--have_data如果0表示沒(méi)有數(shù)據(jù),就需要等
wait_event_interruptible(key_dev->wq_head, key_dev->have_data);
ret = copy_to_user(buf, &key_dev->event, count);
if(ret > 0)
{
printk("copy_to_user error\n");
return -EFAULT;
}
// 清空后,接著去收其他的數(shù)據(jù)
memset(&key_dev->event,0, sizeof(struct key_event));
key_dev->have_data = 0; // 重新設(shè)置成沒(méi)有數(shù)據(jù)
return count;
}
unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
printk("-------^_^ %s-----------\n", __FUNCTION__);
unsigned int mask = 0;
// 將當(dāng)前的等待隊(duì)列注冊(cè)到vfs中
poll_wait(filp, &key_dev->wq_head, pts);
//如果有數(shù)據(jù)的時(shí)候,返回一個(gè)POLLIN
if(key_dev->have_data)
mask |= POLLIN;
return mask; //有數(shù)據(jù)是返回POLLIN,沒(méi)數(shù)據(jù)返回0;
}
const struct file_operations key_fops = {
.open = key_drv_open,
.write = key_drv_write,
.read = key_drv_read,
.release = key_drv_close,
.unlocked_ioctl = key_drv_ioctl,
.poll = key_drv_poll,
};
irqreturn_t key_irq_handler(int irqno, void *dev_id)
{
printk("-------^_^ %s-----------\n", __FUNCTION__);
//區(qū)分不同的中斷
struct key_info *p = (struct key_info *)dev_id;
//區(qū)分是按下還是抬起
int value;
value = gpio_get_value(p->gpionum);
if(value){
//抬起
printk("%s up \n", p->name);
key_dev->event.code = p->code;
key_dev->event.value = 0;
}else{
//按下
printk("%s pressed \n", p->name);
key_dev->event.code = p->code;
key_dev->event.value = 1;
}
wake_up_interruptible(&key_dev->wq_head);//會(huì)喚醒
key_dev->have_data = 1; //表示有數(shù)據(jù)
return IRQ_HANDLED;
}
static int __init key_drv_init(void)
{
int ret;
//申請(qǐng)資源
// 實(shí)例化該對(duì)象
// GFP_KERNEL如果當(dāng)前沒(méi)有內(nèi)存可分配,該函數(shù)會(huì)一直等
key_dev = kzalloc(sizeof(struct s5pv210_key), GFP_KERNEL);
if(key_dev == NULL)
{
printk(KERN_ERR "kzalloc error\n");
return -ENOMEM;
}
// 1, 申請(qǐng)?jiān)O(shè)備號(hào)
key_dev->dev_major = register_chrdev(0, "s5pv210_key_drv", &key_fops);
if(key_dev->dev_major < 0)
{
printk(KERN_ERR "kzalloc error\n");
ret = -ENODEV;
goto err_0;
}
// 2, 自動(dòng)創(chuàng)建文件
// /sys/class/key_cls 文件夾
key_dev->cls = class_create(THIS_MODULE, "key_cls");
if(IS_ERR(key_dev->cls))
{
printk(KERN_ERR "class_create error\n");
ret = PTR_ERR(key_dev->cls);
goto err_1;
}
// /sys/class/key_cls/key/
// /dev/key1
key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,1),NULL, "key1");
if(IS_ERR(key_dev->dev))
{
printk(KERN_ERR "device_create error\n");
ret = PTR_ERR(key_dev->dev);
goto err_2;
}
// 4, 硬件的初始化---中斷
//
//key_dev->irqno = IRQ_EINT(1);
int i;
int irqno;
int flags;
char *name;
for(i=0; i<ARRAY_SIZE(allkeys); i++)
{
irqno = allkeys[i].irqno;
if(irqno == IRQ_EINT16_31)
irqno = gpio_to_irq(allkeys[i].gpionum);
flags = allkeys[i].flags;
name = allkeys[i].name;
// 1. 中斷號(hào) 中斷處理函數(shù) 觸發(fā)方式 中斷名字 傳遞給處理函數(shù)的值
ret = request_irq(irqno, key_irq_handler, flags,name, &allkeys[i]); //中斷申請(qǐng)
if(ret != 0)
{
printk(KERN_ERR "request_irq error : i=%d\n", i);
ret = -EBUSY;
goto err_4;
}
}
//初始化等待隊(duì)列頭
init_waitqueue_head(&key_dev->wq_head);
return 0;
err_4:
i--;
for(; i>0; i--)
{
irqno = gpio_to_irq(allkeys[i].gpionum);
free_irq(irqno, &allkeys[i]);
}
err_3:
device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
err_2:
class_destroy(key_dev->cls);
err_1:
unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
err_0:
kfree(key_dev);
return ret;
}
static void __exit key_drv_exit(void)
{
//釋放資源
int i;
int irqno;
for(i=0; i<ARRAY_SIZE(allkeys); i++)
{
irqno = gpio_to_irq(allkeys[i].gpionum);
free_irq(irqno, &allkeys[i]);
}
device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,1));
class_destroy(key_dev->cls);
unregister_chrdev(key_dev->dev_major, "s5pv210_key_drv");
kfree(key_dev);
}
module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");