实例解析linux内核I2C体系结构

实例解析linux内核I2C体系结构
实例解析linux内核I2C体系结构

实例解析linux内核I2C体系结构

作者:刘洪涛,华清远见嵌入式学院讲师。

一、概述

谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C

设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完成。下面比较下这两种驱动。

第一种方法的好处(对应第二种方法的劣势)有:

●思路比较直接,不需要花时间去了解linux内核中复杂的I2C子系统的操作方法。

第一种方法问题(对应第二种方法的好处)有:

●要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器操作;

●要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写出的程序可移植性差;

●对内核的资源无法直接使用。因为内核提供的所有I2C设备器及设备驱动都是基于I2C子系统的格式。I2C适配器的操作简单还好,如果遇到复杂的I2C适配器(如:基于PCI的I2C适配器),工作量就会大很多。

本文针对的对象是熟悉I2C协议,并且想使用linux内核子系统的开发人员。

网络和一些书籍上有介绍I2C子系统的源码结构。但发现很多开发人员看了这些文章后,还是不清楚自己究竟该做些什么。究其原因还是没弄清楚I2C子系统为我们做了些什么,以及我们怎样利用I2C子系统。本文首先要解决是如何利用现有内核支持的I2C适配器,完成对I2C设备的操作,然后再过度到适配器代码的编写。本文主要从解决问题的角度去写,不会涉及特别详细的代码跟踪。

二、I2C设备驱动程序编写

首先要明确适配器驱动的作用是让我们能够通过它发出符合I2C标准协议的时序。

在Linux内核源代码中的drivers/i2c/busses目录下包含着一些适配器的驱动。如S3C2410的驱动i2c-s3c2410.c。当适配器加载到内核后,接下来的工作就要针对具体的设备编写设备驱动了。

编写I2C设备驱动也有两种方法。一种是利用系统给我们提供的i2c-dev.c 来实现一个i2c适配器的设备文件。然后通过在应用层操作i2c适配器来控制i2c设备。另一种是为i2c设备,独立编写一个设备驱动。注意:在后一种情况下,是不需要使用i2c-dev.c的。

1、利用i2c-dev.c操作适配器,进而控制i2c设备

i2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read()、write()和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的i2c 设备的存储空间或寄存器,并控制I2C设备的工作方式。

需要特别注意的是:i2c-dev.c的read()、write()方法都只适合于如下方式的数据格式(可查看内核相关源码)

图1 单开始信号时序

所以不具有太强的通用性,如下面这种情况就不适用(通常出现在读目标时)。

图2 多开始信号时序

而且read()、write()方法只适用用于适配器支持i2c算法的情况,如:

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {

.master_xfer = s3c24xx_i2c_xfer,

.functionality = s3c24xx_i2c_func,

};

而不适合适配器只支持smbus算法的情况,如:

static const struct i2c_algorithm smbus_algorithm = {

.smbus_xfer = i801_access,

.functionality = i801_func,

};

基于上面几个原因,所以一般都不会使用i2c-dev.c的read()、write()方法。最常用的是ioctl()方法。ioctl()方法可以实现上面所有的情况(两种数据格式、以及I2C算法和smbus算法)。

针对i2c的算法,需要熟悉struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是I2C_RDWR。

struct i2c_rdwr_ioctl_data {

struct i2c_msg __user *msgs;

__u32 nmsgs;

};

struct i2c_msg {

_ _u16 addr;

_ _u16 flags;

_ _u16 len;

_ _u8 *buf;

};

针对smbus算法,需要熟悉struct i2c_smbus_ioctl_data。使用的命令是I2C_SMBUS。对于smbus算法,不需要考虑“多开始信号时序”问题。

struct i2c_smbus_ioctl_data {

__u8 read_write; //读、写

__u8 command; //命令

__u32 size; //数据长度标识

union i2c_smbus_data __user *data; //数据

};

下面以一个实例讲解操作的具体过程。通过S3C2410操作AT24C02 e2prom。实现在AT24C02中任意位置的读、写功能。

首先在内核中已经包含了对s3c2410 中的i2c控制器驱动的支持。提供了i2c算法(非smbus类型的,所以后面的ioctl的命令是I2C_RDWR)

static const struct i2c_algorithm

s3c24xx_i2c_algorithm = {

.master_xfer = s3c24xx_i2c_xfer,

.functionality = s3c24xx_i2c_func,

};

另外一方面需要确定为了实现对AT24C02 e2prom的操作,需要确定AT24C02的地址及读写访问时序。

● AT24C02地址的确定

原理图上将A2、A1、A0都接地了,所以地址是0x50。

● AT24C02任意地址字节写的时序

可见此时序符合前面提到的“单开始信号时序”

● AT24C02任意地址字节读的时序

可见此时序符合前面提到的“多开始信号时序”

下面开始具体代码的分析(代码在2.6.22内核上测试通过):

#include

#include

#include

#include

#include

#include

#include

#include

#define I2C_RETRIES 0x0701

#define I2C_TIMEOUT 0x0702

#define I2C_RDWR 0x0707

struct i2c_msg {

unsigned short addr;

unsigned short flags;

#define I2C_M_TEN 0x0010

#define I2C_M_RD 0x0001

unsigned short len;

unsigned char *buf;

};

struct i2c_rdwr_ioctl_data

{

struct i2c_msg *msgs;

int nmsgs;

};

int main()

