原创 S3C2440 LED驱动程序学习

2009-7-20 20:10 4465 3 3 分类: 软件与OS

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

今天,在友善之笔的LED驱动程序基础上学习了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 LED_ON  1


#define LED_OFF 0


 


#define DEVICE_NAME "leds"


 


static unsigned long led_table [] = {


       S<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3C2410_GPB5,


       S3C2410_GPB6,


       S3C2410_GPB7,


       S3C2410_GPB8,


};


 


static unsigned int led_cfg_table [] = {


       S3C2410_GPB5_OUTP,


       S3C2410_GPB6_OUTP,


       S3C2410_GPB7_OUTP,


       S3C2410_GPB8_OUTP,


};


 


static int s3c2440_leds_ioctl(


       struct inode *inode,


       struct file *file,


       unsigned int cmd,


       unsigned long arg)


{


       if(arg>3){


       printk("Led's number error,please check!");    


       return -EINVAL;


       }


 


       switch(cmd) {


       case LED_ON:


              s3c2410_gpio_setpin(led_table[arg],0); //led low light


              return 0;


       case LED_OFF:


              s3c2410_gpio_setpin(led_table[arg], 1);


              return 0;


       default:


              return -EINVAL;


       }


}


 


static struct file_operations dev_fops = {


       .owner    =     THIS_MODULE,


       .ioctl       =     s3c2440_leds_ioctl,


};


 


static struct miscdevice misc = {


       .minor = MISC_DYNAMIC_MINOR,


       .name = DEVICE_NAME,


       .fops = &dev_fops,


};


 


static int __init dev_init(void)


{


       int ret;


 


       int i;


      


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


              s3c2410_gpio_cfgpin(led_table, led_cfg_table);


              s3c2410_gpio_setpin(led_table, 1);


       }


 


       ret = misc_register(&misc);


 


       printk (DEVICE_NAME"\tinitialized\n");


 


       return ret;


}


 


static void __exit dev_exit(void)


{


       misc_deregister(&misc);


}


 


module_init(dev_init);


module_exit(dev_exit);


MODULE_LICENSE("GPL");


MODULE_AUTHOR("Feng dong rui");


MODULE_DESCRIPTION("Study s3c2440");


 


简单分析:


(1)   友善之臂的mini2440板子上的4LED对应的GPIOGPB5~GPB8,低电平点亮;


(2)   注册设备的时候,有两种方式:一种是使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)LED_MAJOR为定义的主设备号,DEVICE_NAME为定义的设备名称,dev_fops为定义的文件操作结构体。使用该函数向系统注册字符型设备驱动程序,主设备号LED_MAJOR自己定义,如该值为0则系统自动分配主设备号;另一种是使用misc_register(&misc)。如果是非标准设备则使用 misc_register,即一些字符设备不符合预先确定的字符设备范畴,就用这种方式,它固定使用主设备号10注册,如果多个设备次设备号不同。


(3)   使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已在友善的板子上验证)。如果模块使用该方式注册并且LED_MAJOR0(自动分配主设备号),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为2530,则建立节点:mknod leds c 253 0。使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建立节点,否则在应用程序无法打开该设备。


(4)   在构建根文件系统时在配置选项中必须按照如下设置,才能加载和卸载模块:BusyboxLinux Module Utilities-à


       (/lib/modules)Default directory containing modules


       (modules.dep)Default name of modules.dep


  •    insmod


  •    rmmod


  •    lsmod


  •    modprobe


     


    Makefile文件如下:


    obj-m:=led_driver.o


    CURRENT_PATH:=$(shell pwd)


    ARM_LINUX_KERNEL:=/opt/linux-2.6.29.1


    all:


           $(MAKE) -C $(ARM_LINUX_KERNEL) SUBDIRS=$(CURRENT_PATH) modules


    clean:


           rm -rf *.cmd *.o *.ko  *.mod.c *.symvers *.order


     


    测试程序如下:


     


    /*led_app.c*/


    #include <stdio.h>


    #include <stdlib.h>


     


    #define LED_ON   1


    #define LED_OFF  0


    #define LED_DEVICE  "/dev/leds"


     


    int main(int argc,char **argv)


    {


        int fd,led_num;


        fd = open(LED_DEVICE,0);


        if(fd < 0)


        {


            printf("can't open /dev/leds!\n");


            exit(0);


        }


       


        led_num = atoi(argv[1]);


        if(!(strcmp(argv[2],"on")))


        {


            ioctl(fd,LED_ON,led_num);


        }


        else if(!(strcmp(argv[2],"off")))


        {


            ioctl(fd,LED_OFF,led_num);


        }


        else


        {


        exit(0);


        }


        exit(0);


    }


     


     


    Makefile文件:


    all:


           arm-linux-gcc led_app.c -o led_app


    clean:


           rm -rf *.o led_app


     


    编译模块得到leds_driver.ko,我把它拷到根文件系统的额home目录下,并在启动脚本里面设置自动加载,就是在/etc/init.d/rcS里面加了两句:


    echo “---------insmod leds_driver.ko---------


    insmod /home/leds_driver.ko


     


    把编译得到的测试程序led_app拷贝到home目录下,使用命令点亮和熄灭某一LED


     


    ./led_app 0 on                 //点亮LED1


            .


            .


            .


    ./led_app 3 on                 //点亮LED4


     


     


     


    ./led_app 0 off                 //熄灭LED1


            .


            .


            .


    ./led_app 3 off                 //熄灭LED4


     

  • PARTNER CONTENT

    文章评论0条评论)

    登录后参与讨论
    EE直播间
    更多
    我要评论
    0
    3
    关闭 站长推荐上一条 /3 下一条