飞凌2440开发板的led驱动和应用程序

来源:互联网 发布:php mvc框架 编辑:程序博客网 时间:2024/06/05 15:27

led驱动程序

#include <linux/module.h>   /* Every Linux kernel module must include this head */
#include <linux/init.h>     /* Every Linux kernel module must include this head */
#include <linux/kernel.h>   /* printk() */
#include <linux/fs.h>       /* struct fops */
#include <linux/errno.h>    /* error codes */
#include <linux/cdev.h>     /* cdev_alloc()  */
#include <asm/io.h>         /* ioremap()  */
#include <linux/ioport.h>   /* request_mem_region() */


#include <asm/ioctl.h>      /* Linux kernel space head file for macro _IO() to generate ioctl command  */
#ifndef __KERNEL__
#include <sys/ioctl.h>      /* User space head file for macro _IO() to generate ioctl command */
#endif
//#include <linux/printk.h> /* Define log level KERN_DEBUG, no need include here */


#define DRV_DESC                  "S3C24XX LED driver"


#define DEV_NAME                  "led"
#define LED_NUM                   4


/* Set the LED dev major number */
//#define LED_MAJOR                 79
#ifndef LED_MAJOR
#define LED_MAJOR                 0
#endif


#define DRV_MAJOR_VER             1
#define DRV_MINOR_VER             0
#define DRV_REVER_VER             0


#define DISABLE                   0
#define ENABLE                    1


#define GPIO_INPUT                0x00
#define GPIO_OUTPUT               0x01




#define PLATDRV_MAGIC             0x60
#define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)


#define S3C_GPB_BASE              0x56000010
#define GPBCON_OFFSET             0
#define GPBDAT_OFFSET             4
#define GPBUP_OFFSET              8
#define S3C_GPB_LEN               0x10        /* 0x56000010~0x56000020  */


int led[LED_NUM] = {5,6,8,10};  /* Four LEDs use GPB5,GPB6,GPB8,GPB10 */


static void __iomem *s3c_gpb_membase;




#define s3c_gpio_write(val, reg) __raw_writel((val), (reg)+s3c_gpb_membase)      //#define __raw_readl(a)   (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a))
#define s3c_gpio_read(reg)       __raw_readl((reg)+s3c_gpb_membase)              //#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force   *)(a) = (v))




int dev_count = ARRAY_SIZE(led);
int dev_major = LED_MAJOR;
int dev_minor = 0;
int debug = DISABLE;


static struct cdev      *led_cdev;


static int s3c_hw_init(void)       //初始化硬件的函数
{
    int          i;
    volatile unsigned long  gpb_con, gpb_dat, gpb_up;


    if(!request_mem_region(S3C_GPB_BASE, S3C_GPB_LEN, "s3c2440 led"))  //申请一段内存空间失败的话返回为0
    {
        return -EBUSY;
    }


    if( !(s3c_gpb_membase=ioremap(S3C_GPB_BASE, S3C_GPB_LEN)) )   //物理地址到虚拟地址的映射  此时开启了MMU
    {
        release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN);   
        return -ENOMEM;
    }


    for(i=0; i<dev_count; i++)
    {
        /* Set GPBCON register, set correspond GPIO port as input or output mode  */
        gpb_con = s3c_gpio_read(GPBCON_OFFSET); 
        gpb_con &= ~(0x3<<(2*led[i]));   /* Clear the currespond LED GPIO configure register */
        gpb_con |= GPIO_OUTPUT<<(2*led[i]); /* Set the currespond LED GPIO as output mode */
        s3c_gpio_write(gpb_con, GPBCON_OFFSET);


        /* Set GPBUP register, set correspond GPIO port pull up resister as enable or disable  */
        gpb_up = s3c_gpio_read(GPBUP_OFFSET);
        //gpb_up &= ~(0x1<<led[i]); /* Enable pull up resister */
        gpb_up |= (0x1<<led[i]);  /* Disable pull up resister */
        s3c_gpio_write(gpb_up, GPBUP_OFFSET);


        /* Set GPBDAT register, set correspond GPIO port power level as high level or low level */
        gpb_dat = s3c_gpio_read(GPBDAT_OFFSET);
        //gpb_dat &= ~(0x1<<led[i]); /* This port set to low level, then turn LED on */
        gpb_dat |= (0x1<<led[i]);  /* This port set to high level, then turn LED off */
        s3c_gpio_write(gpb_dat, GPBDAT_OFFSET);
    }


    return 0;
}




static void turn_led(int which, unsigned int cmd)   //ioctl 会调用的函数来控制led的开关
{
    volatile unsigned long  gpb_dat;


    gpb_dat = s3c_gpio_read(GPBDAT_OFFSET);


    if(LED_ON == cmd)
    {
        gpb_dat &= ~(0x1<<led[which]); /*  Turn LED On */
    }
    else if(LED_OFF == cmd)
    {
        gpb_dat |= (0x1<<led[which]);  /*  Turn LED off */
    }


    s3c_gpio_write(gpb_dat, GPBDAT_OFFSET);
}


