LinuxにおけるIICデバイス駆動再精読
10822 ワード
S 3 C 440コアIICデバイス駆動確立プロセス:
カーネルによって情報を印刷し、駆動プロセスを追跡する:
カーネル登録プロセス:印刷情報:1.先にi 2 c_を登録driver: i2cdev_driver—driversi 2 ci 2 c-dev.c前に分析しましたが、カーネル起動初期化は関数を実行します:i 2 c_dev_init i2c_dev_init(void) register_chrdev(I2C_MAJOR, “i2c”, &i2cdev_fops);//登録文字デバイス、主デバイス番号:I 2 C_MAJOR、アプリケーション層統一の操作インタフェースはi 2 cdev_fops i2c_dev_class = class_create(THIS_MODULE, “i2c-dev”);//classを構築する:i 2 c_dev_class
印刷情報:i 2 c/dev entries driver
i2c_dev_init, i2c_add_driver: i2cdev_driverそしてi 2 c_を登録するadapter: s3c24xx_i2c.adap —\drivers\i2c\busses\i2c-s3c2410.c
注:ここでは、異なるSocに対してi 2 c adapterを登録し、adapterはハードウェアi 2 cデバイスに対して登録します.
S 3 C 440では、プラットフォームバス駆動を用いてI 2 Cデバイスを登録する.
2.1 i 2 cプラットフォーム設備資源の初期化登録:
2.2登録i 2 cプラットフォームドライバの初期化:
印刷情報:
cnt: 1, i2c_adapter name: s3c2410-i2cさらに説明:i 2 c_を登録するとadapter: s3c24xx_i2c.adapの場合、driversチェーンテーブルを巡ってdriversチェーンテーブルのi 2 c_driverは1つずつ取り出し、i 2 c_を呼び出すdriver.attach_adapter(adapt)関数.前にi 2 c_が1つしか登録されていなかったのでdriver構造体:i 2 cdev_driverなので、関数:i 2 cdev_を呼び出します.driver.attach_adapter(adapter) = i2cdev_attach_adapter(s3c24xx_i2c.adap) i2cdev_attach_adapter(s3c24xx_i2c.adap) device_create(i2c_dev_class, &adap->dev, MKDEV(I2C_MAJOR, adap->nr), “i2c-%d”, adap->nr); この関数は前述のように解析されており、デバイスファイル://dev/i 2 c-0が作成されますので、カーネルが起動すると、確立されたデバイスファイル:ls/dev/i 2 c*-l crw--rw--1 0 0 89、0 Jan 1 00:00/dev/i 2 c-0が表示されます.プライマリ・デバイス番号は89、セカンダリ・スペア番号は0、デバイスファイル:「/dev/i 2 c-0」カーネル印刷情報:cnt:1、i 2 cdev_attach_adapter,adap.name:s3c2410-i2c cnt: 1, i2c_register_driver, i2c_driver->name: dev_driver 問題:上はただ1つの/dev/i 2 c-0デバイスファイルを生成しただけで、本当のIICはデバイスからどのようにドライバを登録しますか?回答:参考例プログラム:linux-2.6.22.6driversi 2 cchipsds 1374.c static int __init ds1374_init(void) i2c_add_driver(&ds1374_driver) i2c_register_driver(THIS_MODULE, driver); driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; driver_register(&driver->driver); i 2 cドライバ5.1を記述してi 2 cを構築する方法をまとめた.driver構造体この構造体は関数を含む:attach_adapter detach_Client 5.2登録i 2 c_driver構造体はカーネルにi 2 c_を登録するdriver、この構造体の下のattach_が呼び出されます.adapter関数5.3だからカーネル登録i 2 c_driverは、まずIICデバイスを検出するときに存在し、存在する場合はattach_を呼び出すadapter関数はprobeデバイスに来て、ある連絡を確立します:5.3.1 attach_adapter関数で、統一された関数インタフェースを呼び出す:i 2 c_probe(adapter、デバイスアドレス、「デバイスの本当のprobe関数」);5.3.2「デバイスの真のprobe関数」で、struct i 2 c_を構築するClient構造体:この構造体の一端には「adapter」が接続され、一端には「i 2 c_driver」は、IICデバイスアドレスを保存します.最後の呼び出し関数i 2 c_attach_クライアントは、このクライアントをカーネルのi 2 c_に登録します.bus_type上.5.3.3ここまで実行すると、IICデバイスが見つかり、クライアントを利用して何らかの連絡が確立されたことを示し、IICデバイスに対応する文字デバイスファイルを作成することができ、この作成プロセスは前述の文字デバイスドライバの確立と同じである.以降IICデバイスファイルの読み書きなどの操作は,クライアントという橋渡しによって行われる.注:5.3.3このステップはあるdriverでは行われていません.注ソースコードで表示します.
カーネルによって情報を印刷し、駆動プロセスを追跡する:
カーネル登録プロセス:印刷情報:1.先にi 2 c_を登録driver: i2cdev_driver—driversi 2 ci 2 c-dev.c前に分析しましたが、カーネル起動初期化は関数を実行します:i 2 c_dev_init i2c_dev_init(void) register_chrdev(I2C_MAJOR, “i2c”, &i2cdev_fops);//登録文字デバイス、主デバイス番号:I 2 C_MAJOR、アプリケーション層統一の操作インタフェースはi 2 cdev_fops i2c_dev_class = class_create(THIS_MODULE, “i2c-dev”);//classを構築する:i 2 c_dev_class
i2c_add_driver(&i2cdev_driver);
i2c_register_driver(THIS_MODULE, driver);
driver_register(&driver->driver);
list_add_tail(&driver->list,&drivers); // i2cdev_driver drivers
// adapters adapter, i2cdev_attach_adapter(adapter)
if (driver->attach_adapter) { // driver->attach_adapter = i2cdev_attach_adapter
struct i2c_adapter *adapter;
// ,adapters , adapter , adapter
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter); // , adapter, 。
}
}
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,
};
:
linux , , i2c ,i2c-driver 。
i2c 。
印刷情報:i 2 c/dev entries driver
i2c_dev_init, i2c_add_driver: i2cdev_driver
注:ここでは、異なるSocに対してi 2 c adapterを登録し、adapterはハードウェアi 2 cデバイスに対して登録します.
S 3 C 440では、プラットフォームバス駆動を用いてI 2 Cデバイスを登録する.
2.1 i 2 cプラットフォーム設備資源の初期化登録:
linux-2.6.22.6\arch\arm\plat-s3c24xx\devs.c
i2c :
struct platform_device s3c_device_i2c = {
.name = "s3c2410-i2c",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_i2c_resource),
.resource = s3c_i2c_resource,
};
linux-2.6.22.6\arch\arm\mach-s3c2440\mach-smdk2440.c
i2c :
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c2440_device_sdi,
};
//
static void __init smdk2440_machine_init(void)
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
platform_device_register(devs[i]); // s3c_device_i2c
2.2登録i 2 cプラットフォームドライバの初期化:
linux-2.6.22.6\drivers\i2c\busses\i2c-s3c2410.c
// i2c :
static int __init i2c_adap_s3c_init(void)
platform_driver_register(&s3c2440_i2c_driver);
// s3c2440 i2c :
static struct platform_driver s3c2440_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.resume = s3c24xx_i2c_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c2440-i2c",
},
};
: i2c_adapter ?
:
i2c , , ,
probe 。
probe , SoC i2c ( i2c ),
i2c_adapter , , i2c_add_adapter( i2c_adapter ), 。
// : driver , , driver probe
s3c24xx_i2c_probe(struct platform_device *pdev)
struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
s3c24xx_i2c_init(i2c); // IIC
i2c_add_adapter(&i2c->adap);
i2c_register_adapter(adapter);
list_add_tail(&adap->list, &adapters); // adapter adapters
// drivers i2c_driver, :driver->attach_adapter
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap); // , i2cdev_driver
// : i2cdev_attach_adapter(adap)
i2cdev_attach_adapter( adapter )
// i2c_dev_class device: i2c_dev->dev,
// : /dev/i2c-0,/dev/i2c-1,... /dev/i2c-n
// : i2c_dev_class
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr),
"i2c-%d", adap->nr);
}
// :i2c_adapter, struct s3c24xx_i2c :
static struct s3c24xx_i2c s3c24xx_i2c = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
.wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
.tx_setup = 50,
// i2c_adapter
.adap = {
.name = "s3c2410-i2c",
.owner = THIS_MODULE,
.algo = &s3c24xx_i2c_algorithm, // i2c I2C , ,
// , 。
.retries = 2,
.class = I2C_CLASS_HWMON,
},
};
印刷情報:
cnt: 1, i2c_adapter name: s3c2410-i2c
// i2c_driver drivers
list_add_tail(&driver->list,&drivers);
// adapters adapter , i2c_driver attach_adapter
if (driver->attach_adapter) {
struct i2c_adapter *adapter;
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter); // attach_adapter = ds1374_attach
// adapter s3c24xx_i2c.adap
// :
ds1374_attach(s3c24xx_i2c.adap)
i2c_probe(s3c24xx_i2c.adap, &addr_data, ds1374_probe);
//
i2c_probe_address(s3c24xx_i2c.adap, IIC , -1, ds1374_probe );
i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL)
// 1. IIC
i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,command,size,data);
// 2. IIC , IIC probe ,
// : ds1374_probe
found_proc(adapter, addr, kind);
ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
// 2.1 i2c_client , IIC
// client 。
struct i2c_client *client;
client->addr = addr;
client->adapter = adap;
client->driver = &ds1374_driver;
i2c_attach_client(client);
// 2.2 i2c_client , i2c_adapter clients
list_add_tail(&client->list,&adapter->clients);
client->dev.bus = &i2c_bus_type;
device_register(&client->dev);
}
}
static struct i2c_driver ds1374_driver = {
.driver = {
.name = DS1374_DRV_NAME,
},
.id = I2C_DRIVERID_DS1374,
.attach_adapter = ds1374_attach,
.detach_client = ds1374_detach,
};
まとめ:i 2 c_を登録するとdriverがカーネルに到達すると、(1)adaptersチェーンテーブルの下からadapterが1つずつ取り出され、(2)新しい登録i 2 c_が呼び出されるdriver構造体の総定義attach_adapter関数、(3)このattach_adapter関数では、カーネル定義の統合インタフェース関数が呼び出されます:i 2 c_probe i2c_probe関数プロトタイプ:int i 2 c_probe(struct i2c_adapter *adapter, struct i2c_client_address_data *address_data, int (found_proc) (struct i2c_adapter , int, int)) (4) i2c_probe , :
a. IIC , probe ;
b. i2c_probe IIC probe ,
IIC probe , I2c_client , IIC
IIC ( : IIC )。