<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 驅(qū)動學(xué)習(xí)1

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

          作者: 時間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
          看了好長一段時間的書,開始做驅(qū)動,從簡單的開始學(xué)習(xí),實現(xiàn)最簡單的字符設(shè)備驅(qū)動,實現(xiàn)的功能是對兩塊內(nèi)存空間(物理內(nèi)存)進行控制,實現(xiàn)讀寫操作。
          基本的實現(xiàn)與很多學(xué)習(xí)驅(qū)動程序設(shè)計的方式一樣,跟著別人的程序跑,自己弄明白,搞清楚其中的道理。具體的實現(xiàn)過程,結(jié)合注釋可以看清楚。主要總結(jié)第一次寫驅(qū)動過程中存在的問題,以及相應(yīng)的解決方法。
          字符設(shè)備驅(qū)動的基本流程:
          首先,驅(qū)動函數(shù)的初始化,以及清除函數(shù)(這部分主要是按著一定的模式編程)
          1、 申請主設(shè)備號,其中可以采用靜態(tài)或者動態(tài)的方式申請。
          2、 創(chuàng)建字符設(shè)備,其中包括初始化字符設(shè)備(分配設(shè)備空間),綁定相關(guān)的操作(相應(yīng)的操作),最后是添加字符設(shè)備(實現(xiàn)所申請的設(shè)備號與設(shè)備的綁定)。
          3、 設(shè)備的具體實現(xiàn)以及錯誤的處理問題。
          4、 清除函數(shù)主要包含分配物理空間的釋放以及設(shè)備號的釋放,字符設(shè)備的注銷等。
          第二,主要是設(shè)備相關(guān)操作的具體實現(xiàn)過程。(這部分主要是涉及內(nèi)核的一些知識)包含具體的文件打開,關(guān)閉,以及讀寫,定位操作。具體的參看源碼。
          第三,Makefile的基本實現(xiàn)(也是一定的模塊,但是能夠了解其中的道理)或者直接編譯到內(nèi)核中。
          出現(xiàn)的問題主要是Makefile文檔的設(shè)計以及加載問題。
          問題一,是kmalloc函數(shù)等的運用需要相應(yīng)的頭文件,kmalloc的頭文件是linux/slab.h,關(guān)于錯誤(errno.h)是與CPU體系密切相關(guān)的,因此通常是asm/errno.h,這個也是常見的問題。
          問題二,是加載出錯的問題。出現(xiàn)下面的錯誤,
          insmod:error inserting /home/gong/program/cprogram/module/memdev/memdev.ko: -1 Device or resource busy
          這個錯誤產(chǎn)生的原因主要是因為主設(shè)備號真正被別的驅(qū)動程序使用導(dǎo)致的。可以通過cat /proc/devices查看具體的情況
          ...
          251 hidraw
          252 usbmon
          253 bsg
          254 rtc
          ...
          需要重新定義主設(shè)備號。然后重新編譯,即可加載成功。
          問題三,Makefile文件的設(shè)計
          編譯驅(qū)動有兩種方法,可以采用直接內(nèi)核編譯的方式,這種方式主要通過修改源碼中的Makefile和Kconfig實現(xiàn)。這種方法比較直觀,但是會破壞源碼的完整性。
          通常采用自己編寫Makefile的方式實現(xiàn)驅(qū)動的編譯。這種方式需要了解Makefile的一些語法,同時需要了解自己的源碼結(jié)構(gòu),但是這種模式具有很大的相似性,都是基于模塊的設(shè)計方式。
          常用的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
          具體的分析我說說自己的理解吧。首先第一句ifneq ($(KERNELRELEASE),)是實現(xiàn)兩個變量的比較。比較兩個參量是否不相等。如果不相等則執(zhí)行下面的語句:obj-m := memdev.o,如果相等就執(zhí)行else后面的語句。
          具體的過程如下:
          如果驅(qū)動代碼是在內(nèi)核源碼中實現(xiàn),那么KERNELRELEASE就是一個已知的值,具體的值是:
          # 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)
          但是另一個值為空,這樣兩個值就是不相等的,這樣就執(zhí)行obj-m := memdev.o。
          但是如果不是在內(nèi)核源碼中實現(xiàn),那么KERNELRELEASE就是一個空值,這樣兩個參數(shù)就是相等的。執(zhí)行else以后的語句。
          KDIR :=/opt/LinuxKernel/linux-2.6.38.1
          PWD :=$(shell pwd)
          上面的兩句是定義兩個變量,其中的KDIR是內(nèi)核源碼的根目錄,PWD則是當前驅(qū)動代碼所在的目錄。
          然后執(zhí)行
          default:
          make -C $(KDIR) M=$(PWD) modules
          default是一個默認的目標,沒有相關(guān)的依賴,規(guī)則是make -C $(KDIR) M=$(PWD) modules
          其中參數(shù)-C和M=都有各自的意義,具體的可以參看Makefile的相關(guān)資料。
          我的理解就是:
          -C 選項的作用是指將當前工作目錄轉(zhuǎn)移到你所指定的位置(頁就是內(nèi)核源碼的根目錄)
          “M=dir”,內(nèi)核程序會自動到你所指定的dir目錄中查找模塊源碼,將其編譯,生成.KO文件。實現(xiàn)驅(qū)動程序的編譯。
          具體的注意事項:KERNELRELEASE這個變量不要寫錯,這個比較容易出錯,還容易檢查出來。我第一次寫代碼就出現(xiàn)了相應(yīng)的錯誤。
          需要注意的是該makefile被執(zhí)行了兩次,其中第一次是由于沒有定義KERNELRELEASE對象,當進入到內(nèi)核源碼以后,這時KERNELRELEASE對象已經(jīng)被定義好了,然后返回到當前的文件夾下,這時候直接執(zhí)行第一句obj-m := memdev.o。這樣就實現(xiàn)了內(nèi)核的編譯。
          具體的應(yīng)用程序代碼我都是按著別人的代碼修改調(diào)試的。
          下面是我的源碼:
          第一個代碼是頭文件:
          #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
          第二個是C文件:
          #include
          #include
          #include
          //#include
          #include
          #include
          #include
          /*該頭文件主要實現(xiàn)內(nèi)存的控制,包括kmalloc等函數(shù)*/
          #include
          #include
          #include
          #include
          /*錯誤的不同,需要具體的類型*/
          #include
          /*自己定義的頭文件*/
          #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)建一個設(shè)備號*/
          dev_t devno = MKDEV(mem_major,0);
          /*注冊一個設(shè)備號*/
          /*如果定義了主設(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;
          /*創(chuàng)建一個設(shè)備*/
          /*初始化cdev,并將相關(guān)的文件操作添加進來*/
          cdev_init(&cdev,&mem_fops);
          cdev.owner = THIS_MODULE;
          cdev.ops = &mem_fops;
          /*注冊字符設(shè)備*/
          cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
          /*分配兩個內(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;
          }
          上一頁 1 2 下一頁

          關(guān)鍵詞: 驅(qū)動學(xué)

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();