{

int fd,ret;

struct i2c_rdwr_ioctl_data

e2prom_data;

fd=open("/dev/i2c-0",O_RDWR);

dev/i2c-0是在注册i2c-dev.c后产生的,代表一个可操作的适配器。如果不使用i2c-dev.c

*的方式,就没有,也不需要这个节点。

*/

if(fd<0)

{

perror("open error");

}

e2prom_data.nmsgs=2;

e2prom_data.msgs=(struct

i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));

if(!e2prom_data.msgs)

{

perror("malloc error");

exit(1);

}

ioctl(fd,I2C_TIMEOUT,1);

ioctl(fd,I2C_RETRIES,2);

e2prom_data.nmsgs=1;

(e2prom_data.msgs[0]).len=2; //1个 e2prom 写入目标的地址和1个数据

(e2prom_data.msgs[0]).addr=0x50; //e2prom 设备地址

(e2prom_data.msgs[0]).flags=0; //write

(e2prom_data.msgs[0]).buf=(unsig ned char*)malloc(2);

(e2prom_data.msgs[0]).buf[0]=0x1 0;// e2prom 写入目标的地址

(e2prom_data.msgs[0]).buf[1]=0x5 8;//the data to write

ret=ioctl(fd,I2C_RDWR,(unsigned

long)&e2prom_data);

if(ret<0)

{

perror("ioctl error1");

}

sleep(1);

e2prom_data.nmsgs=2;

(e2prom_data.msgs[0]).len=1;

//e2prom 目标数据的地址

(e2prom_data.msgs[0]).addr=0x50; // e2prom 设备地址

(e2prom_data.msgs[0]).flags=0;// write

(e2prom_data.msgs[0]).buf[0]=0x1 0;//e2prom数据地址

(e2prom_data.msgs[1]).len=1;//读出的数据

(e2prom_data.msgs[1]).addr=0x50; // e2prom 设备地址

(e2prom_data.msgs[1]).flags=I2C_ M_RD;//read

(e2prom_data.msgs[1]).buf=(unsig ned char*)malloc(1);//存放返回值的地址。

(e2prom_data.msgs[1]).buf[0]=0;/ /初始化读缓冲

ret=ioctl(fd,I2C_RDWR,(unsigned

long)&e2prom_data);

if(ret<0)

{

perror("ioctl error2");

}

printf("buff[0]=%x\n",(e2prom_da ta.msgs[1]).buf[0]);

close(fd);

return 0;

}

以上讲述了一种比较常用的利用i2c-dev.c操作i2c设备的方法,这种方法可以说是在应用层完成了对具体i2c设备的驱动工作。

计划下一篇总结以下几点:

(1)在内核里写i2c设备驱动的两种方式:

● Probe方式(new style),如:

static struct i2c_driver

pca953x_driver = {

.driver = {

.name = "pca953x",

},

.probe =

pca953x_probe,

.remove =

pca953x_remove,

.id_table =

pca953x_id,

};

● Adapter方式(LEGACY),

如:

static struct i2c_driver pcf8575_driver = {

.driver =

{

.owner = THIS_MODULE,

.name = "pcf8575",

},

.attach_adapter = pcf8575_attach_adapter,

.detach_client = pcf8575_detach_client,

};

(2)适配器驱动编写方法

(3)分享一些项目中遇到的问题

希望大家多提意见,多多交流。

2. Linux I2C 结构分析

2.1 层次分析

1. I2C Core

I2C Core用于维护Linux的I2C核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。

static LIST_HEAD(adapters);

static LIST_HEAD(drivers);

I2C core提供接口函数,允许一个I2C adatper,I2C driver和I2C client 初始化时在I2C core中进行注册,以及退出时进行注销。具体可以参见

i2c_core.c代码。

同时还提供了I2C总线读写访问的一般接口(具体的实现在与I2C控制器相关的I2C adapter中实现),主要应用在I2C设备驱动中。

常用的主要是

i2c_master_send()

i2c_master_recv()

i2c_transfer()

2. I2C bus driver

总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。

在系统开机时,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。一个总线驱动通常需要两个模块,一个struct

i2c_adapter和一个struct i2c_algorithm来描述:

在 buses目录下的i2c-pxa.c中实现了PXA的I2C总线适配器,I2C adapter 构造一个对I2C core层接口的数据结构,并通过接口函数向I2C core注册一个控制器。I2C adapter主要实现对I2C总线访问的算法,iic_xfer() 函数就是I2C adapter底层对I2C总线读写方法的实现。同时I2C adpter 中还实现了对I2C控制器中断的处理函数。

1) i2c-pxa.c定义了i2c_algorithm,并且实现了master的发送函数

i2c_pxa_xfer(),以及设备查询总线的模式的函数i2c_pxa_functionality() static const struct i2c_algorithm i2c_pxa_algorithm = {

.master_xfer = i2c_pxa_xfer,

.functionality = i2c_pxa_functionality,

};

2) i2c-pxa.c中,实现了i2c_adapter,主要是在定义pxa-i2c时进行初始化,并且i2c_pxa_probe()中进行填充parent指针,并且调用ret =

i2c_add_adapter(&i2c->adap);进行添加。

static struct pxa_i2c i2c_pxa = {

.lock = SPIN_LOCK_UNLOCKED,

.adap = {

.owner = THIS_MODULE,

.algo = &i2c_pxa_algorithm,

.name = "pxa2xx-i2c.0",

.retries = 5,

},

};

总的来说,在i2c-pxa中,使用platform驱动模型,完成了i2c的总线两种模块struct i2c_adapter和struct i2c_algorithm

3. I2C device driver

I2C只有总线驱动是不够的,必须有设备才能工作。这就是I2C device driver的必要性。I2C的device是有两个模块来描述的,struct i2c_driver 和struct i2c_client。

