2019-08-26 18:04:43 weixin_42462202 阅读数 854
  • linux设备驱动模型-linux驱动开发第5部分

    本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式改造,终目标是让大家彻底掌握linux的总线式设备驱动模型。

    4891 人正在学习 去看看 朱有鹏
2018-03-24 14:50:59 fenglang1233307 阅读数 1138
  • linux设备驱动模型-linux驱动开发第5部分

    本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式改造,终目标是让大家彻底掌握linux的总线式设备驱动模型。

    4891 人正在学习 去看看 朱有鹏

    刚开始接触Linux的驱动,暂时只是从Linux驱动模块的角度出发,编写最简单的linux驱动模块,先贴代码~~~


         一个驱动模块有一下几部分组成:1、头文件 2、模块的装载函数和卸载函数的实现 3、模块的装载函数和卸载函数的声明 4、模块的GPL声明。

       这里说的头文件只是包含最基本的两个头文件:linux/init.h和linux/module.h,装载函数声明的格式就是module_init(),参数自定义,同理,卸载函数的声明也类似,至于装载函数的实现也是类似于上面的格式,唯一注意的是返回值,装载函数有返回值,卸载函数没有。printk只是打印出函数名而已。

好了,最简单的驱动模块写好了,下面就该写Makefile了。


       这里注意三个地方,一个是第4行的根文件系统所在目录,一个是第5行的内核所在目录,一个是第17行目标文件名,其他地方基本相同,以后需要修改的也就只有目标文件了。这里说一下Makefile的实现过程,首先是ifeq里面的内容,第一次执行make时KERNELRELEASE没有在内核定义,所以先执行伪目标all,make -C指定内核所在的目录,当执行到这里时前面的KERNELRELEASE就被内核定义了,继续执行M这句,是在当前目录中编译文件为模块,至于编译当前目录的哪个文件为模块就不知道了。之后make又从头开始执行,这时候KERNELRELEASE已被定义,执行else里面的内容,找到当前目录下的hello.c自动编译成hello.o,最后链接成hello.ko。makefile至此结束。

       将hello.ko手动加载进内核,提示装载函数里面的内容,这是模块的入口函数,加载模块进内核时会自动执行,我们再将模块进行卸载,可以看到此时提示的内容就是模块卸载函数里面的内容,从内核中卸载模块时会自动执行模块卸载函数里的内容。


    好了,这就是一个最简单的内核模块的编写以及加载和卸载。

2016-07-08 11:14:55 cole10540316 阅读数 525
  • linux设备驱动模型-linux驱动开发第5部分

    本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式改造,终目标是让大家彻底掌握linux的总线式设备驱动模型。

    4891 人正在学习 去看看 朱有鹏

linux驱动–LED驱动

配置介绍

前面已经详细的介绍了关于设备注册、驱动注册以及设备节点的生成的相关问题,本文主要介绍如何写LED驱动程序。


主要介绍GPIO的 调用、赋值以及配置的函数

(1)使用一个GPIO前必须对其进行申请,申请GPIO的函数在linux头文件include/linux/gpio.h下

GPIO_request函数有两个参数,第一个gpio为所需要申请的gpio,*label为gpio编号,是为了便于阅读。若该gpio被占用,则返回错误表示被占用。

与GPIO_request对应的是gpio_free函数,操作方法只需要传入gpio端口号即可。


(2)配置完GPIO后,需要对其设置值,就需要使用gpio_set_value函数了

两个参数分别为
unsigned gpio,GPIO
int value,高电平 1 和低电平 0


(3)GPIO输出方式配置
在平台文件中arch/arm/plat-samsung/include/plat/gpio-cfg.h中使用函数extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to)

参数 unsigned int pin,管脚

参数 unsigned int to,配置参数。

to参数可以取值如下
arch/arm/plat-samsung/include/plat/gpio-cfg.h中定义的to取值

