led驱动程序(基于ldd3正常定义的IO命令的实现)

驱动程序源代码:

/*************************************

 

NAME:gt2440_leds.c

COPYRIGHT:www.e-online.cc

 

*************************************/

#ifndef __KERNEL__

#  define__KERNEL__

#endif

#ifndef MODULE

#  define MODULE

#endif

 

#include <mach/regs-gpio.h>

#include <mach/hardware.h>

#include <linux/sched.h>

#include <linux/module.h>

#include <linux/cdev.h>

#include <linux/kernel.h>  

#include <linux/init.h>    

#include <linux/slab.h>  

#include <linux/fs.h>      

#include <linux/errno.h>   

#include <linux/types.h>   

#include <linux/proc_fs.h>

 

#include <asm/system.h> 

#include <asm/uaccess.h>

 

#define DEVICE_NAME "leds"

/* 定义幻数 */

#define LED_IOC_MAGIC 'k'

 

 

/* 定义命令 */

#define IOCTL_LEDS_ON  _IO(LED_IOC_MAGIC, 1)

#define IOCTL_LEDS_OFF _IO(LED_IOC_MAGIC, 2)

#define IOCTL_LED_ON   _IOW(LED_IOC_MAGIC,3, int)

#define IOCTL_LED_OFF        _IOW(LED_IOC_MAGIC,4, int)

 

#define LED_IOC_MAXNR 4

 

/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */

int dev_major=0;

struct cdev cdev;

int MEMDEV_NR_DEVS=2;

/* 用来指定LED所用的GPIO引脚 */

static unsigned long led_table [] =

{

       S3C2410_GPB5,

       S3C2410_GPB6,

       S3C2410_GPB7,

       S3C2410_GPB8,

};

 

/* 用来指定GPIO引脚的功能:输出 */

static unsigned int led_cfg_table [] =

{

       S3C2410_GPB5_OUTP,

       S3C2410_GPB6_OUTP,

       S3C2410_GPB7_OUTP,

       S3C2410_GPB8_OUTP,

};

 

int leds_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)

{

       int err =0;

        

      

       if(_IOC_TYPE(cmd) != LED_IOC_MAGIC){

              printk(KERN_INFO"TYPE ERROR");          

              return-ENOTTY;

       }

       if(_IOC_NR(cmd) > LED_IOC_MAXNR) {

              printk(KERN_INFO"NR ERROR");             

              return-ENOTTY;

       }

      

       if(_IOC_DIR(cmd) & _IOC_READ)            

              err= !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));

       else if(_IOC_DIR(cmd) & _IOC_WRITE)

              err= !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));

       if (err){

              printk(KERN_INFO"arg address error.");

              return-EFAULT;

       }

       switch(cmd)

       {

              caseIOCTL_LEDS_ON:

                     s3c2410_gpio_setpin(led_table[0],0);

                     s3c2410_gpio_setpin(led_table[1],0);

                     s3c2410_gpio_setpin(led_table[2],0);

                     s3c2410_gpio_setpin(led_table[3],0);

                     break;

              caseIOCTL_LEDS_OFF:

                     s3c2410_gpio_setpin(led_table[0],1);

                     s3c2410_gpio_setpin(led_table[1],1);

                     s3c2410_gpio_setpin(led_table[2],1);

                     s3c2410_gpio_setpin(led_table[3],1);

                     break;

              caseIOCTL_LED_ON:

                     //设置指定引脚的输出电平为0

                     ret= __get_user(led_no, (int *)arg);

                     s3c2410_gpio_setpin(led_table[led_no],0);             

                     return0;

 

              caseIOCTL_LED_OFF:

                     //设置指定引脚的输出电平为1

                     ret= __get_user(led_no, (int *)arg);              

                     s3c2410_gpio_setpin(led_table[led_no],1);                    

                     return0;

 

              default:

                     return-EINVAL;

       }

       return 0;

}

static struct file_operations dev_fops = {

       .owner       =     THIS_MODULE,

       .ioctl     =     leds_ioctl,

};

/*卸载函数*/

void memdev_cleanup_module(void)

{

   cdev_del(&cdev);

    /*注销字符设备*/

   unregister_chrdev_region(MKDEV(dev_major,0),2);

}

