您的位置:首页 > 其它

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

2012-05-15 11:29 295 查看
驱动程序源代码:

/*************************************
 
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驱动,这个挺有难度的,我都挂这几天了,可能自己的硬件知识太差劲了,现在好好补补,过段时间再贴出我的程序代码吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  io ioc module table cmd struct
相关文章推荐