原文:Documentation/i2c/upgrading-clients
译者:郭少悲
2010/05/10
更新I2C drivers到新的2.6驱动模型
=================================================
译者注:这里的i2c驱动指的是i2c client driver,比如使用i2c接口的rtc, usb
transceiver的driver等等。
Ben Dooks <[email protected]>
介绍
------------
这篇文档主旨在介绍如何将Linux 2.6中已经存在的i2c client driver从旧模型升级到新
的绑定模型上。
旧模型驱动示例
------------------------
struct example_state {
struct i2c_client client;
....
};
static struct i2c_driver example_driver;
static unsigned short ignore[] = { I2C_CLIENT_END };
static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
static int example_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct example_state *state;
struct device *dev = &adap->dev; /* to use for dev_ reports */
int ret;
state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
if (state == NULL) {
dev_err(dev, "failed to create our state/n");
return -ENOMEM;
}
example->client.addr = addr;
example->client.flags = 0;
example->client.adapter = adap;
i2c_set_clientdata(&state->i2c_client, state);
strlcpy(client->i2c_client.name, "example", I2C_NAME_SIZE);
ret = i2c_attach_client(&state->i2c_client);
if (ret < 0) {
dev_err(dev, "failed to attach client/n");
kfree(state);
return ret;
}
dev = &state->i2c_client.dev;
/* rest of the initialisation goes here. */
dev_info(dev, "example client created/n");
return 0;
}
static int __devexit example_detach(struct i2c_client *client)
{
struct example_state *state = i2c_get_clientdata(client);
i2c_detach_client(client);
kfree(state);
return 0;
}
static int example_attach_adapter(struct i2c_adapter *adap)
{
return i2c_probe(adap, &addr_data, example_attach);
}
static struct i2c_driver example_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "example",
},
.attach_adapter = example_attach_adapter,
.detach_client = __devexit_p(example_detach),
.suspend = example_suspend,
.resume = example_resume,
};
更新client
-------------------
新风格的绑定模型将检查核对其维护的链表所支持的设备和通过代码注册的匹配设备地址
。这意味着driver里的.attach_adapter和.detach_adapter方法以及addr_data被删除不
再使用,如下所示:
- static struct i2c_driver example_driver;
- static unsigned short ignore[] = { I2C_CLIENT_END };
- static unsigned short normal_addr[] = { OUR_ADDR, I2C_CLIENT_END };
- I2C_CLIENT_INSMOD;
- static int example_attach_adapter(struct i2c_adapter *adap)
- {
- return i2c_probe(adap, &addr_data, example_attach);
- }
static struct i2c_driver example_driver = {
- .attach_adapter = example_attach_adapter,
- .detach_client = __devexit_p(example_detach),
}
在i2c_driver里添加probe和remove方法,如下所示:
static struct i2c_driver example_driver = {
+ .probe = example_probe,
+ .remove = __devexit_p(example_remove),
}
修改example_attach方法:方法名,接受新的参数(i2c_client),如下:
- static int example_attach(struct i2c_adapter *adap, int addr, int kind)
+ static int example_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
修改example_attach名为example_probe,probe函数需要被修改因为i2c_client已经被
建立使用。
下面的client fields已经在probe函数调用之前建立起来了,所以下面的client建立代码
可以被删除:
- example->client.addr = addr;
- example->client.flags = 0;
- example->client.adapter = adap;
-
- strlcpy(client->i2c_client.name, "example", I2C_NAME_SIZE);
i2c_set_clientdata现在成为:
- i2c_set_clientdata(&state->client, state);
+ i2c_set_clientdata(client, state);
对i2c_attach_client()的调用不再需要,如果probe函数成功返回,驱动会被i2c-core自动匹
配。probe函数的修改如下:
- ret = i2c_attach_client(&state->i2c_client);
- if (ret < 0) {
- dev_err(dev, "failed to attach client/n");
- kfree(state);
- return ret;
- }
从struct example_state里删除对struct i2c_client域的存储,在example_probe里已经提供
了i2c_client访问参数。需要时,我们只需存储一个指向i2c_client的指针。
struct example_state {
- struct i2c_client client;
+ struct i2c_client *client;
新的i2c client如下:
- struct device *dev = &adap->dev; /* to use for dev_ reports */
+ struct device *dev = &i2c_client->dev; /* to use for dev_ reports */
删除client被attach后的修改保存, driver不再需要注册一个新的client数据结构到core
里。如下:
- dev = &state->i2c_client.dev;
在probe函数里,确保新的state里保存了指向client的指针:
static int example_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct example_state *state;
struct device *dev = &i2c_client->dev;
int ret;
state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
if (state == NULL) {
dev_err(dev, "failed to create our state/n");
return -ENOMEM;
}
+ state->client = i2c_client;
更新detach方法,改example_detach名为example_remove,删除对i2c_detach_client()
的调用。你也可删除返回变量因为它不再被i2c-core function需要。
- static int __devexit example_detach(struct i2c_client *client)
+ static int __devexit example_remove(struct i2c_client *client)
{
struct example_state *state = i2c_get_clientdata(client);
- i2c_detach_client(client);
最后确保我们有一个正确的ID table,供i2c-core和其他utilities使用:
+ struct i2c_device_id example_idtable[] = {
+ { "example", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, example_idtable);
static struct i2c_driver example_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "example",
},
+ .id_table = example_ids,
我们的驱动现在看起来像这样:
struct example_state {
struct i2c_client *client;
....
};
static int example_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct example_state *state;
struct device *dev = &client->dev;
state = kzalloc(sizeof(struct example_state), GFP_KERNEL);
if (state == NULL) {
dev_err(dev, "failed to create our state/n");
return -ENOMEM;
}
state->client = client;
i2c_set_clientdata(client, state);
/* rest of the initialisation goes here. */
dev_info(dev, "example client created/n");
return 0;
}
static int __devexit example_remove(struct i2c_client *client)
{
struct example_state *state = i2c_get_clientdata(client);
kfree(state);
return 0;
}
static struct i2c_device_id example_idtable[] = {
{ "example", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, example_idtable);
static struct i2c_driver example_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "example",
},
.id_table = example_idtable,
.probe = example_probe,
.remove = __devexit_p(example_remove),
.suspend = example_suspend,
.resume = example_resume,
};