LED驱动动态加载方式(xc2440)

来源:互联网 发布:生物医学数据库官网 编辑:程序博客网 时间:2024/05/18 00:56

       上一篇文章,我在ubuntu上创建了一个名为memory的模块,并且通过实验,已经能很好的运行。趁着还有兴趣,而且还有一块闲置的arm9的板子,实验一下在xc2440上搞一个led驱动。以此记录过程:

环境:ubuntu12.04.4  交叉编译器 arm920t-eabi-4.1.2   开发板 XC2440  linux内核版本 2.6.37.4

      准备工作,安装在ubuntu上安装交叉编译工具,这个网上很很多例程,在这就不必啰嗦了,安装好交叉编译器,再找一个linux的源码,我找的是2.6.37.4这个版本的,解压到相应的目录,这个目录自己建一个。然后按照内核移植手册一部分配置一下内核,修改Makefile:  ARCH ?=arm  CROSS_COMPILE ?=arm-linux-   这一系列修改可以参照《xc-2440开发板linux内核移植手册》来完成。如果不配置应该是会出错的,包括什么头文件#include <mach/regs-gpio.h>不存在等等,但是当你在arch/arm/相关目录下查看,会发现这些头文件,我觉得应该是在make menuconfig是选择了默认的2410的配置的原因吧。

     然后找一个led的驱动和测试文件,参照http://blog.csdn.net/shiyi_2012/article/details/7451826   这篇文章的代码,参照电路原理图做一些修改:

//led.c  驱动部分

#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<mach/regs-gpio.h>
#include <mach/hardware.h>
#include<linux/io.h>
#include<asm/uaccess.h>

#define GPIO_LED_MAJOR 97

#define LED_1_ON 1
#define LED_2_ON 2
#define LED_3_ON 3
#define LED_4_ON 4

#define LED_1_OFF 6
#define LED_2_OFF 7
#define LED_3_OFF 8
#define LED_4_OFF 9

#define LED_OFF 5

#define LED1ON    0xFE          
#define LED2ON    0xFD          
#define LED3ON    0xFB           
#define LED4ON    0xF7           

#define LED1OFF    (~LED1ON)          
#define LED2OFF    (~LED2ON)     
#define LED3OFF    (~LED3ON)      
#define LED4OFF    (~LED4ON)      

//              LED1 -- GPF0
//              LED2 -- GPF1
//              LED3 -- GPF2
//              LED4 -- GPF3
 int GPIO_open(struct inode *inode, struct file *file)
 {
printk("Open led successfully!\n\n");

__raw_writel(__raw_readl(S3C2410_GPFCON)&0xFFFFFF55,S3C2410_GPFCON);
__raw_writel((__raw_readl(S3C2410_GPFDAT)|0xFFFF),S3C2410_GPFDAT);
printk("Initialization of LED OK!\n\n");
return 0;
 }

 int GPIO_release(struct inode *inode, struct file *filp)
 {
printk("LED Close successfully!\n\n");
return 0;
 }


ssize_t GPIO_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
 {
  return 0;
}



 ssize_t GPIO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
 {
return count;
 }

 //执行LED运行模式
