2015年9月27日 星期日

[Linux][Driver][I2C] 在device tree的架構下, i2c device與driver如何對應?


在device tree的架構下, i2c device 與 driver 是如何 match
原文: http://janbarry0914.blogspot.tw/2014/08/device-tree-i2c-device-driver-match.html

[文章重點]
了解在 device tree 的架構一下, i2c device 與 i2c driver 是如何 match 進而 call 到 driver 裡的 probe function (本文章是以 Qualcomm MSM8974 liquid board 為例)

[文章目錄]
  1. 在 device tree 架構下的作法
  2. device 如何被註冊
  3. driver 如何與 device 匹配

[在 device tree 架構下的作法]
Linux kernel driver 的架構都是由匯流排 ( bus ), 裝置 ( device ) 和 驅動程式 ( driver ) 所構成, 匯流排將裝置和驅動程式綁定. 當 Linux kernel 在註冊一個裝置的時候, 會尋找與之匹配的驅動程式; 相反的, 當 Linux  kernel 在註冊一個驅動程式的時候, 也會尋找與之匹配的裝置, 而匹配這動作是由匯流排負責完成.  然而 device tree 在做匹配綁定的概念跟之前的作法仍是一致的, 換句話說, 還是利用字串的比對, 只是由原本的 name 屬性改由 device tree 內的 compatible 屬性去做而已.


首先會說明裝置是如何被建立, 是如何被加到匯流排中, 接下來會說明驅動程式在註冊後, 匯流排如何去做這匹配的動作.

[device 如何被註冊]
那裝置是如何被加到匯流排中?  那就是透過 of_platform_populate( ) 這 function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * of_platform_populate() - Populate platform_devices from device tree data
 * @root: parent of the first level to probe or NULL for the root of the tree
 * @matches: match table, NULL to use the default
 * @parent: parent to hook devices from, NULL for toplevel
 *
 * Similar to of_platform_bus_probe(), this function walks the device tree
 * and creates devices from nodes.  It differs in that it follows the modern
 * convention of requiring all device nodes to have a 'compatible' property,
 * and it is suitable for creating devices which are children of the root
 * node (of_platform_bus_probe will only create children of the root which
 * are selected by the @matches argument).
 *
 * New board support should be using this function instead of
 * of_platform_bus_probe().
 *
 * Returns 0 on success, < 0 on failure.
 */
int of_platform_populate(struct device_node *root,
   const struct of_device_id *matches,
   const struct of_dev_auxdata *lookup,
   struct device *parent)
{
 struct device_node *child;
 int rc = 0;

 root = root ? of_node_get(root) : of_find_node_by_path("/");
 if (!root)
  return -EINVAL;

 for_each_child_of_node(root, child) {
  rc = of_platform_bus_create(child, matches, lookup, parent, true);
  if (rc)
   break;
 }

 of_node_put(root);
 return rc;
}

從這 function 的註釋中了解到它會走遍整個 device tree 並為 每一個 device node 去創建 device. 接下透過 call flow來了解先後關係.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
DT_MACHINE_START(MSM8974_DT, "Qualcomm MSM 8974 (Flattened Device Tree)")
 .map_io = msm8974_map_io,
 .init_irq = msm_dt_init_irq,
 .init_machine = msm8974_init,
 .handle_irq = gic_handle_irq,
 .timer = &msm_dt_timer,
 .dt_compat = msm8974_dt_match,
 .reserve = msm_8974_reserve,
 .init_very_early = msm8974_init_very_early,
 .restart = msm_restart,
 .smp = &msm8974_smp_ops,
MACHINE_END

 msm8974_init( ) @ board-8974.c 
 |--> board_dt_populate( ) @ board-dt.c 
     |--> of_platform_populate( )  @ platform.c
        |--> of_plateform_bus_create( ) @ platform.c 
            |--> of_platform_device_create_pdata( ) @ platform.c 
               |--> of_device_alloc( ) @ platform.c
                   /*除了分配struct platform_device的記憶體,
                     還分配了該platform device需要的resource的記憶體*/  
               |--> of_device_add( ) @ device.c /*把這個platform device加入系統中*/  
                   |--> device_add( )  /* 它會call device_create_file( ) 
                                       在 sysfs中建立 attribute file for the device*/

