TQ2440 第一个驱动程序:LED驱动程序

一、安装arm-linux-gcc编译环境

    拷贝天嵌光盘linux资源\linux平台开发工具包\EABI-4.3.3_EmbedSky_20100610.tar.bz2到linux虚拟机中的共享目录share(用户安装VMware tools后方可创建共享目录)。

#mkdir  /opt/EmbedSky

#cp /mnt/hgfs/share/EABI-4.3.3_EmbedSky_20100610.tar.bz2    /opt/EmbedSky

#cd /opt/EmbedSky

#tar xvfj EABI-4.3.3_EmbedSky_20100610.tar.bz2  -C /

到目前为止可以就可以使用这个arm-linux-gcc命令,但是要使用这个命令的绝对位置。为了方便使用我们可以将这个命令的路径添加到系统默认路径PATH中去。

#su //进入管理员权限,/etc/profile只有管理员才能对其操作

#vim /etc/profile

# Path manipulation

if [ "$EUID" = "0" ]; then

    pathmunge /sbin

    pathmunge /usr/sbin

    pathmunge /usr/local/sbin

    pathmunge /opt/EmbedSky/4.3.3/bin//增加该项

#source /etc/profile//使设置生效

#arm-linux-gcc -v //可看到该编译器的信息

二、构建内核数

2.6以后的内核编译驱动不再只要提供linux内核头文件了,还需要构建内核源码树。我们驱动程序要在arm开发板上运行,该开发板使用的内核是linux-2.6.30.4,所以我们在虚拟机上构建的内核树也要使用这个版本。
拷贝天嵌 /TQ2440资料\Linux资源\Linux源码包\2.6.30.4\linux-2.6.30.4_20100531.tar.bz2 到共享目录下  
#tar xvfj /mnt/hgfs/share/linux-2.6.30.4_20100531.tar.bz2 -C /   //将源码解压到/opt/EmbedSky/中
#cp  config_EmbedSky_W43 .config
#source /etc/profile  //确保arm-linux-gcc可用
#make
#make zImage
# make modules
# make modules_install
到此我们的构建内核树工作完成

三、驱动程序

/*头文件路径,不同的内核相关的函数会略有不同*/

/*需找某个函数调用的头文件,可以用sourceinsight软件查询内核源码*/

#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/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/list.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <asm/unistd.h>

#define DEVICE_NAME "led_test"/*注册驱动时自动建立的设备名称*/  #define IOCTL_GPIO_ON    1 #define IOCTL_GPIO_OFF  0 /* 用来指定LED所用的GPIO引脚 */ static unsigned long gpio_table [] = {     S3C2410_GPB5,     S3C2410_GPB6,     S3C2410_GPB7,     S3C2410_GPB8, }; /* 用来指定GPIO引脚的功能:输出 */ static unsigned int gpio_cfg_table [] = {     S3C2410_GPB5_OUTP,     S3C2410_GPB6_OUTP,     S3C2410_GPB7_OUTP,     S3C2410_GPB8_OUTP, };

static int s3c2440_leds_open(struct inode *inode,struct file *filp)/*open函数实现的是led的灯的配置:输出*/  {     int i;     for(i=0;i<4;i++)     {         s3c2410_gpio_cfgpin(gpio_table[i],gpio_cfg_table[i]);     }     return 0; }

static int tq2440_gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)/*实现的是led灯的控制*/  {     if (arg > 4)     {         return -EINVAL;     }     switch(cmd)     {         case IOCTL_GPIO_ON:             s3c2410_gpio_setpin(gpio_table[arg], 0); // 设置指定引脚的输出电平为0              return 0;         case IOCTL_GPIO_OFF:             s3c2410_gpio_setpin(gpio_table[arg], 1);// 设置指定引脚的输出电平为1              return 0;         default:             return -EINVAL;     } }

/*驱动框架必备,file_operations 是包含了对这个设备所能进行的操作*/

static struct file_operations dev_fops = {

       .owner   =   THIS_MODULE,        .ioctl      =    tq2440_gpio_ioctl,        .open    =    s3c2440_leds_open, };

/*驱动框架必备,驱动信息的打包,用于该驱动程序的注册*/ static struct miscdevice misc = {        .minor = MISC_DYNAMIC_MINOR,     .name = DEVICE_NAME,     .fops = &dev_fops, };

/*驱动框架必备,驱动初始化函数*/ static int __init dev_init(void)

{     int ret;     ret = misc_register(&misc);     printk (DEVICE_NAME" initialized\n");     return ret; }

/*驱动框架必备,驱动退出函数*/ static void __exit dev_exit(void)

{     misc_deregister(&misc);

    printk (DEVICE_NAME" is over!\n"); }

/*驱动框架必备,模块初始化入口函数*/ module_init(dev_init);

/*驱动框架必备,模块结束入口函数*/ module_exit(dev_exit);

/*驱动框架必备,通用公共许可*/ MODULE_LICENSE("GPL");

编译这个驱动的Makefile

KERN_DIR = /lib/modules/2.6.30.4-EmbedSky/build/ all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += leddrv.o

4.测试程序:

/*调用系统的头文件*/

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h>

#define on   1 #define off  0 int main(int argc,char **argv) {     int led_num;

   /*检查输入的参数个数*/

  /*第一个为函数名,第二个为开关,第三个为led灯的顺序*/     if (argc != 3)     {         printf("Usage: %s <ON/OFF> <led_num> \n", argv[0]);         return 0;     }        int fd;

    /*打开设备,获得它的文件描述符*/     fd = open("/dev/led_test", O_RDWR);       if (fd < 0)       {            printf("open error\n");           return 0;      }

   /*将接受到的字符参数转换为数字参数*/    led_num=*(argv[2]+0)-48;     if (!strcmp(argv[1], "on"))

  /*调用ioctl函数,该函数会调用file_operations中的ioctl函数*/         ioctl(fd, on,(led_num-1));    else if (!strcmp(argv[1], "off"))         ioctl(fd, off,(led_num-1));    return 0;   }   

在pc机上分别编译好驱动和测试程序,
将以上3个文件leddrv.c Makefile ledtest.c放在fisrtdrv目录中,进入该目录
#make  //编译驱动
#arm-linux-gcc -o  ledtest ledtest.c //编译测试程序
将编译好的leddrv.ko和ledtest拷贝到开发板上,以下在开发板上运行
#insmod leddrv.ko
#ls /dev  //可以看到多了个led_tes设备t出现
#ps
#kill -9 615 //关掉天嵌开机启动的led_player程序
#./ledtest off 1
#./ledtest off 2
#./ledtest off 3
#./ledtest off 4
#./ledtest on 1
#./ledtest on 2
#./ledtest on 3
#./ledtest on 4

你可能感兴趣的:(LED驱动,TQ2440)