久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

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

驅(qū)動(dòng)學(xué)習(xí)1

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

看了好長(zhǎng)一段時(shí)間的書(shū),開(kāi)始做驅(qū)動(dòng),從簡(jiǎn)單的開(kāi)始學(xué)習(xí),實(shí)現(xiàn)最簡(jiǎn)單的字符設(shè)備驅(qū)動(dòng),實(shí)現(xiàn)的功能是對(duì)兩塊內(nèi)存空間(物理內(nèi)存)進(jìn)行控制,實(shí)現(xiàn)讀寫(xiě)操作。
基本的實(shí)現(xiàn)與很多學(xué)習(xí)驅(qū)動(dòng)程序設(shè)計(jì)的方式一樣,跟著別人的程序跑,自己弄明白,搞清楚其中的道理。具體的實(shí)現(xiàn)過(guò)程,結(jié)合注釋可以看清楚。主要總結(jié)第一次寫(xiě)驅(qū)動(dòng)過(guò)程中存在的問(wèn)題,以及相應(yīng)的解決方法。
字符設(shè)備驅(qū)動(dòng)的基本流程:
首先,驅(qū)動(dòng)函數(shù)的初始化,以及清除函數(shù)(這部分主要是按著一定的模式編程)
    1、 申請(qǐng)主設(shè)備號(hào),其中可以采用靜態(tài)或者動(dòng)態(tài)的方式申請(qǐng)。
    2、 創(chuàng)建字符設(shè)備,其中包括初始化字符設(shè)備(分配設(shè)備空間),綁定相關(guān)的操作(相應(yīng)的操作),最后是添加字符設(shè)備(實(shí)現(xiàn)所申請(qǐng)的設(shè)備號(hào)與設(shè)備的綁定)。
    3、 設(shè)備的具體實(shí)現(xiàn)以及錯(cuò)誤的處理問(wèn)題。
    4、 清除函數(shù)主要包含分配物理空間的釋放以及設(shè)備號(hào)的釋放,字符設(shè)備的注銷(xiāo)等。
第二,主要是設(shè)備相關(guān)操作的具體實(shí)現(xiàn)過(guò)程。(這部分主要是涉及內(nèi)核的一些知識(shí))包含具體的文件打開(kāi),關(guān)閉,以及讀寫(xiě),定位操作。具體的參看源碼。
第三,Makefile的基本實(shí)現(xiàn)(也是一定的模塊,但是能夠了解其中的道理)或者直接編譯到內(nèi)核中。
 
出現(xiàn)的問(wèn)題主要是Makefile文檔的設(shè)計(jì)以及加載問(wèn)題。
問(wèn)題一,是kmalloc函數(shù)等的運(yùn)用需要相應(yīng)的頭文件,kmalloc的頭文件是linux/slab.h,關(guān)于錯(cuò)誤(errno.h)是與CPU體系密切相關(guān)的,因此通常是asm/errno.h,這個(gè)也是常見(jiàn)的問(wèn)題。
問(wèn)題二,是加載出錯(cuò)的問(wèn)題。出現(xiàn)下面的錯(cuò)誤,

insmod:error inserting '/home/gong/program/cprogram/module/memdev/memdev.ko': -1 Device or resource busy

這個(gè)錯(cuò)誤產(chǎn)生的原因主要是因?yàn)橹髟O(shè)備號(hào)真正被別的驅(qū)動(dòng)程序使用導(dǎo)致的。可以通過(guò)cat /proc/devices查看具體的情況

...

251 hidraw

252 usbmon

253 bsg

254 rtc

...

需要重新定義主設(shè)備號(hào)。然后重新編譯,即可加載成功。

 

問(wèn)題三,Makefile文件的設(shè)計(jì)

編譯驅(qū)動(dòng)有兩種方法,可以采用直接內(nèi)核編譯的方式,這種方式主要通過(guò)修改源碼中的Makefile和Kconfig實(shí)現(xiàn)。這種方法比較直觀,但是會(huì)破壞源碼的完整性。

通常采用自己編寫(xiě)Makefile的方式實(shí)現(xiàn)驅(qū)動(dòng)的編譯。這種方式需要了解Makefile的一些語(yǔ)法,同時(shí)需要了解自己的源碼結(jié)構(gòu),但是這種模式具有很大的相似性,都是基于模塊的設(shè)計(jì)方式。

常用的Makefile模塊如下所示:

 

ifneq ($(KERNELRELEASE),)

obj-m   := memdev.o

else

KDIR    :=/opt/LinuxKernel/linux-2.6.38.1

PWD      :=$(shell pwd)

default:

        make -C $(KDIR) M=$(PWD) modules

clean:

        rm -f *.ko *.o *.mod.o *.mod.c *.symvers

endif

 

