本節介紹如何利用板載的Led和Linux的內核定時器實現一個簡單的流水燈的驅動,所使用的開發板是TQ2440,內核版本2.6.30.4。
程序比較簡單,也沒涉及到什麼機制,直接上代碼了!關於定時器的使用模板可以參考<<Linux設備驅動開發詳解>>(見http://www.linuxidc.com/Linux/2011-07/38211.htm).
驅動程序:
- #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/types.h>
- #include<linux/fs.h>
- #include<linux/mm.h>
- #include<linux/cdev.h>
- #include<linux/slab.h>
- #include<linux/timer.h>
- #include<linux/jiffies.h>
- #include<asm/io.h>
- #include<asm/uaccess.h>
- #include<mach/regs-gpio.h>
-
-
- #define LED_MAJOR 244
-
-
- #define LED_ON 0
- #define LED_OFF 1
-
- #define LED1_PIN S3C2410_GPB5
- #define LED2_PIN S3C2410_GPB6
- #define LED3_PIN S3C2410_GPB7
- #define LED4_PIN S3C2410_GPB8
-
- static unsigned long led_major = LED_MAJOR;
-
- struct led_dev
- {
- struct cdev cdev;
- struct timer_list s_timer;
- atomic_t led_no; //LED編號
- atomic_t sec_counter; //秒計時數
- };
-
- struct led_dev *led_devp;
-
-
-
- void led_control(int led_no)
- {
- switch(led_no)
- {
- case 1:s3c2410_gpio_setpin(LED1_PIN,LED_ON);
- s3c2410_gpio_setpin(LED2_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED3_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED4_PIN,LED_OFF);
- break;
- case 2:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED2_PIN,LED_ON);
- s3c2410_gpio_setpin(LED3_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED4_PIN,LED_OFF);
- break;
- case 3:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED2_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED3_PIN,LED_ON);
- s3c2410_gpio_setpin(LED4_PIN,LED_OFF);
- break;
- case 4:s3c2410_gpio_setpin(LED1_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED2_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED3_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED4_PIN,LED_ON);
- break;
- default:break;
-
- }
- }
-
-
- //定時器處理函數
- static void sec_timer_handler(unsigned long arg)
- {
- int num;
-
- mod_timer(&led_devp->s_timer,jiffies+HZ);
-
- num = atomic_read(&led_devp->led_no);
- if(num == 4)
- {
- atomic_set(&led_devp->led_no,1);
- }
- else
- {
- atomic_inc(&led_devp->led_no);
- }
-
- num = atomic_read(&led_devp->led_no);
- led_control(num);
-
- atomic_inc(&led_devp->sec_counter);
- num = atomic_read(&led_devp->sec_counter);
- printk(KERN_INFO "sec_count:%d\n",num);
-
- }
-
-
- static int led_open(struct inode *inode,struct file *filp)
- {
- struct timer_list *timer;
-
- timer = &led_devp->s_timer;
- init_timer(timer);
- timer->function = sec_timer_handler;
- timer->expires = jiffies+HZ; //計時頻率為HZ
-
- add_timer(timer);
- atomic_set(&led_devp->sec_counter,0);
- atomic_set(&led_devp->led_no,0);
-
- return 0;
-
- }
-
-
-
- static int led_release(struct inode *inode, struct file *filp)
- {
- del_timer(&led_devp->s_timer);
- return 0;
- }
-
-
-
- static ssize_t led_read(struct file *filp, char __user *buf,
- size_t size, loff_t *ppos)
- {
- int count,led_no;
- int result;
-
- count = atomic_read(&led_devp->sec_counter);
- led_no = atomic_read(&led_devp->led_no);
- result = (count<<3)+led_no;
-
- if(put_user(result,(int*)buf))
- {
- return -EFAULT;
- }
- else
- {
- return sizeof(int);
- }
- }
-
-
-
-
- static const struct file_operations led_fops =
- {
- .owner = THIS_MODULE,
- .read = led_read,
- .open = led_open,
- .release = led_release,
- };
-
-
-
-
- static void led_setup_cdev(struct led_dev *dev, int index)
- {
- int err,devno = MKDEV(led_major,index);
- cdev_init(&dev->cdev,&led_fops);
- dev->cdev.owner = THIS_MODULE;
- err = cdev_add(&dev->cdev,devno,1);
-
- if(err)
- {
- printk(KERN_NOTICE "Error %d adding %d\n",err,index);
- }
- }
-
-
-
-
- static int led_init(void)
- {
- int result;
-
- dev_t devno = MKDEV(led_major,0); //獲取設備號
-
- /*注冊設備*/
- if(led_major)
- result = register_chrdev_region(devno,1,"led");
- else
- {
- result = alloc_chrdev_region(&devno,0,1,"led");
- led_major = MAJOR(devno);
- }
-
- if(result<0)
- {
- printk("register failed!");
- return result;
- }
-
-
- led_devp =(struct led_dev*)kmalloc(sizeof(struct led_dev),GFP_KERNEL);
-
- if(!led_devp)
- {
- result = -ENOMEM;
- unregister_chrdev_region(devno,1);
- }
- memset(led_devp, 0 ,sizeof(struct led_dev));
-
- led_setup_cdev(led_devp,0);
-
- /*配置IO口*/
- s3c2410_gpio_cfgpin(LED1_PIN,S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(LED2_PIN,S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(LED3_PIN,S3C2410_GPIO_OUTPUT);
- s3c2410_gpio_cfgpin(LED4_PIN,S3C2410_GPIO_OUTPUT);
-
- /*初始化IO電平*/
- s3c2410_gpio_setpin(LED1_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED2_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED3_PIN,LED_OFF);
- s3c2410_gpio_setpin(LED4_PIN,LED_OFF);
-
- return 0;
- }
-
-
-
- static void led_exit(void)
- {
- cdev_del(&led_devp->cdev);
- kfree(led_devp);
- unregister_chrdev_region(MKDEV(led_major,0),1);
- }
-
-
-
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Vanbreaker");
-
- module_init(led_init);
- module_exit(led_exit);