linux设备模型之i2c子系统
来源:互联网 发布:腾讯云数据库招聘 编辑:程序博客网 时间:2024/05/21 18:41
===============================
I2c子系统将i2c控制器(i2c寄存器所在的那块电路)抽象出来,用adapter(适配器)这个结构来描述,可以说一个适配器就代表一条i2c总线,而挂接在i2c总线上的设备是用client这个结构体来表述,另外i2c_bus上的设备链表挂接的不单单是连接的这条i2c上的client,同样adapter也作为一个设备挂在其所在的i2c_bus,也就是说控制器和设备都作为i2c_bus上的设备连接在设备链表,他们用内嵌的device的type这个成员来区分,适配器的类型为i2c_adapter_type,client的类型为i2c_client_type。
一、i2c相关的描述结构
首先看一下i2c子系统给adapter定义的描述结构:
1 struct i2c_adapter { 2 struct module *owner; 3 unsigned int id; 4 unsigned int class; // 适配器支持的类型,如传感器,eeprom等 5 const struct i2c_algorithm *algo; //该适配器的通信函数 6 void *algo_data; 7 /* data fields that are valid for all devices */ 8 struct rt_mutex bus_lock; 9 int timeout; //超时时间限定10 int retries; //通信重复次数限定11 /* 12 * 内嵌的标准device,其中dev->type标识该设备13 * 是个adapter,其值为i2c_adapter_type14 */15 struct device dev; 16 17 int nr; //适配器编号也是bus编号,第几条i2c总线18 char name[48]; //名字19 struct completion dev_released;20 struct mutex userspace_clients_lock;21 struct list_head userspace_clients;22 };
再来看一下client的描述结构:
1 struct i2c_client { 2 unsigned short flags; //设备的标志,如唤醒标志等等 3 4 /* chip address - NOTE: 7bit */ 5 /* addresses are stored in the */ 6 /* _LOWER_ 7 bits */ 7 unsigned short addr; //设备的地址 8 char name[I2C_NAME_SIZE]; //设备的名字 9 struct i2c_adapter *adapter; //设备所属的适配器10 struct i2c_driver *driver; //设备的driver11 12 /* 13 * 内嵌的标准device模型,其中dev->type标识该设备14 * 是个client,其值为i2c_client_type15 */16 struct device dev; /* the device structure */17 int irq; //中断号18 struct list_head detected; //挂接点,挂接在adapter19 };
下面是driver的表述结构i2c_driver:
1 struct i2c_driver { 2 unsigned int class; //支持的类型,与adapter的class相对 3 /* Notifies the driver that a new bus has appeared or is about to be 4 * removed. You should avoid using this if you can, it will probably 5 * be removed in a near future. 6 */ 7 8 int (*attach_adapter)(struct i2c_adapter *); //旧式探测函数 9 int (*detach_adapter)(struct i2c_adapter *);10 /* Standard driver model interfaces */11 int (*probe)(struct i2c_client *, const struct i2c_device_id *);12 int (*remove)(struct i2c_client *);13 /* driver model interfaces that don't relate to enumeration */14 void (*shutdown)(struct i2c_client *);15 int (*suspend)(struct i2c_client *, pm_message_t mesg);16 int (*resume)(struct i2c_client *);17 /* Alert callback, for example for the SMBus alert protocol.18 * The format and meaning of the data value depends on the protocol.19 * For the SMBus alert protocol, there is a single bit of data passed20 * as the alert response's low bit ("event flag").21 */22 void (*alert)(struct i2c_client *, unsigned int data);23 /* a ioctl like command that can be used to perform specific functions24 * with the device.25 */26 int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);27 /*28 * 内嵌的标准driver,driver的of_match_table成员也用于标识其支持29 * 的设备,并且优先级高于id_table30 */31 struct device_driver driver;32 33 const struct i2c_device_id *id_table; //支持的client信息表34 /* Device detection callback for automatic device creation */35 36 int (*detect)(struct i2c_client *, struct i2c_board_info *); //探测函数37 const unsigned short *address_list; //driver支持的client地址38 struct list_head clients; //挂接其探测到的支持的设备39 };
另外client端有一条全局链表,用于串联所有i2c的client设备,为__i2c_board_list,也就是说client可以静态注册亦可动态
被探测,静态注册挂接在该链表上的结构为:
1 struct i2c_devinfo { 2 struct list_head list; //连接指针指向前后设备 3 int busnum; //所在bus的编号 4 struct i2c_board_info board_info; //板级平台信息相关的结构体 5 }; 6 //其中 i2c_board_info结构的源码为: 7 struct i2c_board_info { 8 char type[I2C_NAME_SIZE]; //名字 9 unsigned short flags; //标志10 unsigned short addr; //地址11 void *platform_data; //私有特殊数据12 struct dev_archdata *archdata;13 #ifdef CONFIG_OF14 struct device_node *of_node; //节点15 #endi16 int irq; //中断号17 };
i2c_devinfo结构静态注册的信息最后都会被整合集成到client中,形成一个标准的i2c_client设备并注册。
二、i2c核心初始化代码分析
首先看一下i2c平台无关的核心初始化,代码位于drivers/i2c/i2c-core.c下:
1 static int __init i2c_init(void) 2 { 3 int retval; 4 /* 5 * 注册i2c_bus 6 */ 7 retval = bus_register(&i2c_bus_type); 8 if (retval) 9 return retval;10 #ifdef CONFIG_I2C_COMPAT 11 /*12 * 在sys/class下创建适配器目录13 */14 i2c_adapter_compat_class = class_compat_register("i2c-adapter");15 if (!i2c_adapter_compat_class) {16 retval = -ENOMEM;17 goto bus_err;18 }19 20 #endif21 /*22 * 增加一个虚拟的driver23 */24 retval = i2c_add_driver(&dummy_driver); 25 if (retval)26 goto class_err;27 return 0;28 class_err:29 #ifdef CONFIG_I2C_COMPAT30 class_compat_unregister(i2c_adapter_compat_class); 31 bus_err:32 #endif33 bus_unregister(&i2c_bus_type);34 return retval;35 }36 //其中的i2c_bus_type原型为:37 struct bus_type i2c_bus_type = {38 .name = "i2c",39 .match = i2c_device_match,40 .probe = i2c_device_probe,41 .remove = i2c_device_remove,42 .shutdown = i2c_device_shutdown,43 .pm = &i2c_device_pm_ops,44 };
三、i2c_add_driver分析
驱动端的统一接口为i2c_add_driver:
static
inline
int
i2c_add_driver(
struct
i2c_driver *driver)
{
/*
*注册i2c driver,可能是adapter的,也可能是client的
*/
return
i2c_register_driver(THIS_MODULE, driver);
}
int
i2c_register_driver(
struct
module *owner,
struct
i2c_driver *driver)
{
int
res;
/* Can't register until after driver model init*/
if
(unlikely(WARN_ON(!i2c_bus_type.p)))
return
-EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
/*
* i2c_driver内嵌的标准driver赋值,其bus指定为i2c_bus_type
*/
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
/*注册标准的driver,driver注册后会去i2c_bus_type的设备链表上匹配
*设备,匹配函数用的是bus端的,也就是i2c_device_match,如果匹配成功
*将建立标准关联,并且将调用bus端的probe函数初始化这个设备,即
*函数i2c_device_probe,下面会逐个分析
*/
res = driver_register(&driver->driver);
if
(res)
return
res;
pr_debug(
"i2c-core: driver [%s] registered/n"
, driver->driver.name);
/*
* 把该driver的clients初始化,该成员连接着这个driver可以操作的具
* 体设备
*/
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
mutex_lock(&core_lock);
/*
* 遍历挂接在该i2c设备链表上的设备,并对其都调用__process_new_driver
* 函数
*/
bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
mutex_unlock(&core_lock);
return
0;
}
/****************************
* 匹配函数i2c_device_match *
****************************/
static
int
i2c_device_match(
struct
device *dev,
struct
device_driver *drv)
{
/*
* i2c_verify_client检查匹配的这个设备是否为i2c_client_type
* 类型,如果不是则返回NULL,此处的匹配只是针对i2c设备的
* 不是适配器
*/
struct
i2c_client *client = i2c_verify_client(dev);
struct
i2c_driver *driver;
/*
* 如果不是i2c设备类型就返回
*/
if
(!client)
return
0;
/* Attempt an OF style match */
/*
* 如果定义了CONFIG_OF_DEVICE,那么就利用
* drv.of_match_table成员表进行匹配
*/
if
(of_driver_match_device(dev, drv))
return
1;
/*
* 由内嵌的driver得到外面封装的i2c_driver
*/
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
/*
* 如果i2c_driver->id_table存在,也就是支持的设备信息表
* 存在,那么利用这个表进行匹配
*/
if
(driver->id_table)
return
i2c_match_id(driver->id_table, client) != NULL;
return
0;
}
/**********************************
* 初始化设备函数i2c_device_probe *
**********************************/
static
int
i2c_device_probe(
struct
device *dev)
{
/*
* 检查如果设备类型不是client则返回
*/
struct
i2c_client *client = i2c_verify_client(dev);
struct
i2c_driver *driver;
int
status;
if
(!client)
return
0;
/*
* dev->driver指向匹配完成的driver,根据该标准
* driver得到其外围封装的i2c_driver
*/
driver = to_i2c_driver(dev->driver);
/*
* 如果该i2c_driver的probe成员或者id_table成员为
* NULL则退出
*/
if
(!driver->probe || !driver->id_table)
return
-ENODEV;
/*
* client的driver成员赋值为该i2c_driver
*/
client->driver = driver;
/*
* 唤醒该设备
*/
if
(!device_can_wakeup(&client->dev))
device_init_wakeup(&client->dev,
client->flags & I2C_CLIENT_WAKE);
dev_dbg(dev,
"probe/n"
);
/*
* 利用i2c_driver的probe成员初始化该设备,此部分为实际平台相关
*/
status = driver->probe(client, i2c_match_id(driver->id_table, client));
/*
* 失败则清除client指定的driver
*/
if
(status) {
client->driver = NULL;
i2c_set_clientdata(client, NULL);
}
return
status;
}
/*************************************************************
* 下面看一下当找到一个dev后调用的__process_new_driver函数 *
*************************************************************/
static
int
__process_new_driver(
struct
device *dev,
void
*data)
{
/*
* 设备的类型如果不是i2c_adapter类型就推出
* 下面的代码是针对i2c适配器的代码
*/
if
(dev->type != &i2c_adapter_type)
return
0;
/*
* 如果这个设备代表i2c适配器,则调用i2c_do_add_adapter
* 此时的data类型为i2c_driver
*/
return
i2c_do_add_adapter(data, to_i2c_adapter(dev));
//根据设备得到他的适配器
//i2c_driver。第一个是i2c_driver
}
/*************************
* i2c_do_add_adapter函数 *
*************************/
static
int
i2c_do_add_adapter(
struct
i2c_driver *driver,
struct
i2c_adapter *adap)
{
/* Detect supported devices on that bus, and instantiate them */
/*
* 利用该适配器和该i2c_driver探测该适配器所在的这条i2c总线
* 找到该driver支持的设备并实例化它
*/
i2c_detect(adap, driver);
/* Let legacy drivers scan this bus for matching devices */
/*
* 老版本的探测利用i2c_driver的attach_adapter函数
*/
if
(driver->attach_adapter) {
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
return
0;
}
/****************************
* 重点看一下i2c_detect函数 *
****************************/
static
int
i2c_detect(
struct
i2c_adapter *adapter,
struct
i2c_driver *driver)
{
const
unsigned
short
*address_list;
struct
i2c_client *temp_client;
int
i, err = 0;
int
adap_id = i2c_adapter_id(adapter);
/*
* 得到该i2c_driver指定的client地址范围
*/
address_list = driver->address_list;
/*
* driver平台相关的detect函数和client地址范围不能为NULL
*/
if
(!driver->detect || !address_list)
return
0;
/* Set up a temporary client to help detect callback */
/*
* 申请一块client内存
*/
temp_client = kzalloc(
sizeof
(
struct
i2c_client), GFP_KERNEL);
if
(!temp_client)
return
-ENOMEM;
/*
* 申请的client结构的adapter成员设置为当前的adapter
*/
temp_client->adapter = adapter;
/* Stop here if the classes do not match */
/*
* 当前adapter的类型如果和driver的类型不一样,则退出
* 例如:适配器的类型可以为传感器,eeprom,driver类型必须
* 与其匹配
*/
if
(!(adapter->
class
& driver->
class
))
goto
exit_free;
/*
* 根据指定的支持的地址范围开始逐一探测
*/
for
(i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
dev_dbg(&adapter->dev,
"found normal entry for adapter %d, "
"addr 0x%02x/n"
, adap_id, address_list[i]);
/*
* 临时申请的client的地址设置为这次要探测的地址
*/
temp_client->addr = address_list[i];
err = i2c_detect_address(temp_client, driver);
if
(err)
goto
exit_free;
}
exit_free:
kfree(temp_client);
return
err;
}
/**********************************
* 继续跟进i2c_detect_address函数 *
**********************************/
static
int
i2c_detect_address(
struct
i2c_client *temp_client,
struct
i2c_driver *driver)
{
struct
i2c_board_info info;
struct
i2c_adapter *adapter = temp_client->adapter;
int
addr = temp_client->addr;
int
err;
/* Make sure the address is valid */
/*
* 检查该地址是否有效,小于0x08或者大于0x77都是无效
* 地址,该函数在后面介绍
*/
err = i2c_check_addr_validity(addr);
if
(err) {
dev_warn(&adapter->dev,
"Invalid probe address 0x%02x/n"
,
addr);
return
err;
}
/* Skip if already in use */
/*
* 如果地址在使用中则跳过
*/
if
(i2c_check_addr_busy(adapter, addr))
return
0;
/* Make sure there is something at this address */
/*
* 默认初始化探测,确定该地址上有设备存在
*/
if
(!i2c_default_probe(adapter, addr))
return
0;
/* Finally call the custom detection function */
/*
* 走到这里将调用平台相关的自定义探测函数去探测该地址
* 上是否设备,并填充i2c_board_info结构体
*/
memset
(&info, 0,
sizeof
(
struct
i2c_board_info));
info.addr = addr;
err = driver->detect(temp_client, &info);
if
(err) {
/* -ENODEV is returned if the detection fails. We catch it
here as this isn't an error. */
return
err == -ENODEV ? 0 : err;
}
/* Consistency check */
/*
* 填充的info名字为空,则结束否则实例化这个设备
*/
if
(info.type[0] ==
'/0'
) {
dev_err(&adapter->dev,
"%s detection function provided "
"no name for 0x%x/n"
, driver->driver.name,
addr);
}
else
{
struct
i2c_client *client;
/* Detection succeeded, instantiate the device */
dev_dbg(&adapter->dev,
"Creating %s at 0x%02x/n"
,
info.type, info.addr);
/*
* 根据当前适配器和填充的info实例化该地址上探测到的设备
*/
client = i2c_new_device(adapter, &info);
/*
* 实例化成功将该client挂到该driver的clients链表上
*/
if
(client)
list_add_tail(&client->detected, &driver->clients);
//驱动挂到driver下
else
dev_err(&adapter->dev,
"Failed creating %s at 0x%02x/n"
,
info.type, info.addr);
}
return
0;
}
/******************************
* i2c_check_addr_validity函数 *
******************************/
static
int
i2c_check_addr_validity(unsigned
short
addr)
{
/*
* Reserved addresses per I2C specification:
* 0x00 General call address / START byte
* 0x01 CBUS address
* 0x02 Reserved for different bus format
* 0x03 Reserved for future purposes
* 0x04-0x07 Hs-mode master code
* 0x78-0x7b 10-bit slave addressing
* 0x7c-0x7f Reserved for future purposes
*/
if
(addr < 0x08 || addr > 0x77)
return
-EINVAL;
return
0;
}
/*********************************
* 再看一下i2c_default_probe函数 *
*********************************/
static
int
i2c_default_probe(
struct
i2c_adapter *adap, unsigned
short
addr)
{
int
err;
union
i2c_smbus_data dummy;
#ifdef CONFIG_X86
/*
* 这里是对intel特殊设备的检查,就不深入看下去了
*/
if
(addr == 0x73 && (adap->
class
& I2C_CLASS_HWMON)
&& i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE_DATA, &dummy);
else
#endif
/*
* 对特殊设备的检查
*/
if
(!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
&& i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
I2C_SMBUS_QUICK, NULL);
/*
* i2c_check_functionality函数确定该i2c适配器所支持的通信方式
* 如果支持该方式则调用i2c_smbus_xfer函数
*/
else
if
(i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE, &dummy);
else
{
dev_warn(&adap->dev,
"No suitable probing method supported/n"
);
err = -EOPNOTSUPP;
}
return
err >= 0;
}
/******************************
* i2c_check_functionality函数 *
******************************/
static
inline
int
i2c_check_functionality(
struct
i2c_adapter *adap, u32 func)
{
return
(func & i2c_get_functionality(adap)) == func;
}
static
inline
u32 i2c_get_functionality(
struct
i2c_adapter *adap)
{
/*
* 最终会调用adapter通信函数里面的functionality函数确定支持的
* 通信方式
*/
return
adap->algo->functionality(adap);
}
/*********************
* i2c_smbus_xfer函数 *
*********************/
s32 i2c_smbus_xfer(
struct
i2c_adapter *adapter, u16 addr, unsigned
short
flags,
char
read_write, u8 command,
int
protocol,
union
i2c_smbus_data *data)
{
unsigned
long
orig_jiffies;
int
try
;
s32 res;
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
/*
* 如果适配器通信函数中的smbus_xfer函数存在,则直接利用它进行发送
*/
if
(adapter->algo->smbus_xfer) {
i2c_lock_adapter(adapter);
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for
(res = 0,
try
= 0;
try
<= adapter->retries;
try
++) {
res = adapter->algo->smbus_xfer(adapter, addr, flags,
read_write, command,
protocol, data);
if
(res != -EAGAIN)
break
;
if
(time_after(jiffies,
orig_jiffies + adapter->timeout))
break
;
}
i2c_unlock_adapter(adapter);
}
else
/*
* 否则利用i2c_smbus_xfer_emulated处理,此处也就是不支持smbus,
* 则得利用i2c模拟smbus命令
*/
res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
command, protocol, data);
return
res;
}
/******************************
* i2c_smbus_xfer_emulated函数 *
******************************/
static
s32 i2c_smbus_xfer_emulated(
struct
i2c_adapter *adapter, u16 addr,
unsigned
short
flags,
char
read_write, u8 command,
int
size,
union
i2c_smbus_data *data)
{
/* So we need to generate a series of msgs. In the case of writing, we
need to use only one message; when reading, we need two. We initialize
most things with sane defaults, to keep the code below somewhat
simpler. */
/*
* 为了进行通信我们必须创建msgs结构,当写时,我们需要一个这样的结构就
* 够了,当读的时候,我们需要两个
*/
unsigned
char
msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned
char
msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
/*
* 读的时候需要两次
*/
int
num = read_write == I2C_SMBUS_READ ? 2 : 1;
/*
* 填充需要的两个msg结构
*/
struct
i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
};
int
i;
u8 partial_pec = 0;
int
status;
/*
* 将要发送的命令填充到msg0
*/
msgbuf0[0] = command;
switch
(size) {
/*
* 快速传输,多用于确定该地址有应答
*/
case
I2C_SMBUS_QUICK:
msg[0].len = 0;
/* Special case: The read/write field is used as data */
msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
I2C_M_RD : 0);
num = 1;
break
;
/*
* 字节传输,一次读写一个字节
*/
case
I2C_SMBUS_BYTE:
if
(read_write == I2C_SMBUS_READ) {
/* Special case: only a read! */
msg[0].flags = I2C_M_RD | flags;
num = 1;
}
break
;
/*
* 命令+单字节形式传输
*/
case
I2C_SMBUS_BYTE_DATA:
if
(read_write == I2C_SMBUS_READ)
msg[1].len = 1;
else
{
msg[0].len = 2;
msgbuf0[1] = data->byte;
}
break
;
/*
* 命令+字形式传输
*/
case
I2C_SMBUS_WORD_DATA:
if
(read_write == I2C_SMBUS_READ)
msg[1].len = 2;
else
{
msg[0].len = 3;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
}
break
;
/*
* 命令+字形式,需要应答
*/
case
I2C_SMBUS_PROC_CALL:
num = 2;
/* Special case */
read_write = I2C_SMBUS_READ;
msg[0].len = 3;
msg[1].len = 2;
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
break
;
/*
* 多字节数据模式,字节数传输中不确定
*/
case
I2C_SMBUS_BLOCK_DATA:
if
(read_write == I2C_SMBUS_READ) {
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1;
/* block length will be added by
the underlying bus driver */
}
else
{
msg[0].len = data->block[0] + 2;
if
(msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
dev_err(&adapter->dev,
"Invalid block write size %d/n"
,
data->block[0]);
return
-EINVAL;
}
for
(i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
}
break
;
/*
* 多字节数据传输,需要应答
*/
case
I2C_SMBUS_BLOCK_PROC_CALL:
num = 2;
/* Another special case */
read_write = I2C_SMBUS_READ;
if
(data->block[0] > I2C_SMBUS_BLOCK_MAX) {
dev_err(&adapter->dev,
"Invalid block write size %d/n"
,
data->block[0]);
return
-EINVAL;
}
msg[0].len = data->block[0] + 2;
for
(i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1;
/* block length will be added by
the underlying bus driver */
break
;
/*
* 多字节数据传输,传输字节数确定
*/
case
I2C_SMBUS_I2C_BLOCK_DATA:
if
(read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
}
else
{
msg[0].len = data->block[0] + 1;
if
(msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(&adapter->dev,
"Invalid block write size %d/n"
,
data->block[0]);
return
-EINVAL;
}
for
(i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i];
}
break
;
default
:
dev_err(&adapter->dev,
"Unsupported transaction %d/n"
, size);
return
-EOPNOTSUPP;
}
i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA);
if
(i) {
/* Compute PEC if first message is a write */
if
(!(msg[0].flags & I2C_M_RD)) {
if
(num == 1)
/* Write only */
i2c_smbus_add_pec(&msg[0]);
else
/* Write followed by read */
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
}
/* Ask for PEC if last message is a read */
if
(msg[num-1].flags & I2C_M_RD)
msg[num-1].len++;
}
/*
* 调用i2c_transfer传输
*/
status = i2c_transfer(adapter, msg, num);
if
(status < 0)
return
status;
/* Check PEC if last message is a read */
if
(i && (msg[num-1].flags & I2C_M_RD)) {
status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
if
(status < 0)
return
status;
}
/*
* 将得到的数据回传给data
*/
if
(read_write == I2C_SMBUS_READ)
switch
(size) {
case
I2C_SMBUS_BYTE:
data->byte = msgbuf0[0];
break
;
case
I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break
;
case
I2C_SMBUS_WORD_DATA:
case
I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break
;
case
I2C_SMBUS_I2C_BLOCK_DATA:
for
(i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
break
;
case
I2C_SMBUS_BLOCK_DATA:
case
I2C_SMBUS_BLOCK_PROC_CALL:
for
(i = 0; i < msgbuf1[0] + 1; i++)
data->block[i] = msgbuf1[i];
break
;
}
return
0;
}
/*******************
* i2c_transfer函数 *
*******************/
int
i2c_transfer(
struct
i2c_adapter *adap,
struct
i2c_msg *msgs,
int
num)
{
unsigned
long
orig_jiffies;
int
ret,
try
;
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
* there is no way to report "N".
*
* - When we get a NAK after transmitting N bytes to a slave,
* there is no way to report "N" ... or to let the master
* continue executing the rest of this combined message, if
* that's the appropriate response.
*
* - When for example "num" is two and we successfully complete
* the first message but get an error part way through the
* second, it's unclear whether that should be reported as
* one (discarding status on the second message) or errno
* (discarding status on the first one).
*/
/*
* 如果适配器的adap->algo->master_xfer函数存在,则调用它把
* 该信息发送出去
*/
if
(adap->algo->master_xfer) {
#ifdef DEBUG
for
(ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev,
"master_xfer[%d] %c, addr=0x%02x, "
"len=%d%s/n"
, ret, (msgs[ret].flags & I2C_M_RD)
?
'R'
:
'W'
, msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ?
"+"
:
""
);
}
#endif
if
(in_atomic() || irqs_disabled()) {
ret = i2c_trylock_adapter(adap);
if
(!ret)
/* I2C activity is ongoing. */
return
-EAGAIN;
}
else
{
i2c_lock_adapter(adap);
}
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for
(ret = 0,
try
= 0;
try
<= adap->retries;
try
++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if
(ret != -EAGAIN)
break
;
if
(time_after(jiffies, orig_jiffies + adap->timeout))
break
;
}
i2c_unlock_adapter(adap);
return
ret;
}
else
{
dev_dbg(&adap->dev,
"I2C level transfers not supported/n"
);
return
-EOPNOTSUPP;
}
}
/**********************************************
* 回过头来看一下i2c_new_device这个实例化函数*
**********************************************/
struct
i2c_client *
i2c_new_device(
struct
i2c_adapter *adap,
struct
i2c_board_info
const
*info)
{
struct
i2c_client *client;
int
status;
/*
* 为需要实例化的设备申请内存
*/
client = kzalloc(
sizeof
*client, GFP_KERNEL);
if
(!client)
return
NULL;
/*
* 指定适配器以及platform_data
*/
client->adapter = adap;
client->dev.platform_data = info->platform_data;
/*
* info->archdata存在将其赋值给client
*/
if
(info->archdata)
client->dev.archdata = *info->archdata;
/*
* 标志、地址、中断号、名字
*/
client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;
strlcpy(client->name, info->type,
sizeof
(client->name));
/* Check for address validity */
/*
* 检查地址有效性
*/
status = i2c_check_client_addr_validity(client);
if
(status) {
dev_err(&adap->dev,
"Invalid %d-bit I2C address 0x%02hx/n"
,
client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
goto
out_err_silent;
}
/* Check for address business */
/*
* 检查地址是否被使用
*/
status = i2c_check_addr_busy(adap, client->addr);
if
(status)
goto
out_err;
/*
* 内嵌标准device的赋值
*/
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
#ifdef CONFIG_OF
client->dev.of_node = info->of_node;
#endif
dev_set_name(&client->dev,
"%d-%04x"
, i2c_adapter_id(adap),
client->addr);
/*
* 注册内嵌的标准device
*/
status = device_register(&client->dev);
if
(status)
goto
out_err;
dev_dbg(&adap->dev,
"client [%s] registered with bus id %s/n"
,
client->name, dev_name(&client->dev));
return
client;
out_err:
dev_err(&adap->dev,
"Failed to register i2c client %s at 0x%02x "
"(%d)/n"
, client->name, client->addr, status);
out_err_silent:
kfree(client);
return
NULL;
}
以上就是i2c通用driver添加的流程,下面看一下设备端,适配器的流程
四、i2c_add_adapter分析
1 int i2c_add_adapter(struct i2c_adapter *adapter) 2 { 3 int id, res = 0; 4 retry: 5 /* 6 * 得到bus号并将其插入搜索树,便于高效查找 7 * 此处不做深入分析 8 */ 9 if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) 10 return -ENOMEM; 11 mutex_lock(&core_lock); 12 /* "above" here means "above or equal to", sigh */ 13 res = idr_get_new_above(&i2c_adapter_idr, adapter, 14 __i2c_first_dynamic_bus_num, &id); 15 mutex_unlock(&core_lock); 16 if (res < 0) { 17 if (res == -EAGAIN) 18 goto retry; 19 return res; 20 } 21 22 /* 23 * 适配器号赋值,代表i2c的编号 24 */ 25 adapter->nr = id; 26 return i2c_register_adapter(adapter); 27 } 28 /*********************************************** 29 * 来看一下适配器的注册函数i2c_register_adapter* 30 ***********************************************/ 31 static int i2c_register_adapter(struct i2c_adapter *adap) 32 { 33 int res = 0; 34 /* Can't register until after driver model init */ 35 36 /* 37 * bus私有属性结构不能为NULL 38 */ 39 if (unlikely(WARN_ON(!i2c_bus_type.p))) { 40 res = -EAGAIN; 41 goto out_list; 42 } 43 rt_mutex_init(&adap->bus_lock); 44 mutex_init(&adap->userspace_clients_lock); 45 INIT_LIST_HEAD(&adap->userspace_clients); 46 /* Set default timeout to 1 second if not already set */ 47 48 /* 49 * 超时时间设置为1s 50 */ 51 if (adap->timeout == 0) 52 adap->timeout = HZ; 53 54 /* 55 * 设置内嵌device的名字,指定bus,指定自身类型为适配器 56 */ 57 dev_set_name(&adap->dev, "i2c-%d", adap->nr); 58 adap->dev.bus = &i2c_bus_type; 59 adap->dev.type = &i2c_adapter_type; 60 61 /* 62 * 注册内嵌的标准device,此时将会出现在i2c_bus目录下 63 */ 64 res = device_register(&adap->dev); 65 if (res) 66 goto out_list; 67 dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name); 68 #ifdef CONFIG_I2C_COMPAT 69 res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, 70 adap->dev.parent); 71 if (res) 72 dev_warn(&adap->dev, 73 "Failed to create compatibility class link/n"); 74 #endif 75 /* create pre-declared device nodes */ 76 77 /* 78 * client可以静态的添加,如果发现适配器号也就是i2c号 79 * 小于动态bus号,说明设备静态添加,则进行扫描 80 */ 81 if (adap->nr < __i2c_first_dynamic_bus_num) 82 i2c_scan_static_board_info(adap); 83 /* Notify drivers */ 84 mutex_lock(&core_lock); 85 86 /* 87 * 遍历bus的驱动端,对于每一个driver都调用__process_new_adapter 88 */ 89 bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); 90 mutex_unlock(&core_lock); 91 return 0; 92 out_list: 93 mutex_lock(&core_lock); 94 idr_remove(&i2c_adapter_idr, adap->nr); 95 mutex_unlock(&core_lock); 96 return res; 97 } 98 /******************************************* 99 * 先来看一下i2c_scan_static_board_info函数*100 *******************************************/101 static void i2c_scan_static_board_info(struct i2c_adapter *adapter)102 {103 struct i2c_devinfo *devinfo;104 down_read(&__i2c_board_lock);105 /*106 * 遍历全局的i2c的client链表,找到该适配器器所代表107 * 总线上挂接的设备,用i2c_new_device实例化它,108 * i2c_new_device在前面已经分析过了,不在赘述109 */110 list_for_each_entry(devinfo, &__i2c_board_list, list) {111 if (devinfo->busnum == adapter->nr112 && !i2c_new_device(adapter,113 &devinfo->board_info))114 dev_err(&adapter->dev,115 "Can't create device at 0x%02x/n",116 devinfo->board_info.addr);117 }118 up_read(&__i2c_board_lock);119 }120 /**************************************121 * 再来看一下__process_new_adapter函数*122 **************************************/123 static int __process_new_adapter(struct device_driver *d, void *data)124 {125 /*126 * 同样的归宿到了i2c_do_add_adapter下面,与前面分析的127 * __process_new_driver相似,只是driver是针对适配器,128 * 而这次没有这个限制129 */130 return i2c_do_add_adapter(to_i2c_driver(d), data);131 }
依据以上的分析画出流程图如下:
i2c_driver依据内部成员的设定,会走不同的分支,产生不同的作用,下面根据流程前后顺序总结一下:
当发现的是i2c_bus上的一个client时(发生在标准driver注册的匹配):
1、首先会进入到bus定义的匹配函数i2c_device_match如果定义了CONFIG_OF_DEVICE宏并且内部的标准
driver结构定义了of_match_table成员,则利用其进行匹配;
2、否则如果driver->id_table成员设定,则利用其进行匹配,否则匹配失败。
3、如果匹配成功会调用i2c_bus的i2c_device_probe函数,该函数会判断,如果该i2c_driver的probe成员
或者id_table成员为NULL,则返回,否则利用i2c_driver->probe初始化这个client。
当发现的是代表该i2c_bus的上的adapter时(发生在bus的遍历):
1、如果该driver的driver->detect或者address_list为NULL退出
2、如果该adapter->class和driver->class不匹配也退出
3、如果以上都成立最终会调用driver->detect函数,实例化支持的client
4、如果driver->attach_adapter也被设定,含会走旧式的路线,直接利用driver->attach_adapter进行探测
不过,一般不会让3&&4这种结果出现
可见,i2c_driver的设置非常灵活,抓住关键成员就不难掌握其流程。
五、i2c关于dev下节点的产生及其操作
该部分的代码位于rivers/i2c/i2c-dev.c下,我们从头看起:
1 static int __init i2c_dev_init(void) 2 { 3 int res; 4 printk(KERN_INFO "i2c /dev entries driver/n"); 5 /* 6 * 注册名称为i2c主设备号为89的一个字符设备 7 */ 8 res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); 9 if (res)10 goto out;11 /*12 * 在class下产生i2c-dev节点,用于自动产生设备文件13 */14 i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");15 if (IS_ERR(i2c_dev_class)) {16 res = PTR_ERR(i2c_dev_class);17 goto out_unreg_chrdev;18 }19 20 /*21 * i2c_add_driver在上面已经分析过了22 */23 res = i2c_add_driver(&i2cdev_driver);24 if (res)25 goto out_unreg_class;26 return 0;27 out_unreg_class:28 class_destroy(i2c_dev_class);29 out_unreg_chrdev:30 unregister_chrdev(I2C_MAJOR, "i2c");31 out:32 printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__);33 return res;34 }35 //其中i2cdev_driver结构为:36 static struct i2c_driver i2cdev_driver = {37 .driver = {38 .name = "dev_driver",39 },40 .attach_adapter = i2cdev_attach_adapter,41 .detach_adapter = i2cdev_detach_adapter,42 };
由于没有关于client的支持表的定义,因此匹配client时就会直接返回, 由于存在成员attach_adapter,因此当匹配adapter时会进入该函数。
1 /************************************ 2 * 来看一下i2cdev_attach_adapter函数* 3 ************************************/ 4 static int i2cdev_attach_adapter(struct i2c_adapter *adap) 5 { 6 struct i2c_dev *i2c_dev; 7 int res; 8 i2c_dev = get_free_i2c_dev(adap); 9 if (IS_ERR(i2c_dev))10 return PTR_ERR(i2c_dev);11 /* register this i2c device with the driver core */12 13 /*14 * 以上面注册的i2c_dev_class为父节点在目录class/i2c-dev下15 * 产生i2c-0之类的节点,这样上层udev会根据该节点在dev目录下16 * 自动创建对应的设备文件17 */18 i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,19 MKDEV(I2C_MAJOR, adap->nr), NULL,20 "i2c-%d", adap->nr);21 if (IS_ERR(i2c_dev->dev)) {22 res = PTR_ERR(i2c_dev->dev);23 goto error;24 }25 26 /*27 * 产生相关属性文件28 */29 res = device_create_file(i2c_dev->dev, &dev_attr_name);30 if (res)31 goto error_destroy;32 pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",33 adap->name, adap->nr);34 return 0;35 error_destroy:36 device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));37 error:38 return_i2c_dev(i2c_dev);39 return res;40 }
通过以上分析可以看到i2c-dev层,找到一个adapter就会自动为其创建设备节点,形式类似于i2c-*,那么当应用层open对应的设备节点的时候,内核会自动调用刚才注册的字符设备的操作函数, 我们先来看一下刚才注册的字符设备的操作集:
1 static const struct file_operations i2cdev_fops = {2 .owner = THIS_MODULE,3 .llseek = no_llseek,4 .read = i2cdev_read,5 .write = i2cdev_write,6 .unlocked_ioctl = i2cdev_ioctl,7 .open = i2cdev_open,8 .release = i2cdev_release,9 };
按照用户层的流程先看一下open函数i2cdev_open:
1 static int i2cdev_open(struct inode *inode, struct file *file) 2 { 3 unsigned int minor = iminor(inode); //得到次设备号 4 struct i2c_client *client; 5 struct i2c_adapter *adap; 6 struct i2c_dev *i2c_dev; 7 8 /* 9 * 次设备号其实是对应i2c总线号,下面函数遍历由次设备构成的链表10 * i2c_dev_list,找到上面挂接的号码对应的i2c_dev结构11 */12 i2c_dev = i2c_dev_get_by_minor(minor);13 14 if (!i2c_dev) //没找到,出错15 return -ENODEV;16 adap = i2c_get_adapter(i2c_dev->adap->nr); //得到绑定的adapter17 if (!adap)18 return -ENODEV;19 /* This creates an anonymous i2c_client, which may later be20 * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.21 *22 * This client is ** NEVER REGISTERED ** with the driver model23 * or I2C core code!! It just holds private copies of addressing24 * information and maybe a PEC flag.25 */26 client = kzalloc(sizeof(*client), GFP_KERNEL); //申请个client内存27 if (!client) {28 i2c_put_adapter(adap);29 return -ENOMEM;30 }31 32 //命名,依据adapter33 snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);34 35 //指定driver,代表创建他的driver36 client->driver = &i2cdev_driver;37 38 //指定适配器39 client->adapter = adap;40 //通过file的私有成员传递创建的这个client41 file->private_data = client;42 return 0;43 }
由open可见,我们要操作i2c下的设备,始终是需要通过adapter,物理上也是如此,操作设备都是通过控制器进行读写的,因此我们打开的始终是adapter而open过程中会创建client,来表述我们主观上是要操作设备。下面在看一下read函数:
1 static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, 2 loff_t *offset) 3 { 4 char *tmp; 5 int ret; 6 //得到由open传递过来的创建的client 7 struct i2c_client *client = file->private_data; 8 9 //大小不能超过819210 if (count > 8192)11 count = 8192;12 13 //申请count大小内存14 tmp = kmalloc(count, GFP_KERNEL);15 if (tmp == NULL)16 return -ENOMEM;17 pr_debug("i2c-dev: i2c-%d reading %zu bytes./n",18 iminor(file->f_path.dentry->d_inode), count);19 20 //调用i2c_master_recv进行进一步传送21 ret = i2c_master_recv(client, tmp, count);22 if (ret >= 0)23 //read的信息反馈给用户24 ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;25 kfree(tmp);26 return ret;27 }28 /****************************29 * 其中i2c_master_recv函数为*30 ****************************/31 int i2c_master_recv(struct i2c_client *client, char *buf, int count)32 {33 struct i2c_adapter *adap = client->adapter;34 struct i2c_msg msg;35 int ret;36 37 //利用msg组织信息结构38 msg.addr = client->addr;39 msg.flags = client->flags & I2C_M_TEN;40 msg.flags |= I2C_M_RD;41 msg.len = count;42 msg.buf = buf;43 44 //调用i2c_transfer发送45 ret = i2c_transfer(adap, &msg, 1);46 /* If everything went ok (i.e. 1 msg transmitted), return #bytes47 transmitted, else error code. */48 return (ret == 1) ? count : ret;49 }
i2c_transfer函数上面已经分析过了,其会最终调用client所在adapter的adap->algo->master_xfer函数发送。
六、总结
分析了linux下i2c子系统模型及其关键点,针对核心的平台无关代码进行了描述,以上为个人观点,如有不妥,还望指正 ^_^
- linux设备模型之I2C子系统
- linux设备模型之i2c子系统
- linux设备模型之i2c子系统
- linux设备模型之i2c子系统
- linux设备模型之i2c子系统
- linux设备模型之i2c子系统
- linux设备模型之i2c子系统
- Linux设备驱动子系统- I2C
- Linux I2C子系统分析-I2C设备驱动
- Linux I2C子系统分析-I2C设备驱动
- Linux设备模型之input子系统详解
- Linux设备模型之input子系统
- Linux设备模型之input子系统详解
- Linux设备模型之input子系统详解
- Linux设备模型之input子系统详解
- Linux设备模型之input子系统详解
- Linux设备模型之input子系统详解
- linux设备模型之spi子系统
- JAVA进行类型转换
- 【CSDN常见问题解答】使用JNA调用Windows动态库
- C/C++代码(1):队列
- C/C++ via Windows (1) - first thing first
- ios 之contentmode
- linux设备模型之i2c子系统
- office2003word解除安全模式启动
- 错误: 找不到与“EntityFramework 6.0.2-beta1”兼容的“EntityFramework.zh-Hans”版本。
- 百度推广——搜索营销新视角
- iOS学习笔记: 错误记录
- 邮箱pop和smtp协议的说明
- 调试js 试用火狐的firebug
- 一堆C++人找不出内存泄露
- postgresql实现模糊查询 [转]