当前位置:   article > 正文

linux驱动-定时器_linux驱动关闭定时器

linux驱动关闭定时器

今天开始学习下linux的定时器。

设备树还是沿用gpio的设备树。定义下led的结构体,这里追加了timeperiod和timer_list。

  1. #define TIMER_CNT 1
  2. #define TIMER_NAME "timer"
  3. #define CLOSE_CMD (_IO(0XEF, 0x1)) /* 关闭定时器 */
  4. #define OPEN_CMD (_IO(0XEF, 0x2)) /* 打开定时器 */
  5. #define SETPERIOD_CMD (_IO(0XEF, 0x3)) /* 设置定时器周期命令 */
  6. /* leddev设备结构体 */
  7. struct leddev_dev{
  8. dev_t devid; /* 设备号 */
  9. struct cdev cdev; /* cdev */
  10. struct class *class; /* 类 */
  11. struct device *device; /* 设备 */
  12. int major; /* 主设备号 */
  13. int minor;
  14. struct device_node *node; /* LED设备节点 */
  15. int led0; /* LED灯GPIO标号 */
  16. int timeperiod;
  17. struct timer_list timer;
  18. spinlock_t lock;
  19. };
  20. struct leddev_dev leddev; /* led设备 */

定义出口和入口函数

  1. /*
  2. * @description : 驱动模块加载函数
  3. * @param : 无
  4. * @return : 无
  5. */
  6. static int __init leddriver_init(void)
  7. {
  8. printk(" driver initial \r\n");
  9. return platform_driver_register(&led_driver);
  10. }
  11. /*
  12. * @description : 驱动模块卸载函数
  13. * @param : 无
  14. * @return : 无
  15. */
  16. static void __exit leddriver_exit(void)
  17. {
  18. printk(" driver exit \r\n");
  19. platform_driver_unregister(&led_driver);
  20. }
  21. module_init(leddriver_init);
  22. module_exit(leddriver_exit);
  23. MODULE_LICENSE("GPL");
  24. MODULE_AUTHOR("jinqijun");

接下来platform的probe的函数。这里追加了3个函数。

    init_timer(&leddev.timer);
    leddev.timer.function = timer_function;    //回调函数
    leddev.timer.data = (unsigned long)&leddev;

  1. static int led_probe(struct platform_device *dev)
  2. {
  3. printk("probe match\r\n");
  4. spin_lock_init(&leddev.lock);
  5. /* 1、设置设备号 */
  6. if (leddev.major) {
  7. leddev.devid = MKDEV(leddev.major, 0);
  8. register_chrdev_region(leddev.devid, TIMER_CNT, TIMER_NAME);
  9. } else {
  10. alloc_chrdev_region(&leddev.devid, 0, TIMER_CNT, TIMER_NAME);
  11. leddev.major = MAJOR(leddev.devid);
  12. }
  13. /* 2、注册设备 */
  14. cdev_init(&leddev.cdev, &led_fops);
  15. cdev_add(&leddev.cdev, leddev.devid, TIMER_CNT);
  16. /* 3、创建类 */
  17. leddev.class = class_create(THIS_MODULE, TIMER_NAME);
  18. if (IS_ERR(leddev.class)) {
  19. return PTR_ERR(leddev.class);
  20. }
  21. /* 4、创建设备 */
  22. leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, TIMER_NAME);
  23. if (IS_ERR(leddev.device)) {
  24. return PTR_ERR(leddev.device);
  25. }
  26. /* 5、初始化IO */
  27. leddev.node = of_find_node_by_path("/jin-gpio-led");
  28. if (leddev.node == NULL){
  29. printk("gpio node nost find!\r\n");
  30. return -EINVAL;
  31. }
  32. //三个参数,设备节点,设备数属性名称,个数
  33. leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
  34. printk("led0 register\r\n");
  35. if (leddev.led0 < 0) {
  36. printk("can't get led-gpio\r\n");
  37. return -EINVAL;
  38. }
  39. //使用IO,必须先申请 ,使用of_get_named_gpio获取GPIO的属性,led0给GPIO设置了名字
  40. gpio_request(leddev.led0, "jin-led0");
  41. gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */
  42. init_timer(&leddev.timer);
  43. leddev.timer.function = timer_function;
  44. leddev.timer.data = (unsigned long)&leddev;
  45. return 0;
  46. }

