IMX6ULL开发板Linux C语言 timer学习笔记
#define TIMER_CNT 1 /*设备号个数*/
#define TIMER_NAME "timer" /*名字*/
/*3.1:设备结构体*/
struct timerdev_dev{
dev_t devid; /*设备号*/
int major; /*主设备号*/
int minor;
struct cdev cdev;/*3.3.1结构体里先定义字符设备*/
struct class *class; /*4.1:类*/
struct device *device; /*4.1:设备*/
struct device_node *nd; /*5.1设备节点*/
struct timer_list timer; /*定时器*/
int led_gpio;
};
struct timerdev_dev timerdev; /*3.2:led设备*/
static int timer_open(struct inode *inode, struct file *filp)
{
filp->private_data = &timerdev;
return 0;
}
static ssize_t timer_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static ssize_t timer_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
int ret;
return 0;
}
static int timer_release(struct inode *inode, struct file *filp)
{
return 0;
}
static const struct file_operations timerdev_fops = { /*3.4.1:定义字符设备操作集*/
.owner = THIS_MODULE,
.write = timer_write,
.open = timer_open,
.release = timer_release,
};
/*定时器处理函数*/
static void timer_func(unsigned long arg)
{
struct timer_dev *dev = (struct timer_dev*)arg;
static int sta = 1;
sta = !sta;
gpio_set_value(timerdev.led_gpio, sta);
mod_timer(&timerdev.timer, jiffies + msecs_to_jiffies(500));
}
/*初始化LED灯*/
int led_init(struct timer_dev *dev)
{
int ret = 0;
timerdev.nd = of_find_node_by_path("/gpioled");
if(timerdev.nd == NULL){
ret = -EINVAL;
goto fail_fd;
}
timerdev.led_gpio = of_get_named_gpio(timerdev.nd, "led-gpios", 0);
if(timerdev.led_gpio < 0){
ret = -EINVAL;
goto fail_gpio;
}
ret = gpio_request(timerdev.led_gpio, "led");
if(ret) {
ret = -EBUSY;
printk("IO %d can't request!\r\n", timerdev.led_gpio);
goto fail_request;
}
ret = gpio_direction_output(timerdev.led_gpio, 1);/*默认电平高关灯*/
if(ret < 0) {
ret = -EINVAL;
goto fail_gpioset;
}
return 0;
fail_gpioset:
gpio_free(timerdev.led_gpio);
fail_request:
fail_gpio:
fail_fd:
return ret;
}
/*2.入口函数*/
static int __init timer_init(void)
{
int ret = 0;
/*初始化信号量*/
/*3:注册字符设备*/
/*3.0:注册字符设备号*/
timerdev.major = 0;/*3.2:表示设备号由内核分配*/
if(timerdev.major){ /*如果分配了设备号*/
timerdev.devid = MKDEV(timerdev.major, 0);/*那么主设备号和次设备号进行拼凑*/
ret = register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME);
}else { /*如果没有分配了设备号,那么要申请一个设备号*/
ret = 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);
if (ret < 0){
goto fail_devid;
}
/*3.3:添加字符设备*/
timerdev.cdev.owner = THIS_MODULE;
cdev_init(&timerdev.cdev, &timerdev_fops); /*3.4初始化cdev()里第二个参数就是字符设备的操作集见3.4.1*/
ret = cdev_add(&timerdev.cdev, timerdev.devid, TIMER_CNT);
if (ret < 0){
goto fail_cdevadd;
}
/*4:自动创建设备节点*/
timerdev.class = class_create(THIS_MODULE, TIMER_NAME);
if(IS_ERR(timerdev.class)){
ret = PTR_ERR(timerdev.class);
goto fail_class;
}
timerdev.device = device_create(timerdev.class, NULL, timerdev.devid, NULL, TIMER_NAME);
if(IS_ERR(timerdev.device)){
ret = PTR_ERR(timerdev.device);
goto fail_device;
}
/*初始化led灯*/
ret = led_init(&timerdev.timer);
if(ret <0){
goto fail_ledinit;
}
/*初始化定时器*/
init_timer(&timerdev.timer);
timerdev.timer.function = timer_func;
timerdev.timer.expires = jiffies + msecs_to_jiffies(500); /*定时500毫秒*/
timerdev.timer.data = (unsigned long)&timerdev;
add_timer(&timerdev.timer);/*添加到系统*/
return 0;
fail_ledinit:
fail_device:
class_destroy(timerdev.class);
fail_class:
cdev_del(&timerdev.cdev);
fail_cdevadd:
unregister_chrdev_region(timerdev.devid, TIMER_CNT);
fail_devid:
return ret;
}
static void __exit timer_exit(void)
{
gpio_set_value(timerdev.led_gpio, 1);
del_timer(&timerdev.timer);
/*3.5删除字符设备*/
cdev_del(&timerdev.cdev);
/*3.5.1释放设备号*/
unregister_chrdev_region(timerdev.devid, TIMER_CNT);
device_destroy(timerdev.class, timerdev.devid);
/*摧毁类*/
class_destroy(timerdev.class);
gpio_free(timerdev.led_gpio);
}
/*1.注册驱动和卸载驱动*/
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZXL");