驱动学习笔记

一,知识结构 
二、驱动分类  可分为 :字符驱动、块设备驱动、网络设备驱动
      字符设备驱动以字符为访问单位(一个字符可能对应多个字节)进行顺序访问,不能随机读取。
      块设备驱动:以块为访问单位(块可以在内核中进行配置),通常512字节,或者更大的2的N次方。
                           块设备可以随机读取。在linux中块设备也可以以字节为单位进行访问,块设备跟字符设备
                          主要区别是访问接口的不同,并且块设备可以随机访问。
     网络设备:网络设备是以网络接口为访问对象的。可以是一个物理实体,也可以是存软件,例如linux下的lo设备是个存软件的网络设备。
二、驱动的安装方式
      1.驱动可以直接被编译内核,也可以以模块的方式安装,驱动设计的模型跟内核模块设计一样,入口都为module_init(),出口为module_exit();如果想要把驱动编译进内核,需要配置相应的Kconfig 跟config还有makefile文件。
     
三、字符设备驱动程序

      字符设备驱动设计流程:
      设备号:设备号是一个unsigned 型,高12位为住设备号,低20位为次设备号,linux系统提供了MAJOR(dev_t num) ,MINOR(),MKDEV(major,minor).来提取跟分离设备号。其中,主设备号是表明设备类型,是建立应用程序跟设备程序的纽带,往往我们有一个产品中有多个一样的设备,那么我们通常只有一套驱动程序,一个主设备号。通过不同的次设备号来区分访问不同的物理接口。一个主+次设备号对应一个设备文件。

      首先申请设备号,可以通过 alloc_chdev_region(dev_t* dev,unsinged from ,unsigned count ,char* name)设备方法动态申请设备号,当然,也可以用函数 register_chdev_region(dev_t num,unsigned count,char*
name)来静态注册设备号。在静态注册前需要通过cat /dev/ 来查看当前没有使用的设备号,才能分配给我们的设备,要不然,可能会产生设备号重复,而使我们的设备不能加载进内核。设备注销时需要释放设备号unregister_chdev_region(dev_t num,int cout);
     2.设备初始化申明结构体 struct cdev cdev(如果申明为指针在使用前要注意分配内存),定义结构体 struct file_operations file_ops={
.open = mem_open,
.read = mem_read,
.write = mem_write,
.ioctl = mem_ioctl,
.release = mem_release,
.llseek = mem_lseek,
};并初始化功能函数,为对功能函数初始化的,默认为NULL,
然后初始化设备 init_cdev(&cdev,&file_ops),指定模块所有者为模块本身 cdev.owner = THIS_MODULE;
初始化完成后,添加模块:cdev_add(struct cdev* cdev,dev_t dev_num,unsigned count);此时,模块注册已经完成。
在设备卸载时需要释放模块cdev_del(struct cdev* cdev);
3\需要注意的三个重要结构
    1.struct file 在打开文件时由系统创建,代表当前打开文件的相关读写信息。在文件关闭后释放。重要成员 loff_t f_pos;当前读写位置,struct file_operations* f_op;
    2.struct innode 结构,表示文件的物理信息,一个文件可以对应多个struct file 但只能对应一个 struct innode。重要成员 dev_t ir_dev;
  3.struct file_operations 是一个函数指针集合,实现驱动相关函数。在设备添加中,我们讲 file_ops结构传给了cdev结构,但如何再传给struct file结构体的,还不明确,需要再深入研究。
   应用程序在调用库函数fread时最后都会使用到系统调用read然后关联vfs_read,最后将file_operation结构里面的函数关联起来。
   

   设备文件的创建:设备文件可以通过两种方式创建,一种是手工创建设备文件 mknod name c major minor
另一种是自动创建设备文件,分三部完成:
struct class *myclass ;
class_create(THIS_MODULE, “my_device_driver”);
device_create(myclass, NULL, MKDEV(major_num, minor_num), NULL, “my_device”);
这样的module被加载时,udev daemon(在嵌入式linux中是mdev,自动创建设备节点实际上是应用层面进行的。 需要在busybox里面配置号相关选项才可可以)就会自动在/dev下创建my_device设备文件。

我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在 /dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应
device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称 不同,而且里面的参数设置也有一些变化。

其中,读写等,有从用户空间向内核空间传递地址的,地址在使用前必须做有效性检测(因为应用空间使用的是虚拟地址,有可能地址已经被释放了)
检测方法: _access_ok(void* start,)_access_ok(unsigned long addr, unsigned long size)
其中 copy_from_user(void*to ,void* from,size_t size),copy_to_user 都包含了参数检测功能,但__puts_user(),__get_user(),函数并未做参数有效性检测。 

file_operations 重要函数指针原型:

        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
        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 *, struct dentry *, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
        int (*flock) (struct file *, int, struct file_lock *);
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
        ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);

        int (*setlease)(struct file *, long, struct file_lock **);

以上只是一些基础的讲解方面初学者入门,以后将推出信号量,自旋锁,异步通知等的文章。

时间: 2024-08-28 11:50:09

驱动学习笔记的相关文章

Linux驱动学习笔记(6)信号量(semaphore)与互斥量(mutex)【转】

转自:http://blog.chinaunix.net/uid-24943863-id-3193530.html 并发导致竟态,从而导致对共享数据的非控制访问,产生非预期结果,我们要避免竟态的发生.遵循以下原则:1,尽量避免资源共享:2,显示地管理对共享资源的访问.管理技术通常为"锁定"或者"互斥",保证任何时刻只有一个执行线程可操作共享资源.         几个重要的概念:1,原子操作,顾名思义,就是说该操作是原子性的(原子是保持物质物理新性质的最小单位),不

VC文件过滤系统驱动开发Filemon学习笔记

WINDOWS文件过滤系统驱动开发,可用于硬盘还原,防病毒,文件安全防护,文件加密 等诸多领域.而掌握核心层的理论及实践,对于成为一名优秀的开发人员不可或缺. WINDOWS文件过滤系统驱动开发的两个经典例子,Filemon与SFilter,初学者在经 过一定的理论积累后,对此两个例子代码的研究分析,会是步入驱动开发殿堂的重要一步 ,相信一定的理论积累以及贯穿剖析理解此两个例程后,就有能力开始进行文件过滤系统 驱动开发的实际工作了. 对于SFilter例子的讲解,楚狂人的教程已经比较流行, 而F

AM335x(TQ335x)学习笔记——触摸屏驱动编写

前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱动源码,单纯的配置DTS是无法完成TQ335x的触摸驱动移植工作的,因此,本文参考内核中原有的pixcir_i2c_ts驱动编写TQ335x的触摸屏(TN92)驱动. 在之前移植TQ210时,我已经编写过TQ210的触摸屏驱动,我的TQ335x还是使用的TQ210的屏,因此,难度不是很大.这里需要说

Windows驱动开发工具 WDK 学习笔记(1)

目标:能够把电脑当作一个集成有高性能处理器的开发板用起来,当然,还自带了一个高级的操作系统Windows(必须的).总之,就是在一个带了操作系统的高性能开发板上的驱动程序开发. 性质:纯属业余爱好 1.昨天下载了WDK 7.1.0 Free版(From MS的正版,需要注册一个Windows Live ID,下载链接http://www.microsoft.com/downloads/en/confirmation.aspx?familyId=36a2630f-5d56-43b5-b996-76

作为一个新手的Oracle(DBA)学习笔记

Oracle数据库笔记 Jack Chaing 作者QQ595696297 交流群 127591054 祝大家学习进步. 如果大家想看Word版本的可以去下载:Word排版比较清晰一些. http://download.csdn.net/detail/jack__chiang/9810532 此笔记是作者本人去年开始从一个DBA新人的学习笔记,积累至今,希望拿出来给那些对DBA有兴趣的童孩学习,大家一起努力嘛. 此笔记记录了作者工作学习中从零基础的学习的记录,和从中遇见的问题与问题的解决!很高兴

MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)

[正文] 这一周状态不太好,连续打了几天的点滴,所以博客中断了一个星期,现在继续. 我们在之前的几篇文章中学习了JDBC对数据库的增删改查.其实在实际开发中,一般都是使用第三方工具类,但是只有将之前的基础学习好了,在使用开源工具的时才能得心应手.如果对JDBC基础不太清楚,或者对本文看不太懂,建议先回顾一下本人之前的几篇和"MySQL数据库学习笔记"相关的文章.但是不管怎样,今后如果用到了数据库的增删改查,肯定是这篇文章中的代码用的最多. 一.DbUtils简介: DBUtils是ap

kvm虚拟化学习笔记(五)之windows虚拟机性能调整

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://koumm.blog.51cto.com/703525/1290682 KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之linuxkvm虚拟机安装htt

kvm虚拟化学习笔记(二)之linux kvm虚拟机安装

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://koumm.blog.51cto.com/703525/1289627 KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之linuxkvm虚拟机安装htt

AM335x(TQ335x)学习笔记——挂载Ramdisk

上篇文章中我们已经能够通过u-boot启动内核了,但是没有能够启动成功,从内核的log中可以看出,内核启动失败的原因是没有挂载到root文件系统,本文将使用busybox制作根文件系统并打包成ramdisk供u-boot启动内核使用. (1)制作根文件系统 使用busybox构建根文件系统的步骤可以参考本博客的另外一篇文章,该文章链接如下: S5PV210(TQ210)学习笔记--内核移植与文件系统构建 需要补充的是,文章"S5PV210(TQ210)学习笔记--内核移植与文件系统构建"