2.linux arm led驱动

前面写了一个最简单的模块,现在继续写一个简单的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驱动完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值