茫茫網海中的冷日 - 對這文章發表回應
茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1675562 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_DPP_0011.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

對這文章發表回應

發表限制: 非會員 可以發表

發表者: 冷日 發表時間: 2012/7/10 13:46:49

udev-強大的device node管理系統

作者: Joey  日期: 2009-02-02 20:35

過年前跑去書店打發無聊的時間,看到這個月又出了兩本跟linux device driver相關的書籍,隨手拿起來翻翻,發現其中有一篇寫到udev framework,裡面詳盡解釋device node在insert kernel module時如何自動建立,並且可隨著使用者更改規則而產生persistent node…等不同於devfs的變化

udev的官方網頁有篇不錯的conference paper,裡面有提到幾個重點,udev的出現為了解決目前在devfs上碰到的3個問題
1.udev能夠根據規則建立device node(這可以解決probing時,device node可能會依probing的順序不同而改變)
2.udev動態建立device node,不會像以前在/dev資料夾下擺一堆多而無用的device node
3.提供user更方便的API存取目前device的資訊,在kernel 2.6以上已提供sysfs這個device管理機制

udev運作的原理很簡單,它透過netlink得知目前kernel有那些module新增了,在收到kernel module新增的netlink訊息之後,它會先掃描user是否有指派device node rule,如果沒有,會自動根據module的major和minor number建立device node.有一點比較特殊的地方是,udev用inotify監聽rule變化的event,所以可以即時改變device node的狀態,udev的架構圖可參考如下


那我做個小實驗,看看udev到底是如何運作的,這個實驗分為兩個部份,一個是character kernel module,而另外一個就是udev的user space program(下載 udev-137.tar.gz)

character kernel module寫作的重點在於init時會建立class與create device

  1. charmodule_class = class_create ( THIS_MODULE , DEVICE_NAME ) ;
  2. if   ( IS_ERR ( charmodule_class
    ))  
  3. return - EFAULT ;
  4. device_create ( charmodule_class , NULL , MKDEV ( driver_major , 0 ) , DEVICE_NAME ) ;

character kernel moduel移除時會remove class和destroy device


  1. device_destroy ( charmodule_class , MKDEV ( driver_major , 0 )) ;
  2. class_destroy ( charmodule_class ) ;

我把udevd和udevadm移植到實驗平台,並且執行指令udevd –d,當我insert character kernel module時,udevd會自動幫我建立device node,整個實驗過程如下圖

