Linux 设备树详解

Linux 设备树详解
Linux 设备树详解

1、ARM Linux社区为什么要引入设备树

Linux之父Linus Torvalds闲来无事,在翻看ARM Linux代码的时候,有一天终于忍不住了。他在2011年3月17日的ARM Linux邮件列表中说道:“This whole ARM thing is a f*cking pain in the ass”。这句话迫使ARM Linux社区引入了设备树。

Linus Torvalds为什么会发飙呢?而ARM Linux社区的牛人为什么又乖乖地听话了?你得首先理解Linux设备驱动框架中一个非常好的设计:设备信息和驱动分离。

为了说明设备信息和驱动分离的概念,这里用一个简单的模拟代码来解释:

【例-1】实现一个代码,把要使用的信息简单写死在代码中:

int add() /*模拟驱动代码*/

{

return 3+5; /*模拟设备信息*/

}

优点:简单

缺点:一旦加数和被加数发生变化就得改代码

改进设计如下:

【例-2】实现一个代码,把要使用的信息和操作代码分离开来:

struct dev{

int id;

int x;

int y;

}; /*模拟设备信息结构*/

strcut drv{

int id;

int (*add)(struct dev *info);

}; /*模拟驱动结构*/

int add(struct dev *info) /*模拟驱动代码*/

{

return info->x + info->y; /*模拟设备信息-通过参数传递进来*/

}

struct drv drv = {

.id = 1,

.add = add,

};

/*模拟设备信息*/

struct dev dev = {

.id = 1,

.x = 3,

.y = 5,

};

/*模拟总线初始化匹配设备信息和驱动代码*/

int bus()

{

if(dev.id == drv.id){

return drv.add(&dev);

}

...

}

优点:不管加数和被加数怎么变化,不需要修改代码,仅需要修改信息

缺点:结构比较复杂

那这个设备信息和驱动分离的设计跟驱动有什么关系呢?熟悉硬件编程的同学都知道,硬件一般的构成可以使用下图简单表述:

操作外设的驱动代码逻辑,只要硬件是一样的,就不会变化。但是外设挂到不同的主机上,可能会存在I/O地址的变化,如果有中断也是一样的,中断号也可能不同。这些I/O地址和中断号就是设备信息,使用这些信息来操作控制硬件的代码就是驱动。

如果采用【例-1】的设计方式,那么同一个硬件外设接到不同的主机,或是换了地址线/中断线,设备信息就变化了,得去修改驱动。但是采用【例-2】的方式进行设计,问题就迎刃而解:不管同样的外设硬件接到哪里或是那个平台,其驱动代码逻辑并不需要改动,而仅仅需要改变下设备信息,主要的就是I/O 地址和中断号。

说了这么半天,跟引入设备树有什么关系呢?华清教学使用的开发板(A8/A9)都使用DM9000网卡芯片。DM9000驱动是开源的,在主线内核源码中就有。我们每次基于A8/A9板子移植的时候,DM9000驱动并没有修改过,仅仅是选配了下,主要的工作是在板级文件中添加了设备信息。DM9000驱动使用的是platform框架,所以添加了一份DM9000网卡芯片的platform_device信息。问题来了,如果使用C代码的形式来描述设备信息,则在内核源码中,将会有多份DM9000的platform_device设备信息,造成了内核代码冗余。

解决这个问题的办法就是引入设备树,改造【例-2】来说明设备树的作用。

【例-3】实现一个代码,不仅把要使用的信息和操作代码分离开来,而且信息不是C代码编写的,而是文本配置文件保存的:

struct dev{

int id;

int x;

int y;

}; /*模拟设备信息结构*/

strcut drv{

int id;

int (*add)(struct dev *info);

}; /*模拟驱动结构*/

int add(struct dev *info) /*模拟驱动代码*/

{

return info->x + info->y; /*模拟设备信息-通过参数传递进来*/ }

struct drv drv = {

.id = 1,

.add = add,

};

/*模拟设备树-一个特殊的配置文件,xxx.dtbs的文本文件*/ /{

......

Dm9000{

x = 3;

y = 5;

};

......

};

/*模拟总线初始化匹配设备信息和驱动代码*/

int bus()

{

/*模拟设备树初始化处理*/

读文件(xxx.dtbs);

解析文件内容(根据设备树的规则来解析);

生成struct dev设备信息;

if(dev.id == drv.id){

return drv.add(&dev);

}

...

}