卸载函数,这里需要添加del_timer_sync.

  1. static int led_remove(struct platform_device *dev)
  2. {
  3. gpio_set_value(leddev.led0, 1); /* 卸载驱动的时候关闭LED */
  4. gpio_free(leddev.led0); /* 释放IO */
  5. del_timer_sync(&leddev.timer);
  6. cdev_del(&leddev.cdev); /* 删除cdev */
  7. unregister_chrdev_region(leddev.devid, TIMER_CNT); /* 注销设备号 */
  8. device_destroy(leddev.class, leddev.devid);
  9. class_destroy(leddev.class);
  10. printk(" remove \r\n");
  11. return 0;
  12. }

匹配列表,不需要修改。

  1. /* 匹配列表 */
  2. static const struct of_device_id match_tree[] = {
  3. { .compatible = "jin-gpio-led" },
  4. { /* Sentinel */ }
  5. };
  6. /* platform驱动结构体 */
  7. static struct platform_driver led_driver = {
  8. .driver = {
  9. .name = "12345", /* 驱动名字,用于和设备匹配 */
  10. .of_match_table = match_tree, /* 设备树匹配表 */
  11. },
  12. .probe = led_probe,
  13. .remove = led_remove,
  14. };

接下来编写app相关函数,timer_unlocked_ioctl函数里,可以修正定时器的参数。

 timer_function就类似单片机的中断函数,会定时执行。

  1. static int led_open(struct inode *inode, struct file *filp)
  2. {
  3. printk(" led_open \r\n");
  4. filp->private_data = &leddev; /* 设置私有数据 */
  5. leddev.timeperiod = 1000;
  6. return 0;
  7. }
  8. static long timer_unlocked_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
  9. {
  10. struct leddev_dev *dev = (struct timer_dev *)filp->private_data;
  11. int timerperiod;
  12. unsigned long flags;
  13. switch(cmd){
  14. case CLOSE_CMD:
  15. del_timer_sync(&dev->timer);
  16. printk(" close cmd \r\n");
  17. break;
  18. case OPEN_CMD:
  19. spin_lock_irqsave(&dev->lock,flags);
  20. timerperiod = dev->timeperiod;
  21. spin_unlock_irqrestore(&dev->lock,flags);
  22. mod_timer(&dev->timer,jiffies + msecs_to_jiffies(timerperiod));
  23. printk(" open cmd \r\n");
  24. break;
  25. case SETPERIOD_CMD:
  26. spin_lock_irqsave(&dev->lock,flags);
  27. dev->timeperiod = arg;
  28. spin_unlock_irqrestore(&dev->lock, flags);
  29. mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));
  30. printk(" set period cmd \r\n");
  31. break;
  32. default:
  33. break;
  34. }
  35. return 0 ;
  36. }
  37. /* 设备操作函数 */
  38. static struct file_operations led_fops = {
  39. .owner = THIS_MODULE,
  40. .open = led_open,
  41. .unlocked_ioctl = timer_unlocked_ioctl,
  42. };
  43. void timer_function(unsigned long arg)
  44. {
  45. struct leddev_dev *dev = (struct leddev_dev *)arg;
  46. static int sta = 1;
  47. int timerperiod;
  48. unsigned long flags;
  49. sta = !sta;
  50. gpio_set_value(dev->led0,sta);
  51. //printk(" time function \r\n");
  52. spin_lock_irqsave(&dev->lock,flags);
  53. timerperiod = dev->timeperiod;
  54. spin_unlock_irqrestore(&dev->lock,flags);
  55. mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->timeperiod));
  56. }

以上为linux的定时器。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/183440
推荐阅读
相关标签
  

闽ICP备14008679号