一、设备驱动的分类

1.字符设备

字符设备是指那些能一个字节一个字节读取数据的设备,如LED灯、键盘、鼠标等。字符设备一般需要在驱动层实现open()、close()、read()、write()、ioctl()等函数。

2.块设备

块设备与字符设备类似,一般是像磁盘一样的设备。在块设备中还可以容纳文件系统,并存储大量的信息。在linux系统中,进行块设备读写时,每次只能传输一个或者多个块。linux也可以让应用程序像访问字符设备一样访问块设备,一次只读取一个字节。

3.网络设备

网络设备主要负责主机之间的数据交换,与字符设备和块设备完全不同,网络设备主要是面向数据包的接收和发送而设计的。网络设备没有实现类似块设备和字符设备的read()、write()、ioctl()等函数,但是实现了一种套接字接口,任何网络数据传输都可以通过套接字来完成。

二、基础知识介绍

1.直接将模块编译进内核(主要修改两个文件:Kconfig Makefile)

1.1将编写好的模块程序复制到内核代码中(一般根据驱动内容来选择合适的路径)

1.2进入到该路径,打开Kconfig文件:vi Kconfig

说明:Kconfig文件描述了所属目录源文件相关的内核配置菜单

1.3添加:config HELLO_WORLD

 bool "helloworld"

则在menuconfig菜单中出现新的目录:helloworld

1.4修改该目录下的Makefile文件:obj -$(CONFIG_HELLO_WORLD) += hello.o

1.5编译内核

三、字符设备驱动程序设计

1.概念介绍

1.1主次设备号

主设备号用来标识与设备文件相连的驱动程序;次设备号被驱动程序用来辨别操作的是哪个设备。

linux内核中通过dev_t类型描述主次设备号,dev_t其实质为unsigned int 32位整数,高12位为主设备号,低20位为次设备号。通过宏MAJOR(dev_t dev)获得主设备号,MINOR(dev_t dev)获得次设备号。

1.2分配主设备号

静态申请:确定一个系统没有使用的设备号,使用register_chrdev_region函数注册。但是该方式在驱动较多的情况下,很容易导致设备号冲突,而使驱动程序无法注册。

动态分配:通过linux内核自动分配一个未使用的主设备号。使用alloc_chrdev_region()分配设备号。但是该方式无法在安装驱动前创建设备文件,因为安装前驱动程序还没有分配到主设备号。

1.3创建设备文件

使用mknod命令手动创建

mknod用法:mknod filename type major minor

filename:设备文件名

type:设备文件类型(字符设备:c 块设备:b)

major:主设备号

minor:次设备号

自动创建:

2.重要结构

2.1 struct file

代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的struct file,它是由内核在打开文件时创建,在文件关闭时释放。

重要成员:loff_t f_pos /*文件读写位置*/

struct file_operations *f_op

2.2 struct inode

用来记录文件的物理上的信息,因此它和代表打开文件的file结构是不同的,一个文件可以对应多个file结构,但只有一个inode结构。

重要成员:dev_t i_rdev:设备号

2.3 struct file_operations

一个函数指针的集合,定义能在设备上进行的操作。结构中的成员指向驱动中的函数,这些函数实现一个特别的操作,对于不支持的操作保留为NULL。

3.应用程序访问驱动程序

当应用程序使用read函数时,传入要操作的文件file,系统会调用vfs_read函数,根据file去内核中查找相应的file_operations中指定的read函数,vfs_read函数(在read_write.c中)代码如下:

 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret; if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
return -EFAULT; ret = rw_verify_area(READ, file, pos, count);
if (ret >= ) {
count = ret;
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
else
ret = do_sync_read(file, buf, count, pos);
if (ret > ) {
fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
} return ret;
}

4.设备注册

在linux2.6的内核中,字符设备使用struct cdev来描述。

字符设备的注册过程可分为三步:1.分配cdev;2.初始化cdev;3.添加cdev;

四、函数解析

1.分配主设备号相关函数

int register_chrdev_region(dev_t from,unsigned count,coust char *name)

功能说明:申请使用从from开始的count个设备号(主设备号不变,次设备号增加)

参数:from:希望申请使用的设备号

   count:希望申请使用的设备号数目

   name:设备号(体现在/proc/devices)

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)

功能说明:请求内核动态分配count个设备号,且次设备号从baseminor开始。

参数:dev:分配完返回的设备号

   baseminor:起始次设备号

   count:需要分配的设备号数目

   name:设备名(体现在/proc/devices)

void unregister_chrdev_region(dev_t from,unsigned count)

功能说明:释放从from开始的count个设备号

参数:from:需要释放的设备号

   count:希望释放的设备号数目

2.设备注册相关函数

struct cdev *cdev_alloc(void)