如果像【例-3】这样,就可以解决大量设备信息的代码冗余问题。

推而广之,系统的软硬件信息都可以使用设备树来描述。这样的话,ARM Linux社区就不会因为支持板子和驱动越来越多造成内核源码中出现很多冗余代码(主要是板级文件),仅仅需要移植者,把系统的软硬件信息通过设备树提供出来,选配一下内核代码,就可以了。

2、设备树的概述

2.1、参考资料

内核源码目录Documentation\devicetree设备树说明文档

内核源码drivers/of/源码分析

2.2、基本概念

设备树是描述软/硬件信息的,包含节点和属性的一个树形结构。节点用以归类描述了一个硬件信息或是软件信息(好比文件系统的目录)。节点内描述了一个或多个属性,属性是键值对,描述具体的软/硬信息。简单形式如下:

/{

node{

property=value;

...

child_node{

child_property=value;

...

};

...

};

...

};

说明如下:

/:根节点,节点使用“{};”的语法描述作用范围

node:根节点下的一个子节点

child_node:node节点下的一个子节点

property:node节点内描述的属性,value就是属性的值(任意字节数据,可以是整型、字符串、数组、等等)。描述行以“;”结束

2.3、存储形式

在《ARM Linux社区为什么要引入设备树》中,已经讨论过设备树的使用方式。简而言之:内核初始化时,以配置的文件形式读取设备树文件的内容,并解析后生成相应的软/硬件信息,以供相应的内核代码使用。

编写设备树文件是以.dts的文本文件存储的,主要是为了修改、添加编辑方便。

那么问题来了,如果纯文本解析的话,显然比较慢且麻烦。譬如如果属性值是一个I/O地址:

0x80000000,如果是字符串的形式存储,那么“0x80000000”就是一个字符串,内核代码解析这个信息的时候还得转换成整型数,不仅仅是慢,无形设备树文件大小还会增加不少,还得增加更多的初始化代码。

所以.dts的设备树文件,在内核使用前需要转换一次,主要是把繁复的语法形式及属性值转换成字节数据(特殊的数据结构),而非符号。.dts文件转换后是.dtb的二进制文件。

3、节点

3.1、命名

节点的命名以字母、数字、_、等等符号构成。常见的命令方式如下:

A、以“设备名”为节点名,范例:

DM9000命名如下:

/{

...

dm9000{

...

};

...

};

B、以“设备@I/O地址”为“节点名@I/O地址”,范例:

DM9000在主机端的I/O地址为0x8000 0000,可以命名如下:

/{

...

dm9000@80000000{

...

};

...

};

C、以“设备类型@I/O地址”为“节点名@I/O地址”,范例:

DM9000在主机端的I/O地址为0x8000 0000,可以命名如下:

/{

...

ethernet@80000000{

...

};

...

};

3.2、节点路径

A、

/{

...

dm9000{

...

};

...

};

节点名:dm9000

节点路径:/dm9000

B、

/{

...

dm9000@80000000{

...

};

...

};

节点名:dm9000

节点路径:/dm9000@80000000 C、

/{

...

ethernet@80000000{

...

};

...

};

节点名:ethernet

节点路径:/ethernet@80000000

3.3、节点引用

/{

aliases {

demo = &demo;

};

...

demo:demo@80000000{

...

};

...

};

节点名:demo

节点路径:/demo@80000000

引用路径:demo(等价/demo@80000000,解决路径名过程的问题)

设备树中引用节点“/demo@80000000”的范例:

&demo{

...

};

3.4、节点查找

有时候,分享内核代码或是编写内核代码的时候,可能会涉及使用查找节点函数。内核提供很多内核函数来查找(解析设备树)一个指定节点:

A、路径查找

/*

* 功能:通过路径查找指定节点

* 参数:

* const char *path - 节点路径,可以是路径,也可以是路径引用

* 返回值:

* 成功:得到节点对象的首地址;失败:NULL

*/

struct device_node *of_find_node_by_path(const char *path);

B、节点名查找

/*

* 功能:通过节点名查找指定节点

* 参数:

* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始

* const char *name- 节点名

* 返回值:

* 成功:得到节点对象的首地址;失败:NULL

*/

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);

C、通过compatible属性查找

/*

* 功能:通过compatible属性查找指定节点

* 参数:

* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始

* const char *type - 节点类型,可以为NULL

* const char *compat - 指向节点的compatible属性的值(字符串)的首地址

* 返回值:

* 成功:得到节点对象的首地址;失败:NULL

*/

