[転載]LinuxのI 2 C駆動アーキテクチャ

5618 ワード

最近は仕事でI 2 Cバスにかかわっています.I 2 cを使ったことがありますが、Linux kernelを見てみると、layerがこのように完備されていることに気づきました.
1.LinuxのI 2 C駆動アーキテクチャ
LinuxにおけるI 2 Cバスの駆動は、バス駆動(BUS)とデバイス駆動(DEVICE)の2つの部分に分かれている.ここで、バス駆動の役割は、システム内のI 2 Cバスごとに対応する読み書き方法を追加することである.しかし、バスドライバ自体は通信を行わず、デバイスドライバが関数を呼び出すのを待つだけである.
 
デバイス駆動は、I 2 Cバスに掛かる具体的なデバイスと通信する駆動である.I 2 Cバス駆動によって提供される関数によって、デバイス駆動は、ハードウェアデバイスとの詳細な通信を考慮することなく、異なるバスコントローラの違いを無視することができる.
 
1.1バス駆動
システムの電源を入れる時、まず搭載するのはI 2 Cバス駆動です.1つのバスドライバは、特定のI 2 Cバスの読み書きをサポートするために使用される.1つのバス駆動には通常2つのモジュール、1つのstruct i 2 c_が必要です.adapterとstruct i 2 c_Algorithmで説明します.
static struct i2c  _adapter pb1550_board_adapter = { 

  name:              "pb1550 adapter", 

  id:                I2C  _HW_AU1550_PSC, 

  algo:              NULL, 

  algo_data:         &pb1550_i2c  _info, 

  inc_use:           pb1550_inc_use, 

  dec_use:           pb1550_dec_use, 

  client_register:   pb1550_reg, 

  client_unregister: pb1550_unreg, 

  client_count:      0, 

}; 


 
この例では、「pb 1550 adapter」というドライバが接続されています.しかし、このモジュールは読み書き関数を提供しておらず、具体的な読み書き方法は2番目のモジュール、struct i 2 c_によって提供されている.Algorithmが提供します.
 
static struct i2c _algorithm au1550_algo = {
.name         = "Au1550 algorithm",
.id      = I2C _ALGO_AU1550,
.master_xfer  = au1550_xfer,
.functionality     = au1550_func,
};
 
i2c _adap->algo = &au1550_algo;
   
この例は、上記のバス駆動に読み書き「アルゴリズム」を追加した.通常、I 2 Cバスドライバごとに独自の読み書きアルゴリズムが定義されるが、同じアルゴリズムを使用するバスもあるため、同じ読み書き関数セットを共有することができる.この例のドライバは、「Au 1550 algorithm」という名前の独自の読み書きアルゴリズムモジュールを定義します.
 
すべてを入力したら、次のように呼び出します.
i2c _add_adapter(i2c _adap);
 
この2つのモジュールをオペレーティングシステムに登録すると、バスドライバがインストールされます.AMD au 1550の場合、この部分はすでにAMDによって提供されている.
1.2設備駆動
前述したように、バス駆動は、1つのバスに対する読み書きメカニズムを提供するだけであり、それ自体は通信を行わない.通信はI 2 Cデバイスによって駆動され、デバイス駆動はI 2 Cバスを介して具体的なデバイスと通信する.1つのデバイス駆動には2つのモジュールが記述されており、struct i 2 c_driverとstruct i 2 c_client .
 
システムの電源が入り、I 2 Cバス駆動の読み込みが完了すると、デバイス駆動を読み込むことができます.まず、次の構成を読み込みます.
 
static struct i2c _driver driver = {
        .name           = "i2c TV tuner driver",
        .id             = I2C _DRIVERID_TUNER,
        .flags          = I2C _DF_NOTIFY,
        .attach_adapter = tuner_probe,
        .detach_client  = tuner_detach,
        .command        = tuner_command,
};
 
i2c _add_driver(&driver);
 
このi 2 c_driverの読み込みが完了すると、attach_adapter関数が呼び出されます.システム内の各i 2 cバス駆動を巡回し、アクセスしたいデバイスを検出することができる.
 
static int tuner_probe(struct i2c _adapter *adap)
{
return i2c _probe(adap, &addr_data, tuner_attach);
}
 
注意プローブは、複数のデバイスを見つけることができるので、1つのI 2 Cバスが複数の異なるタイプのデバイスを掛けることができるだけでなく、1つのデバイスドライバが複数の異なるI 2 Cバスに掛けられたデバイスに同時にサービスすることもできる.
 
デバイスドライバがサポートできるデバイスを検出するたびにstruct i 2 c_を作成します.クライアントはこのデバイスを識別します.
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &driver;
 
/* Tell the I2C layer a new client has arrived */
err = i2c _attach_client(new_client);
if (err)
    goto error;
 
i 2 c_が表示されますClientは、adapterバス上に位置し、アドレスがaddressであり、driverを使用して駆動されるデバイスを表す.バス駆動とデバイス駆動、およびデバイスアドレスをバインドします.i 2 c_ClientはI 2 Cデバイスを表しています.
 
I 2 Cデバイスが得られると、このデバイスに対して直接読み書きを行うことができる.
/*
 * The master routines are the ones normally used to transmit data to devices
 * on a bus (or read from them). Apart from two basic transfer functions to
 * transmit one message at a time, a more complex version can be used to
 * transmit an arbitrary number of messages without interruption.
 */
extern int i2c _master_send(struct i2c _client *,const char* ,int);
extern int i2c _master_recv(struct i2c _client *,char* ,int);
 
通常の意味での読み書き関数と同様に、この2つの関数はi 2 c_に対してクライアントポインタで指定したデバイスは、int個のcharを読み書きします.値が読み書きのバイト数を返します.我々の既存のSLICの駆動については,最後にバスに読み書きするデータをこの2つの関数に引き出して転送すれば,移植作業が完了してもLinux版のI 2 Cデバイス駆動が得られる.