diff --git a/16_asyncnoti/.vscode/c_cpp_properties.json b/16_asyncnoti/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..fb6d96e4153ea9fb41617ba89d9ec21d3d3811d9 --- /dev/null +++ b/16_asyncnoti/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "/home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/include", + "/home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include", + "/home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/generated", + "/home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/asm", + "/home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga/drivers", + "${workspaceFolder}/**", + "${default}" + ], + "defines": ["__KERNEL__"], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} + diff --git a/16_asyncnoti/.vscode/settings.json b/16_asyncnoti/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..1a2a04ac7a2d6b080404235adcd34b94bc581cb4 --- /dev/null +++ b/16_asyncnoti/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/*.o":true, + "**/*.su":true, + "**/*.cmd":true, + "Documentation":true, + }, + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/*.o":true, + "**/*.su":true, + "**/*.cmd":true, + "Documentation":true, + } +} \ No newline at end of file diff --git a/16_asyncnoti/Makefile b/16_asyncnoti/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..350e25eca8b27e0fcf063454fddedd007afe290c --- /dev/null +++ b/16_asyncnoti/Makefile @@ -0,0 +1,13 @@ +KERNELDIR := /home/youxiu/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga +CURRENT_PATH := $(shell pwd) +obj-m := asyncnoti.o + +build: kernel_modules + +kernel_modules: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules + +clean: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean + + diff --git a/16_asyncnoti/asyncnoti.c b/16_asyncnoti/asyncnoti.c new file mode 100644 index 0000000000000000000000000000000000000000..07195a4f06dc0cb8d866a4d39f6d1d946d434a6b --- /dev/null +++ b/16_asyncnoti/asyncnoti.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define IMX6UIRQ_CNT 1 /* 设备号个数 */ +#define IMX6UIRQ_NAME "asyncnoti" /* 名字 */ +#define KEY0VALUE 0X01 /* key0的按键值 */ +#define INVAKEY 0XFF /* 无效的按键值 */ +#define KEY_NUM 1 /* 按键数量 */ + + +/* 中断io描述结构体 */ +struct irq_keydesc{ + int gpio; + int irqnum; /* 中断号 */ + unsigned char value; /* 按键对应的键值 */ + char name[10]; /* 名字 */ + irqreturn_t (*handler)(int, void *); /* 中断服务函数*/ +}; + +/* imx6uirq设备结构体 */ +struct imx6uirq_dev +{ + dev_t devid; + struct cdev cdev; + struct class *class; + struct device *device; + int major; + int minor; + struct device_node *nd; + atomic_t keyvalue; /* 有效的按键值 */ + atomic_t releasekey; /* 标记是否完成一次完整的按键 */ + struct timer_list timer; /* 定义一个定时器 */ + struct irq_keydesc irqkeydesc; /* 按键描述数组 */ + unsigned char curkeynum; /* 当前的按键号 */ + struct fasync_struct *async_queue; +}; + +struct imx6uirq_dev imx6uirq; /* irq设备 */ + + +static irqreturn_t key0_handler(int irq,void *dev_id) +{ + struct imx6uirq_dev *dev = (struct imx6uirq_dev *)dev_id; + + + dev->curkeynum = 0; + + dev->timer.data = (volatile long)dev_id; + + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10)); + + return IRQ_RETVAL(IRQ_HANDLED); +} + +void timer_function(unsigned long arg) +{ + struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg; + unsigned char keyvalue; + + keyvalue = gpio_get_value(dev->irqkeydesc.gpio); + if (keyvalue == 0) /* 按键被按下 */ + { + atomic_set(&dev->keyvalue, dev->irqkeydesc.value); + } + else{ + atomic_set(&dev->keyvalue, 0x80 | dev->irqkeydesc.value); + atomic_set(&dev->releasekey, 1);/* 松开标记 */ + } + + if (atomic_read(&dev->releasekey)) + { + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); + + } +} + +static int keyio_init(void) +{ + int ret = 0; + imx6uirq.nd = of_find_node_by_path("/key"); + if(!imx6uirq.nd){ + printk("key node not find!\r\n"); + return -EINVAL; + } + + /* 提取GPIO */ + imx6uirq.irqkeydesc.gpio = of_get_named_gpio(imx6uirq.nd, "key-gpio", 0); + if(!gpio_is_valid(imx6uirq.irqkeydesc.gpio)){ + printk("can't get key0 !\r\n"); + return -EINVAL; + } + + memset(imx6uirq.irqkeydesc.name, 0, sizeof(imx6uirq.irqkeydesc.name)); + sprintf(imx6uirq.irqkeydesc.name, "key0"); + gpio_request(imx6uirq.irqkeydesc.gpio,imx6uirq.irqkeydesc.name); + gpio_direction_input(imx6uirq.irqkeydesc.gpio); + + /* 获取中断号 */ + imx6uirq.irqkeydesc.irqnum = irq_of_parse_and_map(imx6uirq.nd, 0); + printk("key0:gpio = %d,irqnum = %d \r\n", imx6uirq.irqkeydesc.gpio, imx6uirq.irqkeydesc.irqnum); + + /* 申请中断 */ + imx6uirq.irqkeydesc.handler = key0_handler; + imx6uirq.irqkeydesc.value = KEY0VALUE; + + /* 请求irq */ + ret = request_irq(imx6uirq.irqkeydesc.irqnum,imx6uirq.irqkeydesc.handler,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + imx6uirq.irqkeydesc.name,&imx6uirq); + if(ret < 0){ + printk("irq %d request failed! \r\n", imx6uirq.irqkeydesc.irqnum); + return -EFAULT; + } + + /* 初始化定时器 */ + init_timer(&imx6uirq.timer); + imx6uirq.timer.function = timer_function; + + return 0; +} + +static int imx6uirq_open(struct inode *inode, struct file *filp) +{ + filp->private_data = &imx6uirq; + + return 0; +} + +static int imx6uirq_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt) +{ + int ret = 0; + unsigned int keyvalue = 0; + unsigned int releasekey = 0; + struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data; + keyvalue = atomic_read(&dev->keyvalue); + releasekey = atomic_read(&dev->releasekey); + if (releasekey) /* 如果按键已经松开 */ + { + if (keyvalue & 0x80) /* 判断按键是否松开,其实到这里,实际已经松开了,但是为了安全,又判断了一次 */ + { + /* 按键已经松开 */ + keyvalue &= ~0x80; /* 清除按下标志 最高位清零*/ + ret = copy_to_user(buf, &keyvalue, sizeof(keyvalue));/* 发送按键值 0x01 */ + }else { + return -EINVAL; + } + atomic_set(&dev->releasekey, 0); /* 清零标志,表示被按下的按键已经被读取 */ + return 0; + }else{ + return -EINVAL; + } + +} + +static int imx6uirq_fasync(int fd, struct file *file, int on) +{ + struct imx6uirq_dev *dev = (struct imx6uirq_dev *)file->private_data; + return fasync_helper(fd, file, on, &dev->async_queue); +} + +static int imx6uirq_release(struct inode *unused, struct file *file) +{ + return imx6uirq_fasync(-1,file,0); +} + + + + +static struct file_operations imx6uirq_fops = { + .owner = THIS_MODULE, + .open = imx6uirq_open, + .read = imx6uirq_read, + .release = imx6uirq_release, + .fasync = imx6uirq_fasync, +}; + + +static __init imx6uirq_init(void) +{ + /* 注册字符设备驱动 */ + /* 1、创建设备号 */ + if(imx6uirq.major){ /* 如果定义了设备号 */ + imx6uirq.devid = MKDEV(imx6uirq.major,0); + register_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT,IMX6UIRQ_NAME); + }else { /* 没有定义设备号 */ + alloc_chrdev_region(&imx6uirq.devid,0,IMX6UIRQ_CNT,IMX6UIRQ_NAME); + imx6uirq.major = MAJOR(imx6uirq.devid); /* 获取分配的主设备号 */ + imx6uirq.minor = MINOR(imx6uirq.devid); /* 获取分配的次设备号 */ + } + + /* 2、初始化cdev */ + imx6uirq.cdev.owner = THIS_MODULE; + cdev_init(&imx6uirq.cdev,&imx6uirq_fops); + + /* 3、添加一个cdev */ + cdev_add(&imx6uirq.cdev,imx6uirq.devid,IMX6UIRQ_CNT); + /* 4、创建类 */ + imx6uirq.class = class_create(THIS_MODULE,IMX6UIRQ_NAME); + if(IS_ERR(imx6uirq.class)){ + return PTR_ERR(imx6uirq.class); + } + + /* 5、创建设备 */ + imx6uirq.device = device_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6UIRQ_NAME); + if(IS_ERR(imx6uirq.device)){ + return PTR_ERR(imx6uirq.device); + } + + atomic_set(&imx6uirq.keyvalue,INVAKEY); + atomic_set(&imx6uirq.releasekey,0); + keyio_init(); + + + return 0; +} + +static __exit imx6uirq_exit(void) +{ + del_timer_sync(&imx6uirq.timer); + free_irq(imx6uirq.irqkeydesc.irqnum, &imx6uirq); + gpio_free(imx6uirq.irqkeydesc.gpio ); + + // 注销字符设备驱动 + cdev_del(&imx6uirq.cdev); + unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT); + + device_destroy(imx6uirq.class,imx6uirq.devid); + class_destroy(imx6uirq.class); + +} + +module_init(imx6uirq_init); +module_exit(imx6uirq_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("zhangchaoliang"); \ No newline at end of file diff --git a/16_asyncnoti/asyncnoti.code-workspace b/16_asyncnoti/asyncnoti.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..a563c858bedf0385cd9bbd6d0395651af865f705 --- /dev/null +++ b/16_asyncnoti/asyncnoti.code-workspace @@ -0,0 +1,41 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "gpio.h": "c", + "*.tcc": "c", + "ioctl.h": "c", + "fstream": "c", + "types.h": "c", + "kernel.h": "c", + "ide.h": "c", + "uaccess.h": "c", + "atomic.h": "c", + "interrupt.h": "c", + "hardirq.h": "c", + "irq.h": "c", + "delay.h": "c", + "init.h": "c", + "module.h": "c", + "cdev.h": "c", + "of_address.h": "c", + "of_gpio.h": "c", + "errno.h": "c", + "device.h": "c", + "of.h": "c", + "of_irq.h": "c", + "timer.h": "c", + "stdlib.h": "c", + "stdio.h": "c", + "driver.h": "c", + "select.h": "c", + "fcntl.h": "c", + "signal.h": "c" + } + + } +} \ No newline at end of file diff --git a/16_asyncnoti/asyncnotiApp.c b/16_asyncnoti/asyncnotiApp.c new file mode 100644 index 0000000000000000000000000000000000000000..4618392ea8818cdf90977a6cdf6c2738de34958e --- /dev/null +++ b/16_asyncnoti/asyncnotiApp.c @@ -0,0 +1,71 @@ +#include "stdio.h" +#include "unistd.h" +#include "sys/types.h" +#include "sys/stat.h" +#include "fcntl.h" +#include "stdlib.h" +#include "string.h" +#include "sys/ioctl.h" +#include "sys/time.h" +#include "poll.h" +#include "sys/select.h" +#include "signal.h" + +static int fd = 0; + +static void sigio_signal_func(int num) +{ + int err; + unsigned int keyvalue = 0; + err = read(fd, &keyvalue, sizeof(keyvalue)); + + if (err<0) + { + printf("err!!! err!!! \r\n"); + } + else + { + printf("sigio signal! key value = %d \r\n", keyvalue); + fflush(stdout); + } +} + +int main(int argc, char *argv[]){ + + int ret; + char flags; + char *filename; + + + if (argc != 2) { + printf("Error Usage!\r\n"); + return -1; + } + + filename = argv[1]; + fd = open(filename, O_RDWR); + if(fd < 0) { + printf("file %s open failed\r\n",filename); + return -1; + } + + signal(SIGIO, sigio_signal_func); + + fcntl(fd, F_SETOWN, getpid()); + flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | FASYNC); + + + + while (1){ + sleep(2); + } + + ret = close(fd); // close文件 + if(ret <0){ + printf("file %s close failed \r\n",argv[1]); + return -1; + } + + return 0; +}