[driver 如何與 device 匹配]
在看完 " device tree 如何新增 device 到系統中" 後, 接下來看 device driver 的註冊過程, 在此, 以 i2c device driver  - audio codec rt5627 為例.

 i2c_add_driver( ) @ i2c.h  
 |-> i2c_register_driver( ) @ i2c-core.c /*將 device_driver中的 bus_type 設成 i2c_bus_type */  
    |--> driver_register( ) @ driver.c  
        |--> bus_add_driver( ) @ bus.c /* 建立 sysfs file node 與 attr*/  
           |--> driver_attach( ) @ dd.c  
              |--> bus_for_each_dev( drv->bus, NULL, drv, __driver_attach) @ bus.c  
                  |--> __driver_attach @ dd.c  
                      |--> driver_match_device(drv, dev) @base.h  
                           |--> i2c_device_match( ) @ i2c-core.c  
                               /***********************************************  
                           如果是device tree, 會透過 of_driver_match_device( ) 去做匹配的動作  
                           如果不是device tree就改用 i2c_match_id( ) 去完成匹配的動作  
                              ***************************************************/  
                  |--> driver_probe_device( ) @ dd.c  
                       /*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/
                       |--> really_probe( ) @ dd.c  
                           |--> i2c_device_probe( ) @ i2c-core.c  
                                |--> rt5627_i2c_probe( ) @ rt5627.c   

從上述的 call flow 得知, device tree 是透過 of_driver_match_device( ) 來做 device 與 driver 匹配的工作. 再從下述的 call flow 得知, 其實最後就是拿 device tree 中的 compatible 屬性跟 driver 中的 of_match_table->compatible 做字串的比較, 如果字串相同, 那就匹配成功囉.

 of_driver_match_device( ) @ of_device.h  
 |--> of_match_device(drv-> of_match_table, dev) @ device.c  
     |--> of_match_node( drv->of_match_table, dev->node) @ base.c  
         |--> of_device_is_compatible(node, drv->of_match_table->compatible) @ base.c 
             |--> of_compat_cmp( ) @ prom.h  
                  /*在 of_compat_cmp( ) 會透過 of_get_property()去取得
                    device tree 中 compatible 對應的值(字串), 
                    再跟 drv->of_match_table->compatible 所指的字串做字串比較*/
                 |--> strncmp( ) /*字串的比較*/  

我們再細看一下 of_match_node( ) 在做什麼事

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * of_match_node - Tell if an device_node has a matching of_match structure
 * @matches: array of of device match structures to search in
 * @node:  the of device structure to match against
 *
 * Low level utility function used by device matching.
 */
const struct of_device_id *of_match_node(const struct of_device_id *matches,
      const struct device_node *node)
{
 if (!matches)
  return NULL;

 while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
  int match = 1;
  if (matches->name[0])
   match &= node->name
    && !strcmp(matches->name, node->name);
  if (matches->type[0])
   match &= node->type
    && !strcmp(matches->type, node->type);
  if (matches->compatible[0])
   match &= of_device_is_compatible(node,
      matches->compatible);
  if (match)
   return matches;
  matches++;
 }
 return NULL;
}
EXPORT_SYMBOL(of_match_node);

就 device tree 而言(大部分 driver 的 of_match_table 裡只有填寫 compatible 屬性, 例如: 在下述 rt5627_match_table  這例子裡, 就是只有填寫 compatible 屬性), 它會跑到 of_device_is_compatible( ) 去檢查是否匹配, 下面是就是 of_device_is_compatible( ) 完整的 source code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/** Checks if the given "compat" string matches one of the strings in
 * the device's "compatible" property
 */
int of_device_is_compatible(const struct device_node *device,
  const char *compat)
{
 const char* cp;
 int cplen, l;

 cp = of_get_property(device, "compatible", &cplen);
 if (cp == NULL)
  return 0;
 while (cplen > 0) {
  if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
   return 1;
  l = strlen(cp) + 1;
  cp += l;
  cplen -= l;
 }

 return 0;
}
EXPORT_SYMBOL(of_device_is_compatible);

貼一下關於 of_match_table 是如何放在 driver 中 (以 audio codec rt5627為例)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#ifdef CONFIG_OF
static struct of_device_id rt5627_match_table[] = {
        { .compatible = "realtek,rt5627",},
        { },
};
#else
#define rt5627_match_table NULL
#endif

