第一个Linux驱动-流水灯
水平有限,描述不当之处请指出,转载请注明出处http://blog.csdn.net/vanbreaker/article/details/7711695
本节介绍如何利用板载的Led和Linux的内核定时器实现一个简单的流水灯的驱动,所使用的开发板是TQ2440,内核版本2.6.30.4。
程序比较简单,也没涉及到什么机制,直接上代码了!关于定时器的使用模板可以参考<<Linux设备驱动开发详解>>.
驱动程序:
#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);