精华内容
下载资源
问答
  • 绝对干货~~学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动设备驱动模型和sysfs等相关概念和技术。对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术...

    Linux驱动开发的童鞋们来膜拜吧:-) 

    学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了。要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码。网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析。对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给学习者而言,横向比较关联各个驱动相关的知识点和纵向剖析Linux整个驱动软件层次是非常有必要的,也非常有意义。

    本文依然是从需求的角度去理解以上知识点,存在即是合理,以上技术知识能够存在,即代表其有一定的作用。我们着重去理解每一个技术点的作用,并明确其在驱动开发中的角色。

    一、设备驱动

    Linux设备驱动分三种,包括字符设备驱动、块设备驱动和网络设备驱动。字符设备只能按字节流先后顺序访问设备内存,不能随机访问。鼠标、触摸屏、LCD等是字符设备的代表。块设备可以随机访问设备内存的任意地址,硬盘、SD卡、NAND FLASH是块设备的代表。网络设备指的是网卡一类使用socket套接字进行通信的设备。本文以字符设备为例讲述相关知识。

    二、字符设备驱动

    字符设备驱动框架请参考嵌入式企鹅圈的两篇文章:

     Linux字符设备驱动剖析

    Linux 设备文件的创建和mdev

    1.    字符设备驱动纵向关系

    从< Linux字符设备驱动剖析>可以看出,应用层访问设备驱动非常简单,即是通过open接口来最终获得设备驱动的操作接口集struct file_opertions.而open接口传入的参数是/dev目录下的设备名。而从<Linux 设备文件的创建和mdev>可以知道,设备名对应的设备文件节点inode会存储设备号,而驱动框架中的全局数组cdev_map则维护设备号和file_opertions的关系。即应用层到底层的关系主要是(忽略VFS这一层):

    设备名-->设备号-->file_opertions

    Open函数返回的局部fd和file_opertions的关系(忽略进程数据结构)如下:

    fd-->file(当前进程数据结构成员)-> file_opertions

    这样,通过fd即可以获得file_opertions,即可以通过read、write等接口来调用驱动的读操作函数和写操作函数、ioctl函数等。

    2.    字符设备驱动的任务

    1)字符设备驱动最本质的任务应该是提供file_opertions的各个open、read、write、ioctl等接口的实现。

    另外从以上的描述中,为了让应用层能够调用到底层的file_opertions还涉及到以下任务:

    2)申请设备号,并将设备号和file_opertions注册(cdev_add接口)到驱动框架中的cdev_map数组。这点应该在字符设备驱动中负责,涉及到其主动向系统报备自己的存在。

    3)在/dev目录中创建设备文件,内容包括设备号。这一点是否由字符设备驱动来负责商榷。字符设备驱动位于内核层,如果由其负责这个任务,那么驱动就得知道它要创建的设备名。简单的字符驱动还好,如果是USB等可插拔的设备,驱动怎么知道自己要创建什么设备名呢?有人说可以写明一套规则。确实如此,但如果把这套规则放到应用层,由应用程序开发人员去明确这个规则(mdev正是这样做的),会不会更好?因为是应用程序直接编程访问这个设备名对应的设备驱动的。所以字符设备驱动不应该直接负责设备文件的创建。

    3. 谁来创建设备文件

           总得有人出来做吧,否则应用层怎么访问啊?

           一种方法就是用户在shell中使用mknod命令创建设备文件,同时传入设备名和设备号。这是人工的做法,很不科学。但它是一种演示的方法。

           另外一种方法就是依赖设备模型来辅助创建设备文件。这也是设备模型的作用之一。

    4. 字符设备驱动编程流程

           1)定义struct file_opertions my_fops并实现其中的各个接口,如open、read、write、ioctl等接口。

           2)实现驱动的入口函数,如chardev_init

                  static int __init chardev_init(void){

                         alloc_chrdev_region(&devno,…);//申请设备号

                         my_cdev=cdev_alloc();

                         cdev_init(my_cdev,&my_fops);

                         cdev_add(my_fops,devno, 1);//注册设备号和file_opertions

                  }

           3)module_init(chardev_init);//宏定义该初始化入口函数。卸载流程不做解释。

           4)insmod加载这个module后,可以人工在shell命令行利用mknod创建设备文件。

           5)应用层即可以用open来打开设备文件来进行访问了。

    5.    总结

    可以看出,字符设备驱动的核心框架跟设备模型、平台设备驱动没有直接关系,不用他们也一样能够正常工作。

    三、设备驱动模型

    我们主要谈及设备驱动模型在linux驱动中的作用和角色,有关设备模型的原理和实现我们另文再述。

    1. 设备驱动模型的作用

    1)设备驱动模型实现uevent机制,调用应用层的medv来自动创建设备文件。这在上面已经论述过。

    2)设备驱动模型通过sysfs文件系统向用户层提供设备驱动视图,如下。


    上图只是可视化的一种表达,有助于大家去理解设备模型,类似于windows的设备管理程序,在嵌入式linux里面并没有相关应用通过图形的方式来展现这种关系。但是用户可以通过命令窗口利用ls命名逐级访问/sys文件夹来获得各种总线、设备、驱动的信息和关系。可以看出,在/sys顶级目录,有三个关键的子目录,就是设备类、设备和总线。

    设备是具体的一个个设备,在/sys/devices/是创建了实际的文件节点。而其他目录,如设备类和总线以下的子目录中出现的设备都是用符号链接指向/sys/devices/目录下的文件。

    设备类是对/sys/devices/下的各种设备进行归类,以体现一类设备的公共属性,如鼠标和触摸屏都是属于input设备类。

    总线目录是总线、设备、驱动模型的核心目录。因为设备和驱动都是依附在某种总线上的,如USB、PCI和平台总线等。设备和驱动正是依靠总线的管理功能才能找到对方,如设备注册到总线时去寻找驱动,而驱动注册的时候去寻找其能够支持的设备。

    最重要的是,如果没有设备模型,那应用层很难知晓驱动和设备的关系,因为字符设备驱动并没有提供这些信息,那对于设备驱动的管理者而言会非常麻烦。

    事实上,内核中的总线class、设备device和驱动device_driver都不会将所有的信息暴露给用户层,例如这三个数据结构都有对应的private数据结构,它用于内核对上下级总线设备驱动的链表关系维护。如果暴露给用户层,那容易被用户层修改而使系统混乱。实际上,用户层只关心三者的视图关联,至于他们的关联在底层怎么实现则不需要关心。

    3)设备驱动模型提供统一的电源管理机制。很明显,我们在字符设备驱动的file_operations接口中并没有看到电源管理方面的接口。而对于操作系统来说,电源功耗管理必不可少。电源管理其实不应该由应用开发人员来负责,而是应该由系统来负责,例如手机很久没有触摸了,那会进入休眠状态。这种状态的改变应该由系统来完成,而各种设备进入睡眠模式也应该由系统来完成。因此file_operations不提供电源管理的接口给应用程序是合理的。而设备模型作为系统管理的一种机制,由它来提供电源管理是非常合理的。

           如设备device数据结构有struct dev_pm_info    power功耗属性参数,驱动device_driver数据结构有struct dev_pm_ops *pm功耗操作接口。

           4)设备驱动模型提供各种对象实例的引用计数,防止对象被应用层误删。设备模型的所有数据结构均是继承kobject而来,而kobject就提供基础的计数功能。

           5)设备驱动模型提供多一种方式给应用层,用户和内核可以通过sysfs进行交互,如通过修改/sys目录下设备的文件内容,即可以直接修改设备对应的参数。

           总结,设备驱动模型侧重于内核对总线、设备和驱动的管理,并向应用层暴露这些管理的信息,而字符设备驱动则侧重于设备驱动的功能实现。

    2. 设备驱动模型的核心接口

           bus_register(struct bus_type *bus) 注册总线

    device_add(struct device *dev) 注册设备

           driver_register(struct device_driver*drv) 注册驱动

           class_create(owner, name) 创建设备类

           等等

    3.    设备驱动模型和字符设备驱动区别

    设备驱动模型侧重于内核对总线、设备和驱动的管理,并向应用层暴露这些管理的信息,而字符设备驱动则侧重于设备驱动的功能实现。

    四、sysfs文件系统

    1.sysfs文件系统和设备驱动模型的关系

    Sysfs文件系统是设备驱动模型得以向用户暴露其管理信息的载体。它们之间的关系如下:

    1)设备驱动模型的上下级关系(如子设备和所属父设备)通过sysfs文件系统的父目录和子目录来体现。

    2)设备驱动模型的平级关系(如设备类管理的设备和具体的设备的关系)则通过sysfs文件系统的目录符号链接来实现。

    3)设备驱动模型的属性(如设备的参数和设备名,设备号等)则通过sysfs文件系统的文件内容来记录实现。

           4)设备驱动模型数据结构中的kobject对应于sysfs文件系统中的目录,而数据结构中的struct attribute成员则对应于sysfs文件系统中的文件。对应的意思是指继续与kobject的device、device_driver和bus等在向系统注册的过程中会调用sysfs的create_dir接口来创建对应的目录,而含有struct attribute成员属性的device、device_driver和bus等在向系统注册的过程中则会调用sysfs的sysfs_create_file接口来创建文件。

    2.sysfs核心接口

           sysfs_create_file(struct kobject * kobj,const struct attribute * attr)创建属性文件

           sysfs_create_dir(struct kobject * kobj)创建目录

           int sysfs_open_file(struct inode *inode,struct file *file)打开sysfs文件系统格式的文件

           sysfs_read_file(struct file *file, char__user *buf, size_t count, loff_t *ppos) 读操作

           sysfs_write_file(struct file *file, constchar __user *buf, size_t count, loff_t *ppos) 写操作

    3. sysfs文件系统与属性文件读写

           sysfs_read_file是sysfs文件系统的读写入口,但是驱动需要向系统提供真正的读写操作,也即是struct sysfs_ops数据结构中的show和store接口。

           Sysfs是基于内存的文件系统,掉电即消失,sysfs所有的操作接口均是对内存中的内核数据结构进行访问操作。假如用户用cat命令去读取一个属性文件(如dev)的内容,那么会产生以下流程:

           1)fd=open(“dev”)->vfs_open(“dev”)->sysfs_open(“dev”)获取该文件的句柄

           2)read()->vfs_read()->sysfs_read_file()->sysfs_ops->show()该show接口即是设备在注册时产生属性文件,并向系统提供该文件的读接口。而读接口的实现中自然是对该属性参数的读访问。

           /sys挂载了sysfs文件系统,因此所有对/sys目录下的文件或者目录的操作都会通过sysfs文件的接口进行访问。

    五、平台设备驱动

    平台设备驱动中的“平台”指的是平台总线,即platform_bus_type,是linux众多总线中的一种,如USB总线、PCI总线、I2C总线等等。只不过平台总线是一种虚拟的总线,专门用来管理SOC上的控制器(如看门狗、LCD、RTC等等),它们都是CPU的总线上直接取址访问设备的。而USB、PCI等设备都有通过特定的时序来访问SOC芯片以外的设备。平台设备驱动体现的关系是设备驱动模型上的一个子集,将平台视为一种总线的概念,那两者的关系就会容易理解。

    1.    平台设备驱动和设备驱动模型的关系

    1)平台设备驱动接口在设备驱动模型视图上创建了相关的平台设备类(/sys/class/platform_bus)、平台总线(/sys/bus/platform)、平台设备(/sys/devices/).

    2)平台设备(platform_device)和平台设备驱动(platform_driver)均注册到平台总线上,即在/sys/bus/platform/目录下创建相应的设备和驱动目录。

    3)平台总线负责匹配注册到其上面的设备和驱动,匹配成功后回调用驱动的probe接口。

    4)平台设备驱动利用设备驱动模型接口来辅助创建对应的设备文件(位于/dev/目录下)。

     

    相关的接口包括:

    platform_device_register(structplatform_device *pdev) 注册平台设备

    platform_driver_register(structplatform_driver *drv) 注册平台设备驱动

    两个接口的实现里面都会对平台驱动和设备进行匹配,匹配成功会调用驱动的probe接口。

     

    2. 平台设备驱动和字符设备驱动的关系

           我们假设这个平台设备是字符设备。

    平台设备驱动和字符设备驱动的关系始于驱动的probe接口,即在probe接口中实现字符设备驱动所要完成的任务,即通过alloc_chrdev_region申请设备号和通过cdev_add注册驱动的struct file_opertions.另外为了自动创建应用层访问的设备文件,还要调用class_create和device_create接口在平台设备类下创建对应的设备类和设备,并发出uevent事件,调用mdev来创建设备文件。

    3. 平台设备驱动的开发流程

           1)将字符设备驱动的char_init函数的实现搬到platform_driver的probe接口中。

           2)在char_init中调用platform_device_register和platform_driver_register分别注册设备和驱动。其实,对于移植好的系统,platform_device_register是在linux启动的过程中完成的。因此char_init一般只有platform_driver_register注册驱动。

           详细的平台设备驱动的实现原理和开发流程另文再述。本次的重点是为了阐述字符设备驱动、设备驱动模型、sysfs和平台设备驱动之间的关系。

     

    博主微信公众号:嵌入式企鹅圈,百分百原创分享嵌入式Linux开发经验知识,绝对干货!


    展开全文
  • 横向比较关联各个驱动相关的知识点(字符设备驱动、平台设备驱动设备驱动模型、sysfs)和纵向剖析Linux整个驱动软件层次,对于Linux驱动的理解和开发很有帮助,绝对干货!

    Linux驱动开发经验总结,绝对干货!

    学习Linux设备驱动开发的过程中自然会遇到字符设备驱动、平台设备驱动、设备驱动模型和sysfs等相关概念和技术。对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了。要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码。网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析。对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给学习者而言,横向比较关联各个驱动相关的知识点和纵向剖析Linux整个驱动软件层次是非常有必要的,也非常有意义。

    本文依然是从需求的角度去理解以上知识点,存在即是合理,以上技术知识能够存在,即代表其有一定的作用。我们着重去理解每一个技术点的作用,并明确其在驱动开发中的角色。

    一、设备驱动

    Linux设备驱动分三种,包括字符设备驱动、块设备驱动和网络设备驱动。字符设备只能按字节流先后顺序访问设备内存,不能随机访问。鼠标、触摸屏、LCD等是字符设备的代表。块设备可以随机访问设备内存的任意地址,硬盘、SD卡、NAND FLASH是块设备的代表。网络设备指的是网卡一类使用socket套接字进行通信的设备。本文以字符设备为例讲述相关知识。

    二、字符设备驱动

    字符设备驱动框架请参考嵌入式企鹅圈的两篇文章:

     Linux字符设备驱动剖析

    Linux 设备文件的创建和mdev

    1.    字符设备驱动纵向关系

    从< Linux字符设备驱动剖析>可以看出,应用层访问设备驱动非常简单,即是通过open接口来最终获得设备驱动的操作接口集struct file_opertions.而open接口传入的参数是/dev目录下的设备名。而从<Linux 设备文件的创建和mdev>可以知道,设备名对应的设备文件节点inode会存储设备号,而驱动框架中的全局数组cdev_map则维护设备号和file_opertions的关系。即应用层到底层的关系主要是(忽略VFS这一层):

    设备名-->设备号-->file_opertions

    Open函数返回的局部fd和file_opertions的关系(忽略进程数据结构)如下:

    fd-->file(当前进程数据结构成员)-> file_opertions

    这样,通过fd即可以获得file_opertions,即可以通过read、write等接口来调用驱动的读操作函数和写操作函数、ioctl函数等。

    2.    字符设备驱动的任务

    1)字符设备驱动最本质的任务应该是提供file_opertions的各个open、read、write、ioctl等接口的实现。

    另外从以上的描述中,为了让应用层能够调用到底层的file_opertions还涉及到以下任务:

    2)申请设备号,并将设备号和file_opertions注册(cdev_add接口)到驱动框架中的cdev_map数组。这点应该在字符设备驱动中负责,涉及到其主动向系统报备自己的存在。

    3)在/dev目录中创建设备文件,内容包括设备号。这一点是否由字符设备驱动来负责商榷。字符设备驱动位于内核层,如果由其负责这个任务,那么驱动就得知道它要创建的设备名。简单的字符驱动还好,如果是USB等可插拔的设备,驱动怎么知道自己要创建什么设备名呢?有人说可以写明一套规则。确实如此,但如果把这套规则放到应用层,由应用程序开发人员去明确这个规则(mdev正是这样做的),会不会更好?因为是应用程序直接编程访问这个设备名对应的设备驱动的。所以字符设备驱动不应该直接负责设备文件的创建。

    3. 谁来创建设备文件

           总得有人出来做吧,否则应用层怎么访问啊?

           一种方法就是用户在shell中使用mknod命令创建设备文件,同时传入设备名和设备号。这是人工的做法,很不科学。但它是一种演示的方法。

           另外一种方法就是依赖设备模型来辅助创建设备文件。这也是设备模型的作用之一。

    4. 字符设备驱动编程流程

           1)定义struct file_opertions my_fops并实现其中的各个接口,如open、read、write、ioctl等接口。

           2)实现驱动的入口函数,如chardev_init

                  static int __init chardev_init(void){

                         alloc_chrdev_region(&devno,…);//申请设备号

                         my_cdev=cdev_alloc();

                         cdev_init(my_cdev,&my_fops);

                         cdev_add(my_fops,devno, 1);//注册设备号和file_opertions

                  }

           3)module_init(chardev_init);//宏定义该初始化入口函数。卸载流程不做解释。

           4)insmod加载这个module后,可以人工在shell命令行利用mknod创建设备文件。

           5)应用层即可以用open来打开设备文件来进行访问了。

    5.    总结

    可以看出,字符设备驱动的核心框架跟设备模型、平台设备驱动没有直接关系,不用他们也一样能够正常工作。

    三、设备驱动模型

    我们主要谈及设备驱动模型在linux驱动中的作用和角色,有关设备模型的原理和实现我们另文再述。

    1. 设备驱动模型的作用

    1)设备驱动模型实现uevent机制,调用应用层的medv来自动创建设备文件。这在上面已经论述过。

    2)设备驱动模型通过sysfs文件系统向用户层提供设备驱动视图,如下。


    上图只是可视化的一种表达,有助于大家去理解设备模型,类似于windows的设备管理程序,在嵌入式linux里面并没有相关应用通过图形的方式来展现这种关系。但是用户可以通过命令窗口利用ls命名逐级访问/sys文件夹来获得各种总线、设备、驱动的信息和关系。可以看出,在/sys顶级目录,有三个关键的子目录,就是设备类、设备和总线。

    设备是具体的一个个设备,在/sys/devices/是创建了实际的文件节点。而其他目录,如设备类和总线以下的子目录中出现的设备都是用符号链接指向/sys/devices/目录下的文件。

    设备类是对/sys/devices/下的各种设备进行归类,以体现一类设备的公共属性,如鼠标和触摸屏都是属于input设备类。

    总线目录是总线、设备、驱动模型的核心目录。因为设备和驱动都是依附在某种总线上的,如USB、PCI和平台总线等。设备和驱动正是依靠总线的管理功能才能找到对方,如设备注册到总线时去寻找驱动,而驱动注册的时候去寻找其能够支持的设备。

    最重要的是,如果没有设备模型,那应用层很难知晓驱动和设备的关系,因为字符设备驱动并没有提供这些信息,那对于设备驱动的管理者而言会非常麻烦。

    事实上,内核中的总线class、设备device和驱动device_driver都不会将所有的信息暴露给用户层,例如这三个数据结构都有对应的private数据结构,它用于内核对上下级总线设备驱动的链表关系维护。如果暴露给用户层,那容易被用户层修改而使系统混乱。实际上,用户层只关心三者的视图关联,至于他们的关联在底层怎么实现则不需要关心。

    3)设备驱动模型提供统一的电源管理机制。很明显,我们在字符设备驱动的file_operations接口中并没有看到电源管理方面的接口。而对于操作系统来说,电源功耗管理必不可少。电源管理其实不应该由应用开发人员来负责,而是应该由系统来负责,例如手机很久没有触摸了,那会进入休眠状态。这种状态的改变应该由系统来完成,而各种设备进入睡眠模式也应该由系统来完成。因此file_operations不提供电源管理的接口给应用程序是合理的。而设备模型作为系统管理的一种机制,由它来提供电源管理是非常合理的。

           如设备device数据结构有struct dev_pm_info    power功耗属性参数,驱动device_driver数据结构有struct dev_pm_ops *pm功耗操作接口。

           4)设备驱动模型提供各种对象实例的引用计数,防止对象被应用层误删。设备模型的所有数据结构均是继承kobject而来,而kobject就提供基础的计数功能。

           5)设备驱动模型提供多一种方式给应用层,用户和内核可以通过sysfs进行交互,如通过修改/sys目录下设备的文件内容,即可以直接修改设备对应的参数。

           总结,设备驱动模型侧重于内核对总线、设备和驱动的管理,并向应用层暴露这些管理的信息,而字符设备驱动则侧重于设备驱动的功能实现。

    2. 设备驱动模型的核心接口

           bus_register(struct bus_type *bus) 注册总线

    device_add(struct device *dev) 注册设备

           driver_register(struct device_driver*drv) 注册驱动

           class_create(owner, name) 创建设备类

           等等

    3.    设备驱动模型和字符设备驱动区别

    设备驱动模型侧重于内核对总线、设备和驱动的管理,并向应用层暴露这些管理的信息,而字符设备驱动则侧重于设备驱动的功能实现。

    四、sysfs文件系统

    1.sysfs文件系统和设备驱动模型的关系

    Sysfs文件系统是设备驱动模型得以向用户暴露其管理信息的载体。它们之间的关系如下:

    1)设备驱动模型的上下级关系(如子设备和所属父设备)通过sysfs文件系统的父目录和子目录来体现。

    2)设备驱动模型的平级关系(如设备类管理的设备和具体的设备的关系)则通过sysfs文件系统的目录符号链接来实现。

    3)设备驱动模型的属性(如设备的参数和设备名,设备号等)则通过sysfs文件系统的文件内容来记录实现。

           4)设备驱动模型数据结构中的kobject对应于sysfs文件系统中的目录,而数据结构中的struct attribute成员则对应于sysfs文件系统中的文件。对应的意思是指继续与kobject的device、device_driver和bus等在向系统注册的过程中会调用sysfs的create_dir接口来创建对应的目录,而含有struct attribute成员属性的device、device_driver和bus等在向系统注册的过程中则会调用sysfs的sysfs_create_file接口来创建文件。

    2.sysfs核心接口

           sysfs_create_file(struct kobject * kobj,const struct attribute * attr)创建属性文件

           sysfs_create_dir(struct kobject * kobj)创建目录

           int sysfs_open_file(struct inode *inode,struct file *file)打开sysfs文件系统格式的文件

           sysfs_read_file(struct file *file, char__user *buf, size_t count, loff_t *ppos) 读操作

           sysfs_write_file(struct file *file, constchar __user *buf, size_t count, loff_t *ppos) 写操作

    3. sysfs文件系统与属性文件读写

           sysfs_read_file是sysfs文件系统的读写入口,但是驱动需要向系统提供真正的读写操作,也即是struct sysfs_ops数据结构中的show和store接口。

           Sysfs是基于内存的文件系统,掉电即消失,sysfs所有的操作接口均是对内存中的内核数据结构进行访问操作。假如用户用cat命令去读取一个属性文件(如dev)的内容,那么会产生以下流程:

           1)fd=open(“dev”)->vfs_open(“dev”)->sysfs_open(“dev”)获取该文件的句柄

           2)read()->vfs_read()->sysfs_read_file()->sysfs_ops->show()该show接口即是设备在注册时产生属性文件,并向系统提供该文件的读接口。而读接口的实现中自然是对该属性参数的读访问。

           /sys挂载了sysfs文件系统,因此所有对/sys目录下的文件或者目录的操作都会通过sysfs文件的接口进行访问。

    五、平台设备驱动

    平台设备驱动中的“平台”指的是平台总线,即platform_bus_type,是linux众多总线中的一种,如USB总线、PCI总线、I2C总线等等。只不过平台总线是一种虚拟的总线,专门用来管理SOC上的控制器(如看门狗、LCD、RTC等等),它们都是CPU的总线上直接取址访问设备的。而USB、PCI等设备都有通过特定的时序来访问SOC芯片以外的设备。平台设备驱动体现的关系是设备驱动模型上的一个子集,将平台视为一种总线的概念,那两者的关系就会容易理解。

    1.    平台设备驱动和设备驱动模型的关系

    1)平台设备驱动接口在设备驱动模型视图上创建了相关的平台设备类(/sys/class/platform_bus)、平台总线(/sys/bus/platform)、平台设备(/sys/devices/).

    2)平台设备(platform_device)和平台设备驱动(platform_driver)均注册到平台总线上,即在/sys/bus/platform/目录下创建相应的设备和驱动目录。

    3)平台总线负责匹配注册到其上面的设备和驱动,匹配成功后回调用驱动的probe接口。

    4)平台设备驱动利用设备驱动模型接口来辅助创建对应的设备文件(位于/dev/目录下)。

     

    相关的接口包括:

    platform_device_register(structplatform_device *pdev) 注册平台设备

    platform_driver_register(structplatform_driver *drv) 注册平台设备驱动

    两个接口的实现里面都会对平台驱动和设备进行匹配,匹配成功会调用驱动的probe接口。

     

    2. 平台设备驱动和字符设备驱动的关系

           我们假设这个平台设备是字符设备。

    平台设备驱动和字符设备驱动的关系始于驱动的probe接口,即在probe接口中实现字符设备驱动所要完成的任务,即通过alloc_chrdev_region申请设备号和通过cdev_add注册驱动的struct file_opertions.另外为了自动创建应用层访问的设备文件,还要调用class_create和device_create接口在平台设备类下创建对应的设备类和设备,并发出uevent事件,调用mdev来创建设备文件。

    3. 平台设备驱动的开发流程

           1)将字符设备驱动的char_init函数的实现搬到platform_driver的probe接口中。

           2)在char_init中调用platform_device_register和platform_driver_register分别注册设备和驱动。其实,对于移植好的系统,platform_device_register是在linux启动的过程中完成的。因此char_init一般只有platform_driver_register注册驱动。

           详细的平台设备驱动的实现原理和开发流程另文再述。本次的重点是为了阐述字符设备驱动、设备驱动模型、sysfs和平台设备驱动之间的关系。

     

    博主微信公众号:嵌入式企鹅圈,百分百原创分享嵌入式Linux开发、物联网IOT开发经验知识,绝对干货!

    展开全文
  • 前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习。   一、platform 驱动的工作过程  platform模型驱动编程,需要实现platform_device...

           前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习。

           

    一、platform 驱动的工作过程

            platform模型驱动编程,需要实现platform_device(设备)platform_driver(驱动)platform(虚拟总线)上的注册、匹配,相互绑定,然后再做为一个普通的字符设备进行相应的应用,总之如果编写的是基于字符设备的platform驱动,在遵循并实现platform总线上驱动与设备的特定接口的情况下,最核心的还是字符设备的核心结构:cdev、 file_operations(他包含的操作函数接口)、dev_t(设备号)、设备文件(/dev)等,因为用platform机制编写的字符驱动,它的本质是字符驱动。

          我们要记住,platform 驱动只是在字符设备驱动外套一层platform_driver 的外壳

         在一般情况下,2.6内核中已经初始化并挂载了一条platform总线在sysfs文件系统中。那么我们编写platform模型驱动时,需要完成两个工作:

    a -- 实现platform驱动 

    b -- 实现platform设备

         然而在实现这两个工作的过程中还需要实现其他的很多小工作,在后面介绍。platform模型驱动的实现过程核心架构就很简单,如下所示:


    platform驱动模型三个对象:platform总线platform设备platform驱动

    platform总线对应的内核结构:struct bus_type-->它包含的最关键的函数:match() (要注意的是,这块由内核完成,我们不参与)

    platform设备对应的内核结构:struct platform_device-->注册:platform_device_register(unregister)

    platform驱动对应的内核结构:struct platform_driver-->注册:platform_driver_register(unregister)

           

    那具体platform驱动的工作过程是什么呢:

         设备(或驱动)注册的时候,都会引发总线调用自己的match函数来寻找目前platform总线是否挂载有与该设备(或驱动)名字匹配的驱动(或设备),如果存在则将双方绑定;

         如果先注册设备,驱动还没有注册,那么设备在被注册到总线上时,将不会匹配到与自己同名的驱动,然后在驱动注册到总线上时,因为设备已注册,那么总线会立即匹配与绑定这时的同名的设备与驱动,再调用驱动中的probe函数等;

        如果是驱动先注册,同设备驱动一样先会匹配失败,匹配失败将导致它的probe函数暂不调用,而是要等到设备注册成功并与自己匹配绑定后才会调用



    二、实现platform 驱动与设备的详细过程

    1、思考问题?

          在分析platform 之前,可以先思考一下下面的问题:

    a -- 为什么要用 platform 驱动?不用platform驱动可以吗?

    b -- 设备驱动中引入platform 概念有什么好处?

            现在先不回答,看完下面的分析就明白了,后面会附上总结。


    2、platform_device 结构体 VS platform_driver 结构体

          这两个结构体分别描述了设备和驱动,二者有什么关系呢?先看一下具体结构体对比

    设备(硬件部分):中断号,寄存器,DMA等
                       platform_device 结构体
      驱动(软件部分)
                              platform_driver 结构体       
    struct platform_device {
         const char    *name;       名字
        int        id;
        bool        id_auto;
        struct device     dev;   硬件模块必须包含该结构体
        u32         num_resources;        资源个数
         struct resource    *resource;         资源  人脉
        const struct platform_device_id    * id_entry;
        /* arch specific additions */
        struct pdev_archdata    archdata;
    };
    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 device_driver  driver;内核里所有的驱动程序必须包含该结构体
        const struct platform_device_id * id_table;  八字
    };
    设备实例:
    static struct platform_device hello_device=
    {
        .name = "bigbang",
        .id = -1,
        .dev.release = hello_release,
    };
    驱动实例:
    static struct platform_driver hello_driver=
    {
        .driver.name = "bigbang",
        .probe = hello_probe,
        .remove = hello_remove,
    };

           前面提到,实现platform模型的过程就是总线对设备和驱动的匹配过程 。打个比方,就好比相亲,总线是红娘,设备是男方,驱动是女方

    a -- 红娘(总线)负责男方(设备)和女方(驱动)的撮合;     

    b -- 男方(女方)找到红娘,说我来登记一下,看有没有合适的姑娘(汉子)—— 设备或驱动的注册

    c -- 红娘这时候就需要看看有没有八字(二者的name 字段)匹配的姑娘(汉子)——match 函数进行匹配,看name是否相同;

    d -- 如果八字不合,就告诉男方(女方)没有合适的对象,先等着,别急着乱做事 —— 设备和驱动会等待,直到匹配成功;

    e -- 终于遇到八字匹配的了,那就结婚呗!接完婚,男方就向女方交代,我有多少存款,我的房子在哪,钱放在哪等等( struct resource    *resource),女方说好啊,于是去房子里拿钱,去给男方买菜啦,给自己买衣服、化妆品、首饰啊等等(int (*probe)(struct platform_device *) 匹配成功后驱动执行的第一个函数),当然如果男的跟小三跑了(设备卸载),女方也不会继续待下去的(  int (*remove)(struct platform_device *))。


    3、设备资源结构体

          在struct platform_device 结构体中有一重要成员 struct resource *resource

    struct resource {
    	resource_size_t start;  资源起始地址   
    	resource_size_t end;   资源结束地址
    	const char *name;      
    	unsigned long flags;   区分是资源什么类型的
    	struct resource *parent, *sibling, *child;
    };
    
    #define IORESOURCE_MEM        0x00000200
    #define IORESOURCE_IRQ        0x00000400   

           flags 指资源类型,我们常用的是 IORESOURCE_MEM、IORESOURCE_IRQ  这两种。start 和 end 的含义会随着 flags而变更,如

    a -- flags为IORESOURCE_MEM 时,start 、end 分别表示该platform_device占据的内存的开始地址和结束值;  

    b -- flags为 IORESOURCE_IRQ   时,start 、end 分别表示该platform_device使用的中断号的开始地址和结束值; 

    下面看一个实例:

    static struct  resource beep_resource[] =
    {
    	[0] = {
            	.start = 0x114000a0,
    		.end = 0x114000a0+0x4,
            	.flags = IORESOURCE_MEM,
    	},
    
    	[1] = {
            	.start = 0x139D0000,
            	.end = 0x139D0000+0x14,
            	.flags = IORESOURCE_MEM,
    	},
    };

    4、将字符设备添加到 platform的driver中
          前面我们提到platform 驱动只是在字符设备驱动外套一层platform_driver 的外壳,下面我们看一下添加的过程:
    static struct file_operations hello_ops=
    {
    	.open = hello_open,
    	.release = hello_release,
    	.unlocked_ioctl = hello_ioctl,
    };
    
    static int hello_remove(struct platform_device *pdev)
    {
    	注销分配的各种资源
    }
    
    static int hello_probe(struct platform_device *pdev)
    {
    	1.申请设备号
    	2.cdev初始化注册,&hello_ops
    	3.从pdev读出硬件资源
    	4.对硬件资源初始化,ioremap,request_irq( )
    }
    
    static int hello_init(void)
    {
    	只注册 platform_driver
    }
    
    static void hello_exit(void)
    {
    	只注销 platform_driver
    }
          可以看到,模块加载和卸载函数仅仅通过paltform_driver_register()、paltform_driver_unregister() 函数进行 platform_driver 的注册和注销,而原先注册和注销字符设备的工作已经被移交到 platform_driver 的 probe() 和 remove() 成员函数中

    5、platform是如何匹配device和driver
          这时就该总线出场了,系统为platform总线定义了一个bus_type 的实例platform_bus_type,其定义如下:
    struct bus_type platform_bus_type = {
    	.name        = "platform",
    	.dev_groups    = platform_dev_groups,
    	.match        = platform_match,
    	.uevent        = platform_uevent,
    	.pm        = &platform_dev_pm_ops,
    };
          其又是怎样工作的呢?在platform.c (e:\linux-3.14-fs4412\drivers\base)    31577    2014/3/31 中可以看到
    __platform_driver_register()
    {
    	drv->driver.bus = &platform_bus_type;     536行
    }
    
        在 platform_bus_type 中调用 了platform_match:
    static int platform_match(struct device *dev, struct device_driver *drv)
    {
    	struct platform_device *pdev = to_platform_device(dev);
    	struct platform_driver *pdrv = to_platform_driver(drv);
    
    	匹配设备树信息,如果有设备树,就调用 of_driver_match_device() 函数进行匹配
    	if (of_driver_match_device(dev, drv))
    		return 1;
    
    
    	匹配id_table
    	if (pdrv->id_table)
    		return platform_match_id(pdrv->id_table, pdev) != NULL;
    
    	最基本匹配规则
    	return (strcmp(pdev->name, drv->name) == 0);
    }
    


    6、解决问题

          现在可以回答这两个问题了

    a -- 为什么要用 platform 驱动?不用platform驱动可以吗?

    b -- 设备驱动中引入platform 概念有什么好处?

          引入platform模型符合Linux 设备模型 —— 总线、设备、驱动,设备模型中配套的sysfs节点都可以用,方便我们的开发;当然你也可以选择不用,不过就失去了一些platform带来的便利;

          设备驱动中引入platform 概念,隔离BSP和驱动。在BSP中定义platform设备和设备使用的资源、设备的具体匹配信息,而在驱动中,只需要通过API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。


    三、实例

            这是一个蜂鸣器的驱动,其实前面已经有解析 Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动, 下面来看一下,套上platform 外壳后的程序:

    1、device.c

    #include <linux/module.h>
    #include <linux/device.h>
    #include <linux/platform_device.h>
    #include <linux/ioport.h>
    
    static struct resource beep_resource[] =
    {
    	[0] ={
    		.start = 0x114000a0,
    		.end =  0x114000a0 + 0x4,
    		.flags = IORESOURCE_MEM,
    	},
    
    	[1] ={
    		.start = 0x139D0000,
    		.end =  0x139D0000 + 0x14,
    		.flags = IORESOURCE_MEM,
    	}
    };
    
    static void hello_release(struct device *dev)
    {
    	printk("hello_release\n");
    	return ;
    }
    
    
    
    static struct platform_device hello_device=
    {
        .name = "bigbang",
        .id = -1,
        .dev.release = hello_release,
        .num_resources = ARRAY_SIZE(beep_resource),
        .resource = beep_resource,
    };
    
    static int hello_init(void)
    {
    	printk("hello_init");
    	return platform_device_register(&hello_device);
    }
    
    static void hello_exit(void)
    {
    	printk("hello_exit");
    	platform_device_unregister(&hello_device);
    	return;
    }
    
    MODULE_LICENSE("GPL");
    module_init(hello_init);
    module_exit(hello_exit);
    

    2、driver.c

    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <linux/platform_device.h>
    #include <asm/io.h>
    
    static int major = 250;
    static int minor=0;
    static dev_t devno;
    static struct class *cls;
    static struct device *test_device;
             
    #define TCFG0         0x0000               
    #define TCFG1         0x0004                            
    #define TCON          0x0008             
    #define TCNTB0        0x000C          
    #define TCMPB0        0x0010           
    
    static unsigned int *gpd0con;
    static void *timer_base;
    
    #define  MAGIC_NUMBER    'k'
    #define  BEEP_ON    _IO(MAGIC_NUMBER    ,0)
    #define  BEEP_OFF   _IO(MAGIC_NUMBER    ,1)
    #define  BEEP_FREQ   _IO(MAGIC_NUMBER   ,2)
    
    static void fs4412_beep_init(void)
    {	
    	writel ((readl(gpd0con)&~(0xf<<0)) | (0x2<<0),gpd0con);
    	writel ((readl(timer_base +TCFG0  )&~(0xff<<0)) | (0xff <<0),timer_base +TCFG0); 
    	writel ((readl(timer_base +TCFG1 )&~(0xf<<0)) | (0x2 <<0),timer_base +TCFG1 ); 
    
    	writel (500, timer_base +TCNTB0  );
    	writel (250, timer_base +TCMPB0 );
    	writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x2 <<0),timer_base +TCON ); 
    }
    
    void fs4412_beep_on(void)
    {
    	writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x9 <<0),timer_base +TCON );
    }
    
    void fs4412_beep_off(void)
    {
    	writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x0 <<0),timer_base +TCON );
    }
    
    static void beep_unmap(void)
    {
    		iounmap(gpd0con);
    		iounmap(timer_base);
    }
    
    static int beep_open (struct inode *inode, struct file *filep)
    {
    	fs4412_beep_on();
    	return 0;
    }
    
    static int beep_release(struct inode *inode, struct file *filep)
    {
    	 fs4412_beep_off();
    	 return 0;
    }
    
    #define BEPP_IN_FREQ 100000
    static void beep_freq(unsigned long arg)
    {
    	writel(BEPP_IN_FREQ/arg, timer_base +TCNTB0  );
    	writel(BEPP_IN_FREQ/(2*arg), timer_base +TCMPB0 );
    
    }
    
    static long beep_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
    {
    	switch(cmd)
    	{
    		case BEEP_ON:
    			fs4412_beep_on();
    			break;
    		case BEEP_OFF:
    			fs4412_beep_off();
    			break;
    		case BEEP_FREQ:
    			beep_freq( arg );
    			break;
    		default :
    			return -EINVAL;
    	}
    	return 0;
    }
    
    static struct file_operations beep_ops=
    {
    	.open     = beep_open,
    	.release = beep_release,
    	.unlocked_ioctl      = beep_ioctl,
    };
    
    static int beep_probe(struct platform_device *pdev)
    {
    	int ret;	
    	printk("match ok!");
    	
    	gpd0con = ioremap(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start);
    	timer_base = ioremap(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start);
    
    	devno = MKDEV(major,minor);
    	ret = register_chrdev(major,"beep",&beep_ops);
    
    	cls = class_create(THIS_MODULE, "myclass");
    	if(IS_ERR(cls))
    	{
    		unregister_chrdev(major,"beep");
    		return -EBUSY;
    	}
    
    	test_device = device_create(cls,NULL,devno,NULL,"beep");//mknod /dev/hello
    	if(IS_ERR(test_device))
    	{
    		class_destroy(cls);
    		unregister_chrdev(major,"beep");
    		return -EBUSY;
    	}
    	
    	fs4412_beep_init();
    	
    	return 0;
    }
    
    static int beep_remove(struct platform_device *pdev)
    {
    	beep_unmap();
    	device_destroy(cls,devno);
    	class_destroy(cls);	
    	unregister_chrdev(major,"beep");
    
    	return 0;
    }
    
    
    static struct platform_driver beep_driver=
    {
        .driver.name = "bigbang",
        .probe = beep_probe,
        .remove = beep_remove,
    };
     
    
    static int beep_init(void)
    {
    	printk("beep_init");
    	
    	return platform_driver_register(&beep_driver);
    }
    
    static void beep_exit(void)
    {
    	printk("beep_exit");
    	platform_driver_unregister(&beep_driver);
    	
    	return;
    }
    
    
    MODULE_LICENSE("GPL");
    module_init(beep_init);
    module_exit(beep_exit);
    

    3、makefile   

    ifneq  ($(KERNELRELEASE),)
    obj-m:=device.o driver.o
    $(info "2nd")
    else
    #KDIR := /lib/modules/$(shell uname -r)/build
    KDIR := /home/fs/linux/linux-3.14-fs4412
    PWD:=$(shell pwd)
    all:
    	$(info "1st")
    	make -C $(KDIR) M=$(PWD) modules
    clean:
    	rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order
    endif
    

    4、test.c
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    main()
    {
    	int fd,i,lednum;
    
    	fd = open("/dev/beep",O_RDWR);
    	if(fd<0)
    	{
    		perror("open fail \n");
    		return ;
    	}
    	
    	sleep(10);
    	close(fd);
    }
    



    展开全文
  • 设备、设备节点和设备驱动详解

    千次阅读 多人点赞 2018-09-28 12:44:03
    设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。 常见的字符设备有鼠标、键盘、串口、控制台等。 常见的块设备有各种硬盘、flash磁盘、RAM磁盘等。 在Linux里一个网络设备...

    Linux下的设备通常分为三类,字符设备,块设备和网络设备。
    设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。
    常见的字符设备有鼠标、键盘、串口、控制台等。
    常见的块设备有各种硬盘、flash磁盘、RAM磁盘等。
    在Linux里一个网络设备也可以叫做一个网络接口,如eth0,应用程序是通过Socket而不是设备节点来访问网络设备,在系统里根本就不存在网络设备节点。网络接口没有像字符设备和块设备一样的设备号,只有一个唯一的名字,如eth0、eth1等,而这个名字也不需要与设备文件节点对应

    设备节点被创建在/dev下,是连接内核与用户层的枢纽,就是设备是接到对应哪种接口的哪个ID 上。 相当于硬盘的inode一样的东西,记录了硬件设备的位置和信息
    在Linux中,所有设备都以文件的形式存放在/dev目录下,都是通过文件的方式进行访问,设备节点是Linux内核对设备的抽象,一个设备节点就是一个文件。应用程序通过一组标准化的调用执行访问设备,这些调用独立于任何特定的驱动程序。而驱动程序负责将这些标准调用映射到实际硬件的特有操作。

    设备节点,驱动,硬件设备是如何关联到一起的呢?
    这是通过设备号实现的,包括主设备号和次设备号。当我们创建一个设备节点时需要指定主设备号和次设备号。应用程序通过名称访问设备,而设备号指定了对应的驱动程序和对应的设备。主设备号标识设备对应的驱动程序,次设备号由内核使用,用于确定设备节点所指设备。

    主设备号:驱动程序在初始化时,会注册它的驱动及对应主设备号到系统中,这样当应用程序访问设备节点时,系统就知道它所访问的驱动程序了。你可以通过/proc/devices文件来查看系统设备的主设备号。

    次设备号:驱动程序遍历设备时,每发现一个它能驱动的设备,就创建一个设备对象,并为其分配一个次设备号以区分不同的设备。这样当应用程序访问设备节点时驱动程序就可以根据次设备号知道它说访问的设备了。

    设备节点(设备文件):Linux中设备节点是通过“mknod”命令来创建的。一个设备节点其实就是一个文件,Linux中称为设备文件。有一点必要说明的是,在Linux中,所有的设备访问都是通过文件的方式,一般的数据文件程序普通文件,设备节点称为设备文件。

    设备驱动:设备驱动程序(device driver),简称驱动程序(driver),是一个允许高级(High level)计算机软件(computer software)与硬件(hardware)交互的程序,这种程序建立了一个硬件与硬件,或硬件与软件沟通的界面,经由主板上的总线(bus)或其它沟通子系统(subsystem)与硬件形成连接的机制,这样的机制使得硬件设备(device)上的数据交换成为可能。想象平时我们说的写驱动,例如点led灯的驱动,就是简单的io操作。

    展开全文
  • Linux驱动之USB设备驱动

    千人学习 2017-01-12 09:48:38
    当一个USB设备被插入的时候,USB设备驱动,也就是usb_generic_driver会跟USB设备交互,得到其所有的各种描述符,并为每个接口都定义成为一个device,之后再加载到usb_bus上,让其去匹配其对应的接口驱动程序。
  • 什么是设备驱动程序同一个应用软件可以在不同的硬件平台的上运行。同样的open函数可以操作不同的硬件设备,实现设备无关性。这些功能的实现都离不开设备确定函数的支持。设备驱动程序是操作系统内核的内容。应用程序...
  • Linux设备驱动程序和设备文件

    千次阅读 2018-01-14 18:25:10
    Linux设备驱动程序和设备文件 设备驱动程序 一个设备驱动程序是一个管理着系统与某种特定硬件之间交互作用的程序。驱动程序在设备可理解的硬件指令和内核使用的固定编程接口之间起转换作用。驱动程序层的存在有...
  • 深入Linux设备驱动程序内核机制 你懂的 好书 今年新书 驱动
  • 本课程是linux驱动开发的第10个课程,主要内容是linux的块设备驱动的介绍,首先详细讲了块设备驱动和字符设备驱动的核心差异,然后以一个内存模拟的块设备驱动源码为案例演示了块设备驱动如何使用,后对源码进行了...
  • linux驱动开发-第一个驱动-简单字符设备驱动

    千次阅读 多人点赞 2019-01-29 14:37:27
    linux设备驱动主要分为三类:字符设备驱动、块设备驱动、网络设备驱动 其中字符设备驱动适合用来入门,结构简单,更多关于设备驱动的东西这里就不作说明。 上传了完整项目文档说明和代码:操作系统课程设计-简单...
  • 本课程是linux驱动开发的第5个课程,主要内容是linux的设备驱动模型,包括总线、类、设备、驱动等概念,重点通过platform平台总线的工作来演示设备驱动模型的工作方法,实践环节对上个课程的LED驱动进行平台总线式...
  • Usb设备驱动1:root hub 设备驱动安装

    千次阅读 2019-01-12 16:52:49
    按照设备模型的总线,设备,驱动模式,一条...同时也需要把usb主控制器,hub的驱动也挂载到驱动链表上,并且使得设备和设备驱动能够相互关联起来,才能使得设备能够使用,完成应有的设备功能。 那么usb hub驱动是如...
  • 初学Linux驱动程序的时候,可能对什么是字符设备驱动(char device)和杂项设备驱动(misc device)并不是很了解,更谈不上如何区分了。我自己当初在学习Linux字符设备驱动的时候,也并没有特地去了解其两者之间的...
  • 本博实时更新《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)的最新进展。 目前已经完成稿件。 2015年8月9日,china-pub开始上线预售: ... 2015年8月20日,各路朋友报喜...
  • 字符设备驱动之misc驱动

    千次阅读 2016-03-29 22:28:50
    字符设备驱动之misc驱动 Misc驱动,在LDD上面基本没讲,但由于其方便,现在使用已经相当广泛。本文首先介绍了普通字符驱动的结构即流程,之后将misc字符驱动与普通字符驱动进行了比较。最后通过源码对misc有更进一步...
  • VxWorks设备驱动开发详解

    千次下载 热门讨论 2013-08-15 10:39:25
    VxWorks设备驱动开发详解 曹桂平 中国科学技术大学
  • Linux驱动入门(一)字符设备驱动基础

    千次阅读 多人点赞 2019-08-20 21:40:29
    Linux驱动入门(一)字符设备驱动基础 Linux驱动入门系列 Linux驱动入门(一)字符设备驱动基础 Linux驱动入门(二)Led驱动 Linux驱动入门(三)轮询实现按键驱动 Linux驱动入门(四)中断实现按键驱动 Linux驱动...
  • linux设备驱动框架

    万次阅读 多人点赞 2018-05-26 11:32:00
    字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序 来实现这种特性。字符设备驱动程序通常至少要实现open、close、read和write的系统调 用。字符终端(/dev/console)...
  • linux驱动由浅入深系列:块设备驱动之一(高通eMMC分区实例)linux驱动由浅入深系列:块设备驱动之二(从用户空间的read、write到实际设备物理操作整体架构分析)linux驱动由浅入深系列:块设备驱动之三(块设备驱动...
  • 字符设备驱动-linux驱动开发第3部分

    千人学习 2016-10-18 11:07:11
    本课程是linux驱动开发的第3个课程,接上部分继续讲解字符设备驱动的开发要点,重点是相关的内核源代码的解析和一些真正驱动惯用的编程手法的引入。本课程的目的是让大家开始逐渐习惯和熟悉真正内核驱动的特征,为...
  • 本课程是linux驱动开发的第11个课程,主要内容是linux的网络驱动的介绍,首先讲述了网络设备驱动接口和之前讲的2种的不同,然后以一个虚拟网卡驱动源码学习了网卡驱动的框架,后分析了一个实际网卡DM9000的驱动细节...
  • Linux设备节点、设备和设备驱动

    千次阅读 2017-09-15 14:44:38
    设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。 设备节点相当于硬盘的inode一样的东西,立面记录了硬件设备的位置和信息 在Linux中,所有设备都以文件的形式存放在/dev目录...
  • 本课程是linux驱动开发的第2个课程,从零开始带领大家逐渐熟悉内核模块,并且一步步写出一个字符设备驱动程序来控制LED等。本课程对驱动的学习非常重要,是驱动学习的入门阶段。
  • LINUX设备驱动程序

    千次下载 热门讨论 2010-10-08 23:42:17
    LINUX设备驱动程序 嵌入式开发资料
  • 在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动。本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存。 下面...
  • ARM嵌入式Linux设备驱动实例开发pdf

    热门讨论 2013-02-02 17:00:09
    此书很好,有8个典型实例。按键设备驱动、触摸屏设备驱动、MMC/SD设备驱动、网卡设备驱动、Framebuffer设备驱动、USB设备驱动、PCI设备驱动
  • linux设备驱动(一)

    万次阅读 2020-01-08 15:47:24
    文章目录基本概念什么是设备驱动无操作系统下的驱动有操作系统下的驱动linux设备分类字符设备块设备网络设备内核的组成源码目录结构内核主要组成部分进程调度SCHED内存管理MM虚拟文件系统VFS网络接口NET进程间通信...
  • 现在,我们来编写自己第一个字符设备驱动 —— 点亮LED。 硬件平台:Exynos4412(FS4412) 编写驱动分下面几步: a -- 查看原理图、数据手册,了解设备的操作方法; b -- 在内核中找到相近的驱动程序,以它为模板...
  • spi驱动框架全面分析,从master驱动到设备驱动

    万次阅读 多人点赞 2016-06-22 19:24:40
    内核版本:linux2.6.32.2  硬件资源:s3c2440 参考: 韦东山SPI视频教程 内容概括:  1、I2C 驱动框架回顾  2、SPI 框架简单介绍 ... 4、SPI 设备驱动框架  4.1 设备层 4.2 驱动层  5、设备

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 582,901
精华内容 233,160
关键字:

设备驱动