具體的分析我說(shuō)說(shuō)自己的理解吧。首先第一句ifneq ($(KERNELRELEASE),)是實(shí)現(xiàn)兩個(gè)變量的比較。比較兩個(gè)參量是否不相等。如果不相等則執(zhí)行下面的語(yǔ)句:obj-m   := memdev.o,如果相等就執(zhí)行else后面的語(yǔ)句。

 

具體的過(guò)程如下:

如果驅(qū)動(dòng)代碼是在內(nèi)核源碼中實(shí)現(xiàn),那么KERNELRELEASE就是一個(gè)已知的值,具體的值是:

# Read KERNELRELEASE from include/config/kernel.release (if it exists)

KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)

KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)

但是另一個(gè)值為空,這樣兩個(gè)值就是不相等的,這樣就執(zhí)行obj-m   := memdev.o。

但是如果不是在內(nèi)核源碼中實(shí)現(xiàn),那么KERNELRELEASE就是一個(gè)空值,這樣兩個(gè)參數(shù)就是相等的。執(zhí)行else以后的語(yǔ)句。

KDIR    :=/opt/LinuxKernel/linux-2.6.38.1

PWD      :=$(shell pwd)

上面的兩句是定義兩個(gè)變量,其中的KDIR是內(nèi)核源碼的根目錄,PWD則是當(dāng)前驅(qū)動(dòng)代碼所在的目錄。

然后執(zhí)行

default:

        make -C $(KDIR) M=$(PWD) modules

default是一個(gè)默認(rèn)的目標(biāo),沒(méi)有相關(guān)的依賴(lài),規(guī)則是make -C $(KDIR) M=$(PWD) modules

其中參數(shù)-C和M=都有各自的意義,具體的可以參看Makefile的相關(guān)資料。

我的理解就是:

-C 選項(xiàng)的作用是指將當(dāng)前工作目錄轉(zhuǎn)移到你所指定的位置(頁(yè)就是內(nèi)核源碼的根目錄)

“M=dir”,內(nèi)核程序會(huì)自動(dòng)到你所指定的dir目錄中查找模塊源碼,將其編譯,生成.KO文件。實(shí)現(xiàn)驅(qū)動(dòng)程序的編譯。

具體的注意事項(xiàng):KERNELRELEASE這個(gè)變量不要寫(xiě)錯(cuò),這個(gè)比較容易出錯(cuò),還容易檢查出來(lái)。我第一次寫(xiě)代碼就出現(xiàn)了相應(yīng)的錯(cuò)誤。


需要注意的是該makefile被執(zhí)行了兩次,其中第一次是由于沒(méi)有定義KERNELRELEASE對(duì)象,當(dāng)進(jìn)入到內(nèi)核源碼以后,這時(shí)KERNELRELEASE對(duì)象已經(jīng)被定義好了,然后返回到當(dāng)前的文件夾下,這時(shí)候直接執(zhí)行第一句obj-m   := memdev.o。這樣就實(shí)現(xiàn)了內(nèi)核的編譯。

 

具體的應(yīng)用程序代碼我都是按著別人的代碼修改調(diào)試的。

下面是我的源碼:

 

    第一個(gè)代碼是頭文件:
    #ifndef _MEMDEV_H_H_
    #define _MEMDEV_H_H_

    #ifndef MEMDEV_MAJOR
    #define MEMDEV_MAJOR 555
    #endif

    #ifndef MEMDEV_NR_DEVS
    #define MEMDEV_NR_DEVS 2
    #endif

    #ifndef MEMDEV_SIZE
    #define MEMDEV_SIZE 2048
    #endif


    struct mem_dev
    {
            char *data;
            unsigned long size;
    };

    #endif
    第二個(gè)是C文件:
    #include<linux/module.h>
    #include<linux/types.h>
    #include<linux/fs.h>
    //#include<linux/errno.h>
    #include<linux/sched.h>
    #include<linux/init.h>
    #include<linux/cdev.h>

    /*該頭文件主要實(shí)現(xiàn)內(nèi)存的控制,包括kmalloc等函數(shù)*/
    #include<linux/slab.h>

    #include<asm/system.h>
    #include<asm/io.h>
    #include<asm/uaccess.h>
    /*錯(cuò)誤的不同,需要具體的類(lèi)型*/
    #include<asm/errno.h>

    /*自己定義的頭文件*/
    #include"memdev.h"

    static mem_major = MEMDEV_MAJOR;

    module_param(mem_major,int,S_IRUGO);
    module_param(mem_major,int,S_IRUGO);

    struct mem_dev *mem_devp;

    struct cdev cdev;

    /*函數(shù)的聲明*/
    static int memdev_init(void);
    static void memdev_exit(void);
    int mem_open(struct inode *inode,struct file *filp);
    int mem_release(struct inode *inode, struct file *flip);
    static ssize_t mem_read(struct file *flip,char __user *buf, size_t size,loff_t *ppos);
    static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos);
    static loff_t mem_llseek(struct file *filp,loff_t offset, int whence);

    /*添加該模塊的基本文件操作支持*/
    static const struct file_operations mem_fops =
    {
            .owner = THIS_MODULE,
            .llseek = mem_llseek,
            .read = mem_read,
           .write = mem_write,
            .open = mem_open,
            .release = mem_release,
    };

    /*初始化函數(shù)*/
    static int memdev_init(void)
    {
            int result;
            int i;

            /*創(chuàng)建一個(gè)設(shè)備號(hào)*/
            dev_t devno = MKDEV(mem_major,0);

            /*注冊(cè)一個(gè)設(shè)備號(hào)*/
            /*如果定義了主設(shè)備號(hào)采用靜態(tài)申請(qǐng)的方式*/
            if(mem_major)
                    result = register_chrdev_region(devno,2,"mem_dev");
            else/*動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)*/
            {
                    result = alloc_chrdev_region(&devno,0,2,"mem_dev");
                    mem_major = MAJOR(result);
            }
            /*錯(cuò)誤處理*/
            if(result < 0)
                    return result;

            /*創(chuàng)建一個(gè)設(shè)備*/

            /*初始化cdev,并將相關(guān)的文件操作添加進(jìn)來(lái)*/
            cdev_init(&cdev,&mem_fops);
            cdev.owner = THIS_MODULE;
            cdev.ops = &mem_fops;
            /*注冊(cè)字符設(shè)備*/
            cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);

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

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

            for(i = 0; i < MEMDEV_NR_DEVS; ++i)
            {
                    mem_devp[i].size = MEMDEV_SIZE;
                    mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
                    /*問(wèn)題,沒(méi)有進(jìn)行錯(cuò)誤的控制*/
                    memset(mem_devp[i].data,0,MEMDEV_SIZE);
            }
            return 0;
    fail_malloc:
            unregister_chrdev_region(devno,1);
            return result;
    }

    /*模塊清除函數(shù)*/
    static void memdev_exit(void)
    {
            cdev_del(&cdev);/*注銷(xiāo)字符設(shè)備*/
            /*釋放兩個(gè)物理內(nèi)存*/
            kfree(mem_devp[0].data);
            kfree(mem_devp[1].data);

            kfree(mem_devp);/*釋放設(shè)備結(jié)構(gòu)體內(nèi)存*/
            unregister_chrdev_region(MKDEV(mem_major,0),2);
    }

    /*定義相關(guān)的操作函數(shù)*/

    /*mem_open*/
    int mem_open(struct inode *inode,struct file *filp)
    {
            struct mem_dev *dev;

            /*判斷設(shè)備文件的次設(shè)備號(hào)*/
            int num = MINOR(inode->i_rdev);

            if(num >= MEMDEV_NR_DEVS)
                    return -ENODEV;
            dev = &mem_devp[num];

            /*將數(shù)據(jù)指向兩個(gè)內(nèi)存空間*/
            filp->private_data = dev;

            return 0;
    }

    /*release函數(shù)的實(shí)現(xiàn)*/
    int mem_release(struct inode *inode, struct file *flip)
    {
            return 0;
    }

    /*read函數(shù)的實(shí)現(xiàn)*/
    static ssize_t mem_read(struct file *filp,char __user *buf, size_t size,loff_t *ppos)
    {
            unsigned long p = *ppos;
            unsigned int count = size;
            int ret = 0;

            /*獲得file結(jié)構(gòu)體上的指針*/
            struct mem_dev *dev = filp->private_data;

            /*參數(shù)的檢查*/
            if(p >= MEMDEV_SIZE)
                    return 0;
            if(count > MEMDEV_SIZE - p)
                    count = MEMDEV_SIZE - p;

            /*從內(nèi)核讀數(shù)據(jù)到用戶(hù)空間*/
            if(copy_to_user(buf,(void *)(dev->data + p),count))
            {
                    /*出錯(cuò)誤*/
                    ret = -EFAULT;
            }
            else
            {
                    /*移動(dòng)當(dāng)前文件光標(biāo)的位置*/
                    *ppos += count;
                    ret = count;

                    printk(KERN_INFO "read %d bytes(s) from %d\n",count,p);
        }
            return ret;
    }

    /*write函數(shù)的實(shí)現(xiàn)*/
    static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
    {
            unsigned long p = *ppos;
            unsigned int count = size;
            int ret = 0;

            /*獲得設(shè)備結(jié)構(gòu)體的指針*/
            struct mem_dev *dev = filp->private_data;

            /*檢查參數(shù)的長(zhǎng)度*/
            if(p >= MEMDEV_SIZE)
                    return 0;
            if(count > MEMDEV_SIZE - p)
                    count = MEMDEV_SIZE - p;

            if(copy_from_user(dev->data + p,buf,count))
                    ret = -EFAULT;
            else
            {
                    /*改變文件位置*/
                    *ppos += count;
                    ret = count;
                    printk(KERN_INFO "writted %d bytes(s) from %d\n",count,p);
            }
            return ret;
    }

    /*lseek的實(shí)現(xiàn)*/
    static loff_t mem_llseek(struct file *filp,loff_t offset, int whence)
    {
            loff_t newpos;
            switch(whence)
            {
                    case 0:/*SEEK_SET*/
                            newpos = offset;
                            break;
                    case 1:/*SEEK_CUR*/
                            newpos = filp->f_pos + offset;
                            break;
                    case 2:/*SEEK_END*/
                            newpos = MEMDEV_SIZE - 1 + offset;
                            break;
                    default:
                            return -EINVAL;
            }
            filp->f_pos = newpos;

            return newpos;
    }

    /*作者以及權(quán)限的聲明*/
    MODULE_AUTHOR("GongPing");
    MODULE_LICENSE("GPL");

    /*通過(guò)宏module_init和module_exit實(shí)現(xiàn)模塊添加*/
    module_init(memdev_init);
    module_exit(memdev_exit);


    第三個(gè)是Makefile:
    ifneq ($(KERNELRELEASE),)

    obj-m := memdev.o

    else

    #KDIR :=/usr/src/kernels/2.6.35.14-96.fc14.i686
    #KDIR :=/lib/modules/2.6.35.14-96.fc14.i686/build
    #KDIR ?=/opt/LinuxKernel/linux-2.6.38.1
    KDIR :=/opt/LinuxKernel/linux-2.6.38.1

    PWD :=$(shell pwd)

    default:
            make -C $(KDIR) M=$(PWD) modules

    clean:
            rm -f *.ko *.o *.mod.o *.mod.c *.symvers

    endif

    第4個(gè)是應(yīng)用程序:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>

    int main()
    {
            FILE *fp0 = NULL;

            char Buf[4096];
            /*復(fù)制數(shù)據(jù)到buf中*/
            strcpy(Buf,"Mem is char devices!");

            printf("Buf: %s\n",Buf);

            /*打開(kāi)設(shè)備文件*/
            fp0 = fopen("/dev/memdev0","rw");
            /*錯(cuò)誤處理*/
            if(fp0 == NULL)
            {
                    printf("Open Memdev0 Error!\n");
                    return -1;
            }
            /*寫(xiě)數(shù)據(jù)到設(shè)備中*/
            //fread(Buf,sizeof(Buf),1,fp0);
            fwrite(Buf,sizeof(Buf),1,fp0);
            /*定位*/
            fseek(fp0,0,SEEK_SET);
            /*復(fù)制數(shù)據(jù)到Buf*/
            strcpy(Buf,"Buf is NULL!");
            /*打印*/
            printf("Buf: %s\n",Buf);
            /*讀數(shù)據(jù)*/
            fread(Buf,sizeof(Buf),1,fp0);

            printf("BUF: %s\n",Buf);

            fclose(fp0);

            return 0;
    }

 

源碼是別人的,我只是做了一下注釋?zhuān)缓笞隽诉m當(dāng)?shù)男薷模?qū)動(dòng)程序與應(yīng)用程序以及硬件代碼存在較大的差別,以后要多寫(xiě),多理解,多總結(jié)。

關(guān)閉窗口

相關(guān)文章

主站蜘蛛池模板: 免费爱爱视频 | 国产精品毛片久久久久久久 | 国产精品毛片一区二区在线看 | 91大神在线资源观看无广告 | 久久久久久精 | 天堂av免费观看 | 欧美日韩黄色一级片 | 美女福利视频一区 | 亚洲欧美一区二区三区1000 | 亚洲欧美国产毛片在线 | 毛片链接| 91精品国模一区二区三区 | 国产二区精品视频 | 日本视频一区二区 | 亚洲手机视频在线 | 欧美日本在线观看 | 久久综合狠狠综合久久综合88 | 国内精品一区二区三区 | 国产日本精品视频 | 中文字幕第一页在线 | 国产农村一级片 | av三级在线观看 | 98久久| 狠狠色狠狠色综合日日92 | 国产成人精品区一区二区不卡 | 日日爽 | 91.色 | 亚洲视频免费在线观看 | 久久久久国产一区二区三区 | 亚洲精品在线视频 | 国产精品国产精品国产专区不卡 | 91天堂网| 黄色片免费 | 国产日韩欧美一区二区 | 久久久久久久亚洲精品 | 国产精品国产馆在线真实露脸 | 99免费视频 | 国产一区免费 | 一区二区不卡视频 | 欧洲成人免费视频 | 国产精品视频999 |