static struct i2c_driver rt5627_i2c_driver = {
 .driver = {
  .name = "rt5627",
  .owner = THIS_MODULE,
  .of_match_table = of_match_ptr(rt5627_match_table),
 },
 .probe =    rt5627_i2c_probe,
 .remove =   rt5627_i2c_remove,
 .id_table = rt5627_i2c_id,
};

看一下 device tree ( msm8974-liquid.dtsi ) 內, 我們新增一個 i2c device - rt5627 

 &soc {  
    ..  
     i2c@f9923000 {  
           realtek_rt5627@18 {  
                compatible = "realtek,rt5627";  
                reg = <0x18>;  
           };  
      };  
    ...  
 };  

我們將 Realtek rt5627 這顆 audio DAC ( 其 i2c address 是 0x18 ) 掛在 i2c bus 上 ( 其 physical address 為 0xf9923000 的 i2c bus 上).

[結論] 
在使用 device tree 時, 其匹配是利用 device tree 中 的 compatible 屬性, 跟 driver 中的 of_match_tabl e-> compatible 所指的字串做比較, 所以兩個字串要相同, 這樣才會匹配成功.

 [補充]
   針對 rt5627 這 i2c device 是如何被加進系統中做一個補充, 其實在device tree 章節中就有說明 device 是如何被加到系統中 ( board_dt_populate() ->  of_platform_populate( ) -> .... -> device_add( )), 但那只是針對一些父節點而言. 此例中, i2c@f9923000 是父節點, 而 realtek_rt5627@18 是子節點, 那子節點是何時被加到系統中? 在Qualcomm msm8974 平台上, 是在 i2c driver 的 probe function 中去實現, 所以是父節點做完 device <--> driver 的匹配動作之後, 在父節點的 driver 中的 probe function 裡再去找 device tree 中是否還有子節點, 如果有, 就開始一連串 device 註冊的動作.

 qup_i2c_probe( ) @ i2c-qup.c  
 |--> i2c_add_numbered_adapter( ) @ i2c-core.c   
     /* 宣告 i2c adapter 並給予 bus number*/  
 |--> of_i2c_register_device( ) @ of_i2c.c  
     /*走遍 child nodes, 並為 child nodes 註冊 device nodes*/  
     |--> i2c_new_device( ) @ i2c-core.c   
         /*為這 i2c device 依bus number 與 address命名, 例如: 4-0018  
          表示該 device 位於 bus 4, i2c address 是 0018*/  
        |--> device_register( ) @ core.c  
            |--> device_add ( ) @ core.c  

[Linux][USB] How to mount a USB flash disk ?


If you are not sure what device your system is using, type:
tail -f /var/log/messages

Now insert the usb device.
You should see similar output appear on your console:
Initializing USB Mass Storage driver...
usb.c: registered new driver usb-storage
scsi3 : SCSI emulation for USB Mass Storage devices
Vendor: Generic Model: STORAGE DEVICE Rev: 1.02
Type: Direct-Access ANSI SCSI revision: 02
Attached scsi removable disk sda at scsi3, channel 0, id 0, lun 0
SCSI device sda: 512000 512-byte hdwr sectors (262 MB)
sda: Write Protect is off
sda: sda1
WARNING: USB Mass Storage data integrity not assured
USB Mass Storage device found at 2
USB Mass Storage support registered.
usb.c: USB disconnect on device 00:1d.7-6 address 2

Make note of the line:
sda: sda1
This is the device your system is using.

If it doesn't work then try this: 
mount -t vfat /dev/sda1 /mnt/usb 

If it still doesn't work try this (some usb keys don't have a partition table on them): 
mount -t vfat /dev/sda /mnt/usb

If this still doesn't work, try to reload the modules:
modprobe -r usb-storage 
modprobe usb-storage

Then try to mount again.

2015年9月6日 星期日

fatal: Path 'XXX' is in submodule 'YYY' when git add

$ git ls-tree HEAD YYY 
 160000 commit c0f065504bb0e8cfa2b107e975bb9dc5a34b0398  mysubmodule 
That doesn't depend on the presence of the .gitmodule file, or on the content of mysubmodule.

You need to remove that entry from the index first:
$ git rm --cached YYY

2015年9月2日 星期三

vi內按方向鍵會出現ABCD

echo "set nocompatible" > ~/.vimrc