struct device_node *of_find_compatible_node(struct device_node *from,

const char *type, const char *compat);

设备ID表结构

struct of_device_id {

char name[32]; /*设备名*/

char type[32]; /*设备类型*/

char compatible[128]; /*用于与设备树compatible属性值匹配的字符串*/

const void *data; /*私有数据*/

};

/*

* 功能:通过compatible属性查找指定节点

* 参数:

* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始

* const struct of_device_id *matches - 指向设备ID表

* 注意ID表必须以NULL结束

* 范例:const struct of_device_id mydemo_of_match[] = {

{ .compatible = "fs4412,mydemo", },

{}

};

* 返回值:

* 成功:得到节点对象的首地址;失败:NULL

*/

struct device_node *of_find_matching_node(struct device_node *from,

const struct of_device_id *matches);

D、查找子节点

/*

* 功能:查找指定节点的子节点

* 参数:

* const struct device_node *node - 指向要查找子节点的父节点

* const char *name - 子节点名

* 返回值:

* 成功:得到子节点对象的首地址;失败:NULL

*/

struct device_node *of_get_child_by_name(const struct device_node *node,

const char *name);

3.5、节点内容合并

有时候,一个硬件设备的部分信息不会变化,但是部分信息是可能会变化的,就出现了节点内容合并。即:先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。

在同级路径下,节点名相同的“两个”节点实际是一个节点。

/*参考板的已经编写好的node节点*/

/{

node{

item1=value;

};

};

/*移植者添加的node节点*/

/{

node{

item2=value;

};

等价于:

/{

node{

item1=value;

item2=value;

};

};

3.6、节点内容替换

有时候,一个硬件设备的部分属性信息可能会变化,但是设备树里面已经描述了所有的属性值,使用者可以添加已有的属性值,以替换原有的属性值,就出现了节点内容替换。

另外,节点的内容即使不会变化,但是可能不会使用。

在同级路径下,节点名相同的“两个”节点实际是一个节点。

内容替换的常见形式之一:

/*参考板的已经编写好的node节点*/

/{

node{

item=value1;

};

};

/*移植者添加的node节点*/

/{

node{

item=value2;

};

};

等价于:

/{

node{

item=value2;

};

};

内容替换的常见形式之二:

/*参考板的已经编写好的node节点*/

node{

item=value;

status = "disabled";

};

};

/*移植者添加的node节点*/

/{

node{

status = "okay";

};

};

等价于:

/{

node{

item=value;

status = "okay";

};

};

3.7、节点内容引用

有时候,一个节点需要使用到别的节点的属性值,就需要引用的概念。有时候在设备树编写时,要替换节点属性值,或是合并节点的属性值,也会使用引用。

A、引用节点完成属性值的替换及合并:

/*参考板的已经编写好的node节点*/

/{

node:node@80000000{

item1=value;

status = "disabled";

};

};

/*移植者添加的node节点*/