在介绍chips目录下的device driver前有必要介绍一下i2c-dev.c文件。

i2c-dev.c中提供了一个通用的I2C设备的驱动程序,实现了字符类型设备的访问接口,对设备的具体访问是通过I2C adapter来实现的。构造一个对I2C core层接口的数据结构,通过接口函数向 I2C Core注册一个I2C设备驱动。同时构造一个对用户层接口的数据结构,并通过接口函数向内核注册为一个主设备号为89的字符类型设备。

static struct i2c_driver i2cdev_driver = {

.driver = {

.name = "dev_driver",

},

.id = I2C_DRIVERID_I2CDEV,

.attach_adapter = i2cdev_attach_adapter,

.detach_adapter = i2cdev_detach_adapter,

.detach_client = i2cdev_detach_client,

};

struct i2c_dev {

struct list_head list;

struct i2c_adapter *adap;

struct device *dev;

};

该文件提供了用户层对I2C设备的访问,包括open,read,write,ioctl,release等常规文件操作,我们可以通过open函数打开 I2C的设备文件,通过ioctl函数设定要访问从设备的地址,然后就可以通过 read和write函数完成对I2C设备的读写操作。

static const struct file_operations i2cdev_fops = {

.owner = THIS_MODULE,

.llseek = no_llseek,

.read = i2cdev_read,

.write = i2cdev_write,

.ioctl = i2cdev_ioctl,

.open = i2cdev_open,

.release = i2cdev_release,

};

注:通过I2C driver提供的通用方法可以访问任何一个I2C

的设备,但是其中实现的read,write及ioctl等功能完全是基于一般设备的实现,所有的操作数据都是基于字节流,没有明确的格式和意义。为了更方便和有效地使用I2C设备,我们可以为一个具体的I2C设备开发特定的I2C设备驱动程序,在驱动中完成对特定的数据格式的解释以及实现一些专用的功能。

在chips目录下包含着各种device 的driver,完成各种从设备的注册。作为一般的I2C设备,使用i2c-dev.c里的操作足够完成操作了。

当然如果不能完成,则需要独立完成该驱动,这就是chips目录下的代码。因为i2c-dev.c已经实现了I2C设备的文件操作接口,所以只要实现struct

i2c_driver就可以了。对于某些特殊的操作,可以使用command接口进行控制。当然,对于i2接口的fm芯片,则将struct i2c_driver放在i2c的chips目录

Linux内核修改与编译图文教程

Linux 内核修改与编译图文教程 1

1、实验目的 针对Ubuntu10.04中,通过下载新的内核版本,并且修改新版本内核中的系统调用看,然后,在其系统中编译,加载新内核。 2、任务概述 2.1 下载新内核 https://www.360docs.net/doc/5d13654431.html,/ 2.2 修改新内核系统调用 添加新的系统调用函数,用来判断输入数据的奇偶性。 2.3 进行新内核编译 通过修改新版内核后,进行加载编译。最后通过编写测试程序进行测试 3、实验步骤 3.1 准备工作 查看系统先前内核版本: (终端下)使用命令:uname -r 2

3.2 下载最新内核 我这里使用的内核版本是 3.3 解压新版内核 将新版内核复制到“/usr/src”目录下 在终端下用命令:cd /usr/src进入到该文件目录 解压内核:linux-2.6.36.tar.bz2,在终端进入cd /usr/src目录输入一下命令: bzip2 -d linux-2.6.36.tar.bz2 tar -xvf linux-2.6.36.tar 文件将解压到/usr/src/linux目录中 3

使用命令: ln -s linux-2.6.36 linux 在终端下输入一下命令: sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot sudo aptitude install libqt3-headers libqt3-mt-dev libqt3-compat-headers libqt3-mt 4

Linux内核崩溃原因分析及错误跟踪技术

Linux内核崩溃原因分析及错误跟踪技术 随着嵌入式Linux系统的广泛应用,对系统的可靠性提出了更高的要求,尤其是涉及到生命财产等重要领域,要求系统达到安全完整性等级3级以上[1],故障率(每小时出现危险故障的可能性)为10-7以下,相当于系统的平均故障间隔时间(MTBF)至少要达到1141年以上,因此提高系统可靠性已成为一项艰巨的任务。对某公司在工业领域14 878个控制器系统的应用调查表明,从2004年初到2007年9月底,随着硬软件的不断改进,根据错误报告统计的故障率已降低到2004年的五分之一以下,但查找错误的时间却增加到原来的3倍以上。 这种解决问题所需时间呈上升的趋势固然有软件问题,但缺乏必要的手段以辅助解决问题才是主要的原因。通过对故障的统计跟踪发现,难以解决的软件错误和从发现到解决耗时较长的软件错误都集中在操作系统的核心部分,这其中又有很大比例集中在驱动程序部分[2]。因此,错误跟踪技术被看成是提高系统安全完整性等级的一个重要措施[1],大多数现代操作系统均为发展提供了操作系统内核“崩溃转储”机制,即在软件系统宕机时,将内存内容保存到磁盘[3],或者通过网络发送到故障服务器[3],或者直接启动内核调试器[4]等,以供事后分析改进。 基于Linux操作系统内核的崩溃转储机制近年来有以下几种: (1) LKCD(Linux Kernel Crash Dump)机制[3]; (2) KDUMP(Linux Kernel Dump)机制[4]; (3) KDB机制[5]; (4) KGDB机制[6]。 综合上述几种机制可以发现,这四种机制之间有以下三个共同点: (1) 适用于为运算资源丰富、存储空间充足的应用场合; (2) 发生系统崩溃后恢复时间无严格要求; (3) 主要针对较通用的硬件平台,如X86平台。 在嵌入式应用场合想要直接使用上列机制中的某一种,却遇到以下三个难点无法解决: (1) 存储空间不足 嵌入式系统一般采用Flash作为存储器,而Flash容量有限,且可能远远小于嵌入式系统中的内存容量。因此将全部内存内容保存到Flash不可行。

