乾坤合一~Linux設備驅動之I2C核心、總線以及設備驅動

  • 我思念的城市已經是黃昏
  • 爲什麼我總對你一往情深
  • 曾經給我快樂 也給我創傷
  • 曾經給我但願 也給我絕望
  • 我在遙遠的城市 陌生的人羣
  • 感受着你遙遠的憂傷
  • 個人幻想

你的憂傷,像個人的絕望,那樣漫長,,,,,這是今天的旋律,直入心底~~~~~~~~~~~~~~~~html

  在Linux 系統中,I2C 驅動由3 部分組成,即I2C 核心、I2C 總線驅動和I2C 設備驅動,I2C 總線僅僅使用SCL、SDA 這兩根信號線就實現了設備之間的數據交互,極大地簡化了對硬件資源和PCB 板佈線空間的佔用數組

1 Linux的I2C體系結構數據結構

1.1 組成部分函數

1) I2C核心ui

I2C核心提供了I2C總線驅動和設備驅動的註冊、註銷方法,i2C通訊方法等等spa

2) I2C總線驅動設計

I2C 總線驅動主要包含了I2C 適配器數據結構i2c_adapter、I2C 適配器的algorithm數據結構i2c_algorithm 和控制I2C適配器產生通訊信號的函數。是對I2C硬件體系結構中適配器端的實現適配器可由CPU 控制,甚至能夠直接集成在CPU 內部。指針

3) I2C設備驅動htm

I2C 設備驅動主要包含了數據結構i2c_driver 和i2c_client ,咱們須要根據具體設備實現其中的成員函數。是對I2C硬件體系結構中設備端的實現,設備通常掛接在受 CPU 控制的I2C適配器上,經過I2C 適配器與CPU 交換數據。blog

1.2 I2C設備

全部的I C 設備都在sysfs 文件系統中顯示,存於/sys/bus/i2c/目錄,以適配器地址和芯片地址的形式列出,我在Linux上輸入命令得出:

1.3 i2C.h頭文件

  內核中的 i2c.h 這個頭文件對 i2c_driver 、i2c_client 、i2c_adapter 和i2c_algorithm 這4 個數據結構進行了定義。理解這4個結構體的做用十分關鍵.下面分析這4個數據結構之間的關係以及做用.至於各個結構具體的代碼本身在這個文件中查找就能夠啦。

1) i2c_adapter 與i2c_algorithm。 

  i2c_adapter 對應於物理上的一個適配器,而i2c_algorithm 對應一套通訊方法。一個I C 適配器須要i2c_algorithm 中提供的通訊函數來控制適配器上產生特定的訪問週期。缺乏i2c_algorithm 的i2c_adapter 什麼也作不了,所以i2c_adapter 中包含其使用的i2c_algorithm 的指針。i2c_algorithm 中的關鍵函master_xfer()用於產生 I2C 訪問週期須要的信號,以i2c_msg (即I2C 消息)爲單位

2) i2c_driver 與i2c_client 。 

  i2c_driver 對應一套驅動方法,是純粹的用於輔助做用的數據結構,它不對應於任何的物理實體。i2c_client 對應於真實的物理設備,每一個I C 設備都須要一個i2c_client來描述。i2c_client 通常被包含在I C 字符設備的私有信息結構體中。 i2c_driver 與i2c_client 發生關聯的時刻在i2c_driver 的attach_adapter() 函數被運行時。attach_adapter()會探測物理設備,當肯定一個 client 存在時,把該 client 使用的 i2c_client 數據結構的adapter 指針指向對應的i2c_adapter,driver 指針指向該i2c_driver,並會調用 i2c_adapter 的 client_register() 函數。相反的過程發生在 i2c_driver 的 detach_client()函數被調用的時候。

3) i2c_adpater 與i2c_client 

  i2c_adpater 與 i2c_client 的關係與 I C 硬件體系中適配器和設備的關係一致,即i2c_client 依附於 i2c_adpater.因爲一個適配器上能夠鏈接多個 I2C 設備,因此一個i2c_adpater 也能夠被多個i2c_client 依附,i2c_adpater 中包括依附於它的i2c_client 的鏈表。

