linux驱动之内核定时器

driver

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/compat.h>
#include <linux/chio.h>			/* here are all the ioctls */
#include <linux/mutex.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/timer.h>

#include "cmd.h"

//本驱动基于pinctrl与gpio子系统,自旋锁,以及内核定时器
//设置内核时钟为100HZ(每秒进内核中断100次)

static int major;
static struct class *led_class;
static struct device *led_device;

//在全局下定义自旋锁,(使用自旋锁的目的是为了保护一些重要变量)
spinlock_t lock;
//定时器停止时间
static int timeperiod;

//定义一个内核定时器变量
struct timer_list timer;


int led_open (struct inode *inode, struct file *file)//不允有两个同时打开
{
	printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
	return 0;
}
int led_release (struct inode *inode, struct file *file)
{
	printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
	del_timer_sync(&timer);
	return 0;
}
long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
	unsigned long flags;
	printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
	if(_IOC_TYPE(cmd)!='k'){
		printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
		return -EINVAL;
	}
	if(arg<0)
	{
		printk(KERN_ERR	"ioctrl arg error!\n");
		return -1;
	}
	switch(arg){
		case 1:
			mod_timer(&timer, jiffies+msecs_to_jiffies(timeperiod));
			break;
		case 0:
			del_timer_sync(&timer);//这个函数可能会阻塞,不能放在中断中否则引起panic
			break;
		default ://表示reset
			timeperiod = arg;
			spin_lock_irqsave(&lock, flags);
			mod_timer(&timer, jiffies+msecs_to_jiffies(timeperiod));
			spin_unlock_irqrestore(&lock, flags);
			break;
		}
	return 0;
}

static struct file_operations led_ops = {
	.open = led_open,
	.unlocked_ioctl = led_ioctl,
	.release = led_release,
	.owner = THIS_MODULE,
};



void timer_function(struct timer_list *t);//内核4.14之后
void Timer_init(void)
{
	//初始化定时器变量
	timer_setup(&timer,timer_function,0);//4.14内核之后
    //设置定时器初始时间
	timeperiod = 1000;//单位ms
	//mod_timer与add_timer都可以激活定时器,对应del_timer
}

static int __init timer_init(void)
{
	int ret;
	printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
		
	//注册file_operators与设备节点
	major = register_chrdev(0, "Atom_Led", &led_ops);
	if(major<0){
		printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
		return -EINVAL;
	}
	led_class = class_create(THIS_MODULE,"Led_class");
	if (IS_ERR(led_class)) {//IS_ERR判断Led_class是否为有效的地址(除NULL外,指向最后一页的地址的指针也是错误指针)
		printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
		return -PTR_ERR(led_class);
	}
	led_device = device_create(led_class, NULL, MKDEV(major,0), NULL,"Atom_Led");
	if (IS_ERR(led_device)) {//IS_ERR判断Led_class是否为有效的地址(除NULL外,指向最后一页的地址的指针也是错误指针)
		printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
		return -PTR_ERR(led_device);
	}
	
	//初始化定时器
	Timer_init();
	
	return ret;
}

//每隔一段时间printk一次
void timer_function(struct timer_list *t)
{
	printk("timer_function runing!\n");
	//按照一定时间重启定时器
	mod_timer(&timer, jiffies+msecs_to_jiffies(timeperiod));//msecs_to_jiffies将ms换成节拍
}

static void __exit timer_exit(void)
{
	printk("%s %s %d\n", __FILE__,__FUNCTION__,__LINE__);
	del_timer_sync(&timer);//注销定时器
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);
	unregister_chrdev(major, "Atom_Led");
}

module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");

test

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "linux/ioctl.h"
#include <stdlib.h>
#include <sys/ioctl.h>

#include "cmd.h"

int main(int argc, char **argv)
{
	int cnt;
	int fd;
	unsigned int arg;
	int ret;
	
	if(argc!=2||argc!=3)
	{
		printf("input error\n");
		return -1;
	}
	fd = open("/dev/Atom_Led", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file\n");
		return -1;
	}

	if(strcmp(argv[1],"ON")==0)
	{
		arg = 1;
		ioctl(fd,MY_CTRL,arg);
	}
	else if(strcmp(argv[1],"OFF")==0)
	{
		arg = 0;
		ioctl(fd,MY_CTRL,arg);
	}
		else if(strcmp(argv[1],"RESET")==0)
			{
				arg = atoi(argv[2]);
				ioctl(fd,MY_CTRL,arg);
			}
	
	while(cnt < 5){
		sleep(5);
		cnt++;
		printf("APP is Runing\r\n");
	}

	ret = close(fd);
	if(ret<0){
		printf("close error!\r\n");
		return -1;
	}
	
	return 0;
}

cmd.h

#ifndef __CMD_H
#define __CMD_H

#define DEV_FIFO_TYPE 'k'//幻数

#define MY_CTRL _IOW(DEV_FIFO_TYPE,2,int)//2表示写,0表示就控制,1表示读,int 表示写入的数据类型

#endif

程序讲解

1.功能
    1.	./test ON(开始执行定时器,默认给了1s定时。)
        在中断函数中
            1.打印信息
            2.继续填入下一次的延时时间
    2.	./test OFF(关闭定时器)
    3.	./test RESET Xs设置下一次将会在x/1000s之后进入中断
2.版本差别:
	4.14之前:
		1.init_timer(&timer)
		timer.function = GetIntrTimerCallback;
		2.void GetIntrTimerCallback(unsigned long devAddr)//中断调用
	4.14之后:
		1.timer_setup(&timer, GetIntrTimerCallback, 0);
		void timer_function(struct timer_list *t)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值