第一个Linux驱动-流水灯


本节介绍如何利用板载的Led和Linux的内核定时器实现一个简单的流水灯的驱动,所使用的开发板是TQ2440,内核版本2.6.30.4。

程序比较简单,也没涉及到什么机制,直接上代码了!关于定时器的使用模板可以参考<<Linux设备驱动开发详解>>(见).

驱动程序:

  1. #include<linux/module.h>   
  2. #include<linux/init.h>   
  3. #include<linux/types.h>   
  4. #include<linux/fs.h>   
  5. #include<linux/mm.h>   
  6. #include<linux/cdev.h>   
  7. #include<linux/slab.h>   
  8. #include<linux/timer.h>   
  9. #include<linux/jiffies.h>   
  10. #include<asm/io.h>   
  11. #include<asm/uaccess.h>   
  12. #include<mach/regs-gpio.h>   
  13.   
  14.   
  15. #define LED_MAJOR 244   
  16.   
  17.   
  18. #define LED_ON  0   
  19. #define LED_OFF 1   
  20.   
  21. #define LED1_PIN S3C2410_GPB5   
  22. #define LED2_PIN S3C2410_GPB6   
  23. #define LED3_PIN S3C2410_GPB7   
  24. #define LED4_PIN S3C2410_GPB8    
  25.   
  26. static unsigned long led_major = LED_MAJOR;  
  27.   
  28. struct led_dev   
  29. {  
  30.     struct cdev cdev;  
  31.     struct timer_list s_timer;  
  32.     atomic_t led_no;       //LED编号   
  33.     atomic_t sec_counter;  //秒计时数   
  34. };  
  35.   
  36. struct led_dev *led_devp;  
  37.   
  38.   
  39.   
  40. void led_control(int led_no)  
  41. {  
  42.     switch(led_no)  
  43.     {  
  44.         case 1:s3c2410_gpio_setpin(LED1_PIN,LED_ON);  
  45.                s3c2410_gpio_setpin(LED2_PIN,LED_OFF);  
  46.                s3c2410_gpio_setpin(LED3_PIN,LED_OFF);  
  47.                s3c2410_gpio_setpin(LED4_PIN,LED_OFF);  
  48.                break;  
  49.         case 2:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);  
  50.                s3c2410_gpio_setpin(LED2_PIN,LED_ON);  
  51.                s3c2410_gpio_setpin(LED3_PIN,LED_OFF);  
  52.                s3c2410_gpio_setpin(LED4_PIN,LED_OFF);  
  53.                break;  
  54.         case 3:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);  
  55.                s3c2410_gpio_setpin(LED2_PIN,LED_OFF);  
  56.                s3c2410_gpio_setpin(LED3_PIN,LED_ON);  
  57.                s3c2410_gpio_setpin(LED4_PIN,LED_OFF);  
  58.                break;  
  59.         case 4:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);  
  60.                s3c2410_gpio_setpin(LED2_PIN,LED_OFF);  
  61.                s3c2410_gpio_setpin(LED3_PIN,LED_OFF);  
  62.                s3c2410_gpio_setpin(LED4_PIN,LED_ON);  
  63.                break;  
  64.         default:break;  
  65.           
  66.     }  
  67. }  
  68.   
  69.   
  70. //定时器处理函数   
  71. static void sec_timer_handler(unsigned long arg)  
  72. {  
  73.     int num;  
  74.   
  75.     mod_timer(&led_devp->s_timer,jiffies+HZ);  
  76.       
  77.     num = atomic_read(&led_devp->led_no);  
  78.     if(num == 4)  
  79.     {  
  80.         atomic_set(&led_devp->led_no,1);  
  81.     }     
  82.     else  
  83.     {  
  84.         atomic_inc(&led_devp->led_no);  
  85.     }  
  86.       
  87.     num = atomic_read(&led_devp->led_no);  
  88.     led_control(num);  
  89.   
  90.     atomic_inc(&led_devp->sec_counter);  
  91.     num = atomic_read(&led_devp->sec_counter);  
  92.     printk(KERN_INFO "sec_count:%d\n",num);  
  93.           
  94. }  
  95.   
  96.   
  97. static int led_open(struct inode *inode,struct file *filp)  
  98. {  
  99.     struct timer_list *timer;  
  100.   
  101.     timer = &led_devp->s_timer;  
  102.     init_timer(timer);  
  103.     timer->function = sec_timer_handler;  
  104.     timer->expires = jiffies+HZ;       //计时频率为HZ   
  105.   
  106.     add_timer(timer);  
  107.     atomic_set(&led_devp->sec_counter,0);     
  108.     atomic_set(&led_devp->led_no,0);  
  109.   
  110.     return 0;  
  111.   
  112. }  
  113.   
  114.   
  115.   
  116. static int led_release(struct inode *inode, struct file *filp)  
  117. {  
  118.     del_timer(&led_devp->s_timer);  
  119.     return 0;     
  120. }  
  121.   
  122.   
  123.   
  124. static ssize_t led_read(struct file *filp, char __user *buf,   
  125.             size_t size, loff_t *ppos)  
  126. {  
  127.     int count,led_no;  
  128.     int result;  
  129.   
  130.     count = atomic_read(&led_devp->sec_counter);  
  131.     led_no = atomic_read(&led_devp->led_no);  
  132.     result = (count<<3)+led_no;  
  133.   
  134.     if(put_user(result,(int*)buf))  
  135.     {  
  136.         return -EFAULT;  
  137.     }     
  138.     else  
  139.     {  
  140.         return sizeof(int);  
  141.     }  
  142. }  
  143.   
  144.   
  145.   
  146.   
  147. static const struct file_operations led_fops =  
  148. {  
  149.     .owner = THIS_MODULE,  
  150.     .read = led_read,  
  151.     .open = led_open,  
  152.     .release = led_release,  
  153. };  
  154.   
  155.   
  156.   
  157.   
  158. static void led_setup_cdev(struct led_dev *dev, int index)  
  159. {  
  160.     int err,devno = MKDEV(led_major,index);  
  161.     cdev_init(&dev->cdev,&led_fops);  
  162.     dev->cdev.owner = THIS_MODULE;  
  163.     err = cdev_add(&dev->cdev,devno,1);  
  164.   
  165.     if(err)  
  166.     {  
  167.         printk(KERN_NOTICE "Error %d adding %d\n",err,index);  
  168.     }  
  169. }  
  170.   
  171.   
  172.   
  173.   
  174. static int led_init(void)  
  175. {  
  176.     int result;  
  177.   
  178.     dev_t devno = MKDEV(led_major,0); //获取设备号   
  179.   
  180.     /*注册设备*/  
  181.     if(led_major)  
  182.         result = register_chrdev_region(devno,1,"led");  
  183.     else  
  184.     {  
  185.         result = alloc_chrdev_region(&devno,0,1,"led");  
  186.         led_major = MAJOR(devno);  
  187.     }  
  188.   
  189.     if(result<0)  
  190.     {  
  191.         printk("register failed!");  
  192.         return result;  
  193.     }  
  194.   
  195.       
  196.     led_devp =(struct led_dev*)kmalloc(sizeof(struct led_dev),GFP_KERNEL);  
  197.       
  198.     if(!led_devp)  
  199.     {  
  200.         result = -ENOMEM;  
  201.         unregister_chrdev_region(devno,1);  
  202.     }  
  203.     memset(led_devp, 0 ,sizeof(struct led_dev));  
  204.   
  205.     led_setup_cdev(led_devp,0);  
  206.   
  207.     /*配置IO口*/  
  208.     s3c2410_gpio_cfgpin(LED1_PIN,S3C2410_GPIO_OUTPUT);  
  209.     s3c2410_gpio_cfgpin(LED2_PIN,S3C2410_GPIO_OUTPUT);  
  210.     s3c2410_gpio_cfgpin(LED3_PIN,S3C2410_GPIO_OUTPUT);  
  211.     s3c2410_gpio_cfgpin(LED4_PIN,S3C2410_GPIO_OUTPUT);  
  212.   
  213.          /*初始化IO电平*/  
  214.     s3c2410_gpio_setpin(LED1_PIN,LED_OFF);  
  215.     s3c2410_gpio_setpin(LED2_PIN,LED_OFF);  
  216.     s3c2410_gpio_setpin(LED3_PIN,LED_OFF);  
  217.     s3c2410_gpio_setpin(LED4_PIN,LED_OFF);  
  218.   
  219.     return 0;  
  220. }  
  221.   
  222.   
  223.   
  224. static void led_exit(void)  
  225. {  
  226.     cdev_del(&led_devp->cdev);  
  227.     kfree(led_devp);  
  228.     unregister_chrdev_region(MKDEV(led_major,0),1);  
  229. }  
  230.   
  231.   
  232.   
  233. MODULE_LICENSE("GPL");  
  234. MODULE_AUTHOR("Vanbreaker");  
  235.   
  236. module_init(led_init);  
  237. module_exit(led_exit);  
  • 1
  • 2
  • 3
  • 下一页

相关内容