&node{

item2=value;

status = "okay";

等价于:

/{

node : node@80000000{

item1=value;

item2=value;

status = "okay";

};

};

B、节点引用另一个节点:

/*参考板的已经编写好的node节点*/

/{

node:node@80000000{

item=value;

};

};

/*移植者添加的demo节点*/

/{

demo{

item=<&node>;

};

};

说明:

demo节点的属性item引用了节点的node的属性值,具体怎么使用node节点的属性值,在属性章节进行讨论。

《实用操作系统》实验报告五linux设备管理

《实用操作系统》实验报告 实验报告: 5 实验项目名称:设备管理 班级:学号:姓名: 地点:时间:2013 年11 月13 日 一、实验内容 1、添加硬盘,创建二个主分区、一个扩展分区,二个逻辑分区 注意:ide、scsi 提示:分区、格式化、挂载(fdisk,mkfs,mount) 2、查看常见的设备文件有哪些?(ls /dev ) 常见的设备文件:/dev/hd* IDE接口的硬盘(IDE接口的设备) /dev/sd* SCSI/USB设备/dev/cua* 串口设备/dev/lp* 并口设备/dev/tty* 终端设备/dev/consol 控制台设备/dev/eth* 以太网设备/dev/cdrom IDE光驱/dev/fd* 软驱/dev/audio 音频设备/dev/scd SCSI的光驱/dev/ppp PPP设备/dev/isdn* ISDN设备 3、挂载光盘,查看光盘内容创建挂载点要求:以本人姓名缩写为目录mkdir / 目录/设备挂载mount 空格源设备空格挂载点 4、显示管理System-config-display 5、声卡管理System-config-soundcard 6、打印机管理System-config-printer 7、网卡管理System-config-network 二、实验步骤及结果 1.添加硬盘,创建分区; 在启动虚拟机前,在工具栏中点击“虚拟机”,找到“设置”选项,在左面的硬件中找到硬盘,进行硬盘设备添加,这里有IDE和SCSI两种硬盘类型可供选择添加。完成硬盘添加后即可启动虚拟机进入linux系统。在这我添加了容量相同的硬盘设备类型各一;

Linux命令大全(设备管理)

设备管理-setleds 名称:setleds 使用权限:一般使用者 使用方式: setleds [-v] [-L] [-D] [-F] [{+|-}num] [{+|-}caps] [{+|-}scroll]说明: 用来设定键盘上方三个LED 的状态。在Linux 中,每一个虚拟主控台都有独立的设定。 参数: -F 预设的选项,设定虚拟主控台的状态。 -D 除了改变虚拟主控台的状态外,还改变预设的状态。 -L 不改变虚拟主控台的状态,但直接改变LED 显示的状态。这会使得LDE 显示和目前虚拟主控台的状态不符合。我们可以在稍后用-L 且不含其它选项的setleds 命令回复正常状态。 -num +num 将数字键打开或关闭。 -caps +caps 把大小写键打开或关闭。 -scroll +scroll 把选项键打开或关闭。 范例: 将数字键打开,其馀二个灯关闭。 # setleds +num -caps -scroll 设备管理-loadkeys 名称: loadkeys 使用权限: 所有使用者

使用方式: loadkeys [ -d --default ] [ -h --help ] [ -q --quiet ] [ -v --verbose [ -v --verbose ]...] [ -m --mktable ] [ -c --clearcompose ] [ -s --clearstrings ] [ filename... ] 使用说明: 这个命令可以根据一个键盘定义表改变linux 键盘驱动程序转译键盘输入过程。详细的说明请参考dumpkeys。 选项: -v --verbose 印出详细的资料,你可以重复以增加详细度。 -q --quiet 不要显示任何讯息。 -c --clearcompose 清除所有composite 定义。 -s --clearstrings 将定串定义表清除。 相关命令: dumpkeys 设备管理-rdev 名称:rdev 使用权限:所有使用者 使用方式:使用这个指令的基本方式是:rdev [-rsvh ] [-o offset ] [ image [value [ offset ] ] ] 但是随著使用者想要设定的参数的不同,底下的方式也是一样: rdev [ -o offset ] [ image [ root_device [ offset ] ] ] swapdev [ -o offset ] [ image [ swap_device [ offset ] ] ] ramsize [ -o offset ] [ image [ size [ offset ] ] ] videomode [ -o offset ] [ image [ mode [ offset ] ] ] rootflags [ -o offset ] [ image [ flags [ offset ] ] ]

Netbackup设备管理之Linux篇

Netbackup设备管理之Linux篇 在备份软件的使用过程中,关于磁盘、磁带的治理一样会花费储备治理员专门大比例的时刻和精力。因此,关于设备的治理的方便程度,是衡量一个备份软件好坏的重要的标准。Netbackup作为业界最为知名的备份软件之一,能够为用户提供最为方便的设备治理操作。 现在,随着Redhat和SuSE以及oracle Linux的日益成熟,越来越多的用户选择使用Linux平台来部署其商用环境。这就要求储备设备治理员能够在各种Linux平台的操作和使用各种硬件设备。然而,尽管Netbackup在不同的操作系统上提供了统一的治理界面,然而由于操作系统的差异,使得系统治理员不得不自己配置新购置的磁盘阵列和磁带库,使得其能够被Netback up识不和有效利用。本文介绍的重点在Linux上面的设备治理,使得Netbac kup能够能够正确的识不AIX操作系统上的磁盘阵列、机械手和磁带库等设备。具体的Netbackup中如何使用差不多识不的设备的内容,在各个操作系统是没有差异的,它们将会在后面的文章中予以介绍。 一,检查Netbackup软件的兼容性列表 用户在配置设备时,第一需要注意的情况是检查该软件的兼容性列表,检查该软件是否支持用户当前正在使用的操作系统版本和磁盘、磁带等设备。一样来讲,使用主流的操作系统和应用广泛的设备,都可不能有什么咨询题。然而如果用户使用的是比较专门的应用环境,那么就需要提早检查一下兼容性列表了,以免在使用过程中显现错误,一样来讲这种错误都不容易诊断出来。 二,确认驱动程序差不多安装: # lsmod |grep st 确认已在内核中安装或装入了 sg (机械手)设备驱动程序。此驱动程序承诺向 SCSI 磁带机发出PASSTHRU 命令和操纵机械手设备。

实验九Linux设备管理实验

实验九Linux设备管理实验 一、实验目的: 掌握linux系统重定向、管道操作和设备管理的法。 二、预备知识 1.标准的输入输出和重定向 执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin,通常对应终端的键盘);标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。 用户在输入输出数据时存在以下问题: ●从终端输入数据时,用户输入的数据只能用一次,如果下次再想用这些 数据时就得重新输入。而且在终端上输入时,项输入有误修改起来不是 很便。 ●输出到屏幕上的信息只能看不能动,无法对此输出作更多处理,如将作 为另一命令的输入进行进一步的处理等。 为了解决上述问题,Linux系统为输入输出的传送引入了另外两种机制,即输入输出重定向。输入重定向是指把命令(或可执行程序)的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。因此,输入重定向主要用于改变一个命令的输入源,告别是改变那些需要大量输入的输入源。输出重定向是批把命令(或可执行程序)的标准输出或标准错误输出重定