character kernel module程式如下

  1. #include
    < linux/module.h >  
  2. #include < linux/kernel.h >  
  3. #include < linux/init.h >  
  4. #include < linux/major.h >  
  5. #include < linux/device.h >  
  6. #include < linux/poll.h
    >  
  7.  
  8. #define   dbg ( fmt , args ... ) printk ( " [%s]:%d => " fmt , __FUNCTION__ , __LINE__ ,## args )
  9. #define DBG () printk ( " [%s]:%d => \ n " , __FUNCTION__ , __LINE__ )
  10. #define DEVICE_NAME " charmodule "
  11. #define STRING_SIZE 256
  12. #define STRING_CHANGE_TIME 2 //seconds
  13.  
  14. static   int driver_major ;
  15. static int string_counter =
    1 ;
  16. static struct class * charmodule_class ;
  17.  
  18. typedef   struct _driver_private_data  
  19. {  
  20. wait_queue_head_t   wait ;
  21. struct fasync_struct *
    fasync ;
  22. struct timer_list char_timer ;
  23. char my_string [ 256 ] ;
  24. int flag ;
  25.  
  26. } driver_private_data ;
  27.  
  28. driver_private_data
    * gpd ;
  29. void   MyTimerFunction ( unsigned long data ) ;
  30.  
  31. static   ssize_t char_read ( struct file * file , char
    __user * buffer , size_t count , loff_t * ppos )  
  32. {  
  33. int   retval = 0 ;
  34. driver_private_data * dpd =
    file -> private_data ;
  35.  
  36. DBG () ;
  37. if   ( count < STRING_SIZE ) return - EINVAL ;
  38. while   (( retval +
    STRING_SIZE ) <= count )  
  39. {  
  40. if   ( copy_to_user ( buffer , dpd -> my_string , STRING_SIZE ))  
  41. return - EFAULT
    ;
  42. retval += STRING_SIZE ;
  43. }  
  44. dpd -> flag = 0 ;
  45. return   retval ;
  46. }  
  47.  
  48. static   ssize_t
    char_write ( struct file * file , const char __user * buffer , size_t count , loff_t * ppos )  
  49. {  

  50. return   STRING_SIZE ; //just a demo, I dont implement this
  51. }  
  52.  
  53. static   int char_open ( struct inode * inode , struct file * file )
     
  54. {  
  55.  
  56. driver_private_data * dpd ;
  57.  
  58. DBG () ;
  59. dpd = ( driver_private_data * ) file -> private_data ;
  60. if  
    ( ! dpd )  
  61. {  
  62. dpd = ( driver_private_data * ) kmalloc ( sizeof ( driver_private_data ) , GFP_ATOMIC ) ;
  63. file ->
    private_data = dpd ;
  64. sprintf ( dpd -> my_string , " string_counter %d \ n " , string_counter ) ;
  65. dpd -> flag = 0 ;

  66. string_counter ++;
  67. init_waitqueue_head ( & dpd -> wait ) ;
  68. gpd = dpd ;
  69. init_timer ( & dpd -> char_timer ) ;
  70. dpd ->
    char_timer . function = MyTimerFunction ;
  71. dpd -> char_timer . expires = jiffies + STRING_CHANGE_TIME * HZ ;
  72. dpd -> char_timer . data = (
    unsigned   long ) gpd ;
  73. add_timer ( & dpd -> char_timer ) ;
  74. }  
  75. return   0 ;
  76. }  
  77. static   unsigned
    int char_poll ( struct file * file , poll_table * wait )  
  78. {  
  79. driver_private_data * dpd = file -> private_data ;
  80. int
      mask = 0 ;
  81.  
  82. DBG () ;
  83. poll_wait ( file , & dpd -> wait , wait ) ;
  84. if   ( dpd ->
    flag == 1 )  
  85. mask |= POLLIN | POLLRDNORM ;
  86. return   mask ;
  87. }  
  88.  
  89. static   int char_release ( struct
    inode * inode , struct file * file )  
  90. {  
  91. driver_private_data * dpd ;
  92.  
  93. DBG () ;
  94. dpd = ( driver_private_data
    * ) file -> private_data ;
  95. del_timer ( & dpd -> char_timer ) ;
  96. return   0 ;
  97. }  
  98.  
  99.  
  100.  
  101.  
  102. static   const struct file_operations chardev_fops =
  103. {  
  104. . owner = THIS_MODULE ,
  105. . read = char_read ,
  106. . write = char_write
    ,
  107. . poll = char_poll ,
  108. . open = char_open ,
  109. . release = char_release ,
  110. } ;
  111.  
  112. void   MyTimerFunction ( unsigned long
    data )  
  113. {  
  114. driver_private_data * dpd = ( driver_private_data * ) data ;
  115. if   ( dpd )  
  116. {  

  117. sprintf ( dpd -> my_string , " string_counter %d \ n " , string_counter ) ;
  118. string_counter ++;
  119. //wake_up_interruptible(&dpd->wait);
  120. dpd -> flag = 1 ;
  121. init_timer ( & dpd -> char_timer ) ;
  122. dpd -> char_timer . function = MyTimerFunction ;
  123. dpd -> char_timer . expires = jiffies +
    STRING_CHANGE_TIME * HZ ;
  124. dpd -> char_timer . data = ( unsigned   long ) dpd ;
  125. add_timer ( & dpd -> char_timer ) ;

  126. }  
  127. }  
  128.  
  129. static   int __init charmodule_init ( void )  
  130. {  
  131.  
  132. dbg ( " char module demo \ n
    " ) ;
  133. driver_major = register_chrdev ( 0 , DEVICE_NAME , & chardev_fops ) ;
  134. if   ( driver_major < 0 )  
  135. {  

  136. dbg ( " Register character device failed \ n " ) ;
  137. return - EFAULT ;
  138. }  
  139. else   dbg ( " mknod /dev/%s c %d 0 \ n "
    , DEVICE_NAME , driver_major ) ;
  140. charmodule_class = class_create ( THIS_MODULE , DEVICE_NAME ) ;
  141. if   ( IS_ERR ( charmodule_class ))  
  142. return
    - EFAULT ;
  143. device_create ( charmodule_class , NULL , MKDEV ( driver_major , 0 ) , DEVICE_NAME ) ;
  144.  
  145. return   0 ;
  146. }
     
  147.  
  148. static   void __exit charmodule_exit ( void )  
  149. {  
  150. unregister_chrdev ( driver_major , DEVICE_NAME ) ;
  151. device_destroy ( charmodule_class
    , MKDEV ( driver_major , 0 )) ;
  152. class_destroy ( charmodule_class ) ;
  153. dbg ( " remove driver successfully \ n " ) ;
  154. }  

  155. module_init ( charmodule_init ) ;
  156. module_exit ( charmodule_exit ) ;
  157.  
  158. MODULE_DESCRIPTION ( " led module " ) ;
  159. MODULE_AUTHOR ( " Joey Cheng<jemicheng@gmail.com> "
    ) ;
  160. MODULE_LICENSE ( " GPL " ) ;
  161. MODULE_ALIAS ( " QT2410:char module " ) ;


原文出處: udev-強大的device node管理系統 - 程式設計 - 愛做夢的蘆薈
內容圖示
url email imgsrc image code quote
樣本
bold italic underline linethrough   












 [詳情...]
validation picture

注意事項:
預覽不需輸入認證碼,僅真正發送文章時才會檢查驗證碼。
認證碼有效期10分鐘,若輸入資料超過10分鐘,請您備份內容後,重新整理本頁並貼回您的內容,再輸入驗證碼送出。

選項

Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|