欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機教程網(wǎng) >> MCU設(shè)計實例 >> 瀏覽文章

設(shè)備驅(qū)動總結(jié)4 自動創(chuàng)建設(shè)備文件

作者:公平   來源:本站原創(chuàng)   點擊數(shù):  更新時間:2014年03月14日   【字體:

自動創(chuàng)建設(shè)備文件
設(shè)備文件是非常重要的文件,是應(yīng)用程序與設(shè)備驅(qū)動交換數(shù)據(jù),控制硬件的橋梁。在驅(qū)動程序中open、release的實現(xiàn)過程中其中的一個參數(shù)struct inode實質(zhì)就是設(shè)備文件的索引,沒有這個索引也就沒有后期的各種操作,通常設(shè)備文件也被稱為設(shè)備文件節(jié)點。因此沒有設(shè)備文件后期的各種實現(xiàn)都是多余的。設(shè)備文件的創(chuàng)建有兩種方法,其中就是在創(chuàng)建文件系統(tǒng)過程中用到的mknod命令。
該命令的形式如下:
mknod filename (type,c,b,l) 主設(shè)備號 次設(shè)備號
其中type說明是那一類設(shè)備(字符設(shè)備c,塊設(shè)備b,套接字l),主設(shè)備號用來確定那一類設(shè)備,而次設(shè)備號主要用來確定這一類設(shè)備中的某一個設(shè)備。
例如:mknod memdev0  c 555 0 就是創(chuàng)建了一個主設(shè)備號為555,次設(shè)備號為0的字符設(shè)備。

這種方法比較快速,但是在編寫設(shè)備驅(qū)動的時候很難確定那個設(shè)備號是可以使用的,因此很不方便開發(fā)。在2.4內(nèi)核中引入了devfs,但是因為性能等方面的原因,在2.6內(nèi)核中被udev逐漸取代。udev的設(shè)備命名策略、權(quán)限控制和事件處理都是在用戶態(tài)下完成的,它利用sysfs中的信息來進行創(chuàng)建設(shè)備文件節(jié)點等工作。其實對于我們寫程序而言并沒有多大的區(qū)別,這是內(nèi)核的設(shè)計者考慮的問題。兩個都能夠?qū)崿F(xiàn)設(shè)備文件的動態(tài)創(chuàng)建,具體的實現(xiàn)方法也很類似。在嵌入式中是采用mdev實現(xiàn)類似udev的動態(tài)創(chuàng)建設(shè)備文件,在制作文件系統(tǒng)的過程中應(yīng)該注意在linux system項選上mdev,不過一般默認情況下都選擇上。

在驅(qū)動中動態(tài)添加設(shè)備文件節(jié)點會減少麻煩。
具體的實現(xiàn)主要包括兩個過程。
1、創(chuàng)建一個設(shè)備類,主要依據(jù)函數(shù)class_create()實現(xiàn)。
2、依據(jù)設(shè)備類創(chuàng)建一個設(shè)備文件,主要依據(jù)device_create()或者有些較低版本中的class_device_create()實現(xiàn)。

基本的實現(xiàn)過程應(yīng)該是在設(shè)備驅(qū)動初始化過程中首先得到申請到設(shè)備號之后創(chuàng)建一個設(shè)備類,采用class_create()實現(xiàn)。
函數(shù)class_create()的形式如下:

    #define class_create(owner, name)        \
    ({                        \
        static struct lock_class_key __key;    \
        __class_create(owner, name, &__key);    \
    })

參數(shù)的意義:owner是指設(shè)備的擁有者,因此可以直接THIS_MODULE復(fù)制給owner,而name是設(shè)備類的名字。返回值是一個設(shè)備類的指針。這樣就創(chuàng)建了一個設(shè)備類。

    static struct class *myclass;
    ...
    static int memdev_init(void)
    {
      ...
     /*如果定義了主設(shè)備號采用靜態(tài)申請的方式*/
            if(mem_major)
                    result = register_chrdev_region(devno,2,"mem_dev");
            else/*動態(tài)申請設(shè)備號*/
            {
                    result = alloc_chrdev_region(&devno,0,2,"mem_dev");
                    mem_major = MAJOR(result);
            }
            /*錯誤處理*/
            if(result < 0)
                    return result;

            /*在設(shè)備號申請完成以后可以為設(shè)備創(chuàng)建一個設(shè)備類,用于設(shè)備文件的創(chuàng)建*/
            myclass = class_create(THIS_MODULE,"memdev_class");
            /*創(chuàng)建一個設(shè)備*/

            /*初始化cdev,并將相關(guān)的文件操作添加進來*/
            cdev_init(&cdev,&mem_fops);
       ...
    }

在設(shè)備初始化完成、綁定好文件操作、設(shè)備添加到內(nèi)核中以后然后根據(jù)設(shè)備類要創(chuàng)建設(shè)備文件,依據(jù)device_create實現(xiàn)函數(shù),其中的函數(shù)形式如下實現(xiàn)。

    struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
    {
        va_list vargs;
        struct device *dev;

        va_start(vargs, fmt);
        dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
        va_end(vargs);
        return dev;
    }

參數(shù)的意義分別是設(shè)備類指針、設(shè)備的父設(shè)備,設(shè)備號、以及設(shè)備的數(shù)據(jù)、然后是設(shè)備文件的名字,參數(shù)具有不定性。具體的實現(xiàn)如下:

    ...

           /*初始化cdev,并將相關(guān)的文件操作添加進來*/
            cdev_init(&cdev,&mem_fops);
            /*設(shè)備引用*/
            cdev.owner = THIS_MODULE;
            cdev.ops = &mem_fops;
            /*注冊字符設(shè)備*/
            cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
            /*以上設(shè)備添加完成*/

            /*分配兩個內(nèi)存空間,此處是在物理內(nèi)存上實現(xiàn)分配,實質(zhì)是創(chuàng)建兩個設(shè)備的描述*/
            mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev),GFP_KERNEL);
            if(!mem_devp)/*出錯的相應(yīng)操作*/
            {
                    result = -ENOMEM;
                    /*錯誤處理,采用典型的goto語句*/
                    goto fail_malloc;
            }

            /*清除空間*/
            memset(mem_devp,0,sizeof(struct mem_dev));

            for(i = 0; i < MEMDEV_NR_DEVS; ++i)
            {
                    device_create(myclass,NULL,MKDEV(mem_major,i),NULL,"memdev%d",i);
                    /*
                    myclass為設(shè)備類
                    NULL 表示父設(shè)備為空
                    MKDEV(mem_major,i) 表示設(shè)備號
                    NULL 表示設(shè)備數(shù)據(jù)為空
                    后面的參數(shù)是用來設(shè)置 設(shè)備文件的名字
                    */
                    mem_devp[i].size = MEMDEV_SIZE;
                    /*對設(shè)備的數(shù)據(jù)空間分配空間*/
                    mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
                    /*問題,沒有進行錯誤的控制*/
                    memset(mem_devp[i].data,0,MEMDEV_SIZE);

                    /*初始化定義的互信息量*/
                    //mutex_init(&mem_devp[i].sem);
                    //初始化定義的自旋鎖ua
                    spin_lock_init(&mem_devp[i].lock);
            }
    ...

以上的操作都是在模塊初始化過程中完成的。這樣在加載過程中就會在/dev目錄下添加好設(shè)備文件。在設(shè)備退出過程中我們當(dāng)然也要釋放分配好的這些資源。具體的采用device_destroy釋放分配好的設(shè)備文件,

    void device_destroy(struct class *class, dev_t devt)
    {
        struct device *dev;

        dev = class_find_device(class, NULL, &devt, __match_devt);
        if (dev) {
            put_device(dev);
            device_unregister(dev);
        }
    }

參數(shù)主要是設(shè)備類和設(shè)備號。
同時也要釋放設(shè)備類。主要采用函數(shù)class_destroy()

    void class_destroy(struct class *cls)
    {
        if ((cls == NULL) || (IS_ERR(cls)))
            return;

        class_unregister(cls);
    }

參數(shù)是設(shè)備類。
設(shè)備的退出過程如下:

    /*模塊清除函數(shù)*/
    static void memdev_exit(void)
    {
            cdev_del(&cdev);/*注銷字符設(shè)備*/
            /*釋放兩個物理內(nèi)存*/

            kfree(mem_devp[0].data);
            kfree(mem_devp[1].data);
            device_destroy(myclass,MKDEV(mem_major,0));
            device_destroy(myclass,MKDEV(mem_major,1));

            kfree(mem_devp);/*釋放設(shè)備結(jié)構(gòu)體內(nèi)存*/

            class_destroy(myclass);
            unregister_chrdev_region(MKDEV(mem_major,0),2);
    }

基本的形式如上所示。
驅(qū)動的出錯順序與錯誤處理順序應(yīng)該是一個相反的過程,這樣才能保證區(qū)域的包含關(guān)系。由于設(shè)備類的創(chuàng)建過程是在設(shè)備號申請的后面完成,因此釋放應(yīng)該在設(shè)備號釋放之前注銷掉。因此形成一個先進后處理的關(guān)系,類似于一個堆棧的形式。
測試過程:
[gong@Gong-Computer mem_waitqueue]$ ls -al /dev/mem*
crw-r----- 1 root kmem 1, 1 Dec  5 12:55 /dev/mem
[gong@Gong-Computer mem_waitqueue]$ sudo insmod memwait_queue.ko
[sudo] password for gong:
[gong@Gong-Computer mem_waitqueue]$ ls -al /dev/mem*
crw-r----- 1 root kmem   1, 1 Dec  5 12:55 /dev/mem
crw------- 1 root root 555, 0 Dec  5 16:50 /dev/memdev0
crw------- 1 root root 555, 1 Dec  5 16:50 /dev/memdev1
[gong@Gong-Computer mem_waitqueue]$ sudo rmmod memwait_queue
[gong@Gong-Computer mem_waitqueue]$ ls -al /dev/mem*
crw-r----- 1 root kmem 1, 1 Dec  5 12:55 /dev/mem

以上的結(jié)果表明,采用上面的方式能夠自動的創(chuàng)建設(shè)備文件,相比手動創(chuàng)建更加的方便自如。

關(guān)閉窗口

相關(guān)文章