探究linux内核,超详细解析子系统

探究linux内核,超详细解析子系统 Perface 前面已经写过一篇《嵌入式linux内核的五个子系统》,概括性比较强,也比较简略,现在对其进行补充说明。 仅留此笔记,待日后查看及补充!Linux内核的子系统 内核是操作系统的核心。Linux内核提供很多基本功能,如虚拟内存、多任务、共享库、需求加载、共享写时拷贝(Copy-On-Write)以及网络功能等。增加各种不同功能导致内核代码不断增加。 Linux内核把不同功能分成不同的子系统的方法,通过一种整体的结构把各种功能集合在一起,提高了工作效率。同时还提供动态加载模块的方式,为动态修改内核功能提供了灵活性。系统调用接口用户程序通过软件中断后,调用系统内核提供的功能,这个在用户空间和内核提供的服务之间的接口称为系统调用。系统调用是Linux内核提供的,用户空间无法直接使用系统调用。在用户进程使用系统调用必须跨越应用程序和内核的界限。Linux内核向用户提供了统一的系统调用接口,但是在不同处理器上系统调用的方法

各不相同。Linux内核提供了大量的系统调用,现在从系统 调用的基本原理出发探究Linux系统调用的方法。这是在一个用户进程中通过GNU C库进行的系统调用示意图,系 统调用通过同一个入口点传入内核。以i386体系结构为例,约定使用EAX寄存器标记系统调用。 当加载了系统C库调用的索引和参数时,就会调用0x80软件中断,它将执行system_call函数,这个函数按照EAX 寄存器内容的标示处理所有的系统调用。经过几个单元测试,会使用EAX寄存器的内容的索引查system_call_table表得到系统调用的入口,然后执行系统调用。从系统调用返回后,最终执行system_exit,并调用resume_userspace函数返回用户空间。 linux内核系统调用的核心是系统多路分解表。最终通过EAX寄存器的系统调用标识和索引值从对应的系统调用表 中查出对应系统调用的入口地址,然后执行系统调用。 linux系统调用并不单层的调用关系,有的系统调用会由

如何自行编译一个Linux内核的详细资料概述

如何自行编译一个Linux内核的详细资料概述 曾经有一段时间,升级Linux 内核让很多用户打心里有所畏惧。在那个时候,升级内核包含了很多步骤,也需要很多时间。现在,内核的安装可以轻易地通过像 apt 这样的包管理器来处理。通过添加特定的仓库,你能很轻易地安装实验版本的或者指定版本的内核(比如针对音频产品的实时内核)。 考虑一下,既然升级内核如此容易,为什么你不愿意自行编译一个呢?这里列举一些可能的原因: 你想要简单了解编译内核的过程 你需要启用或者禁用内核中特定的选项,因为它们没有出现在标准选项里 你想要启用标准内核中可能没有添加的硬件支持 你使用的发行版需要你编译内核 你是一个学生,而编译内核是你的任务 不管出于什么原因,懂得如何编译内核是非常有用的,而且可以被视作一个通行权。当我第一次编译一个新的Linux 内核(那是很久以前了),然后尝试从它启动,我从中(系统马上就崩溃了,然后不断地尝试和失败)感受到一种特定的兴奋。 既然这样,让我们来实验一下编译内核的过程。我将使用Ubuntu 16.04 Server 来进行演示。在运行了一次常规的 sudo apt upgrade 之后,当前安装的内核版本是 4.4.0-121。我想要升级内核版本到 4.17,让我们小心地开始吧。 有一个警告:强烈建议你在虚拟机里实验这个过程。基于虚拟机,你总能创建一个快照,然后轻松地从任何问题中回退出来。不要在产品机器上使用这种方式升级内核,除非你知道你在做什么。 下载内核 我们要做的第一件事是下载内核源码。在 Kernel 找到你要下载的所需内核的URL。找到URL 之后,使用如下命令(我以 4.17 RC2 内核为例)来下载源码文件: wget https://git.kernel/torvalds/t/linux-4.17-rc2.tar.gz

Linux下I2C驱动介绍

1、I2C概述 I2C是philips公司提供的外设总线,I2C有两条数据线,一条是串行数据线SDA、一条是时钟线SCL,使用SDA和SCL实现了数据的交换,便于布线。I2C总线方便用在EEPROM、实时钟、小型LCD等与CPU外部的接口上。 2、Linux下的驱动思路 Linux系统下编写I2c驱动主要有两种方法:一种是把I2C当做普通字符设备来使用;另一种利用Linux下驱动的体系结构来实现。 第一种方法: 优点:思路比较直接,不用花费大量时间去了解Linux系统下I2C体系结构 缺点:不仅对I2C设备操作要了解,还有了解I2C的适配器操作 不仅对I2C设备器和设备操作需要了解,编写的驱动移植性差,内核 提供的I2C设备器都没有用上。 第二种方法: 第一种的优点就是第二种的缺点,第一种的缺点就是第二种的优点。 3、I2C框架概述 Linux的I2C体系结构分为3部分: 1)I2C核心I2C核心提供了I2C总线驱动和设备驱动的注册和注销的方法,I2C 通信方法(algorithm)上层,与具体适配器无关的代码,检测设备上层的代 码等。 2)I2C总线驱动I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可以直接受CPU来控制。 3)I2C设备驱动I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备端挂在受CPU控制的适配器上,通过I2C适配器与CPU交换数据。 Linux下的I2C体系结构: 1)Linux下的I2C体系结构 4、I2C设备驱动编写方法 首先让我们明白适配器驱动的作用是让我们能够通过它发出标准的I2C时序,在linux