向到指定文件中。这样,命令的输出就不显示在屏幕上,而是写入到指定文件中。2.管道 将一个程序或命令的输出作为另一个程序或命令的输入可有两种法,一种是通过一个临时文件将两个命令或程序联系在一起;另一种是Linux所提供的管道功能,这种法比前一种法更好。管道可以把一系列命令连接起来,这就意味着第一个命令的输出会将为第二个命令的输入通过管道传给第二个命令,而第二个命令的输出又作为第三个命令的输入,以此类推。显示在屏幕上的是管道行中最后一个命令的输出(如果命令行中示使用输出重定向)。用户还可以通过使用管道符“|”来建立一个管道行。 3.文件备份和压缩 参见第二章相关的ppt。 三、实验容和实验步骤(实验情况请截图和说明) 1.基本实验 (1)标准输入输出文件使用 通过wc命令统计指定文件包含的行数、单词数和字符数。 实验步骤一:在命令提示符输入ls,显示当前目录下的文件。 [m112013@tan ~]$ ls ch4 ch5 lab1 lab2 lab3 lab4 lab5 lab6 lab7 lab8 lab9 subdir [m112013@tan ~]$ cd lab9 [m112013@tan lab9]$ ls test.c

linux设备管理命令

linux设备管理命令 1.1 stty [语法]: stty [-a] [-g] [选项] [说明]: 本命令设置终端,无参数时报告终端设置,本命令功能十分强大,应谨慎使用,下面仅介绍部分常用功能 ?-a 显示当前终端所有设置 ?-g 以能作为 stty 命令参数的方式显示终端设置以下是终端常用设置,在设置前加-表示清除设置: o1.控制方式,ispeed 0 110 300 600 1200 1800 2400 4800 9600 19200 38400,本命令设置终端输入波特率,若为0则使用缺省波 特率。例如 stty ispeed 9600 ospeed 0 110 300 600 1200 1800 2400 4800 9600 19200 38400本命令设置终端输出波特率,参看 ispeed。 o2.输入方式 ?ingbrk(-ignbrk) 忽略(不忽略)中断(BREAK) ?brkint(-brkint) 设置(清除)信号INTR为中断信号 ?inlcr(-inlcr) 将换行转换(不转换)成回车 ?icrnl( -icrnl) 将回车转换(不转换)成换行 ?igncr(-ignrc) 忽略(不忽略)回车 ?iuclc( -iuclc) 将大写字母转换(不转换)成小写字母o3.输出方式 ?olcut(-olcut) 将小写字母转换(不转换)为大写字母 ?onlcr(-onlcr) 输出时将换行符转换(不转换)为回车换行 ?ocrnl(-ocrnl) 输出时将回车符转换(不转换)为换行符o4.本地方式 ?echo (-echo) 设置(清除)回显 ?stwrap(-stwrap) 截断(不截断)大于79个字符的行 ?echoctl(-echoctr) 将控制键回显为^ 1.2 tty [语法]: tty [说明]: 显示出终端的设备名 [例子]: tty 1.3 lp [语法]: lp 文件... [说明]: 将文件送打印机打印 [例子]: lp myfile将文件myfile 送打印机输出 1.4 lpstat [语法]: lpstat [选项] [打印任务号] [说明]: 显示打印机状态,选项的意义如下:

Linux统一设备管理平台platform之设备注册流程V2版-李枝果

Linux lizhiguo0532@https://www.360docs.net/doc/a83109899.html, --------------------------------------------------------------------------------------------------------------------- https://www.360docs.net/doc/a83109899.html,/sz_farsight ---------------------------------------------------------------------------------------------------------------------- linux-2.6.14 1. linux2.6 platform_device platform_driver Linux Platform_device Platform_driver platform driver device driver ( driver_register ) platform platform device 2.s3c2410 3. a. :include\linux\ioport.h struct resource { const char *name; /* */ unsigned long start, end; /* cpu * start cpu * end */ unsigned long flags; /* */ /* */ /* */ struct resource *parent, *sibling, *child; /* */ }; /* * ,

设备管理--Linux设备驱动程序安装

集美大学计算机工程学院实验报告 课程名称:操作系统班级:xxx实验成绩: 指导教师:姓名:xxx ( 学号:xxxx上机实践日期:xxx 实验项目名称: 设备管理——Linux设备驱动程序安装 实验项目编号:组号:上机实践时间: 2 学时~ 一、目的(本次实验所涉及并要求掌握的知识点) 1.认识Linux的设备的种类和设备工作方式; 2.理解设备驱动程序的工作原理; 3.掌握设备驱动程序的编写规范,能编写并安装简单的设备驱动程序。 二、实验内容与设计思想(设计思路、主要数据结构、主要代码结构、主要代码段分析、电路图) 实验内容: ¥ 在Linux系统中,编写一个简单的字符型设备驱动程序模块,设备具有独占特性,可执行读和写操作,相关系统调用为open, close, read, write,open和close分别相当于请求和释放设备,read和write内容保存在设备模块内的缓冲区中。设备模块可动态注册和卸载,并建立与之对应的特殊文件/dev/mydev。 实验设计: 1.按照要求编写设备驱动模块,同时编写一个测试程序 2.分别对其编译,注意编译时的项 3.设备模块加载 4.创建特殊文件 5.分析执行结果 6.设备模块卸载 < 三、实验使用环境(本次实验所使用的平台和相关软件) Linux 四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析) LINUX_VERSION_CODE is * the code (as per KERNEL_VERSION) of this version. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0) < #include /* for put_user */ #endif #define SUCCESS 0 #define DEVICE_NAME "kueng_char_dev"

Linux设备驱动程序的概念、作用以及模块

Linux设备驱动程序的概念、作用以及模块 我们首先对linux系统整个框架要有个了解。Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。 Linux 内核将这4G字节的空间分为两部分,分别是用户空间(0~3G)和内核空间(3G~4G)。其中,用户空间存放的是应用程序,而内核空间存放的是内核,设备驱动和硬件。 为什么需要存在设备驱动呢?我们知道,内核是操作系统基本的部分,而操作系统是不能够直接控制硬件的,这样我们就需要设备驱动作为操作系统和硬件设备间的粘合剂,相当于一个中间人吧,负责上下两边的沟通。驱动负责将操作系统的请求传输,转化为特定物理设备控制器能够理解的命令。 这样我们就知道,驱动需要完成两大功能: 1、为linux内核提供调用接口。 2、控制硬件。因为寄存器是控制硬件的操作,所以驱动程序控制硬件,也就是要通过读写硬件寄存器达到控制硬件的目的。 内核是为应用程序服务的,其本质其实是函数的集合,内核要实现的功能我们可以分为两部门:基本功能和扩展功能。其中,基本功能包括进程管理,线程管理等等,而扩展功能,可以根据用户的需求自行添加。 下面我们就来探讨一下怎样向内核添加一项功能呢? 1、我们首先想到,肯定需要写一个功能函数,假如我们命名为fun.c,那么函数写好后,必须要和linux源码一起编译,生成zImage内核镜像文件。 2、重新编译内核。 这样就得到了新的内核,这种添加的方式我们称为静态添加。大家发现,每次修改一次fun.c,都要重新编译一次内核,灰常的麻烦,所以引进了内核模块机制,只需要加载或卸载模块,就可以动态的增加或者删除内核的功能,不用每次都重新编译,是不是很方便?那么接下来我们会想到,这个模块怎么就能和内核连接在一起呢?其实很简单,fun.c文件除了要实现功能呢,还需要包含和内核的接口,内核也提供了模块的接口,只要这两个接口一致,模块就可以融入内核,成为内核的一部分。Linux驱动程序都是以模块的形式存在的,所以我们称之为驱动模块。 所以我们总结出添加模块的步骤是: 1、写功能函数fun.c。 怎么样编写模块的源码文件,我们以一个Hello模块实例分析。 #include #include //①模块的头文件,在对应内核下 的include目录中{ … //②功能函数hello.c(同普通} 的.c文件) Static int __int hellomudule_init(void) //③模块初始化函数 { Printk(“Hello world!\n”); Return 0; }

