diff --git a/12_timer/.vscode/c_cpp_properties.json b/12_timer/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..c83cbcfaf81f0a413c36565d1f8d467ae23f6a0a --- /dev/null +++ b/12_timer/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "../../../linux-imx-rel_imx_4.1.15_2.1.0_ga/include/**", + "../../../linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/**", + "../../../linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/generated/**", + "../../../linux-imx-rel_imx_4.1.15_2.1.0_ga/drivers/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} + diff --git a/12_timer/.vscode/settings.json b/12_timer/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..1a2a04ac7a2d6b080404235adcd34b94bc581cb4 --- /dev/null +++ b/12_timer/.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/12_timer/12_timer.code-workspace b/12_timer/12_timer.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..c20f397cb3458db57801e41b1fccc1a99ac01bbf --- /dev/null +++ b/12_timer/12_timer.code-workspace @@ -0,0 +1,15 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "gpio.h": "c", + "*.tcc": "c", + "ioctl.h": "c" + } + + } +} \ No newline at end of file diff --git a/12_timer/Makefile b/12_timer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fe20c1685aacbde72314b89dd9fbb63334b1da5c --- /dev/null +++ b/12_timer/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 := timer.o + +build: kernel_modules + +kernel_modules: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules + +clean: + $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean + + diff --git a/12_timer/timer.c b/12_timer/timer.c new file mode 100644 index 0000000000000000000000000000000000000000..628d46d0ca0bc0832844a03a30165c5074153995 --- /dev/null +++ b/12_timer/timer.c @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define TIMER_CNT 1 +#define TIMER_NAME "timer" +#define LED_ON 1 +#define LED_OFF 0 +#define CLOSE_CMD (_IO(0XEF, 0X1)) +#define OPEN_CMD (_IO(0XEF, 0X2)) +#define SETPERIOD_CMD (_IO(0XEF, 0X3)) + +/* timer设备结构体 */ +struct timer_dev{ + dev_t devid; /* 设备号 */ + int major; /* 主设备号 */ + int minor; /* 次设备号 */ + struct cdev cdev; /* cdev */ + struct class *class; /* 类 */ + struct device *device; /* 设备 */ + struct device_node *nd; /* 设备节点 */ + int led_gpio; + int timeperiod; + struct timer_list timer; /* 定义一个定时器 */ + spinlock_t lock; /*定义自旋锁 */ +}; + +struct timer_dev timerdev; + + + +static int led_init(void) +{ + timerdev.nd = of_find_node_by_path("/gpioled"); + if(timerdev.nd == NULL) + return -EINVAL; + timerdev.led_gpio = of_get_named_gpio(timerdev.nd,"led-gpio",0); + if(!gpio_is_valid(timerdev.led_gpio)) + return -EINVAL; + + /* 初始化led所使用的IO */ + gpio_request(timerdev.led_gpio,"led"); + gpio_direction_output(timerdev.led_gpio, 1); + + return 0; +} + +static int timer_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + filp->private_data = &timerdev; + timerdev.timeperiod = 1000; + ret = led_init(); + if(ret < 0) return ret; + return 0; +} + + +void timer_function(unsigned long arg) +{ + struct timer_dev *dev = (struct timer_dev *)arg; + static int sta = 1; + sta = !sta; + gpio_set_value(dev->led_gpio, sta); + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod)); +} + + +static long timer_unlocked_ioclt(struct file *filp,unsigned int cmd,unsigned long arg) +{ + struct timer_dev *dev = (struct timer_dev *)filp->private_data; + unsigned int timerperiod = 0; + unsigned long flags; + unsigned int CMD = cmd; + switch (CMD) + { + case CLOSE_CMD: + del_timer_sync(&dev->timer); + break; + case OPEN_CMD: + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod)); + break; + case SETPERIOD_CMD: + spin_lock_irqsave(&dev->lock, flags); + dev->timeperiod = arg; + spin_unlock_irqrestore(&dev->lock,flags); + mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->timeperiod)); + break; + + default: + printk("CMD = %d\r\n", cmd); + break; + } +} + +static struct file_operations timer_fops = { + .owner = THIS_MODULE, + .open = timer_open, + .unlocked_ioctl = timer_unlocked_ioclt, +}; + +static __init timer_init(void) +{ + /* 初始化自旋锁 */ + spin_lock_init(&timerdev.lock); + /* 注册字符设备驱动 */ + /* 1、创建设备号 */ + if(timerdev.major){ /* 如果定义了设备号 */ + timerdev.devid = MKDEV(timerdev.major,0); + register_chrdev_region(timerdev.devid,TIMER_CNT,TIMER_NAME); + }else { /* 没有定义设备号 */ + alloc_chrdev_region(&timerdev.devid,0,TIMER_CNT,TIMER_NAME); + timerdev.major = MAJOR(timerdev.devid); /* 获取分配的主设备号 */ + timerdev.minor = MINOR(timerdev.devid); /* 获取分配的次设备号 */ + } + + /* 2、初始化cdev */ + timerdev.cdev.owner = THIS_MODULE; + cdev_init(&timerdev.cdev,&timer_fops); + + /* 3、添加一个cdev */ + cdev_add(&timerdev.cdev,timerdev.devid,TIMER_CNT); + /* 4、创建类 */ + timerdev.class = class_create(THIS_MODULE,TIMER_NAME); + if(IS_ERR(timerdev.class)){ + return PTR_ERR(timerdev.class); + } + + /* 5、创建设备 */ + timerdev.device = device_create(timerdev.class,NULL,timerdev.devid,NULL,TIMER_NAME); + if(IS_ERR(timerdev.device)){ + return PTR_ERR(timerdev.device); + } + + /* 6、初始化timer */ + init_timer(&timerdev.timer); + timerdev.timer.function = timer_function; + timerdev.timer.data = (unsigned long)&timerdev; + timerdev.timeperiod = 1000; + timerdev.timer.expires = jiffies + msecs_to_jiffies(500); + add_timer(&timerdev.timer); + return 0; +} + +static __exit timer_exit(void) +{ + gpio_free(timerdev.led_gpio); + del_timer_sync(&timerdev.timer); + // 注销字符设备驱动 + cdev_del(&timerdev.cdev); + unregister_chrdev_region(timerdev.devid,TIMER_CNT); + + device_destroy(timerdev.class,timerdev.devid); + class_destroy(timerdev.class); + +} + +module_init(timer_init); +module_exit(timer_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("zhangchaoliang"); diff --git a/12_timer/timerAppp.c b/12_timer/timerAppp.c new file mode 100644 index 0000000000000000000000000000000000000000..36382ff452aa853daf5d9f232bee3b80be4a462b --- /dev/null +++ b/12_timer/timerAppp.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" + +/* 定义命令 */ +#define CLOSE_CMD (_IO(0XEF, 0X1)) +#define OPEN_CMD (_IO(0XEF, 0X2)) +#define SETPERIOD_CMD (_IOW(0XEF, 0X3,int)) + + + +/* + +*/ +int main(int argc, char *argv[]){ + int fd, ret; + unsigned int cmd; + unsigned int arg; + char *filename; + unsigned char str[99]; + + 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",argv[1]); + return -1; + } + + while (1) + { + printf("input CMD: "); + ret = scanf("%d", &cmd); + if(ret != 1){ + gets(str); + } + + if(cmd == 1){ + cmd = CLOSE_CMD; + } + else if(cmd == 2){ + cmd = OPEN_CMD; + } + else if(cmd == 3){ + cmd = SETPERIOD_CMD; + printf("input timer period:"); + ret = scanf("%d", &arg); + if(ret!=1){ + gets(str); + } + } + ioctl(fd, cmd, arg); + } + + ret = close(fd); // close文件 + if(ret <0){ + printf("file %s close failed\r\n",argv[1]); + return -1; + } + + return 0; +}