/*加载函数*/

int memdev_init_module(void)

{

    intresult,i;

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

    {

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

       s3c2410_gpio_setpin(led_table[i],0);

    }

    dev_t devno= MKDEV(dev_major,0);

    /*静态申请设备号*/

   if(dev_major)

       result=register_chrdev_region(devno,2,"led");//从0开始分配两个连续的次设备号

    else{/*动态申请主设备号*/

       result=alloc_chrdev_region(&devno,0,2,"led");//从0开始分配两个连续的次设备号    

       dev_major=MAJOR(devno);

      

       staticstruct class *led_class;//mknod

           /*自动创建设备文件*/ 

    led_class =class_create(THIS_MODULE,"led_dev"); /*在sys下创建类目录/sys/class/led_dev*/ 

     

   device_create(led_class, NULL, MKDEV(dev_major,0), NULL,"led0");

    }

   if(result<0){

       gotofail_malloc;

       returnresult;

    }

    /*注册字符设备*/

    cdev_init(&cdev,&dev_fops);

    cdev.owner =THIS_MODULE;

    cdev.ops=&dev_fops;

   cdev_add(&cdev,MKDEV(dev_major,0),MEMDEV_NR_DEVS);/*MEMDEV_NR_DEVS添加和memdev这个设备相关联的设备数量,次设备编号从0开始,到MEMDEV_NR_DEVS*/

    return 0;

      

  fail_malloc:

   memdev_cleanup_module();

    returnresult;

}

 

 

module_init(memdev_init_module);

module_exit(memdev_cleanup_module);

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("www.e-online.cc");

MODULE_DESCRIPTION("LEDS control for GT2440Board");b

遇到的问题:

由于刚开始我用的是Red Hat 9,大家应该都知道这个当年经典的操作系统,可惜内核是2.4.20的,而现在转向2.6的linux内核后,我是通过下面的方法实现的(这是我用ARM开发板户手则上学到的):

Step1:编辑配置文件Kconfig,加入驱动选项,使之在makemenuconfig的时候出现

打开 kernel-2.6.30.4/drivers/char/Kconfig文件,添加下面的代码所示:

config GT2440_LED

       tristate "GT2440 LED Driver"

       depends on ARCH_S3C2440

       default y if ARCH_S3C2440

       help

         GT2440 User led, use GPB[5:8].

Step2:保存退出,这时在linux-2.6.30.4目录位置运行一下makemenuconfig就可以在Device Drivers -> Character devices菜单中看到刚才所添加的选项了,按下空格键将会选择为<M>,此意为要把该选项编译为模块方式;再按下空格会变为<*>,意为要把该选项编译到内核中,在此我们选择<M>

Step3:通过上一步,我们虽然可以在配置内核的时候进行选择,但实际上此

时执行编译内核还是不能把gt2440_hello_module.c编译进去的,还需要在

Makefile 中把内核配置选项和真正的源代码联系起来,打开linux-2.6.30.4/drivers/char/Makefile,添加如下代码并保存退出:

obj-$(CONFIG_GT2440_HELLO_MODULE)       +=gt2440_hello_module.o

obj-$(CONFIG_GT2440_LEDS)               += gt2440_leds.o

obj-$(CONFIG_GT2440_LED)               += leds.o

obj-$(CONFIG_GT2440_PWM_BEEPER) += gt2440_pwm.o

2.将驱动模块拷贝到开发板后,先别急着加载模块,先停掉开发板上的又来的自动循环led程序:

#/etc/rc.d/init.d/leds stop

3.在成功之后,卸载驱动模块出现问题

使用rmmod会出现 rmmod : chdir(/lib/modules): No such file or directory ?
原来现在的内核模块在插入卸载时都会要转到
/lib/modules/(内核版本号)/这个目录里。所以只要建立这个目录并且把要使用的模块.ko文件复制到这个目录就行了。
         
mkdir -p /lib/modules/$(uname -r)

4.ok, 接下来,推荐大家采用IO内存映射的方法实现led驱动,这个挺有难度的,我都挂这几天了,可能自己的硬件知识太差劲了,现在好好补补,过段时间再贴出我的程序代码吧。


你可能感兴趣的:(led驱动程序(基于ldd3正常定义的IO命令的实现))