目录

一、I/O 体系结构

二、与外设的交互

1、I/O端口:

2、I/O内存映射

3、轮询和中断

三、驱动分类

四、注册

五、与文件系统关联

六、资源管理

七、结构体总结


一、I/O 体系结构

与外设的通信通常称之为输入输出,一般都缩写为I/O
实现外设的I/O时,内核必须处理3个可能出现问题的领域
  1. 必须根据具体的设备类型和模型,使用各种方法对硬件寻址
  2. 内核必须向用户应用程序和系统工具提供访问各种设备的方法
  3. 用户空间需要知道内核中有哪些设备可用

外设寻址的分层模型
对各个设备的访问,通过层次化的多个抽象层进行。在层次结构的底部是设备自身,它通过总线
系统连接到其他设备和系统CPU

二、与外设的交互

1、I/O端口:

在这种情况下,内核发送数据给 I/O 控制器。数据的目标设备通过唯一的端口号标识,数据被传输到设备进行处理。

每种处理器类型实现端口访问的方式都不同。因此,内核必须提供一个适当的抽象层。诸如outb (写一个字节)、outw(写一个字)、inb(读取一个字节)之类的命令

2、I/O内存映射

处理器提供了对I/O端口进行内存 映射的选项,将特定外设的端口地址映射到普通内存中,可以像处理普通内存那样操作外设。诸如PCI之类的系统总线通常也是通过I/O地址映射进行寻址的。
内核提供了一个小的抽象层,主 要包括ioremap和iounmap命令

3、轮询和中断

轮询(polling)重复询问设备数据是否可用,如果可用,则处理器取回数据。这样做比较浪费资源,从而会影响重要 任务的执行。
中断是更好的备选方案。每个CPU都提供了中断线(interrupt line),可由各个系统设备共享。每个中断通过一个唯一的号码标识,内核对使用的
系统就不再需要频繁检查是否有新的数据可用。

三、驱动分类

1、字符设备、块设备和其他设备
wolfgang@meitner> ls -l /dev/sd{a,b} /dev/ttyS{0,1}
brw-r-----1 root disk 8, 0 2008-02-21 21:06 /dev/sda
brw-r-----1 root disk 8, 16 2008-02-21 21:06 /dev/sdb
crw-rw----1 root uucp 4, 64 2007-09-21 21:12 ttyS0
crw-rw----1 root uucp 4, 65 2007-09-21 21:12 ttyS1
  • 访问权限前的字母是b或c,分别表示块设备和字符设备
  • 设备文件没有文件长度,而增加了另外的两个值,分别是主设备号和从设备号。
2、网卡设备
字符设备和块设备不是内核管理的全部设备类别。网卡没有设备文件。用户程序必须使用套接字与网卡通信。套接字是一个抽象层,对所有网卡提供了一个抽象视图。标准库的网络相关函数调用socketcall系统调用与内核通信交互,进而访问网卡。

四、注册

1、设备数据库
每个字符设备都表示为struct cdev的一个实例。
struct kobj_map {struct probe {struct probe *next;dev_t dev;//设备号unsigned long range;//设备号的范围struct module *owner;//提供设备驱动程序的模块kobj_probe_t *get;//指向可以返回与设备关联的kobject实例int (*lock)(dev_t, void *);void *data;//字符设备指向 struct cdev实例;块设备 指向struct genhd实例} *probes[255];struct mutex *lock;
};

2、字符设备范围数据库
管理为驱动程序分配的设备号范围,确保指定的范围不与现存的范围重叠。
static struct char_device_struct {struct char_device_struct *next;unsigned int major;//主设备号unsigned int baseminor;//baseminor是包含minorct个从设备号的连续范围中最小的从设备号int minorct;char name[64];//标识struct cdev *cdev;       /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

3、设备号

1)动态静态设备号申请

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

void cdev_init(struct cdev *cdev, const struct file_operations *fops);
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
在获取了设备号范围之后,需要将设备添加到字符设备数据库,以激活设备。在cdev_add成功返回后,设备进入活动状态。
2)动态创建设备文件
每当内核检测到一个设备时,都会创建一个内核对象kobject。该对象借助于sysfs 文件系统导出到用户层。内核还向用户空间发送一个热插拔消息。
udevd是一个守护进程,允许从用户层动态创建设备文件。

如果在系统启动期间发现新设备,或在运行期间有新设备接入(如USB 存储棒),内核产生的热 插拔消息包含了驱动程序为设备分配的主从设备号。udevd守护进程所需完成的所有工作,就是监听 这些消息。在注册新设备时,会在/dev中创建对应的项,接下来就可以从用户层访问该设备了。

五、与文件系统关联

1、 inode中的设备文件成员

虚拟文件系统中的每个文件都关联到一个inode,用于管理文件属性。inode与驱动程序有关的成员如下:

struct inode { ... dev_t i_rdev; //标识与一个设备文件关联的设备... umode_t i_mode; ... struct file_operations *i_fop; //一组函数指针的集合... union { ... struct block_device *i_bdev; struct cdev *i_cdev; }; ...
};

2,标准文件操作