#define S3C_GPIO_INPUT    (S3C_GPIO_SPECIAL(0))
#define S3C_GPIO_OUTPUT   (S3C_GPIO_SPECIAL(1))
#define S3C_GPIO_SFN(x)    (S3C_GPIO_SPECIAL(x))

LED驱动例程

    #include <linux/module.h>//与module相关的信息
    #include <linux/kernel.h>
    #include <linux/init.h>      //与init相关的函数
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    /***gpio申请和释放***/
    #include <linux/gpio.h>
    /*******************/
    #include <plat/gpio-cfg.h>
    /*********************/
    #include <mach/gpio-exynos4.h>
    #include <mach/gpio.h>
    /***************用到的函数与结构体******************
    extern int platform_driver_register(struct platform_driver *);
    extern void platform_driver_unregister(struct platform_driver *);

            int (*probe)(struct platform_device *);
            int (*remove)(struct platform_device *);
            void (*shutdown)(struct platform_device *);
            int (*suspend)(struct platform_device *, pm_message_t state);
            int (*resume)(struct platform_device *);
    杂项设备结构体
    struct miscdevice  {
            int minor;
            const char *name;
            const struct file_operations *fops;
            struct list_head list;
            struct device *parent;
            struct device *this_device;
            const char *nodename;
            mode_t mode;
    };

    extern int misc_register(struct miscdevice * misc);
    extern int misc_deregister(struct miscdevice *misc);

    struct file_operations {
            struct module *owner;
             long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
            long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
            int (*mmap) (struct file *, struct vm_area_struct *);
            int (*open) (struct inode *, struct file *);
            int (*flush) (struct file *, fl_owner_t id);
            int (*release) (struct inode *, struct file *);
            int (*fsync) (struct file *, int datasync);
            int (*aio_fsync) (struct kiocb *, int datasync);
            int (*fasync) (int, struct file *, int);
            int (*lock) (struct file *, int, struct file_lock *);
    static inline int gpio_request(unsigned gpio, const char *label)
    static inline void gpio_free(unsigned gpio)
    static inline void gpio_set_value(unsigned gpio, int value)
    EXYNOS4_GPIO_L2
    s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
    S3C_GPIO_OUTPUT
    **********************************/

    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("zhangsan");

    #define DRIVER_NAME "hello_ctl"
    #define DEVICE_NAME "hello_ctl"

    static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
        printk(KERN_INFO "The cmd is %d,arg is %d\n",cmd,arg);
        if(cmd>1)
        {
           printk(KERN_INFO "cmd should be 0 or 1\n");
        }
        if(arg>1)   
        printk(KERN_INFO "arg must be 1\n");
        gpio_set_value(EXYNOS4_GPL2(0), cmd);//关闭
        return 0;
    }
    static int hello_release(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "hello_release\n");    
        return 0;
    }
    static int hello_open(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "hello_open\n");   
        return 0;
    }

    static struct file_operations hello_ops={

        .owner=THIS_MODULE,
        .open=hello_open,
        .release=hello_release,
        .unlocked_ioctl=hello_ioctl,
    };

    static struct miscdevice hello_dev={
        .minor=MISC_DYNAMIC_MINOR,
        .name=DEVICE_NAME,
        .fops=&hello_ops,
    };

    static int hello_probe(struct platform_device *pdv)
    {
        int ret;
        printk(KERN_INFO "program inited!\n");
        ret=gpio_request(EXYNOS4_GPL2(0),"LED1");
        if(ret<0)
        {
           printk(KERN_INFO "request gpio failed\n");
           return ret;  
        }
        s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
        gpio_set_value(EXYNOS4_GPL2(0), 0);//关闭
        misc_register(&hello_dev);

        return 0;
    }
    static int hello_remove(struct platform_device *pdv)
    {
        gpio_free(EXYNOS4_GPL2(0));
        misc_deregister(&hello_dev);
        return 0;
    }
    static void hello_shutdown(struct platform_device *pdv)
    {
        printk(KERN_INFO "hello_shutdown\n");   
    }
    static int hello_suspend(struct platform_device *pdv)
    {
        printk(KERN_INFO "Hello_suspend\n");
        return 0;
    }
    static int hello_resume(struct platform_device *pdv)
    {
        printk(KERN_INFO "Hello_resume\n");
        return 0;
    }

    struct  platform_driver hello_driver={
        .probe=hello_probe,
        .remove=hello_remove,
        .shutdown=hello_shutdown,
        .suspend=hello_suspend,
        .resume=hello_resume,
        .driver={
            .name=DRIVER_NAME,
            .owner=THIS_MODULE,
        }
    };

    static int hellodriver_init()
    {
        int Driverstate;
        //printk(KERN_INFO "Hello_init\n");
        Driverstate=platform_driver_register(&hello_driver);
        printk(KERN_INFO "Driverstate is %d\n",Driverstate);
        return 0;
    }

    static void hellodriver_exit()
    {

        printk(KERN_INFO "Hello_exit\n");
        platform_driver_unregister(&hello_driver);
    }


    module_init(hellodriver_init);
    module_exit(hellodriver_exit);

