您的位置:首页 > 运维架构 > Linux

2.linux arm led驱动

2013-10-29 16:28 309 查看
前面写了一个最简单的模块,现在继续写一个简单的linux下led的驱动。

先看一下简单的驱动代码,命名为led_driver.c:

#include <linux/miscdevice.h>

#include <linux/delay.h>

#include <asm/irq.h>

#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/delay.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#define DEVICE_NAME "leds"

//the next two structs used to config the pins for leds

static unsigned long led_table[] = {

S3C2410_GPF4,

S3C2410_GPF5,

S3C2410_GPF6,

S3C2410_GPF7,

};

static unsigned int led_cfg_table[] = {

S3C2410_GPF4_OUTP,

S3C2410_GPF5_OUTP,

S3C2410_GPF6_OUTP,

S3C2410_GPF7_OUTP,

};

//cmd: 0---off 1---on

//arg: the led number(0----3)

static int s3c2440_led_ioctl(

struct inode *inode,

struct file *file,

unsigned int cmd,

unsigned long arg)

{

switch(cmd){

case 0:

case 1:

if(arg > 3) {

return -EINVAL;

}

s3c2410_gpio_setpin(led_table[arg],!cmd);

return 0;

default:

return -EINVAL;

}

}

static struct file_operations dev_ops = {

.owner = THIS_MODULE,

.ioctl = s3c2440_led_ioctl,

};

static struct miscdevice misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_ops,

};

static int __init led_init()

{

int i;

int ret;

for(i = 0; i < 4; i++) {

s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);

s3c2410_gpio_setpin(led_table[i],0);

}

ret = misc_register(&misc);

printk(DEVICE_NAME "initialized\n");

return ret;

}

static void __exit led_exit()

{

misc_deregister(&misc);

}

module_init(led_init);

module_exit(led_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("");

linux对ARM支持很好,有关gpio的操作都有函数写好了,直接用就可以。不需要我们自己去操作IO控制寄存器等。

s3c2410_gpio_cfgpin和s3c2410_gpio_setpin定义在linux/arch/arm/plat-s3c24xx/gpio.c这样的板级适配文件中。

对于不同的板子定义的gpio的操作是不一样的,我们s3c2440为例,其对于的gpio的操作函数定义在linux/arch/arm/plat-s3c24xx/gpio.c。如果是at91,就定义在linux/arch/arm/plat-at91/gpio.c。

而S3C2410_GPF4和S3C2410_GPF4_OUTP这样的管脚定义在arch/arm/mach-s3c2410/include/mach/regs-gpio.h中定义好了。

对于不同的硬件连接驱动会使用不同的io口。所以在写驱动的时候你需要按照你板子的原理图编写程序。我的板子使用的是DPF4.5.6.7连接led。所以我使用S3C2410_GPF。像友善的mini2440就是使用的S3C2410_GPB5.6.7.8。

这里我们使用到了杂设备的注册和卸载函数

misc_register(miscdevice *); //注册一个misc设备

misc_deregister(miscdevice * ); //卸载一个misc设备

miscdevice结构体定义在linux/miscdevice.h里面。minor为次设备号。调用misc_register(&misc);就完成一个杂设备的注册。

驱动写好了,Makefile可以直接借用上一篇hello_module的,只需要把Makefile里面的hello_module改为我们的led_driver就可以了。

测试程序:

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/ioctl.h>

int main(int argc, char **argv)

{

int fd;

int led_num; //led编号(0---3)

int cmd ;//控制led 0:off 1:on

if(argc !=3 || sscanf(argv[1],"%d", &led_num)!=1 ||sscanf(argv[2], "%d", &cmd)!=1

|| cmd<0 ||cmd >1 || led_num < 0 || led_num >3) {

fprintf(stderr, "param erro!\n");

exit(1);

}

printf("open device\n");

fd = open("/dev/leds",0);

if(fd <0){

perror("open device leds error!\n");

exit(1);

}

ioctl(fd, cmd, led_num);

close(fd);

return 0;

}

使用交叉编译器编译后就可以放到板子上测试了。

点亮第0个灯#./led 0 1

点亮第1个灯#./led 1 1

关闭第0个灯#./led 0 0

你可以在你打板子上看到效果。led驱动完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: