<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • Linux設備模型

    發布時間:2009-12-14 17:00    發布者:linux_Ultra
    關鍵詞: linux , 模型 , 設備
    Linux設備驅動程序學習(15)
    -Linux設備模型(熱插拔、mdev 與 firmware)

    熱插拔
    有 2 個不同角度來看待熱插拔:
       從內核角度看,熱插拔是在硬件、內核和內核驅動之間的交互。
       從用戶角度看,熱插拔是內核和用戶空間之間,通過調用用戶空間程序(如hotplug、udev 和 mdev)的交互。 當需要通知用戶內核發生了某種熱插拔事件時,內核才調用這個用戶空間程序。
    現在的計算機系統,要求 Linux 內核能夠在硬件從系統中增刪時,可靠穩定地運行。這就對設備驅動作者增加了壓力,因為在他們必須處理一個毫無征兆地突然出現或消失的設備。
    熱插拔工具
    當用戶向系統添加或刪除設備時,內核會產生一個熱插拔事件,并在 /proc/sys/kernel/hotplug 文件里查找處理設備連接的用戶空間程序。這個用戶空間程序主要有
    hotplug:這個程序是一個典型的 bash 腳本,只傳遞執行權給一系列位于 /etc/hot-plug.d/ 目錄樹的程序。hotplug 腳本搜索所有的有 .hotplug后綴的可能對這個事件進行處理的程序并調用它們, 并傳遞給它們許多不同的已經被內核設置的環境變量。(基本已被淘汰,具體內容請參閱《LDD3》)
    udev :用于linux2.6.13或更高版本的內核上,為用戶空間提供使用固定設備名的動態/dev目錄的解決方案。它通過在 sysfs 的 /class/ 和/block/ 目錄樹中查找一個稱為 dev的文件,以確定所創建的設備節點文件的主次設備號。所以要使用udev,驅動必須為設備在sysfs中創建類接口及其dev屬性文件,方法和sculld模塊中創建dev屬性相同。 udev的資料網上十分豐富,我就不在這廢話了,給出以下鏈接有興趣的自己研究:
    《UDEV Primer》(英文),地址:
    http://webpages.charter.net/decibelshelp/LinuxHelp_UDEVPrimer.html

    《udev規則編寫》(luofuchong翻譯),地址:
    http://www.cnitblog.com/luofuchong/archive/2007/12/18/37831.html

    《什么是udev》地址:
    http://blog.csdn.net/steganography/archive/2006/04/10/657620.aspx

    《udev-FAQ 中文翻譯》地址:
    http://gnawux.bokee.com/3225765.html

    《udev輕松上路》地址:
    http://www.blog.edu.cn/user1/3313/archives/2007/1635169.shtml

    《Udev (簡體中文)》地址:
    http://wiki.archlinux.org/index.php/Udev_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87
    )

    Udev官方主頁:
    http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
    下載地址:
    http://www.kernel.org/pub/linux/utils/kernel/hotplug/

    在《LFS》中也有介紹udev的使用,很值得參考!下載地址:
    http://lfs.osuosl.org/lfs/downloads/stable/


    mdev:一個簡化版的udev,是busybox所帶的程序,十分適合嵌入式系統。

    因為hotplug現在也在被慢慢地淘汰,udev不再依賴hotplug了,所以這里不再介紹;
    udev較mdev復雜,不太適合嵌入式使用。(本人也有做udev的實驗,交叉編譯是通過了,但是使用上有問題,沒有實現其功能。也許是我的文件系統沒做好,以后有時間再研究和寫記錄。有成功高人的通知一聲,交流一下經驗。^_^謝謝。;
    mdev簡單易用,比較適合嵌入式系統,實驗成功。以下詳細介紹mdev的使用。
    mdev

    在一開始建立根文件系統時,我根據 WeiBing 的博客上《UDEV on embeded Linux-2.6.19.2》(地址:
    http://weibing.blogbus.com/logs/4485453.html
    )這篇文章的提示,開始使用mdev,但是當時只是啟動時mdev -s一下,并沒有深究,F在在學習了Linux設備模型之后,對于Linux中/dev目錄的動態管理有了更深的認識,并認真的看了一下busybox中的mdev.txt文檔并翻譯了一下,做成了PDF(下載地址:
    http://blogimg.chinaunix.net/blog/upfile2/080111091002.pdf
    ),在看下面的內容時請先看看這篇文檔。

    先聲明一個要點:要實現設備節點文件的自動、動態的增刪,必須在你自己的驅動源碼中實現 類 接口,并在類設備的目錄中添加包含設備號的名為“dev”的屬性文件。

    mdev原理及bug

    要使用mdev,適當知道一下原理是必不可少的(能完整地研究mdev源碼是最好的)。說實話起初我并沒有想看mdev的源碼,是在使用時發現了問題后才去研究了一下mdev的源碼,F在簡單介紹一下mdev的原理:

    執行mdev -s:以‘-s’為參數調用位于/sbin目錄寫的mdev(其實是個鏈接,作用是傳遞參數給/bin目錄下的busybox程序并調用它),mdev掃描 /sys/class 和/sys/block中所有的類設備目錄,如果在目錄中含有名為“dev”的文件,且文件中包含的是設備號,則mdev就利用這些信息為這個設備在/dev下創建設備節點文件。一般只在啟動時才執行一次 “mdev -s”。

    熱插拔事件:由于啟動時運行了命令:echo /sbin/mdev > /proc/sys/kernel/hotplug,那么當有熱插拔事件產生時,內核就會調用位于 /sbin目錄的mdev。這時mdev通過環境變量中的 ACTION 和DEVPATH,來確定此次熱插拔事件的動作以及影響了/sys中的那個目錄。接著會看看這個目錄中是否有“dev”的屬性文件,如果有就利用這些信息為這個設備在/dev 下創建設備節點文件。

    源碼的bug(個人意見):由于mdev是通過判斷“dev”屬性文件的路徑字符串中的第6個字符是否為‘c’,來決定設備是字符設備還是塊設備【type = (path[5] == 'c' ? S_IFCHR : S_IFBLK);例如path = "/sys/class/ldd/sculld*/"為字符設備,而/sys/devices/ldd0/sculld*/就會被誤判為塊設備】,那么如果你在非 /sys/class 和 /sys/block目錄下建立了“dev”屬性文件且內容是設備號(像sculld中就這樣做了),那么mdev也會在/dev下創建設備節點文件。這樣可能所創建的設備節點文件是錯的。
    以我實驗為例,我以上一篇的文章中的sculld為基礎,加上了類接口(這樣在/sys/devices/ldd0/sculld*/和 /sys/class/ldd/sculld* 中都有內容為設備號的“dev”屬性文件)。在運行時發現一直會將有的sculld*創建為塊設備節點文件。郁悶死了,難道我的驅動有錯???最后研究了mdev源碼之后發現,只要在/sys中建立了“dev”屬性文件且內容是設備號,mdev就會以所在的目錄為名在/dev下創建設備節點文件。像sculld模塊,mdev會為一個設備創建兩次設備文件,由于文件名一樣,第二次的文件會覆蓋第一次的。如果第二次是因為/sys/devices/ldd0/sculld*/dev 產生的設備節點文件,那么設備節點文件就會被錯誤地創建為塊設備。
    我認為這個bug的解決辦法有如下兩種:
    (1)在你寫驅動的時候,只在/sys/class 和 /sys/block 中的類設備目錄中存在包含設備號的“dev”屬性文件。(你無法保證被人的驅動會這么做)
    (2)修正mdev源碼:
    修改/busybox-1.9.0/util-linux/mdev.c文件的第328行:
    if (!strcmp(action, "remove"))
           make_device(temp, 1);
    else if (!strcmp(action, "add")) {
             if (env_path[2]=='l') make_device(temp,0);  //tekkamanninja
                if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)
                    load_firmware(getenv("FIRMWARE"), temp);
            }
    也就是在增加設備節點文件之前檢查/sys/目錄下的路徑是否為/class和/block(通過檢查路徑字符串的第3個字符是否為‘l’)。

    本人推薦第二種做法!

    mdev使用
    mdev的使用在busybox中的mdev.txt文檔已經將得很詳細了。但作為例子,我簡單講講我的使用過程:

    (1)在編譯時加上對mdev的支持(我是使用的是busybox1.9.0):
        Linux System Utilities  --->   
                
    mdev      
                   Support /etc/mdev.conf
                     Support command execution at device addition/removal

    (2)在啟動時加上使用mdev的命令:
    我在自己創建的根文件系統(nfs)中的/linuxrc文件中添加了如下指令:
    #掛載/sys為sysfs文件系統
        echo "----------mount /sys as sysfs"
        /bin/mount -t tmpfs mdev /dev
        /bin/mount -t sysfs sysfs /sys
        echo "----------Starting mdev......"
        /bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
        mdev -s
    注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,并非/bin/echo /bin/mdev > /proc/sys/kernel/hotplug。busybox的文檔有錯!
      
    (3)在你的驅動中加上對類設備接口的支持,并在類設備目錄下添加包含設備號的名為“dev”的屬性文件。

    (4)至于/etc/mdev.conf文件,可有可無,不影響使用,只是添加了些功能。
         為了實驗我在/etc創建了mdev.conf文件并輸入了:
        sculld[0-1] 0:0 666 * echo tekkaman > /tmp/mdev
         這樣,在掛載和卸載sculld.ko時,在/tmp/下會出現mdev文件,里面字符為tekkaman
    具體的實驗源碼和現象在文章后面有。

    firmware
    硬件市場的激烈競爭, 使得制造商連一點用于設備控制固件的 EEPROM 的成本都不愿意花費。因此固件一般發布在和硬件配套的驅動包中,由操作系統(其實是驅動程序)負責傳送固件到設備。
    內核固件接口
    獲取固件的正確方法是當需要時從用戶空間獲取它。一定不要試圖從內核空間直接打開包含固件的文件,那是一個易出錯的操作, 因為它把策略(以文件名的形式)包含進了內核。正確的方法是使用固件接口:
    #include linux/firmware.h>
    int request_firmware(const struct firmware **fw,
                         const char *name, /* name 為固件文件名*/
                         struct device *device);
    /*要求用戶空間定位并提供一個固件映象給內核;若成功加載, 返回值是 0(否則返回錯誤碼)*/
    /*因為 request_firmware 需要用戶空間的操作, 所以返回前將保持休眠。若驅動必須使用固件而不能進入休眠時,可使用以下異步函數:*/
    int request_firmware_nowait(
        struct module *module, /* = THIS_MODULE*/
        int uevent,
        const char *name,
        struct device *device,
        void *context,/*不由固件子系統使用的私有數據指針*/
        void (*cont)(const struct firmware *fw, void *context));
    /*如果一切正常,request_firmware_nowait 開始固件加載過程并返回 0. 過了一段時間后(默認10秒),將用加載的結果(若加載失敗, fw 為 NULL)作為參數調用 cont。*/
    /* fw 參數指向以下結構體:*/
    struct firmware {
        size_t size;
        u8 *data;
    };
    /*那個結構包含實際的固件, 它現在可被下載到設備中.但是請注意:在發送它到硬件之前,必須檢查這個文件以確保它是正確的固件映象(設備固件常常包含標識字符串、 校驗和等等)*/
    /*當固件已經發送到設備后,應當釋放 firmware 結構體, 使用:*/
    void release_firmware(struct firmware *fw);
    注意:要使用firmware,必須要在配置內核時選上:
       Device Drivers  --->   
              Generic Driver Options  --->      
                   Userspace firmware loading support
    否則會出現: Unknown symbol release_firmware 和: Unknown symbol request_firmware 的錯誤。
                   
    固件接口工作原理
    固件子系統使用 sysfs 和熱插拔機制工作。當調用 request_firmware時, 函數將在 /sys/class/firmware 下創建一個以設備名為目錄名的新目錄,其中包含 3 個屬性:
    loading :這個屬性應當被加載固件的用戶空間進程設置為 1。當加載完畢, 它將被設為 0。被設為 -1 時,將中止固件加載。
    data :一個用來接收固件數據的二進制屬性。在設置 loading 為1后, 用戶空間進程將固件寫入這個屬性。
    device :一個鏈接到 /sys/devices 下相關入口項的符號鏈接。
    一旦創建了 sysfs 入口項, 內核將為設備產生一個熱插拔事件,并傳遞包括變量 FIRMWARE 的環境變量給處理熱插拔的用戶空間程序。FIRMWARE 被設置為提供給 request_firmware 的固件文件名。
    用戶空間程序定位固件文件, 并將其拷貝到內核提供的二進制屬性;若無法定位文件, 用戶空間程序設置 loading 屬性為 -1。
    若固件請求在 10 秒內沒有被服務, 內核就放棄并返回一個失敗狀態給驅動。超時周期可通過 sysfs 屬性 /sys/class/firmware/timeout 屬性改變。
    request_firmware 接口允許使用驅動發布設備固件。當正確地集成進熱插拔機制后, 固件加載子系統允許設備不受干擾地工作。顯然這是處理問題的最好方法,但固件受版權保護,小心違反版權法。
    ARM9開發板實驗

    實驗源碼:
    http://blogimg.chinaunix.net/blog/upfile2/080114113255.gz


    實驗現象:
    [Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*
    ls: /dev/sculld*: No such file or directory
    [Tekkaman2440@SBC2440V4]#cat /tmp/mdev
    cat: can't open '/tmp/mdev': No such file or directory

    [Tekkaman2440@SBC2440V4]#insmod /lib/modules/lddbus.ko
    Mount lddbus ok !
    Bus device is ldd0 !
    You can see me in sys/module/ , sys/devices/ , sys/class/ and sys/bus/ !
    [Tekkaman2440@SBC2440V4]#insmod /lib/modules/sculld.ko
    [Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*
    crw-rw-rw-    1 root     root     252,   0 Jan  1 00:00 /dev/sculld0
    crw-rw-rw-    1 root     root     252,   1 Jan  1 00:00 /dev/sculld1
    crw-rw----    1 root     root     252,   2 Jan  1 00:00 /dev/sculld2
    crw-rw----    1 root     root     252,   3 Jan  1 00:00 /dev/sculld3
    [Tekkaman2440@SBC2440V4]#rmmod sculld
    The LDD class
    ldd_classdev_release : sculld0 release!
    The LDD class
    ldd_classdev_release : sculld1 release!
    The LDD class
    ldd_classdev_release : sculld2 release!
    The LDD class
    ldd_classdev_release : sculld3 release!
    [Tekkaman2440@SBC2440V4]#ls -l /dev/sculld*
    ls: /dev/sculld*: No such file or directory
    [Tekkaman2440@SBC2440V4]#cat /tmp/mdev
    tekkaman



    到此 Linux設備模型 的學習暫時告一段落。
    本文地址:http://www.portaltwn.com/thread-6525-1-1.html     【打印本頁】

    本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
    linux_Ultra 發表于 2009-12-14 18:35:46
    udev實現原理

                

    轉載時請注明出處和作者聯系方式:http://blog.csdn.net/absurd

    作者聯系方式:李先靜

    更新時間:2007-4-29



    相對于linux來說,udev還是一個新事物。然而,盡管它03年才出現,盡管它很低調(J),但它無疑已經成為linux下不可或缺的組件了。udev是什么?它是如何實現的?最近研究Linux設備管理時,花了一些時間去研究udev的實現。



    udev是什么?u 是指user space,dev是指device,udev是用戶空間的設備驅動程序嗎?最初我也這樣認為,調試內核空間的程序要比調試用戶空間的程序復雜得多,內核空間的程序的BUG所引起的后果也嚴重得多,device driver是內核空間中所占比較最大的代碼,如果把這些device driver中硬件無關的代碼,從內核空間移動到用戶空間,自然是一個不錯的想法。



    但我的想法并不正確,udev的文檔是這樣說的,

    1.         dynamic replacement for /dev。作為devfs的替代者,傳統的devfs不能動態分配major和minor的值,而major和minor非常有限,很快就會用完了。udev能夠像DHCP動態分配IP地址一樣去動態分配major和minor。



    2.         device naming。提供設備命名持久化的機制。傳統設備命名方式不具直觀性,像/dev/hda1這樣的名字肯定沒有boot_disk這樣的名字直觀。udev能夠像DNS解析域名一樣去給設備指定一個有意義的名稱。



    3.         API to access info about current system devices 。提供了一組易用的API去操作sysfs,避免重復實現同樣的代碼,這沒有什么好說的。



    我們知道,用戶空間的程序與設備通信的方法,主要有以下幾種方式,

    1.         通過ioperm獲取操作IO端口的權限,然后用inb/inw/ inl/ outb/outw/outl等函數,避開設備驅動程序,直接去操作IO端口。(沒有用過)

    2.         用ioctl函數去操作/dev目錄下對應的設備,這是設備驅動程序提供的接口。像鍵盤、鼠標和觸摸屏等輸入設備一般都是這樣做的。

    3.         用write/read/mmap去操作/dev目錄下對應的設備,這也是設備驅動程序提供的接口。像framebuffer等都是這樣做的。



    上面的方法在大多數情況下,都可以正常工作,但是對于熱插撥(hotplug)的設備,比如像U盤,就有點困難了,因為你不知道:什么時候設備插上了,什么時候設備拔掉了。這就是所謂的hotplug問題了。



    處理hotplug傳統的方法是,在內核中執行一個稱為hotplug的程序,相關參數通過環境變量傳遞過來,再由hotplug通知其它關注hotplug事件的應用程序。這樣做不但效率低下,而且感覺也不那么優雅。新的方法是采用NETLINK實現的,這是一種特殊類型的socket,專門用于內核空間與用戶空間的異步通信。下面的這個簡單的例子,可以監聽來自內核hotplug的事件。

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include



    static int init_hotplug_sock(void)

    {

        struct sockaddr_nl snl;

        const int buffersize = 16 * 1024 * 1024;

        int retval;



        memset(&snl, 0x00, sizeof(struct sockaddr_nl));

        snl.nl_family = AF_NETLINK;

        snl.nl_pid = getpid();

        snl.nl_groups = 1;



        int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

        if (hotplug_sock == -1) {

            printf("error getting socket: %s", strerror(errno));

            return -1;

        }



        /* set receive buffersize */

        setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));



        retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));

        if (retval < 0) {

            printf("bind failed: %s", strerror(errno));

            close(hotplug_sock);

            hotplug_sock = -1;

            return -1;

        }



        return hotplug_sock;

    }



    #define UEVENT_BUFFER_SIZE      2048



    int main(int argc, char* argv[])

    {

             int hotplug_sock       = init_hotplug_sock();

            

             while(1)

             {

                       char buf[UEVENT_BUFFER_SIZE*2] = {0};

                       recv(hotplug_sock, &buf, sizeof(buf), 0);

                       printf("%s\n", buf);

             }



             return 0;

    }



    編譯:

    gcc -g hotplug.c -o hotplug_monitor



    運行后插/拔U盤,可以看到:

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0

    add@/class/scsi_host/host2

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83

    add@/class/usb_device/usbdev2.2

    add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0

    add@/class/scsi_disk/2:0:0:0

    add@/block/sda

    add@/block/sda/sda1

    add@/class/scsi_device/2:0:0:0

    add@/class/scsi_generic/sg0

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep81

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep02

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/usbdev2.2_ep83

    remove@/class/scsi_generic/sg0

    remove@/class/scsi_device/2:0:0:0

    remove@/class/scsi_disk/2:0:0:0

    remove@/block/sda/sda1

    remove@/block/sda

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/host2/target2:0:0/2:0:0:0

    remove@/class/scsi_host/host2

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0

    remove@/class/usb_device/usbdev2.2

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1/usbdev2.2_ep00

    remove@/devices/pci0000:00/0000:00:1d.1/usb2/2-1



    udev的主體部分在udevd.c文件中,它主要監控來自4個文件描述符的事件/消息,并做出處理:

    1.         來自客戶端的控制消息。這通常由udevcontrol命令通過地址為/org/kernel/udev/udevd的本地socket,向udevd發送的控制消息。其中消息類型有:

    l         UDEVD_CTRL_STOP_EXEC_QUEUE 停止處理消息隊列。

    l         UDEVD_CTRL_START_EXEC_QUEUE 開始處理消息隊列。

    l         UDEVD_CTRL_SET_LOG_LEVEL 設置LOG的級別。

    l         UDEVD_CTRL_SET_MAX_CHILDS 設置最大子進程數限制。好像沒有用。

    l         UDEVD_CTRL_SET_MAX_CHILDS_RUNNING 設置最大運行子進程數限制(遍歷proc目錄下所有進程,根據session的值判斷)。

    l         UDEVD_CTRL_RELOAD_RULES 重新加載配置文件。

    2.         來自內核的hotplug事件。如果有事件來源于hotplug,它讀取該事件,創建一個udevd_uevent_msg對象,記錄當前的消息序列號,設置消息的狀態為EVENT_QUEUED,然后并放入running_list和exec_list兩個隊列中,稍后再進行處理。

    3.         來自signal handler中的事件。signal handler是異步執行的,即使有signal產生,主進程的select并不會喚醒,為了喚醒主進程的select,它建立了一個管道,在signal handler中,向該管道寫入長度為1個子節的數據,這樣就可以喚醒主進程的select了。

    4.         來自配置文件變化的事件。udev通過文件系統inotify功能,監控其配置文件目錄/etc/udev/rules.d,一旦該目錄中文件有變化,它就重新加載配置文件。



    其中最主要的事件,當然是來自內核的hotplug事件,如何處理這些事件是udev的關鍵。udev本身并不知道如何處理這些事件,也沒有必要知道,因為它只實現機制,而不實現策略。事件的處理是由配置文件決定的,這些配置文件即所謂的rule。



    關于rule的編寫方法可以參考《writing_udev_rules》,udev_rules.c實現了對規則的解析。



    在規則中,可以讓外部應用程序處理某個事件,這有兩種方式,一種是直接執行命令,通常是讓modprobe去加載驅動程序,或者讓mount去加載分區。另外一種是通過本地socket發送消息給某個應用程序。



    在udevd.c:udev_event_process函數中,我們可以看到,如果RUN參數以”socket:”開頭則認為是發到socket,否則認為是執行指定的程序。



    下面的規則是執行指定程序:

    60-pcmcia.rules:                RUN+="/sbin/modprobe pcmcia"



    下面的規則是通過socket發送消息:

    90-hal.rules:RUN+="socket:/org/freedesktop/hal/udev_event"



    hal正是我們下一步要關心的,接下來我會分析HAL的實現原理。



    ~~end~~
    linux_Ultra 發表于 2009-12-14 18:37:18
    第一、什么是udev?

    這篇文章UDEV Primer給我們娓娓道來,花點時間預習一下是值得的。當然,不知道udev是什么也沒關系,
    把它當個助記符好了,有了下面的上路指南,可以節省很多時間。我們只需要樹立一個信念:udev很簡單!
    嵌入式的udev應用尤其簡單。

    第二、為什么udev要取代devfs?

    這是生產關系適應生產力的需要,udev好,devfs壞,用好的不用壞的。

    udev是硬件平臺無關的,屬于user space的進程,它脫離驅動層的關聯而建立在操作系統之上,基于這種設
    計實現,我們可以隨時修改及刪除/dev下的設備文件名稱和指向,隨心所欲地按照我們的愿望安排和管理設
    備文件系統,而完成如此靈活的功能只需要簡單地修改udev的配置文件即可,無需重新啟動操作系統。udev
    已經使得我們對設備的管理如探囊取物般輕松自如。

    第三、如何得到udev?

    udev的主頁在這里:http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
    我們按照下面的步驟來生成udev的工具程序,以arm-linux為例:
    1、wget http://www.us.kernel.org/pub/linux/utils/kernel/hotplug/udev-100.tar.bz2
    2、tar xjf udev-100.tar.bz2
    3、cd udev-100 編輯Makefile,查找CROSS_COMPILE,修改CROSS_COMPILE ?= arm-linux-
    4、make

    沒有什么意外的話當前目錄下生成udev,udevcontrol,udevd,udevinfo,udevmonitor,udevsettle,udevstart,
    udevtest,udevtrigger九個工具程序,在嵌入式系統里,我們只需要udevd和udevstart就能使udev工作得很好,
    其他工具則幫助我們完成udev的信息察看、事件捕捉或者更高級的操作。

    另外一個方法是直接使用debian提供的已編譯好的二進制包,美中不足的是版本老了一些。
    1、wget http://ftp.us.debian.org/debian/pool/main/u/udev/udev_0.056-3_arm.deb
    2、ar -xf udev_0.056-3_arm.deb
    3、tar xzf data.tar.gz

    在sbin目錄里就有我們需要的udevd和udevstart工具程序。

    建議大家采用第一種方式生成的udevd和udevstart。為什么要用最新udev呢?新的強,舊的弱,用強的不用弱的。

    第四、如何配置udev?

    首先,udev需要內核sysfs和tmpfs的支持,sysfs為udev提供設備入口和uevent通道,tmpfs為udev設備文件提
    供存放空間,也就是說,在上電之前系統上是沒有足夠的設備文件可用的,我們需要一些技巧讓kernel先引導
    起來。

    由于在kernel啟動未完成以前我們的設備文件不可用,如果使用mtd設備作為rootfs的掛載點,這個時候/dev/mtdblock
    是不存在的,我們無法讓kernel找到rootfs,kernel只好停在那里驚慌。
    這個問題我們可以通過給kernel傳遞設備號的方式來解決,在linux系統中,mtdblock的主設備號是31,part號
    從0開始,那么以前的/dev/mtdblock/3就等同于31:03,以次類推,所以我們只需要修改bootloader傳給kernel
    的cmd line參數,使root=31:03,就可以讓kernel在udevd未起來之前成功的找到rootfs。
    O.K.下一個問題。

    其次,需要做的工作就是重新生成rootfs,把udevd和udevstart復制到/sbin目錄。然后我們需要在/etc/下為udev
    建立設備規則,這可以說是udev最為復雜的一步。這篇文章提供了最完整的指導:Writing udev rules
    文中描述的復雜規則我們可以暫時不用去理會,上路指南將帶領我們輕松穿過這片迷霧。這里提供一個由簡入
    繁的方法,對于嵌入式系統,這樣做可以一勞永逸。

    1、在前面用到的udev-100目錄里,有一個etc目錄,里面放著的udev目錄包含了udev設備規則的詳細樣例文
    本。為了簡單而又簡潔,我們只需要用到etc/udev/udev.conf這個文件,在我們的rootfs/etc下建立一個udev目
    錄,把它復制過去,這個文件很簡單,除了注釋只有一行,是用來配置日志信息的,嵌入式系統也許用不上
    日志,但是udevd需要檢查這個文件。

    2、在rootfs/etc/udev下建立一個rules.d目錄,生成一個空的配置文件touch etc/udev/rules.d/udev.conf。然后
    我們來編輯這個文件并向它寫入以下配置項:

    ###############################################
    # vc devices
    KERNEL=="tty[0-9]*", NAME="vc/%n"

    # block devices
    KERNEL=="loop[0-9]*", NAME="loop/%n"

    # mtd devices
    KERNEL=="mtd[0-9]*", NAME="mtd/%n"
    KERNEL=="mtdblock*", NAME="mtdblock/%n"

    # input devices
    KERNEL=="mice" NAME="input/%k"
    KERNEL=="mouse[0-9]*", NAME="input/%k"
    KERNEL=="ts[0-9]*", NAME="input/%k"
    KERNEL=="event[0-9]*", NAME="input/%k"

    # misc devices
    KERNEL=="apm_bios", NAME="misc/%k"
    KERNEL=="rtc", NAME="misc/%k"
    ################################################

    保存它,我們的設備文件系統基本上就可以了,udevd和udevstart會自動分析這個文件。

    3、為了使udevd在kernel起來后能夠自動運行,我們在rootfs/etc/init.d/rcS中增加以下幾行:

    ##################################
    /bin/mount -t tmpfs tmpfs /dev

    echo "Starting udevd..."
    /sbin/udevd --daemon
    /sbin/udevstart
    ##################################

    4、重新生成rootfs,燒寫到flash指定的rootfs part中。

    5、如果需要動態改變設備規則,可以把etc/udev放到jffs或yaffs part,以備修改,根據需求而定,可以隨時擴
    充udev.conf中的配置項。
    linux_Ultra 發表于 2009-12-14 18:37:59
    Udev (簡體中文)
    From ArchWiki
    Jump to: navigation, search


    i18n
    English
    Русский
    繁體中文
    簡體中文

    注意: 如果您是從DevFS升級到Udev, 請查看 DevFS to Udev.

    這篇文檔將介紹udev的一些新的變化。從084版開始,udev能夠代替hotplug和coldplug的所有功能。正因為這樣,hotplug包已經從Arch倉庫中去掉了。
    Contents
    [hide]

        * 1 重要提示
        * 2 基本需求
        * 3 最近更新
        * 4 模塊禁用列表
        * 5 load_modules: 有用的啟動參數
        * 6 已知的硬件問題
        * 7 自動加載帶來的一些問題
              o 7.1 CPUFreq模塊
              o 7.2 聲音問題和一些不能自動加載的模塊
              o 7.3 多個同類型設備(網卡,聲卡)每次啟動的都不同
        * 8 自己編譯內核造成的一些已知問題
              o 8.1 Udev無法啟動
              o 8.2 CD/DVD符號和權限錯誤
        * 9 Udev小竅門
              o 9.1 自動加載usb設備

    重要提示

    ...切記,在使用udev加載任何modules(內核模塊)之前(無論是否是啟動時自動加載),您必須在/etc/rc.conf將MOD_AUTOLOAD選項設置為yes ,否則您必須手動加載這些modules。您可以修改rc.conf中的MODULES或者使用modprobe命令來手動加載您所需要的modules。另一種方法是用hwdetect --modules生成系統硬件的modules列表,然后將這個列表添加到rc.conf中讓系統啟動時自動加載這些modules。
    基本需求

        * 內核: 2.6.15或更高版本。
        * 您將無法在fstab和bootloader設置中再使用DevFS格式的設備名稱! 更多相關內容請查看DevFS to Udev。

    最近更新

        * startudev程序被取出。如果需要重新加載udev規則請使用 /etc/start_udev。
        * Udev代替了hotplug和hwdetect的功能。同時我們保存了hwdetect,并且只在 mkinitrd程序生成initrd的時候用到。
        * Udev可以同時加載多個模塊,這樣可以加快啟動速度,然而,這樣做的結果是她不能保證每次加載的順序,所以當你使用多聲卡或網卡的時候就會出現問題,這個問題下面將會再討論。

    模塊禁用列表

    udev也會犯錯或加載錯誤的模塊。為了防止錯誤的發生,你可以使用模塊禁用列表 。一旦加入該列表的模塊,無論是啟動時,或者是運行時(如usb硬盤等)udev都不會加載這些模塊。

    只需在您在 rc.conf的MODULES中對應模塊前加上感嘆號(!)就可禁用該模塊。

    例如,

    MODULES=(!moduleA !moduleB)

    load_modules: 有用的啟動參數

    如果您在內核啟動參數中加入load_modules=off,那么udev會停止任何自動加載工作. 如果系統出現問題時,這個功能會十分有用。如果udev加載了有問題的模塊導致系統掛起或者其它嚴重的問題時,你可以使用這個參數來禁用自動加載,以此來防止加載有問題的模塊。
    已知的硬件問題

    - BusLogic設備被損壞而且導致啟動時死機。

    這是一個內核的Bug目前還沒有修正。

    - PCMCIA讀卡器被認為是可移除設備.

    把它們加入到/etc/pmount.allow中,使用hal的pmount來讀取

    自動加載帶來的一些問題
    CPUFreq模塊

    我門還沒有找到一個很好的方法加載不同的CPUFreq控制器,所以我們把從自動加載進程里把它去掉了。如果您需要測量CPU頻率,你必須在rc.conf的MODULES隊列中顯式的加入合適的模塊。
    聲音問題和一些不能自動加載的模塊

    一些用戶跟蹤發現問題出在/etc/modprobe.conf中一些舊的部分,試著去掉這些舊的部分再試試看。
    多個同類型設備(網卡,聲卡)每次啟動的都不同

    因為udev同時加載所有模塊,所以一些設備可能初始化順序不同。例如同時有兩個網卡時,它們總是在eth0和eth1之間變來變去。

    常用的解決辦法是在您的rc.conf文件中通過修改MODULES隊列來指明順序。這個隊列里的模塊將在udev自動加載之前由系統加載,因此您可以控制模塊在啟動時加載順序。

    # 在e100之前加載8139too
    MODULES=(8139too e100)

    另一個解決網卡的方法是使用udev-sanctified方法為每個網卡靜態命名。創建文件/etc/udev/rules.d/10-network.rules然后將不同的網卡通過MAC地址綁定到不同的名字上:

    SUBSYSTEM=="net", SYSFS{address}=="aa:bb:cc:dd:ee:ff", NAME="lan0"
    SUBSYSTEM=="net", SYSFS{address}=="ff:ee:dd:cc:bb:aa", NAME="wlan0"

    同時,您需要注意以下內容:

        * 您可以通過下面的命令獲得網卡的MAC地址:: udevinfo -a -p /sys/class/net/<你的網卡>
        * 注意在udev規則文件中使用小寫的16進制MAC地址,因為udev無法識別大寫的MAC地址。
        * 一些用戶在使用舊的命名方式時出現問題,例如: eth0, eth1, 等等. 如果出現這個問題,試試使用 "lan"或者"wlan"之類的名字.

    注意不要忘記修改您的/dec/rc.conf和其它使用ethX命名的配置文件。
    自己編譯內核造成的一些已知問題
    Udev無法啟動

    請確定您的內核版本大于或等于2.6.15。較早的內核沒有udev自動裝載所需要的uevent功能。
    CD/DVD符號和權限錯誤

    如果您使用2.6.15的內核的話,您需要安裝ABS的uevent補。ㄋ鼜2.6.16內核中抽取了一些uevent功能)。您可以使用abs命令來同步ABS樹,然后您就可以在/var/abs/kernels/kernel26/下找到abs補丁。
    Udev小竅門
    自動加載usb設備

    KERNEL=="sd[a-z]", NAME="%k", SYMLINK+="usb%m", GROUP="users", OPTIONS="last_rule"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", SYMLINK+="usb%n", GROUP="users", NAME="%k"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mkdir -p /mnt/usb%n"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", PROGRAM=="/lib/udev/vol_id -t %N", RESULT=="vfat", RUN+="/bin/mount -t vfat -o rw,noauto,sync,dirsync,noexec,nodev,noatime,dmask=000,fmask=111 /dev/%k /mnt/usb%n", OPTIONS="last_rule"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mount -t auto -o rw,noauto,sync,dirsync,noexec,nodev,noatime /dev/%k /mnt/usb%n", OPTIONS="last_rule"
    ACTION=="remove", KERNEL=="sd[a-z][0-9]", RUN+="/bin/umount -l /mnt/usb%n"
    ACTION=="remove", KERNEL=="sd[a-z][0-9]", RUN+="/bin/rmdir /mnt/usb%n", OPTIONS="last_rule"

    把這些udev規則放到/etc/udev/rules.d/下任何一個文件名以.rules結尾的文件中,例如/etc/udev/rules.d/sda.rules。

    如果想同時建立/media到/mnt符號連接,可以使用下面的版本:

    KERNEL=="sd[a-z]", NAME="%k", SYMLINK+="usbhd-%k", GROUP="users", OPTIONS="last_rule"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", SYMLINK+="usbhd-%k", GROUP="users", NAME="%k"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mkdir -p /media/usbhd-%k"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/ln -s /media/usbhd-%k /mnt/usbhd-%k"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", PROGRAM=="/lib/udev/vol_id -t %N", RESULT=="vfat", RUN+="/bin/mount -t vfat -o rw,noauto,sync,dirsync,noexec,nodev,noatime,dmask=000,fmask=111 /dev/%k /media/usbhd-%k", OPTIONS="last_rule"
    ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mount -t auto -o rw,noauto,sync,dirsync,noexec,nodev,noatime /dev/%k /media/usbhd-%k", OPTIONS="last_rule"
    ACTION=="remove", KERNEL=="sd[a-z][0-9]", RUN+="/bin/rm -f /mnt/usbhd-%k"
    ACTION=="remove", KERNEL=="sd[a-z][0-9]", RUN+="/bin/umount -l /media/usbhd-%k"
    ACTION=="remove", KERNEL=="sd[a-z][0-9]", RUN+="/bin/rmdir /media/usbhd-%k", OPTIONS="last_rule"

    注意!如果你是用的其它的固定設備(例如SATA的硬盤,您可以從/etc/fstab中查看)被識別為/dev/sdX,您必須從sd[a-z] 中去掉你的那個sdX。例如,如果您的SATA硬盤被是識別為/dev/sda,您就需要把所有的“sd[a-z]”替換成“sd[b-z]”。在規則文件的文件名前加上數字(如:010.udev.rules)是個很好的主意,這樣udev在讀取標準規則前,將會讀取這個規則文件。這些規則設置后不需要修改/etc/fstab文件。請查看mount命令的參數來修改權限等特性(您可以從論壇搜索查看mount命令的參數,然后根據您的需要修改它們)。
    linux_Ultra 發表于 2009-12-14 18:39:20
    udev 是Linux kernel 2.6系列的設備管理器。它主要的功能是管理/dev目錄底下的設備節點。它同時也是用來接替devfs及hotplug的功能,這意味著它要在添加/刪除硬件時處理/dev目錄以及所有用戶空間的行為,包括加載firmware時。

    udev的最新版本依賴于升級后的Linux kernel 2.6.13的uevent接口的最新版本。使用新版本udev的系統不能在2.6.13以下版本啟動,除非使用noudev參數來禁用udev并使用傳統的/dev來進行設備讀取。
    目錄
    [隱藏]

        * 1 概要
        * 2 運行方式
        * 3 系統架構
        * 4 作者
        * 5 外部鏈接
        * 6 參考文獻

    [編輯] 概要

    在傳統的Linux系統中,/dev目錄下的設備節點為一系列靜態存在的文件,而udev則動態提供了在系統中實際存在的設備節點。雖然devfs提供了類似功能,udev的支持者也給出了很多udev實現比devfs好的理由[1]:

        * udev支持設備的固定命名,而并不依賴于設備插入系統的順序。默認的udev設置提供了存儲設備的固定命名。任何硬盤都根據其唯一的文件系統id、磁盤名稱及硬件連接的物理位置來進行識別。
        * udev完全在用戶空間執行,而不是像devfs在內核空間一樣執行。結果就是udev將命名策略從內核中移走,并可以在節點創建前用任意程序在設備屬性中為設備命名。

    [編輯] 運行方式

    udev是一個通用的內核設備管理器。它以守護進程的方式運行于Linux系統,并監聽在新設備初始化或設備從系統中移除時內核(通過netlink socket)發出的uevent。

    系統提供了一套規則用于匹配可發現的設備事件和屬性的導出值。匹配規則可能命名并創建設備節點,并運行配置程序來對設備進行設置。udev規則可以匹配像內核子系統、內核設備名稱、設備的物理等屬性,或設備序列號的屬性。規則也可以請求外部程序提供信息來命名設備,或指定一個永遠一樣的自定義名稱來命名設備,而不管設備什么時候被系統發現。
    [編輯] 系統架構
    Ambox outdated serious.svg
            當前條目或章節需要更新。
    請更新本文以反映近況和新增內容。完成修改時,請移除本模板。

    udev系統可以分為三個部分:

        * namedev函數庫,處理設備的命名。
        * libsysfs函數庫,進行設備信息的讀。080版本后廢棄)
        * 守護進程udevd,處于用戶空間,用于創建虛擬/dev

    系統獲取內核通過netlink socket發出的信息。早期的版本使用hotplug,并在/etc/hotplug.d/default添加一個鏈接到自身來達到目的。
    [編輯] 作者

    udev由Greg Kroah-Hartman和Kay Sievers共同開發,并得到Dan Stekloff等人的幫助。
    [編輯] 外部鏈接

        * (英文)udev在kernel.org的主頁
        * (英文)Kay Sievers寫的udev最近動態
        * (英文)如何編寫udev規則
        * (英文)udev問答集
        * (英文)Gentoo的udev指南
        * (英文)udev和devfs的對比
        * (英文)Linux1394常見問題:在不同驅動器上創建設備節點要如何設置udev規則
        * (英文)udev教程

    [編輯] 參考文獻

       1. ^ (英文)udev and devfs - The final word(2003年12月30日).於2008年1月13日查閱.
    geyingzhen 發表于 2009-12-15 15:26:24
    alpha321 發表于 2009-12-16 09:42:14
    非常感謝樓主提供這么精彩的文章!
    cybxlyh 發表于 2011-1-26 11:30:56
    樓主,我在板子上運行udevd后,插入U盤,內核有打印信息,并且在/sys/block下有sdb,sdb1以及里面的dev和uevent,但是udevd卻捕獲不到uevent事件,導致無法創建節點,規則文件無法運行,U盤也無法掛載。如果我運行udevstart,節點就可以被創建,規則文件就能被執行,實現U盤掛載,這說明dev,uevent事件是有效的,只是udevd無法自動進行捕獲處理,你知道這會是什么原因嗎?
    freeboy898 發表于 2011-11-4 14:46:15
    相當詳細的文章哦,非常感謝樓主分享!
    wk978 發表于 2016-8-14 15:02:36
    謝謝分享
    您需要登錄后才可以發表評論 登錄 | 立即注冊

    廠商推薦

    • Microchip視頻專區
    • 利用SAM E54 Xplained Pro評估工具包演示CAN轉USB橋接器以及基于CAN的主機和自舉程序應用程序
    • 使用SAM-IoT Wx v2開發板演示AWS IoT Core應用程序
    • 使用Harmony3加速TCP/IP應用的開發培訓教程
    • 集成高級模擬外設的PIC18F-Q71家族介紹培訓教程
    • 貿澤電子(Mouser)專區

    相關視頻

    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