2 Linux I2C核心

2.1 增長/刪除i2c_adapter 。

int i2c add adapter(struct i2c adapter *adap);

int i2c del adapter(struct i2c adapter *adap);

2.2 增長/刪除i2c_driver 。

int i2c register driver(struct module *owner, struct i2c driver *driver); 

int i2c del driver (struct i2c driver *driver); 

inline int i2c add driver(struct i2c driver *driver);

2.3 i2c_client 依附/脫離

int i2c attach client (struct i2c client *client);

int i2c detach client (struct i2c client *client)

 

 2.4 I2C 傳輸、發送和接收

int i2c transfer (struct i2c adapter * adap, struct i2c msg *msgs, int num); 

int i2c master send (struct i2c client *client,const char *buf ,intcount); 

int i2c master recv (struct i2c client *client, char *buf ,int count); 

2.5 I2C 控制命令分配

下面函數有助於將發給 I C 適配器設備文件 ioctl 的命令分配給對應適配器的algorithm 的algo_control()函數或i2c_driver 的command()函數,以下所示: 

int i2c control(struct i2c client *client, unsigned int cmd, unsigned long arg);

void i2c clients command (struct i2c adapter *adap, unsigned int cmd,void *arg);

3 Linux I2C總線驅動

3.1 I2C 適配器驅動加載與卸載

//I2C 總線驅動的模塊加載和卸載函數模板以下代碼 

       static int      init i2c adapter xxx init (void) 

       { 

         xxx adpater hw init (); 

         i2c add adapter(&xxx adapter); 

       } 

       static void      exit i2c adapter xxx exit (void) 

       { 
 
         xxx adpater hw free (); 

        i2c del adapter(&xxx adapter); 

      } 
//xxx_adpater_hw_init()和xxx_adpater_hw_free()函數的實現都與具體的CPU 和I2C 設備硬件直接相關

3.2 I2C 總線通訊方法

  其通訊方法主要是實現 i2c_algorithm 的master_xfer() 函數和functionality()函數。functionality()函數很是簡單,用於返回algorithm 所支持的通訊協議,master_xfer() 函數在I2C 適配器上完成傳遞給它的i2c_msg 數 中的每一個I2C 消息,如下代碼 所示爲xxx 設備的master_xfer() 函數模板。

static int i2c adapter xxx xfer (struct i2c adapter *adap, struct i2c msg *msgs, int num) 
       { 
         ... 
         for (i = 0; i < num; i++) 
         { 
         
           i2c adapter xxx start (); /*產生開始位*/ 
           /*是讀消息*/ 
                        
           if (msgs[i]->flags &I2C M RD) 
          { 
          
            i2c adapter xxx setaddr((msg->addr << 1) | 1); /*發送從設備讀地址*/ 

            i2c adapter xxx wait ack (); /*得到從設備的ack*/ 
          
            i2c adapter xxx readbytes(msgs[i]->buf, msgs[i]->len); /*讀取msgs[i] ->len 
              長的數據到msgs[i]->buf*/ 
          } 
          else 
     /*是寫消息*/ 
         { 
          
           i2c adapter xxx setaddr(msg->addr << 1); /*發送從設備寫地址*/ 
            
           i2c adapter xxx wait ack (); /*得到從設備的ack*/ 
        
           i2c adapter xxx writebytes(msgs[i]->buf, msgs[i]->len); /*讀取msgs[i] ->len 
             長的數據到msgs[i]->buf*/ 
         } 
        } 
         
       i2c adapter xxx stop (); /*產生中止位*/ 
     } 

3.3 xxx_i2c  結構體

  多數I2C 總線驅動會定義一個 xxx_i2c 結構體,做爲 i2c_adapter 的algo_data(相似「私有數據」),其中包含I C 消息數 指針、數 索引及I C 適配器algorithm訪問控制用的自旋鎖、等待隊列等,而master_xfer()函數完成消息數 中消息的處理也可經過對 xxx_i2c 結構體相關成員的訪問來控制,xxx_i2c 結構體的定義以下:

struct xxx i2c 
       { 
               
        spinlock t        lock; 
             
        wait queue head t     wait; 
             
        struct i2c msg  *msg; 
                             
        unsigned int          msg num; 
                               
        unsigned int          msg idx; 
                                  
        unsigned int          msg ptr; 
        ... 
           
       struct i2c adapter adap; 
      }; 

4 Linux I2C設備驅動

  I2C 設備驅動要使用 i2c_driver和 i2c_client 數據結構並填充其中的成員函數

4.1 模塊加載與卸載 

I2C 設備驅動的加載與卸載函數模板代碼以下:

static int      init yyy init (void) 
       { 
         int res; 
         /*註冊字符設備*/ 
                
         res = register chrdev (YYY MAJOR, "yyy", &yyy fops); //老內核接口 
//說明註冊「yyy 」這個字符設備時,使用的 file_operations 結構體爲 yyy_fops說明註冊「yyy 」這個字符設備時,使用的 file_operations結構體爲yyy_fops
         if (res) 
           goto out; 
            
         /*添加i2c driver*/ 
           
         res = i2c add driver (&yyy driver); 
        if (res) 
            
          goto out unreg class; 
        return 0; 

        out unreg chrdev : unregister chrdev (I2C MAJOR, "i2c"); 
                      
        out: printk (KERN ERR "%s: Driver Initialisation failed\n",          FILE ); 
        return res; 
      } 

      static void      exit yyy exit (void) 
      { 
           
        i2c del driver (&i2cdev driver); 
               
        unregister chrdev (YYY MAJOR, "yyy"); 
      }

 4.2 i2c_driver 成員函數 

  i2c_add_driver的執行會引起i2c_driver 結構體中yyy_attach_adapter()函數的執行,咱們能夠在yyy_attach_adapter() 函數裏探測物理設備。爲了實現探測,yyy_attach_adapter() 函數裏面也只需簡單地調用I2C 核心的i2c_probe()函數,I2C設備驅動的i2c_attach_adapter 函數代碼以下:

static int yyy attach adapter(struct i2c adapter *adapter)
{ 
   return i2c probe (adapter, &addr data, yyy detect); 
} 
//第1 個參數是i2c_adapter指針,第2 個參數是要探測的地址數據,第3個參數是具體的探測函數

  i2c_probe()函數會引起yyy_detect()函數的調用,能夠在yyy_detect()函數中初始化i2c_client,I2C設備驅動的detect 函數代碼以下:

static int yyy detect (struct i2c adapter *adapter, int address, int kind) 
       { 
              
        struct i2c client *new client; 
              
        struct yyy data *data; 
        int err = 0; 

        if (!i2c check functionality (adapter, I2C FUNC XXX) 
           goto exit; 

      if (!(data = kzalloc (sizeof(struct yyy data), GFP KERNEL))) 
//分配私有信息結構體的內存,i2c_client 也被建立
       { 
           err =  - ENOMEM; 
           goto exit; 
       } 
 
       new client = &data->client; 
            
       new client->addr = address; 
         
       new client->adapter = adapter; 
          
       new client->driver = &yyy driver; 
           
       new client->flags = 0; 
      
       /* 新的client 將依附於adapter */ 
   
       if ((err = i2c attach client (new client))) 
//調用內核的i2c_attach_client()知會I C 核心系統中包含了一個新的I C 設備                   
           goto exit kfree; 
      
       
       yyy init client (new client); //初始化i2c_client 對應的I2C 設備
       return 0; 
             
       exit kfree: kfree (data); 
       exit: return err; 
     } 

  I2C 設備驅動的卸載函數進行 i2c_del_driver調用後,會引起與 yyy_driver 關聯的每一個i2c_client 與之解除關聯,函數yyy_detach_client() 的設計的代碼以下:

static int yyy detach client (struct i2c client *client) 
      { 
        int err; 
         
        struct yyy data *data = i2c get clientdata (client); 
//i2c_get_clientdata()函數用於從 yyy_data私有信息結構中的i2c_client  的指針獲yyy_data  的指針

        if ((err = i2c detach client (client))) 
//調用I C 核心函數i2c_detach_client(),這個函數會引起i2c_adapter 的client_unregister()函數被調用
         return err; 
      
        kfree (data);    //釋放yyy_data的內存。 
       return 0; 
      } 

4.3 yyy_command() 的實現

  它實現了針對設備的控制命令。具體的控制命令是設備相關的,假設yyy 設備接受兩類命令YYY_CMD1 和YYY_CMD2 ,而處理這兩個命令的函數分別yyy_cmd1()和yyy_cmd2(), I2C 設備驅動的command 函數代碼以下:

static int yyy command (struct i2c client *client, unsigned int cmd, void  *arg) 

      { 

        switch (cmd) 

         { 

           case YYY CMD1: 

           return yyy cmd1(client, arg); 

          case YYY CMD2: 

             return yyy cmd2(client, arg); 

          default: 

            return  - EINVAL; 

        } 

     } 

  具體命令的實現是經過 件i2c_msg 消息數 ,並調用I2C 核心的傳輸、發送和接收函數,由I C 核心的傳輸、發送和接收函數調用I C 適配器對應的algorithm相關函數來完成的.

4.4 文件操做接口

  做爲一種字符類設備,Linux I C 設備驅動的文件操做接口與普通的設備驅動是徹底一致的,可是在其中要使用i2c_client 、i2c_driver、i2c_adapter 和i2c_algorithm 結構體和I2C 核心,而且對設備的讀寫和控制須要藉助體系結構中各組成部分的協同合做,下面舉一個I2C 設備文件的接口寫函數的例子:

static ssize t yyy write (struct file *file, char *buf, size t count, loff t off) 
       { 

       struct       i2c client       *client       =      (struct i2c client*)file->private data; 
    
        i2c msg msg[1]; 
         char *tmp; 
         int ret; 
         tmp = kmalloc(count, GFP KERNEL); 
         if (tmp == NULL) 
          return  - ENOMEM; 

        if (copy from user (tmp, buf, count)) 
        { 
          kfree (tmp); 
          return  - EFAULT; 
        } 
      
        msg[0].addr = client->addr;//地址 
        msg[0].flags = 0;               //0 爲寫 
        msg[0].len = count;             //要寫的字節數 
        msg[0].buf = tmp;               //要寫的數據 

        ret = i2c transfer (client->adapter, msg, 1);  //傳輸I C 消息 
        return (ret == 1) ? count : ret; 
      } 

I2C 設備的寫操做經歷 了以下幾個步驟:

  1. 從用戶空間到字符設備驅動寫函數接口,寫函數構造I2C 消息數 。
  2. 寫函數把構造的I C 消息數 傳遞給I2C 核心的傳輸函數i2c_transfer() 。
  3. I2 C 核心的傳輸函數 i2c_tr ansfer() 找到對應適配器 algorithm 的通訊方法函數 master_xfer()去最終完成 I2C 消息的處理。

4.5 i2c-dev.c 文件分析

  i2c-dev.c 中提供i2cdev_read()、i2cdev_write()函數來對應用戶空間要使用的read()和write() 文件操做接口,這兩個函數分別調用 I C 核心的 i2c_master_recv() 和i2c_master_send()函數來構造一條I2C 消息並引起適配器algorithm 通訊函數的調用, 完成消息的傳輸.可是i2c-dev.c 中i2cdev_read()和i2cdev_write()函數不具有太強的通用性,沒有太大的實用價值,只能適用於非RepStart 模式的狀況。對於兩條以上消息成的讀寫,在用戶空間須要 織i2c_msg 消息數組並調用I2C_RDWR IOCTL 命令。

 

  版權全部,轉載請註明轉載地址: http://www.cnblogs.com/lihuidashen/p/4511469.html

相關文章
相關標籤/搜索