drv_timer.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
#include <mach/regs-gcr.h>
#include <mach/irqs.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h> // copy_from_user
#define TIMER_CNT 1 /* 设备号个数 */
#define TIMER_NAME "timer" /* 名字 */
#define CLOSE_CMD (_IO(0xEF,0x1)) /* 关闭定时器 */
#define OPEN_CMD (_IO(0xEF,0x2)) /* 打开定时器 */
#define SETPERIOD_CMD (_IO(0xEF,0x3)) /* 设置定时器周期命令 */
#define LEDON 1 /* 开灯*/
#define LEDOFF 0 /* 关灯*/
/* timer 设备结构体 */
struct timer_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
//struct device_node *nd; /* 设备节点*/
//int led_gpio; /* led 使用的gpio编号*/
int timeperiod; /* 定时周期,单位为ms*/
struct timer_list timer; /* 定义一个定时器*/
};
struct timer_dev timerdev; /* timer 设备 */
static int nuc977_timer_open(struct inode *ino, struct file *file)
{
file->private_data = &timerdev; /* 设置私有数据 */
timerdev.timeperiod=1000; /*1000 ms*/
return 0;
}
static long nuc977_timer_unlock_ioctl( struct file *files, unsigned int cmd, unsigned long arg)
{
printk("cmd is %d,arg is %d \n",cmd,(unsigned int)(arg));
struct timer_dev *dev= (struct timer_dev *)files->private_data;
int timerperiod;
//unsigned long flags;
switch(cmd)
{
case CLOSE_CMD: /* 关闭定时器*/
{
printk(KERN_INFO "CLOSE_CMD \n");
del_timer_sync(&dev->timer);
break;
}
case OPEN_CMD: /* 打开定时器*/
{
printk(KERN_INFO "OPEN_CMD \n");
//gpio_set_value(NUC970_PB0, 1);
timerperiod=dev->timeperiod;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(timerperiod));
break;
}
case SETPERIOD_CMD: /* 设定定时器周期 */
dev->timeperiod=arg;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(arg));
break;
}
return 0;
}
/*定时器回调函数 */
void timer_function(unsigned long arg)
{
struct timer_dev *dev = (struct timer_dev *)arg;
static int sta=1;
//int timerperiod;
//unsigned long flags;
sta=!sta; /*取反 led反转*/
gpio_set_value(NUC970_PB0, sta);
/* 重启定时器*/
//timerperiod=dev->timeperiod;
mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));
}
/* 设备操作函数 */
static struct file_operations timer_fops = {
.owner = THIS_MODULE,
.open = nuc977_timer_open,
.unlocked_ioctl = nuc977_timer_unlock_ioctl,
};
static int __init nuc977_timer_init(void)
{
u32 ret;
ret = gpio_request(NUC970_PB0,"NUC970_PB0");
if(ret < 0){
printk(KERN_EMERG "gpio_request NUC970_PB0 failed!\n");
return ret;
}
gpio_direction_output(NUC970_PB0,1);
/* 注册字符设备驱动 */
/* 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); /* 获取次设备号 */
}
printk("timerdev major=%d,minor=%d\r\n",timerdev.major,timerdev.minor);
/* 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;
printk(KERN_INFO "nuc977_timer_init module initialized\n");
return 0;
}
static void __exit nuc977_timer_exit(void)
{
del_timer_sync(&timerdev.timer);/* 删除定时器*/
/* 注销字符设备 */
cdev_del(&timerdev.cdev);/* 删除 cdev */
unregister_chrdev_region(timerdev.devid, TIMER_CNT);
device_destroy(timerdev.class, timerdev.devid);
class_destroy(timerdev.class);
printk(KERN_INFO "nuc977_timer_exit module exited\n");
}
module_init(nuc977_timer_init);
module_exit(nuc977_timer_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HBIN");
app_timer.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "string.h"
#include "linux/ioctl.h"
#define CLOSE_CMD (_IO(0xEF,0x1)) /* 关闭定时器 */
#define OPEN_CMD (_IO(0xEF,0x2)) /* 打开定时器 */
#define SETPERIOD_CMD (_IO(0xEF,0x3)) /* 设置定时器周期命令 */
int main(int argc, char *argv[])
{
int fd ,ret,i;
char *filename;
unsigned int cmd;
//unsigned int period;
unsigned int arg=1000;
unsigned char databuf[1];
//unsigned int buf[1];
if (argc < 3){
printf("Error Usage!");
return -1;
}
for(i=0;i<argc;i++)
printf(" argv[%d]= %s \n",i,argv[i]);
filename=argv[1];
fd = open(filename, O_RDWR); // 打开设备
if (fd < 0) {
printf("Can't open %s \n",argv[1]);
return -1;
}
databuf[0] = atoi(argv[2]); /* 要执行的操作:cmd */
if (argc == 3)
{
if (databuf[0]==1)
{
printf("1: databuf[0] %d \n",databuf[0]);
cmd = CLOSE_CMD;
ioctl(fd,cmd,arg);
}
else if (databuf[0]==2)
{
printf("2: databuf[0] %d \n",databuf[0]);
cmd = OPEN_CMD;
ioctl(fd,cmd,arg);
}
}
else if (argc == 4)
{
cmd = SETPERIOD_CMD;
//databuf[0] = atoi(argv[3]);//*100
//arg=databuf[0]*100;
arg= atoi(argv[3]);
ioctl(fd,cmd,arg);
}
close(fd);
return 0;
}
argv[i]= 3000
/mnt/app # ./app_timer2 /dev/timer 3 10
argv[i]= ./cmd is 61187,arg is 10
app_timer2
argv[i]= /dev/timer
argv[i]= 3
argv[i]= 10
/mnt/app # ./app_timer2 /dev/timer 3 100
argv[i]= ./cmd is 61187,arg is 100
app_timer2
argv[i]= /dev/timer
argv[i]= 3
argv[i]= 100
/mnt/app # ./app_timer2 /dev/timer 3 50
argv[i]= ./cmd is 61187,arg is 50
app_timer2
argv[i]= /dev/timer
argv[i]= 3
argv[i]= 50
/mnt/app # ./app_timer2 /dev/timer 3 300
argv[i]= ./cmd is 61187,arg is 300
app_timer2
argv[i]= /dev/timer
argv[i]= 3
argv[i]= 300
/mnt/app # ./app_timer2 /dev/timer 3 1000
argv[i]= ./cmd is 61187,arg is 1000
测试led闪烁成功。