功能说明:分配cdev

返回值:分配的cdev指针

void cdev_init(struct cdev *cdev,const struct file_operations *fops)

功能说明:初始化字符设备

参数:cdev:待初始化的cdev结构

   fops:设备对应的操作函数集

int cdev_add(struct cdev *p,dev_t dev,unsigned count)

功能说明:添加字符设备

参数:p:待添加到内核的字符设备结构

   dev:设备号

   count:添加的设备个数

int cdev_del(struct cdev *p)

功能说明:设备注销

参数:p:要注销的字符设备结构

3.设备操作函数

int (*open)(struct inode *,struct file *)

功能说明:在设备文件上的第一个操作,并不要求驱动程序一定要实现这个方法。如果该项为NULL,设备的打开操作永远成功。系统中通过fs/open.c中的do_sys_open函数实现。

void (*release)(struct inode *,struct file *)

功能说明:当设备文件被关闭时调用这个操作,与open相同,release也可以没有。

ssize_t (*read)(struct file *,char __user *,size_t,loff_t *)

功能说明:从设备中读取数据。

ssize_t (*write)(struct file *,const char __user *,size_t,loff_t *)

功能说明:向设备发送数据。

unsigned int (*poll)(struct file *,struct poll_table_struct *)

功能说明:对应select系统调用。

int (*ioctl)(struct inode *,struct file *,unsigned int,unsigned long)

功能说明:控制设备。

int (*mmap)(struct file *,struct vm_area_struct *)

功能说明:将设备映射到进程虚拟地址空间中。

off_t (*Ilseek)(struct file *,loff_t,int)

功能说明:修改文件的当前读写位置,并将新位置作为返回值。

linux字符设备驱动--基本知识介绍的更多相关文章

  1. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  2. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  3. Linux字符设备驱动基本结构

    1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...

  4. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  5. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

  6. Linux字符设备驱动实现

    Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...

  7. 一步步理解linux字符设备驱动框架(转)

    /* *本文版权归于凌阳教育.如转载请注明 *原作者和原文链接 http://blog.csdn.net/edudriver/article/details/18354313* *特此说明并保留对其追 ...

  8. Linux 字符设备驱动模型

    一.使用字符设备驱动程序 1. 编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块 2. 创建设备文件 通 ...

  9. Linux字符设备驱动框架

    字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...

随机推荐

  1. 小记同学一次奇葩的DNS欺骗实验失败经历

    这是一个DNS欺骗实验,使用kali的ettercap.有受害者.攻击者(虚拟机).Web服务器三台机器.受害者的事124.16.70.105虚拟机的是124.16.71.48web服务器是124.1 ...

  2. android Choose library dependency 搜索不到目标库

    问题:Choose library dependency 搜索不到目标库,百度了一下,发现尽是废话,无解,反正就是升级ide,我是 android studio是2.3.3(网上说升级到3.+就好了, ...

  3. C++ GUID和string转化函数【转载】

    原文地址:https://blog.csdn.net/zgl7903/article/details/5488294 因为这两个函数太好用,解决了大问题,我必须转载一下了.转自csdn牛人 zgl79 ...

  4. 中国2017 Google 开发者大会第二天简单回顾

    昨天早晨发布了第一天的开发者大会回顾文章后,就匆匆忙忙赶去会场继续享受高科技的盛宴,接下来简单回顾一下第二天的大会参与情况. 昨天早晨下着小雨,并带着微风,在外面还是挺冷的,这里不得不给工作人员点个赞 ...

  5. uwp之拍照(使用后置摄像头)

    参考:wp8.1之拍照(获取焦点,使用后置摄像头) uwp开启摄像头要借助CaptureElement呈现来自捕获设备(如照相机或网络摄像机)的流.今天讲讲如何打开摄像头,获取焦点,以及拍照.废话不多 ...

  6. Voovan 是一个高性能异步网络框架和 HTTP(Java)

    Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操 ...

  7. Linux运维工程师成长路线及应实现的目标

    作为一名运维工程师,需要学习的东西非常多,在学习的过程中也没有任何捷径可言,必须一步一个脚印地学习.积累才能把个人技能提升到相应的高度.根据目前流行的发行版及国际流行的Linux认证,红帽认证和LPI ...

  8. Hadoop集群(第5期)SecureCRT使用

    1.SecureCRT简介   SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,同时支持Telnet和rlogin协议.SecureCRT是一款用于连接运行包括Windows. ...

  9. Spring之基于注解的注入

    对于DI使用注解,将不再需要在Spring配置文件中声明Bean实例.Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变,完成以下三个步骤. (1)导入AOP的Jar包.因为注解 ...

  10. 玩转java多线程(wait和notifyAll的正确使用姿势)

    转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...