内核源代码中driver/I2C/buss包含一些适配器的驱动,例如s3c2410的驱动I2C-s3c2410.c,适配器被加载到内核中,接下的任务就是实现设备驱动的编写。编写设备驱动的方法主要分为两种方法: 第一种:利用设备提供的I2C-dev.c来实现I2C适配器设备文件,然后通过上层应用程序来操作I2C设备器来控制I2C设备。 第二种:为I2C设备独立编写一个设备驱动 注意:第二种方法不能用设备提供的I2C-dev.c 5、I2C系统下的文件架构 在linux下driver下面有个I2C目录,在I2C目录下包含以下文件和文件夹 1)I2C-core.c 这个文件实现I2C核心功能以及/proc/bus/I2C*接口 2)I2C-dev.c 实现I2C适配器设备文件的功能,每个I2C适配器被分配一个设备,通过 适配器访问设备的时候,主设备号是89,此设备号是0-255. I2C-dev.c并没有针对特定设备而设计,只提供了read() write()和ioctl()等接口,应用层可以通过这些接口访问挂在适配器上的I2C设备存储空间和寄存器,并控制I2C设备的工作方式。 3)Chips 这个文件下面包含特定的I2C设备驱动。 4)Busses 这个文件包含一些I2C总线驱动。 5)Algos文件夹下实现了I2C总线适配器的algorithm 6、重要结构体 1)在内核中的I2C.h这个头文件中对I2C_driver;I2C_client;I2C_adapter和I2C_algorithm 这个四个结构体进行了定义。理解这4个结构体的作用十分关键。 i2c_adapter结构体 struct i2c_adapter { struct module *owner; //所属模块 unsigned int id; //algorithm的类型,定义于i2c-id.h, unsigned int class; const struct i2c_algorithm *algo; //总线通信方法结构体指针 void *algo_data;//algorithm数据 struct rt_mutex bus_lock; //控制并发访问的自旋锁 int timeout; int retries; //重试次数 struct device dev; //适配器设备 int nr; char name[48]; //适配器名称 struct completion dev_released; //用于同步 struct list_head userspace_clients; //client链表头

linux内核IMQ源码实现分析

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.360docs.net/doc/5d13654431.html, 来源: https://www.360docs.net/doc/5d13654431.html,/?business&aid=6&un=wwwlkk#7 linux2.6.35内核IMQ源码实现分析 (1)数据包截留并重新注入协议栈技术 (1) (2)及时处理数据包技术 (2) (3)IMQ设备数据包重新注入协议栈流程 (4) (4)IMQ截留数据包流程 (4) (5)IMQ在软中断中及时将数据包重新注入协议栈 (7) (6)结束语 (9) 前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。 首先揭示IMQ的核心技术: 1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。 2.如何做到及时的将数据包重新注入协议栈。 实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。下面先介绍这2个技术。 (1)数据包截留并重新注入协议栈技术

(2)及时处理数据包技术 QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数

激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的 证了数据包会被及时的发送。 这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。

嵌入式Linux系统内核的配置、编译和烧写

实验二 嵌入式Linux系统内核的配置、编译和烧写 1.实验目的 1)掌握交叉编译的基本概念; 2)掌握配置和编译嵌入式Linux操作系统内核的方法; 3)掌握嵌入式系统的基本架构。 2.实验环境 1)装有Windows系统的计算机; 2)计算机上装有Linux虚拟机软件; 3)嵌入式系统实验箱及相关软硬件(各种线缆、交叉编译工具链等等)。 3.预备知识 1)嵌入式Linux内核的配置和裁剪方法; 2)交叉编译的基本概念及编译嵌入式Linux内核的方法; 3)嵌入式系统的基本架构。 4.实验内容和步骤 4.1 内核的配置和编译——配置内核的MMC支持 1)由于建立交叉编译器的过程很复杂,且涉及汇编等复杂的指令,在这里 我们提供一个制作好的编译器。建立好交叉编译器之后,我们需要完成 内核的编译,首先我们要有一个完整的Linux内核源文件包,目前流行 的源代码版本有Linux 2.4和Linux 2.6内核,我们使用的是Linux 2.6内核; 2)实验步骤: [1]以root用户登录Linux虚拟机,建立一个自己的工作路径(如用命令 “mkdir ‐p /home/user/build”建立工作路径,以下均采用工作路径 /home/user/build),然后将“cross‐3.3.2.tar.bz2、dma‐linux‐2.6.9.tar.gz、 dma‐rootfs.tar.gz”拷贝到工作路径中(利用Windows与虚拟机Linux 之间的共享目录作为中转),并进入工作目录; [2]解压cross‐3.3.2.tar.bz2到当前路径:“tar ‐jxvf cross‐3.3.2.tar.bz2”; [3]解压完成后,把刚刚解压后在当前路径下生成的“3.3.2”文件夹移 动到“/usr/local/arm/”路径下,如果在“/usr/local/”目录下没有“arm” 文件夹,用户创建即可; [4]解压“dma‐linux‐2.6.9.tar.gz”到当前路径下:

Linux下I2C驱动架构全面分析概要