static void s3c_hw_term(void)    //在rmmode的时候会调用 做一些清理的工作 关灯和 内存释放取消地址的映射
{
    int                     i;
    volatile unsigned long  gpb_dat;


    for(i=0; i<dev_count; i++)
    {
        gpb_dat = s3c_gpio_read(GPBDAT_OFFSET);
        gpb_dat |= (0x1<<led[i]);  /* Turn LED off */
        s3c_gpio_write(gpb_dat, GPBDAT_OFFSET);
    }


    release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN);  //宏,释放指定的I/O内存资源  #define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) 
    iounmap(s3c_gpb_membase);  //iounmap函数用于取消ioremap()所做的映射
}




static int led_open(struct inode *inode, struct file *file)   //传给file_opertion的.open 函数 就是给函数钩子赋值
{
    int minor = iminor(inode);    //iminor这个宏在 inode的这个结构体中有定义 这个宏是用来获得此设备号


    file->private_data = (void *)minor;


    printk(KERN_DEBUG "/dev/led%d opened.\n", minor);
    return 0;
}


static int led_release(struct inode *inode, struct file *file)     //在file_opertion 结构体中给.release 函数钩子 赋值
{
    printk(KERN_DEBUG "/dev/led%d closed.\n", iminor(inode));


    return 0;
}


static void print_help(void)
{
    printk("Follow is the ioctl() commands for %s driver:\n", DEV_NAME);
    //printk("Enable Driver debug command: %u\n", SET_DRV_DEBUG);
    printk("Turn LED on command  : %u\n", LED_ON);
    printk("Turn LED off command : %u\n", LED_OFF);


    return;
}


static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int which = (int)file->private_data;


    switch (cmd)
    {
        case LED_ON:


            turn_led(which, LED_ON);
            break;


        case LED_OFF:
            turn_led(which, LED_OFF);
            break;
    
        default:
            printk(KERN_ERR "%s driver don't support ioctl command=%d\n", DEV_NAME, cmd);
            print_help();
            break;
    }


    return 0;
}




static struct file_operations led_fops = 
{
    .owner = THIS_MODULE,
    .open = led_open,
    .release = led_release,  
    .unlocked_ioctl = led_ioctl,
};


static int __init s3c_led_init(void)
{
    int                    result;    //
    dev_t                  devno;    //设备编号


    if( 0 != s3c_hw_init() )
    {
        printk(KERN_ERR "s3c2440 LED hardware initialize failure.\n");
        return -ENODEV;
    }


    /*  Alloc the device for driver */
    if (0 != dev_major) /*  Static */
    {
        devno = MKDEV(dev_major, 0);            // 将主设备号和次设备号转换成dev_t 即转换成设备编号
        result = register_chrdev_region (devno, dev_count, DEV_NAME);   //如果分配成功进行, register_chrdev_region 的返回值是 0,失败的话返回个了负数 不能存取请求的空间
    }
    else
    {
        result = alloc_chrdev_region(&devno, dev_minor, dev_count, DEV_NAME); //在上面静态分配出错时,就会使用该函数动态分配。&devno就是为把分配的设备编号放在这个地址
        dev_major = MAJOR(devno);
    }


    /*  Alloc for device major failure */
    if (result < 0)   
    {
        printk(KERN_ERR "S3C %s driver can't use major %d\n", DEV_NAME, dev_major);
        return -ENODEV;
    } 
    printk(KERN_DEBUG "S3C %s driver use major %d\n", DEV_NAME, dev_major);


    if(NULL == (led_cdev=cdev_alloc()) )     
    {
        printk(KERN_ERR "S3C %s driver can't alloc for the cdev.\n", DEV_NAME);
        unregister_chrdev_region(devno, dev_count);
        return -ENOMEM;
    }
    
    led_cdev->owner = THIS_MODULE;
    cdev_init(led_cdev, &led_fops);


    result = cdev_add(led_cdev, devno, dev_count);
    if (0 != result)
    {   
        printk(KERN_INFO "S3C %s driver can't reigster cdev: result=%d\n", DEV_NAME, result); 
        goto ERROR;
    }


            
    printk(KERN_ERR "S3C %s driver[major=%d] version %d.%d.%d installed successfully!\n", 
            DEV_NAME, dev_major, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);
    return 0;




ERROR:
    printk(KERN_ERR "S3C %s driver installed failure.\n", DEV_NAME);
    cdev_del(led_cdev);
    unregister_chrdev_region(devno, dev_count);
    return result;
}


static void __exit s3c_led_exit(void)
{
    dev_t devno = MKDEV(dev_major, dev_minor);


    s3c_hw_term();


    cdev_del(led_cdev);
    unregister_chrdev_region(devno, dev_count);


    printk(KERN_ERR "S3C %s driver version %d.%d.%d removed!\n", 
            DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);


    return ;
}






/* These two functions defined in <linux/init.h> */
module_init(s3c_led_init);
module_exit(s3c_led_exit);


module_param(debug, int, S_IRUGO);    //在insmod的时候可以传参   
module_param(dev_major, int, S_IRUGO);


MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");

下面是我们应用程序

#include <stdio.h>
  2 #include <sys/ioctl.h>
  3 #include <sys/stat.h>
  4 #include <unistd.h>
  5 #include <stdarg.h>
  6 #include <errno.h>
  7 #include <sys/types.h>   //open
  8 #include <sys/stat.h> //open 
  9 #include <fcntl.h>     //open
 10 #include <string.h>
 11 #include <unistd.h>   //close
 12 
 13 #define  LED_NUM   4
 14 #define   DEVNAMELEN  10
 15 
 16 
 17 
 18 #define  PLATDRV_MAGIC   0x60
 19 #define  LED_ON       _IO(PLATDRV_MAGIC,0x18)
 20 #define  LED_OFF       _IO(PLATDRV_MAGIC,0x19)
 21 
 22 
 23 
 24 int main(int argc, char ** argv)
 25 {
 26     int i;
 27     char dev_name[DEVNAMELEN]={0};
 28     int fd[LED_NUM];
 29     int b;
 30 
 31      for(i=0;i<LED_NUM;i++)
 32     {
 33         snprintf(dev_name,sizeof(dev_name),"/dev/led%i",i);   //snprint 并不是打印在标称输出上让是在发音在第一个参数里边
 34         fd[i]=open(dev_name,O_RDWR,755);      
 35        if(fd[i]<0)
 36        {
 37            printf("open file  %s deflout,%s",dev_name,strerror(errno));
 38            for(b=0;b<i;b++)               //如果出错了把之前打开的文件一定要close
 39           {
 40            if(fd[b]>0)
 41            close(fd[b]);
 42            }
42            }
 43          return -1;
 44        }
 45     }
 46 
 47 
 48 
 49 
 50    while(1)
 51    {
 52 
 53      for(i=0;i<LED_NUM;i++)
 54       {
 55          ioctl(fd[i], LED_ON);
 56          sleep(1);  
 57          ioctl(fd[i], LED_OFF);
 58 
 59       }
 60 
 61     }
 62 
 63       for(i=0;i<LED_NUM;i++)
 64     {
 65         close(fd[i]);
 66     }
 67 }
这个应用程序要用我们自己的交叉编译器编译通过之后,再把可执行文件通过tftp放在我们的2440开发板上

 Makefile的编写

 Makefile                                                                                                                                                              
  1 CC=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc
  2 KDIR?=/home/guanlei/fl2440/kernel/linux-3.0
  3 obj-m:=s3c_led.o
  4 
  5 default:
  6     $(MAKE) -C $(KDIR) M=`pwd` modules
  7     make clean
  8 
  9 clean:
 10     rm -f *.ko.* *.o *mod.c *.order *.symvers

make 会生成led.ko的文件,这个文件也是我们所要的led驱动模块,同样也把驱动模块tftp到我们的飞凌2440开发板上,如果完成上边的步骤在板子上会有我们的ledapp文件和s3c_led.ko的文件。开始加载驱动 

insmod s3c_led.ko这是我们可以看到自己的主设备号【major=252】

因为在我们的驱动中并没有自动的创建设备结点所以我们要手动的创建设备结点

mknod  /dev/led0 c 252 0

mknod  /dev/led1 c 252 1

.....             

mknod  /dev/led3 c 252  3                               

查看我们设备文件

ls -l  dev/led* 

下面就是激动人心的时刻 ./ledapp 看见酷炫的跑马灯了吧!!!!


                                                                                                                                                           

  










0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 生完孩子有肚腩怎么办 生完宝宝肚子还是很大怎么办 生完孩子小腹大怎么办 生完孩子肚皮松怎么办 生过孩子肚子松怎么办 生完孩子肚皮痒怎么办 生完小孩肚子松弛怎么办 生了孩子肚子大怎么办 嫁到别的省户口怎么办 孕中期假性宫缩怎么办 频繁的假性宫缩怎么办 显卡风扇不转了怎么办 老是想不好的事怎么办 做人工受孕多囊怎么办 子宫内有囊肿该怎么办 子宫长了个囊肿怎么办 怀孕后不想要该怎么办 20多岁雌激素低怎么办 生完小孩后子宫下垂怎么办 取环之前同房了怎么办 做人流后又怀孕怎么办 仓鼠长了个肿瘤怎么办 过敏留下的黑印怎么办 脸上痘痘发炎了怎么办 脸上皮肤红痒怎么办啊 皮肤有一片红痒怎么办 脸过敏期间很干怎么办 怀孕了用了消糜栓怎么办 乳酸杆菌少或无怎么办 怀孕了白带有异味怎么办 怀孕清洁度iv度怎么办 怀孕了下面有异味怎么办 孕妇尿白细胞1是怎么办 药流期间喂奶了怎么办 20多岁卵巢早衰怎么办 3岁儿童肚子胀气怎么办 肚子又胀又痛怎么办 1岁宝宝肚子胀气怎么办 2岁宝宝肚子胀气怎么办 产后腰粗肚子大怎么办 发烧后腹泻拉水怎么办