驱动调用程序

写简单的驱动调用程序测试驱动

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

    int main()
    {
        int fd;
        char *hellonode="/dev/hello_ctl";
        if((fd=open(hellonode,O_RDWR|O_NOCTTY|O_NDELAY))<0)
        {
            printf("open %s.failed",hellonode);
        }
        else
        {
            printf("APP open %s sucess!",hellonode);
            ioctl(fd,0,1);
            sleep(2);
            ioctl(fd,1,1);
            sleep(2);
            ioctl(fd,0,1);
            sleep(2);
            ioctl(fd,1,1);
            sleep(2);
        }

        close(fd);
        return 0;
    }
2019-11-21 14:43:00 gaoyanli1972 阅读数 151
  • linux设备驱动模型-linux驱动开发第5部分

    本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式改造,终目标是让大家彻底掌握linux的总线式设备驱动模型。

    4891 人正在学习 去看看 朱有鹏

Linux驱动开发培训系列教程网址https://edu.csdn.net/course/detail/26814

一,如何学习Linux驱动

我们学习驱动的目的是自己编写驱动。由此延伸出的学习技巧就是:
1,写一个驱动,尽量多参考别人的驱动,在他人驱动的基础上进行修改。尽量回避从零开始写一个驱动。
2,不要总是想着分析内核代码,能正确使用内核提供的相关函数即可。Linux内核中涉及的知识点总是互相交错,不适合初学者阅读。在有一定的基础之后,分析和自己直接相关的内核源代码,可以加深对驱动的理解。
3,百度是最好的老师。遇到问题,不要到处跪求。我们平时遇到的问题,在百度中基本都有答案,要培养自学的能力。

二,Linux驱动开发流程介绍

第一步:根据需求,上网搜索相关资料。
第二步:在一个驱动模板基础上进行修改。
第三步:把该驱动文件以模块的形式,进行编译。然后插入内核,进行调试。如果有错,从内核中移除该模块,修改之后再次调试。直到正确为止。
第四步:把该模块编译进内核,成为内核代码的一部分。

2014-10-07 17:33:07 PAPOSKY 阅读数 276
  • linux设备驱动模型-linux驱动开发第5部分

    本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式改造,终目标是让大家彻底掌握linux的总线式设备驱动模型。

    4891 人正在学习 去看看 朱有鹏

加油,今天很美好,明天会更好!

最近用十天的时间把linux设备驱动的课程基本过了一遍,但是还是感觉如蜻蜓点水,所以打算写下一些博客重新总结自己学过的所有驱动,并深入源码剖析驱动过程。

驱动开发是和硬件息息相关的,所以我一直觉得自己干的更像是硬件工程师的活,后面的所有驱动分析都先从硬件入手,也就是datasheet,原理图,从原理图看出硬件相关属性,从datasheet看出寄存器的配置,从源代码找到驱动接口。

linux驱动程序设计

阅读数 741

linux驱动概述

阅读数 209

没有更多推荐了,返回首页