Linux下I2C驱动架构全面分析 I2C概述 I2C是philips提岀的外设总线. I2C只有两条线,一条串行数据线:SDA, —条是时钟线SCL,使用SCL , SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线。 因此,I2C总线被非常广泛地应用在EEPROM,实时钟,小型LCD等设备与CPU的接口中。 linux下的驱动思路 在linux系统下编写I2C驱动,目前主要有两种方法,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux下I2C驱动体系结构来完成。下面比较下这两种方法: 第一种方法: 优点:思路比较直接,不需要花很多时间去了解linux中复杂的I2C子系统的操作方法。 缺点: 要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器(I2C控制器)操作。要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写岀的程序可以移植性差。 对内核的资源无法直接使用,因为内核提供的所有I2C设备器以及设备驱动都是基于I2C 子系统的格式。 第一种方法的优点就是第二种方法的缺点, 第一种方法的缺点就是第二种方法的优点。 I2C架构概述 Linux的I2C体系结构分为3个组成部分: I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册,注销方法,I2C通信方法 (” algorithm 上层的,与具体适配器无关的代码以及探测设备,检测设备地址的上层代码等。 I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。 I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

Linux内核结构详解教程

Linux内核结构详解教程 ─────Linux内核教程 linux内核就像人的心脏,灵魂,指挥中心。 内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等. 严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux. 一个Linux内核很少1.2M左右,一张软盘就能放下. 内容基础,语言简短简洁 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章及教程基本能满足不同水平的朋友学习。 红联Linux门户: https://www.360docs.net/doc/5d13654431.html, 红联Linux论坛: https://www.360docs.net/doc/5d13654431.html,/bbs 红联Linux 论坛大全,所有致力点都体现在这 https://www.360docs.net/doc/5d13654431.html,/bbs/rf/linux/07.htm

目录 Linux内核结构详解 Linux内核主要五个子系统详解 各个子系统之间的依赖关系 系统数据结构 Linux的具体结构 Linux内核源代码 Linux 内核源代码的结构 从何处开始阅读源代码 海量Linux技术文章

Linux内核结构详解 发布时间:2006-11-16 19:05:29 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

Linux内核主要五个子系统详解 发布时间:2006-11-16 19:05:54 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

linux、内核源码、内核编译与配置、内核模块开发、内核启动流程

linux、内核源码、内核编译与配置、内核模块开发、内核启动流程(转) linux是如何组成的? 答:linux是由用户空间和内核空间组成的 为什么要划分用户空间和内核空间? 答:有关CPU体系结构,各处理器可以有多种模式,而LInux这样的划分是考虑到系统的 安全性,比如X86可以有4种模式RING0~RING3 RING0特权模式给LINUX内核空间RING3给用户空间 linux内核是如何组成的? 答:linux内核由SCI(System Call Interface)系统调用接口、PM(Process Management)进程管理、MM(Memory Management)内存管理、Arch、 VFS(Virtual File Systerm)虚拟文件系统、NS(Network Stack)网络协议栈、DD(Device Drivers)设备驱动 linux 内核源代码 linux内核源代码是如何组成或目录结构? 答:arc目录存放一些与CPU体系结构相关的代码其中第个CPU子目录以分解boot,mm,kerner等子目录 block目录部分块设备驱动代码 crypto目录加密、压缩、CRC校验算法 documentation 内核文档 drivers 设备驱动 fs 存放各种文件系统的实现代码 include 内核所需要的头文件。与平台无关的头文件入在include/linux子目录下,与平台相关的头文件则放在相应的子目录中 init 内核初始化代码 ipc 进程间通信的实现代码 kernel Linux大多数关键的核心功能者是在这个目录实现(程序调度,进程控制,模块化) lib 库文件代码 mm 与平台无关的内存管理,与平台相关的放在相应的arch/CPU目录net 各种网络协议的实现代码,注意而不是驱动 samples 内核编程的范例 scripts 配置内核的脚本 security SElinux的模块 sound 音频设备的驱动程序 usr cpip命令实现程序 virt 内核虚拟机 内核配置与编译 一、清除 make clean 删除编译文件但保留配置文件

linux下iic(i2c)读写AT24C02

https://www.360docs.net/doc/5d13654431.html,/jammy_lee/ https://www.360docs.net/doc/5d13654431.html, linux下iic(i2c)读写AT24C02 linux驱动2010-02-09 16:02:03 阅读955 评论3 字号:大中小订阅 linux内核上已有iic的驱动,因此只需要对该iic设备文件进行读写则能够控制外围的iic器件。这里以AT24C02为对象,编写一个简单的读写应用程序。iic设备文件在我的开发板上/dev/i2c/0 ,打开文件为可读写。AT24C02的器件地址为0x50 ,既是iic总线上从器件的地址,每次只读写一字节数据。 /************************************************************/ //文件名:app_at24c02.c //功能:测试linux下iic读写at24c02程序 //使用说明: (1) // (2) // (3) // (4) //作者:jammy-lee //日期:2010-02-08 /************************************************************/ //包含头文件 #include #include #include #include #include #include #include

#include #include #include //宏定义 #define Address 0x50 //at24c02地址 #define I2C_RETRIES 0x0701 #define I2C_TIMEOUT 0x0702 #define I2C_SLAVE 0x0703 //IIC从器件的地址设置 #define I2C_BUS_MODE 0x0780 typedef unsigned char uint8; uint8 rbuf[8] = {0x00}; //读出缓存 uint8 wbuf[8] = {0x01,0x05,0x06,0x04,0x01,0x01,0x03,0x0d}; //写入缓存int fd = -1; //函数声明 static uint8 AT24C02_Init(void); static uint8 i2c_write(int fd, uint8 reg, uint8 val); static uint8 i2c_read(int fd, uint8 reg, uint8 *val); static uint8 printarray(uint8 Array[], uint8 Num); //at24c02初始化 static uint8 AT24C02_Init(void) { fd = open("/dev/i2c/0", O_RDWR); //允许读写 if(fd < 0) { perror("Can't open /dev/nrf24l01 \n"); //打开iic设备文件失败 exit(1);

linux内核编译和生成makefile文件实验报告

操作系统实验报告 姓名:学号: 一、实验题目 1.编译linux内核 2.使用autoconf和automake工具为project工程自动生成Makefile,并测试 3.在内核中添加一个模块 二、实验目的 1.了解一些命令提示符,也里了解一些linux系统的操作。 2.练习使用autoconf和automake工具自动生成Makefile,使同学们了解Makefile的生成原理,熟悉linux编程开发环境 三、实验要求 1使用静态库编译链接swap.c,同时使用动态库编译链接myadd.c。可运行程序生成在src/main目录下。 2要求独立完成,按时提交 四、设计思路和流程图(如:包括主要数据结构及其说明、测试数据的设计及测试结果分析) 1.Makefile的流程图: 2.内核的编译基本操作 1.在ubuntu环境下获取内核源码 2.解压内核源码用命令符:tar xvf linux- 3.18.12.tar.xz 3.配置内核特性:make allnoconfig 4.编译内核:make 5.安装内核:make install

6.测试:cat/boot/grub/grub.conf 7.重启系统:sudo reboot,看是否成功的安装上了内核 8.详情及结构见附录 3.生成makefile文件: 1.用老师给的projec里的main.c函数。 2.需要使用automake和autoconf两个工具,所以用命令符:sudo apt-get install autoconf 进行安装。 3.进入主函数所在目录执行命令:autoscan,这时会在目录下生成两个文件 autoscan.log和configure.scan,将configure.Scan改名为configure.ac,同时用gedit打开,打开后文件修改后的如下: # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE(main,1.0) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT(Makefile) 4.新建Makefile文件,如下: AUTOMAKE_OPTIONS=foreign bin_PROGRAMS=main first_SOURCES=main.c 5.运行命令aclocal 命令成功之后,在目录下会产生aclocal.m4和autom4te.cache两个文件。 6.运行命令autoheader 命令成功之后,会在目录下产生config.h.in这个新文件。 7.运行命令autoconf 命令成功之后,会在目录下产生configure这个新文件。 8.运行命令automake --add-missing输出结果为: Configure.ac:11:installing./compile’ Configure.ac:8:installing ‘.install-sh’ Configure.ac:8:installing ‘./missing’ Makefile.am:installing ‘./decomp’ 9. 命令成功之后,会在目录下产生depcomp,install-sh和missing这三个新文件和执行下一步的Makefile.in文件。 10.运行命令./configure就可以自动生成Makefile。 4.添加内核模块

实例解析linux内核I2C体系结构(2)

实例解析linux内核I2C体系结构(2) 华清远见刘洪涛四、在内核里写i2c设备驱动的两种方式 前文介绍了利用/dev/i2c-0在应用层完成对i2c设备的操作,但很多时候我们还是习惯为i2c设备在内核层编写驱动程序。目前内核支持两种编写i2c驱动程序的方式。下面分别介绍这两种方式的实现。这里分别称这两种方式为“Adapter方式(LEGACY)”和“Probe方式(new style)”。 (1)Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式,即Probe方式) ●构建i2c_driver static struct i2c_driver pca953x_driver = { .driver = { .name= "pca953x", //名称 }, .id= ID_PCA9555,//id号 .attach_adapter= pca953x_attach_adapter, //调用适配器连接设备 .detach_client= pca953x_detach_client,//让设备脱离适配器 }; ●注册i2c_driver static int __init pca953x_init(void) { return i2c_add_driver(&pca953x_driver); } module_init(pca953x_init); ●attach_adapter动作 执行i2c_add_driver(&pca953x_driver)后会,如果内核中已经注册了i2c适配器,则顺序调用这些适配器来连接我们的i2c设备。此过程是通过调用i2c_driver中的attach_adapter方法完成的。具体实现形式如下: static int pca953x_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, pca953x_detect); /* adapter:适配器 addr_data:地址信息 pca953x_detect:探测到设备后调用的函数 */ } 地址信息addr_data是由下面代码指定的。 /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END}; I2C_CLIENT_INSMOD;

Linux内核分析-网络[五]:网桥

看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的容。 view plaincopy to clipboardprint? 1. s kb = handle_bridge(skb, &pt_prev, &ret, orig_dev); 网桥可以简单理解为交换机,以下图为例,一台linux机器可以看作网桥和路由的结合,网桥将物理上的两个局域网LAN1、LAN2当作一个局域网处理,路由连接了两个子网1.0和2.0。从eth0和eth1网卡收到的报文在Bridge模块中会被处理成是由Bridge收到的,因此Bridge也相当于一个虚拟网卡。 STP五种状态 DISABLED BLOCKING LISTENING LEARNING FORWARDING 创建新的网桥br_add_bridge [net\bridge\br_if.c] 当使用SIOCBRADDBR调用ioctl时,会创建新的网桥br_add_bridge。 首先是创建新的网桥: view plaincopy to clipboardprint?

1. d ev = new_bridge_dev(net, name); 然后设置dev->dev.type为br_type,而br_type是个全局变量,只初始化了一个名字变量 view plaincopy to clipboardprint? 1. S ET_NETDEV_DEVTYPE(dev, &br_type); 2. s tatic struct device_type br_type = { 3. .name = "bridge", 4. }; 然后注册新创建的设备dev,网桥就相当一个虚拟网卡设备,注册过的设备用ifconfig 就可查看到: view plaincopy to clipboardprint? 1. r et = register_netdevice(dev); 最后在sysfs文件系统中也创建相应项,便于查看和管理: view plaincopy to clipboardprint? 1. r et = br_sysfs_addbr(dev); 将端口加入网桥br_add_if() [net\bridge\br_if.c] 当使用SIOCBRADDIF调用ioctl时,会向网卡加入新的端口br_add_if。 创建新的net_bridge_port p,会从br->port_list中分配一个未用的port_no,p->br会指向br,p->state设为BR_STATE_DISABLED。这里的p实际代表的就是网卡设备。 view plaincopy to clipboardprint? 1. p = new_nbp(br, dev); 将新创建的p加入CAM表中,CAM表是用来记录mac地址与物理端口的对应关系;而刚刚创建了p,因此也要加入CAM表中,并且该表项应是local的[关系如下图],可以看到,CAM表在实现中作为net_bridge的hash表,以addr作为hash值,链入 net_bridge_fdb_entry,再由它的dst指向net_bridge_port。

史上最全linux内核配置详解

对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development and/or incomplete code/drivers,设置界面中显示还在开发或者还没有完成的代码与驱动,最好选上,许多设备都需要它才能配置。 [ ]Cross-compiler tool prefix,交叉编译工具前缀,如果你要使用交叉编译工具的话输入相关前缀。默认不使用。嵌入式linux更不需要。 [ ]Local version - append to kernel release,自定义版本,也就是uname -r可以看到的版本,可以自行修改,没多大意义。 [ ]Automatically append version information to the version string,自动生成版本信息。这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。这需要Perl的支持。由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。 Kernel compression mode (LZMA),选择压缩方式。 [ ]Support for paging of anonymous memory (swap),交换分区支持,也就是虚拟内存支持,嵌入式不需要。 [*]System V IPC,为进程提供通信机制,这将使系统中各进程间有交换信息与保持同步的能力。有些程序只有在选Y的情况下才能运行,所以不用考虑,这里一定要选。 [*]POSIX Message Queues,这是POSIX的消息队列,它同样是一种IPC(进程间通讯)。建议你最好将它选上。 [*]BSD Process Accounting,允许进程访问内核,将账户信息写入文件中,主要包括进程的创建时间/创建者/内存占用等信息。可以选上,无所谓。 [*]BSD Process Accounting version 3 file format,选用的话统计信息将会以新的格式(V3)写入,注意这个格式和以前的v0/v1/v2 格式不兼容,选不选无所谓。 [ ]Export task/process statistics through netlink (EXPERIMENTAL),通过通用的网络输出工作/进程的相应数据,和BSD不同的是,这些数据在进程运行的时候就可以通过相关命令访问。和BSD类似,数据将在进程结束时送入用户空间。如果不清楚,选N(实验阶段功能,下同)。 [ ]Auditing support,审计功能,某些内核模块需要它(SELINUX),如果不知道,不用选。 [ ]RCU Subsystem,一个高性能的锁机制RCU 子系统,不懂不了解,按默认就行。 [ ]Kernel .config support,将.config配置信息保存在内核中,选上它及它的子项使得其它用户能从/proc/ config.gz中得到内核的配置,选上,重新配置内核时可以利用已有配置Enable access to .config through /proc/config.gz,上一项的子项,可以通过/proc/ config.gz访问.config配置,上一个选的话,建议选上。 (16)Kernel log buffer size (16 => 64KB, 17 => 128KB) ,内核日志缓存的大小,使用默认值即可。12 => 4 KB,13 => 8 KB,14 => 16 KB单处理器,15 => 32 KB多处理器,16 => 64 KB,17 => 128 KB。 [ ]Control Group support(有子项),使用默认即可,不清楚可以不选。 Example debug cgroup subsystem,cgroup子系统调试例子 Namespace cgroup subsystem,cgroup子系统命名空间 Device controller for cgroups,cgroups设备控制器

Linux_I2C总线分析(主要是probe的方式)1

Linux I2C 总线浅析 ㈠ Overview 内核空间层次! i2c adapter 是一个struct, 用来抽象一个物理i2c bus ,而且还和linux 设备驱动架构柔和在一起.. 如果只说硬件的话,就是在CPU内部集成的一个I2C控制器(提供给用户的就是那几个register),硬件上并没的所谓的adapter,client这些东东,,adapter和client都是linux 驱动软件抽象出来的东西 资料帖子: i2c_algorithm { /* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated

using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a negative value on error */ i nt (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); i nt (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* To determine what the adapter supports */ u32 (*functionality) (struct i2c_adapter *); }; /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ struct i2c_adapter { s truct module *owner; u nsigned int id; u nsigned int class; /* classes to allow probing for */ c onst struct i2c_algorithm *algo; /* the algorithm to access the bus */ v oid *algo_data; /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ s truct mutex bus_lock; i nt timeout; /* in jiffies */ i nt retries; s truct device dev; /* the adapter device */ i nt nr; c har name[48]; s truct completion dev_released; }; Linux的I2C体系结构分为3个组成部分: 1·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。这部分是与平台无关的。 2·I2C总线驱动: I2C总线驱动是对I2C硬件体系结构中适配器端的实现。I2C总线驱动主要包含了I2C适配

相关文档
最新文档