NBU60网络备份大全之Linux设备管理(参考Word)

NBU6.0网络备份大全之Linux设备管理 在备份软件的使用过程中,对于磁盘、磁带的管理一般会花费存储管理员很大比例的时间和精力。因此,对于设备的管理的方便程度,是衡量一个备份软件好坏的重要的标准。 现在,随着Redhat和SuSE以及oracle Linux的日益成熟,越来越多的用户选择使用Linux平台来部署其商用环境。这就要求存储设备管理员能够在各种Linux平台的操作和使用各种硬件设备。 虽然Netbackup在不同的操作系统上提供了统一的管理界面,但是由于操作系统的差异,使得系统管理员不得不自己配置新购置的磁盘阵列和磁带库,使得其能够被Netbackup识别和有效利用。本文介绍的重点在Linux上面的设备管理,使得Netbackup可以能够正确的识别AIX操作系统上的磁盘阵列、机械手和磁带库等设备。具体的Netbackup中如何使用已经识别的设备的内容,在各个操作系统是没有差异的,它们将会在后面的文章中予以介绍。 一,检查Netbackup软件的兼容性列表 用户在配置设备时,第一需要注意的事情是检查该软件的兼容性列表,检查该软件是否支持用户当前正在使用的操作系统版本和磁盘、磁带等设备。一般来说,使用主流的操作系统和应用广泛的设备,都不会有什么问题。但是如果用户使用的是比较特殊的应用环境,那么就需要提前检查一下兼容性列表了,以免在使用过程中出现错误,一般来说这种错误都不容易诊断出来。 二,确认驱动程序已经安装 1,确认已在内核中安装或装入了 st (磁带)设备驱动程序。此驱动程序允许使用 SCSI 磁带机:# lsmod |grep st 2,确认已在内核中安装或装入了 sg (机械手)设备驱动程序。此驱动程序允许向 SCSI 磁带机发出PASSTHRU 命令和控制机械手设备。# lsmod |grep sg 3,如果st磁带驱动程序或者sg机械手驱动程序不存在,那么需要手动加载它们: /sbin/modprobe st /sbin/modprobe sg (注意)自动加载的驱动程序可能在操作系统重新启动后无法自动加载,导致Netbackup无法识别并使用之前配置好的设备。这个问题可能会给Netbackup的使用者带来困惑。所以最好利用某种办法(很多不一一累述),保证系统启动能够自动加载st和sg程序到内核中。 三,配置机械手: 在Linux操作系统中,主要是区别2.4内核还是2.6内核的操作系统,分别有不同的配置方法。 针对2.4内核的操作系统,Netbackup在安装时后自动运行/usr/openv/volmgr/bin/make_scsi_dev命令,该命令在/dev/sg目录下自动创建设备文件,文件格式为hHOSTcCHANNELtTARGETlLUN,其中:HOST 是主机总线适配器;CHANNEL 是通道;TARGET 是目标 ID;LUN 是逻辑单元号。例如h10c0t1l0就是一个合法的设备文件名称。 在2.6内核的操作系统中,操作系统使用/dev目录下的sgN设备文件,N是0到255之间的任意整数。四,配置磁带驱动器 在2.4内核的操作系统中,/usr/openv/volmgr/bin/make_scsi_dev命令将会在/dev/st 目录中创建设备文件。该目录中的无倒带设备文件的名称具有以下格式:nhHOSTcCHANNELtTARGETlLUN,其中:n 是“关闭时无倒带”设备文件;HOST 是主机总线适配器;CHANNEL 是通道;TARGET 是目标 ID;LUN 是逻辑单元号。例如nh10c0t2l0就是一个合法的磁带驱动器的名称。 在2.6内核的系统中,NetBackup 仅使用 /dev/nstX 文件,其中 X 一个介于 0到 127 之间的十进制数。五,验证机械手和磁带库的配置 在Linux系统中,/proc/scsi/scsi 文件显示了 SCSI 驱动程序识别的所有设备。要确定操作系统能否看到设备,可从终端窗口运行以下命令来查看该文件: # cat /proc/scsi/scsi