int GPIO_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long org)
 {


switch(cmd)
         {
           case LED_1_ON:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)&LED1ON,S3C2410_GPFDAT);
                 printk("LED_1 light!\n");
                 break;
                 }
          case LED_2_ON:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)&LED2ON,S3C2410_GPFDAT);
                printk("LED_2 light!\n");
                 break;
                 }
          case LED_3_ON:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)&LED3ON,S3C2410_GPFDAT);
                 printk("LED_3 light!\n");
                 break;
                 }
          case LED_4_ON:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)&LED4ON,S3C2410_GPFDAT);
                 printk("LED_4 light!\n");
                 break;
                 }
          case LED_1_OFF:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)|LED1OFF,S3C2410_GPFDAT);
                 printk("LED_1 shutdown!\n");
                 break;
                 }
          case LED_2_OFF:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)|LED2OFF,S3C2410_GPFDAT);
                printk("LED_2 shutdown!\n");
                 break;
                 }
          case LED_3_OFF:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)|LED3OFF,S3C2410_GPFDAT);
                 printk("LED_3 shutdown!\n");
                 break;
                 }
          case LED_4_OFF:
                 {
                 __raw_writel(__raw_readl(S3C2410_GPFDAT)|LED4OFF,S3C2410_GPFDAT);
                 printk("LED_4 shutdown!\n");
                 break;
                 }

          case LED_OFF:
                 {
                __raw_writel(__raw_readl(S3C2410_GPFDAT)|0xFFFF,S3C2410_GPFDAT);
                printk("LED OFF!\n");
                break;
                 }


          default:
                 {
                 printk("led control:no cmd run \n");
                 return -EINVAL;
                 }
         return 0;
         }
 }



 struct file_operations GPIO_LED_ctl_ops={
         .owner  =THIS_MODULE,
         .open   =GPIO_open,
         .read   =GPIO_read,
         .write  =GPIO_write,
         .unlocked_ioctl  =GPIO_ioctl,
         . release =GPIO_release, 
 };


 static int GPIO_init(void)
 {
   int ret=-ENODEV;
   printk("LED Register...\n\n");
   ret=register_chrdev(GPIO_LED_MAJOR,"led",&GPIO_LED_ctl_ops);
if(ret<0)
{
return ret;
}
else
{


}
return ret;
}

static int __init s3c2440_led_init()
 {
int ret=-ENODEV;
ret=GPIO_init();
if(ret)
return ret;
return 0;
 }
 static void s3c2440_led_exit(void)
 {
unregister_chrdev(GPIO_LED_MAJOR,"led");
 }


 module_init(s3c2440_led_init);
 module_exit(s3c2440_led_exit);
 MODULE_LICENSE("Dual BSD/GPL");

对于驱动部分,由于我们使用的是2.6.37.4版本的内核,有一部分函数有变化,原先的老版本

  int (*ioctl)(struct inode*, struct file*, unsigned int, unsigned long);

被改为了      

   long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

因而在实际驱动中,我们需要将原先的写的ioctl函数头给改成下面的unlocked_ioctl,在file_operations结构体的填充中也是一样。

在编译成模块时,我们需要在Makefile文件中指明内核所在路径

参照网上的资料改写的一个Makefile文件:

#kefile2.6
 ifneq ($(KERNELRELEASE),)
  #kbuild syntax. dependency relationshsip of files and target modules are listed here.
mymodule-objs := led.o
obj-m := led.o  
 else
 PWD  := $(shell pwd)
 KVER ?= $(shell uname -r)
 KDIR := /opt/FriendlyARM/mini2440/linux-2.6.37.4
 all:
 $(MAKE) -C $(KDIR) M=$(PWD)
 clean:
 rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
 endif

下面是测试文件:

//led_test.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>

#define LED_1_ON 1
#define LED_2_ON 2
#define LED_3_ON 3
#define LED_4_ON 4

#define LED_1_OFF 6
#define LED_2_OFF 7
#define LED_3_OFF 8
#define LED_4_OFF 9

#define LED_OFF 5

int main()
{
int ret,fd;
int result = 1;
printf("\nstart led_driver test...\n\n");
fd=open("/dev/led",O_RDWR);

if(fd==-1)
{
printf("open device  error\n");
return ;
}

while(1)
{


ioctl(fd,0,LED_1_ON);
sleep(2);
ioctl(fd,0,LED_1_OFF);
ioctl(fd,0,LED_2_ON);
sleep(2);
ioctl(fd,0,LED_2_OFF);
ioctl(fd,0,LED_3_ON);
sleep(2);
ioctl(fd,0,LED_3_OFF);
ioctl(fd,0,LED_4_ON);
sleep(2);
ioctl(fd,0,LED_4_OFF);
sleep(2);
}
ret=close(fd);
printf("close led test\n");
return 0;
 }

上面的代码是经过反复测试所得确定是正确的,使用make命令生成led.ko 使用arm-linux-gcc -o led_test led_test.c 生成可执行文件led_test  然后就是测试了,使用rz命令将文件下载到开发板,chomd 777 led_test 给文件全部权限,insmod led.ko安装模块,cd /dev 到dev路径创建设备节点,mknod led c 97 0   然后回到根目录,执行./led_test

通过观察,led驱动已经能很好的运行了。



1 0
原创粉丝点击