在打开一个设备文件时,各种文件系统的实现会调用init_special_inode函数,为块设备或字 符设备文件创建一个inode。
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{inode->i_mode = mode;if (S_ISCHR(mode)) {inode->i_fop = &def_chr_fops;inode->i_rdev = rdev;} else if (S_ISBLK(mode)) {inode->i_fop = &def_blk_fops;inode->i_rdev = rdev;} else if (S_ISFIFO(mode))inode->i_fop = &pipefifo_fops;else if (S_ISSOCK(mode));  /* leave it no_open_fops */elseprintk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"" inode %s:%lu\n", mode, inode->i_sb->s_id,inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);

3,字符设备的标准操作

struct file_operations def_chr_fops = { .open = chrdev_open,
};
chrdev_open函数的主要任务就是向该结构填入适用于已打开设备的函数指针, 使得能够在设备文件上执行有意义的操作,并最终能够操作设备自身。
4、字符设备的表示
struct cdev { struct kobject kobj; //一个嵌入在该结构中的内核对象,它用于该数据结构的一般管理struct module *owner; //指向驱动程序的模块const struct file_operations *ops; //硬件通信的具体操作struct list_head list; dev_t dev; //设备号unsigned int count;
};

六、资源管理

为使得各种不同的驱动程序彼此互不干扰,有必要事先为驱动程序分配端口和I/O内存范围。这确保几种设备驱动程序不会试图访问同样的资源。
struct resource { resource_size_t start; //start和end类型为unsigned long,指定了一个一般性的
区域resource_size_t end; const char *name; unsigned long flags; //用于更准确地描述资源及其当前状态struct resource *parent, *sibling, *child; //父子兄弟之间关系
};

资源分配它连续地扫描现存的资源,将新资源添加到正确的位置,或发现与已经分配区域的冲突。完成所述工作,需要遍历兄弟结点的链表。如果 所需的资源区域是空闲的,则插入新的resource实例,这样就完成了资源的分配。如果该区域不是空 闲的,则分配失败。
//资源请求
static struct resource * request_resource(struct resource *root,
struct resource *new);//资源释放
void release_resource(struct resource *old)

七、结构体总结

上述介绍的结构体在内核中的使用如下

内核启动start_kernel到kobj_map注册


参考:

《深入理解linux内核》

linux内核源码分析之设备驱动相关推荐

  1. linux内核源码分析 - nvme设备的初始化

    [好文推荐] 浅析linux内核网络协议栈--linux bridge 深入理解SR-IOV和IO虚拟化 virtio-net 实现机制[一](图文并茂) 驱动的加载 驱动加载实际就是module的加 ...

  2. iostat IO统计原理linux内核源码分析----基于单通道SATA盘

    iostat IO统计原理linux内核源码分析----基于单通道SATA盘 先上一个IO发送submit_bio流程图,本文基本就是围绕该流程讲解. 内核版本 3.10.96 详细的源码注释:htt ...

  3. Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】...

    原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...

  4. Linux内核源码分析《进程管理》

    Linux内核源码分析<进程管理> 前言 1. Linux 内核源码分析架构 2. 进程原理分析 2.1 进程基础知识 2.2 Linux进程四要素 2.3 进程描述符 task_stru ...

  5. Linux内核源码分析方法—程序员进阶必备

    一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是 ...

  6. Linux内核源码分析—从用户空间复制数据到内核空间

    Linux内核源码分析-从用户空间复制数据到内核空间 本文主要参考<深入理解Linux内核>,结合2.6.11.1版的内核代码,分析从用户空间复制数据到内核空间函数. 1.不描述内核同步. ...

  7. v67.03 鸿蒙内核源码分析(字符设备) | 绝大多数设备都是这类 | 百篇博客分析OpenHarmony源码

    曾子曰:"君子以文会友,以友辅仁." <论语>:颜渊篇 百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 绝大多数设备都是这类 文件系统相关篇 ...

  8. Linux内核源码分析之内存管理

    本文站的角度更底层,基本都是从Linux内核出发,会更深入.所以当你都读完,然后再次审视这些功能的实现和设计时,我相信你会有种豁然开朗的感觉. 1.页 内核把物理页作为内存管理的基本单元. 尽管处理器 ...

  9. 【技术分享篇】Linux内核——手把手带你实现一个Linux内核文件系统丨Linux内核源码分析

    手把手带你实现一个Linux内核文件系统 1. 内核文件系统架构分析 2. 行行珠玑,代码实现 [技术分享篇]Linux内核--手把手带你实现一个Linux内核文件系统丨Linux内核源码分析 更多L ...

最新文章

  1. go dll char* memcpy
  2. ABAP股票查看代码
  3. 【Python】函数的可变可选参数传递及返回值
  4. maven deploy上传本地jar至私服
  5. C++ 线程安全的单例模式
  6. can硬件结构和工作原理_汽车CAN总线工作原理及测量方法详解
  7. 演化博弈及Python实现
  8. 微信电影影视小程序系统源码
  9. android抽屉式listview,Android 抽屉效果的导航菜单实现
  10. git init和git clone获取仓库 (一)
  11. java 实现EME2000(国家大地坐标系)转ECEF坐标系(地心地固坐标系)
  12. colorFormat颜色转换插件
  13. 计算幻术之路(二):增强现实的现实
  14. c++中sprintf和sprintf_s的区别
  15. debugger在js中是什么
  16. jai-code实现tiff文件转jpg功能
  17. 青柠日语五十音QuickStart
  18. px4通过mavros+wifi+板载计算机连接地面站
  19. jar包升级,升级springboot默认mysql-connet-java版本
  20. c 语言编写的一元二次方程的根,编写C#程序,计算一元二次方程ax^2+bx+c得实根

热门文章

  1. 用python爬取实时基金估值
  2. 独家 | 合成资产平台Synthetix:鲜为人知,却身处DeFi中心
  3. 神经网络如何识别图像,神经网络与模式识别
  4. CSS的Flex布局的学习
  5. 第三代双倍速率同步动态随机存储器(Double-Data-Rate 3 Synchronous Dynamic RAM,DDR3 SDRAM):简介及内容导航
  6. 十多位IT专家分享他们离不开的实用工具
  7. 微软拼音输入法团队博客搬家通知
  8. mysql中的视图作用是什么意思_mysql数据库视图的作用是什么意思
  9. 零基础入门CV赛事- 街景字符编码识别
  10. vue使用antd实现日历待办标记