Linux设备文件浅析

linux下的文件分为常规文件和设备文件,常规文件一定在某一个设备上被存储,不论这个设备是真实的还是虚拟的,这里的设备是linux中vfs层中的设备,也就是前面所说的设备文件中的设备,vfs层的设备分为字符设备和块设备,字符设备可以类比为一个fifo的队列,无论读还是写都必须顺序进行,而块设备就可以随机进行读写,常规的文件一般都在块设备上被存储,包括设备文件本身也在一个块设备上被存储着,可以说vfs层解决了这种混乱,它提供给上面的操作者一个十分统一的接口,实际上vfs下面十分不雅,败絮其中吗?等你看了linux源代码就不会这么认为了,linux内核是分层次的,vfs仅仅是其中的一个罢了,即使下面很乱也不是很无序的乱,总体看来是很乱,那是因为你混合看所有设备那当然混乱,因为字符设备和块设备的管理方式就不同,如果理一下思路就会很自然的想到在vfs接口下面有三条线,一条是常规文件,一条是字符设别文件,另一条就是块设备文件。 linux用很好的数据结构组织了两类设备文件,对于字符设备比较简单,就是将所有的字符设备都置于一个map中,就是cdev_map,所有的字符设备在注册的时候都会加入这个map: int register_chrdev(unsigned int major, const char *name, struct file_operations *fops) { struct char_device_struct *cd; struct cdev *cdev; char *s; int err = -ENOMEM; cd = __register_chrdev_region(major, 0, 256, name);

linux设备号详解

转载】设备文件简介 linux 中的设备有2种类型:字符设备(无缓冲且只能顺序存取)、块设备(有缓冲且可以随机存取)。每个字符设备和块设备都必须有主、次设备号,主设备号相同的设备是同类设备(使用同一个驱动程序)。这些设备中,有些设备是对实际存在的物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,又称为"虚拟设备")。每个设备在 /dev 目录下都有一个对应的文件(节点)。可以通过 cat /proc/devices 命令查看当前已经加载的设备驱动程序的主设备号。内核能够识别的所有设备都记录在原码树下的 documentation/devices.txt 文件中。在 /dev 目录下除了字符设备和块设备节点之外还通常还会存在:fifo管道、socket、软/硬连接、目录。这些东西没有主/次设备号。 $ ls -l /dev/rfd0 /dev/fd0 brw-r----- 9 root operator 2, 0 nov 12 13:32 /dev/fd0 crw-r----- 9 root operator 9, 0 nov 12 13:32 /dev/rfd0 可以看到原来显示文件大小的地方,现在改为显示两个用逗号分隔的数字。这是系统用来表示设备的两个重要的序号,第一个为主设备号(major number),用来表示设备使用的硬件驱动程序在系统中的序号;第二个为从设备号(minor number)。 linux内核所能识别的所有设备都记录在 https://www.360docs.net/doc/a83109899.html,/docs/device-list/ 而内核原码树中的 documentation/devices.txt 可能不是最新版本。 了解这些设备的最基本要求就是对每个设备文件的含义了如指掌,下面就医列表的形式列出常见的设备文件以及相应的含义(比较偏僻的就省略了): 代 码:---------------------------------------------------------------------- 主设备号设备类型 次设备号=文件名简要说明 ---------------------------------------------------------------------- 0 未命名设备(例如:挂载的非设备) 0 = 未空设备号保留 1 char 内存设备 1 = /dev/mem 直接存取物理内存 2 = /dev/kmem 存取经过内核虚拟之后的内存 3 = /dev/null 空设备。任何写入都将被直接丢弃,任何读取都将得到eof。 4 = /dev/port 存取 i/o 端口 5 = /dev/zero 零字节源,只能读取到无限多的零字节。 7 = /dev/full 满设备。

相关文档
最新文档