全部博文(36)
分类: 嵌入式
2012-11-26 17:01:05
欢迎转载和指导,然后再吐槽!!!
升级I2C驱动到新的2.6设备模型中
——————————————————————
Ben Dooks
介绍
——————————————————————
这个指导概括了怎么样改变目前linux 2.6内核中client驱动的方法从老的到新的绑定方法。
Old-style 驱动例子:
——————————————————————————————
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; /* 用于 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;
/* 做剩下的初始化工作. */
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
————————————————————————————————————
New style绑定模型会核对所支持设备的一个表,他们代码提供用于注册总线的相关地址。就是说驱动 .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_probe的名字改成example_probe使得它和i2c_driver的入口名字进行匹配。Probe程序的剩下部分也得改了,因为这个时候i2c_client已经设置可以使用了。
在probe函数调用前,必须的client域已经建立设置了,所以下面的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程序成功结束的话,驱动就不会自动附上通过核心。改变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,当我们需要它的时候,我们就可以取它的一个指针。
struct example_state {
- struct i2c_client client;
+ struct i2c_client *client;
新的I2c client如下:
- struct device *dev = &adap->dev; /* 用于 dev_ reports */
+ struct device *dev = &i2c_client->dev; /* 用于 dev_ reports */
我们client附上之后,就可以移除这个改变了,因为驱动不再需要在核心中注册一个client 结构体
- 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方法,通过改变_remove 然后删除i2c_detach_client 调用。有可能你也会移除ret变量 ,因为它对于很多核心的函数不再需要。
- 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表用于i2c-core 和其他的一些工具。
+ 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,
};