1.应用程序需要完成如下三个步骤:
(1)signal(SIGIO, sig_handler);
调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。
(2)fcntl(fd, F_SET_OWNER, getpid());
指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。
(3)f_flags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, f_flags | FASYNC);
在设备文件中添加FASYNC标志,驱动中就会调用将要实现的test_fasync函数。
三个步骤执行后,一旦有信号产生,相应的进程就会收到。
2.驱动需要完成下面四个步骤:
(1)定义结构体fasync_struct。
struct fasync_struct *async_queue;
(2)实现test_fasync,把函数fasync_helper将fd,filp和定义的结构体传给内核。
int test_fasync (int fd, struct file *filp, int mode)
{
struct _test_t *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
(3)当设备可写时,调用函数kill_fasync发送信号SIGIO给内核。
if (dev->async_queue){
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
3.驱动代码
#include <linux/types.h>
#include #include #include #include #include #include #include #include #include #include #include #include #include #include struct key_desc{ unsigned int pin; unsigned char value; }; static dev_t devno; static struct cdev cdev; static struct class* buttons_class; static struct device* buttons_device; static wait_queue_head_t button_waitq; static struct timer_list buttons_timer; static volatile int pressed = 0; static unsigned int key_val; static struct fasync_struct *button_async; static struct key_desc *irq_pd; static volatile unsigned long *gph3con; static volatile unsigned long *gph3dat; static struct key_desc key_descs[8] = { [0] = { .pin = S5PV210_GPH2(3), .value = 0x00, }, [1] = { .pin = S5PV210_GPH2(4), .value = 0x01, }, [2] = { .pin = S5PV210_GPH2(5), .value = 0x02, }, [3] = { .pin = S5PV210_GPH2(6), .value = 0x03, }, [4] = { .pin = S5PV210_GPH2(7), .value = 0x04, }, }; static void buttons_timer_function(unsigned long data) { struct key_desc * pindesc = irq_pd; unsigned int pinval; if (!pindesc) return; pinval = gpio_get_value(pindesc->pin); if (pinval) { /* 松开 */ key_val = 0x80 | pindesc->value; } else { /* 按下 */ key_val = pindesc->value; } pressed = 1; wake_up_interruptible(&button_waitq); kill_fasync (&button_async, SIGIO, POLL_IN); } static irqreturn_t buttons_irq(int irq, void *dev_id){ printk('buttons_irq happenn'); /* 10ms后启动定时器 */ irq_pd = (struct key_desc *)dev_id; mod_timer(&buttons_timer, jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); } static int buttons_open(struct inode *inode, struct file *file){ int ret; ret = request_irq(IRQ_EINT(19), buttons_irq, IRQ_TYPE_EDGE_BOTH, 'key1', &key_descs[0]); if(ret) return ret; ret = request_irq(IRQ_EINT(20), buttons_irq, IRQ_TYPE_EDGE_BOTH, 'key2', &key_descs[1]); if(ret) return ret; ret = request_irq(IRQ_EINT(21), buttons_irq, IRQ_TYPE_EDGE_BOTH, 'key3', &key_descs[2]); if(ret) return ret; ret = request_irq(IRQ_EINT(22), buttons_irq, IRQ_TYPE_EDGE_BOTH, 'key4', &key_descs[3]); if(ret) return ret; ret = request_irq(IRQ_EINT(23), buttons_irq, IRQ_TYPE_EDGE_BOTH, 'key5', &key_descs[4]); if(ret) return ret; return 0; } static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){ if (count != 1) return -EINVAL; if (file->f_flags & O_NONBLOCK) { if (!pressed) return -EAGAIN; } wait_event_interruptible(button_waitq, pressed); pressed = 0; if(copy_to_user(data, &key_val, 1)){ printk(KERN_ERR 'The driver can not copy the data to user area!n'); return -ENOMEM; } return 0; } static int buttons_close(struct inode *inode, struct file *file){ free_irq(IRQ_EINT(19), &key_descs[0]); free_irq(IRQ_EINT(20), &key_descs[1]); free_irq(IRQ_EINT(21), &key_descs[2]); free_irq(IRQ_EINT(22), &key_descs[3]); free_irq(IRQ_EINT(23), &key_descs[4]); return 0; } static int buttons_fasync (int fd, struct file *filp, int on) { printk('driver: buttons_fasyncn'); return fasync_helper (fd, filp, on, &button_async); } struct file_operations buttons_ops = { .open = buttons_open, .read = buttons_read, .release = buttons_close, .fasync = buttons_fasync, }; int buttons_init(void){ int ret; init_timer(&buttons_timer); buttons_timer.function = buttons_timer_function; //buttons_timer.expires = 0; add_timer(&buttons_timer); cdev_init(&cdev, &buttons_ops); cdev.owner = THIS_MODULE; ret = alloc_chrdev_region(&devno, 0, 1, 'buttons'); if(ret){ printk(KERN_ERR 'alloc char device region faild!n'); return ret; } ret = cdev_add(&cdev, devno, 1); if(ret){ printk(KERN_ERR 'add char device faild!n'); goto add_error; } buttons_class = class_create(THIS_MODULE, 'buttonsdrv'); if(IS_ERR(buttons_class)){ printk(KERN_ERR 'create class error!n'); goto class_error; } buttons_device = device_create(buttons_class, NULL, devno, NULL, 'buttons'); if(IS_ERR(buttons_device)){ printk(KERN_ERR 'create buttons device error!n'); goto device_error; } init_waitqueue_head(&button_waitq); gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16); gph3dat = gph3con + 1; *gph3con &= (~0x000000ff); *gph3con |=0x11; *gph3dat &= ~0x03; printk('buttons initn'); return 0; device_error: class_destroy(buttons_class); class_error: cdev_del(&cdev); add_error: unregister_chrdev_region(devno,1); return -ENODEV; } void buttons_exit(void){ printk('buttons exitn'); device_destroy(buttons_class, devno); class_destroy(buttons_class); cdev_del(&cdev); unregister_chrdev_region(devno, 1); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE('GPL'); 4.用户空间代码: #include #include #include #include #include #include #include int fd; void sig_handler(int signum) { unsigned char key_val; read(fd, &key_val, 1); printf('key_val: 0x%xn', key_val); } int main(int argc, char **argv) { unsigned char key_val; int ret; int Oflags; signal(SIGIO, sig_handler); fd = open('/dev/buttons', O_RDWR | O_NONBLOCK); if (fd < 0){ printf('can't open!n'); return -1; } fcntl(fd, F_SETOWN, getpid()); Oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, Oflags | FASYNC); while(1); return 0; } 5.测试结果: [210_Liujia]#insmod buttons.ko [210_Liujia]#./buttons_test key_val: 0x1 key_val: 0x81 key_val: 0x0 key_val: 0x80 key_val: 0x2 key_val: 0x82 key_val: 0x3 key_val: 0x83 key_val: 0x4 key_val: 0x84 key_val: 0x1 key_val: 0x81 key_val: 0x2 key_val: 0x82 key_val: 0x4 key_val: 0x84 key_val: 0x3 key_val: 0x83
上一篇:【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
下一篇:代码示例_中断
- 热门资源推荐
- 热门放大器推荐
- 使用 ON Semiconductor 的 FAN2518S 的参考设计
- LTC1530S8、3.3V/3A 稳压器
- 使用 ON Semiconductor 的 ADP3167 的参考设计
- 使用 Analog Devices 的 LT3420EDD 的参考设计
- 基于Kinetis® M的低成本单相电表参考设计
- LTC3708、具有上升/下降轨跟踪功能的 2.5V/15A 和 1.2V/15A 稳压器
- NXQ1TXH5插件板
- 应变仪仪表放大器
- WRL-13287,基于 ESP8266 802.11 无线局域网的 SparkFun Wi-Fi Shield
- 4.1W、3-LED 通用 LED 照明驱动器

非常经典的关于LLC的杨波博士论文
OP413EY

XC6406PP60DL






京公网安备 11010802033920号