乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      cdev 結(jié)構(gòu)體與字符設(shè)備的注冊(cè)

       liangliang186 2011-12-13


      cdev結(jié)構(gòu)

      在Linux2.6內(nèi)核中一個(gè)字符設(shè)備用cdev結(jié)構(gòu)來描述,其定義如下:
      struct cdev {
              struct kobject kobj;
              struct module *owner;   //所屬模塊
              const struct file_operations *ops;  
                      //文件操作結(jié)構(gòu),在寫驅(qū)動(dòng)時(shí),其結(jié)構(gòu)體內(nèi)的大部分函數(shù)要被實(shí)現(xiàn)
              struct list_head list;
              dev_t dev;          //設(shè)備號(hào),int 類型,高12位為主設(shè)備號(hào),低20位為次設(shè)備號(hào)
              unsigned int count;
      };
      可以使用如下宏調(diào)用來獲得主、次設(shè)備號(hào):
      MAJOR(dev_t dev)
      MINOR(dev_t dev)
      MKDEV(int major,int minor) //通過主次設(shè)備號(hào)來生成dev_t
      以上宏調(diào)用在內(nèi)核源碼中如此定義:

      #define MINORBITS       20
      #define MINORMASK       ((1U << MINORBITS) - 1)
              //(1<<20 -1) 此操作后,MINORMASK宏的低20位為1,高12位為0
      #define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
      #define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))
      #define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))
      //摘自:
      http://lxr./linux/include/linux/kdev_t.h#L1
      下面一組函數(shù)用來對(duì)cdev結(jié)構(gòu)體進(jìn)行操作:
      void cdev_init(struct cdev *, const struct file_operations *);
              //初始化,建立cdev和file_operation 之間的連接
      struct cdev *cdev_alloc(void);  //動(dòng)態(tài)申請(qǐng)一個(gè)cdev內(nèi)存
      void cdev_put(struct cdev *p);   //釋放
      int cdev_add(struct cdev *, dev_t, unsigned); 
              //注冊(cè)設(shè)備,通常發(fā)生在驅(qū)動(dòng)模塊的加載函數(shù)中
      void cdev_del(struct cdev *);//注銷設(shè)備,通常發(fā)生在驅(qū)動(dòng)模塊的卸載函數(shù)中

      在注冊(cè)時(shí)應(yīng)該先調(diào)用:int register_chrdev_region(dev_t from,unsigned count,const char *name)函數(shù)為其分配設(shè)備號(hào),此函數(shù)可用:int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)函數(shù)代替,他們之間的區(qū)別在于:register_chrdev_region()用于已知設(shè)備號(hào)時(shí),另一個(gè)用于動(dòng)態(tài)申請(qǐng),其優(yōu)點(diǎn)在于不會(huì)造成設(shè)備號(hào)重復(fù)的沖突。
      在注銷之后,應(yīng)調(diào)用:void unregister_chrdev_region(dev_t from,unsigned count)函數(shù)釋放原先申請(qǐng)的設(shè)備號(hào)。
      他們之間的順序關(guān)系如下:
      register_chrdev_region()-->cdev_add()     //此過程在加載模塊中
      cdev_del()-->unregister_chrdev_region()     //此過程在卸載模塊中

      cdev 結(jié)構(gòu)體與字符設(shè)備的注冊(cè)

      在 linux 2.6內(nèi)核中,使用 cdev結(jié)構(gòu)體描述字符設(shè)備,cdev 的定義在 <linux/cdev.h> 中可找到,其定義如下:
      引用
      struct cdev {
              struct kobject kobj;
              struct module *owner;
              const struct file_operations *ops;
              struct list_head list;
              dev_t dev;
              unsigned int count;
      };

      cdev 結(jié)構(gòu)體中的 dev_t 成員定義了設(shè)備號(hào),為 32 位,其中高 12 位為主設(shè)備號(hào),低 20 位為次設(shè)備號(hào)。
      其中,struct kobject 是內(nèi)嵌的 kobject 對(duì)象;
                  struct module 是所屬模塊;
                  struct file_operations 為文件操作結(jié)構(gòu)體。

      使用以下宏可以從 dev_t 獲得主設(shè)備號(hào)和次設(shè)備號(hào):
      引用
              MAJOR (dev_t dev);
              MINOR (dev_t dev);

      而使用下面宏可以通過主設(shè)備號(hào)和次設(shè)備號(hào)生成 dev_t  :
      引用
      MKDEV (int major, int minor);

       

      有兩個(gè)方法可以分配并初始化 cedv 結(jié)構(gòu)。如果希望在運(yùn)行時(shí)動(dòng)態(tài)的獲得一個(gè)獨(dú)立的 cdev 結(jié)構(gòu),可以如下這么做:
      引用
      struct cdev *my_cdev = cdev_alloc();
      my_cdev->ops = &my_fops;

      cdev_alloc(void) 函數(shù)的代碼為(對(duì) cdev 結(jié)構(gòu)體操作的系列函數(shù)可在 fs/char_dev.c 中找到):
      引用
      struct cdev *cdev_alloc(void)
      {
              struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
              if (p) {
                      INIT_LIST_HEAD(&p->list);
                      kobject_init(&p->kobj, &ktype_cdev_dynamic);
              }
              return p;
      }

      cdev_alloc() 的源代碼可能由于內(nèi)核版本號(hào)的不同而有差別(上面的代碼為 2.6.30)

       

      有時(shí)可能希望就把 cdev 結(jié)構(gòu)內(nèi)嵌在自己的特定設(shè)備結(jié)構(gòu)里,那么在分配好 cdev 結(jié)構(gòu)后,就用 cdev_init() 函數(shù)對(duì)其初始化:
      引用
      void cdev_init (struct cdev *cdev, struct file_operations *fops)

      cdev_init() 函數(shù)代碼為:
      引用
      void cdev_init(struct cdev *cdev, const struct file_operations *fops)
      {
              memset(cdev, 0, sizeof *cdev);
              INIT_LIST_HEAD(&cdev->list);
              kobject_init(&cdev->kobj, &ktype_cdev_default);
              cdev->ops = fops;
      }

      另外,像 cdev 中的 owner 要設(shè)置為 THIS_MOULE 。
      一旦 cdev 結(jié)構(gòu)體設(shè)置完畢,最后一步就是要把這事告訴給內(nèi)核,使用下面的函數(shù):
      引用
      int cdev_add(struct cdev *p, dev_t dev, unsigned count)

      cdev_add() 對(duì)應(yīng)的代碼為:
      引用
      /**
      * cdev_add() - add a char device to the system
      * @p: the cdev structure for the device
      * @dev: the first device number for which this device is responsible
      * @count: the number of consecutive minor numbers corresponding to this
      *         device
      *
      * cdev_add() adds the device represented by @p to the system, making it
      * live immediately.  A negative error code is returned on failure.
      */
      int cdev_add(struct cdev *p, dev_t dev, unsigned count)
      {
              p->dev = dev;
              p->count = count;
              return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
      }

      參數(shù) p 是 cdev 結(jié)構(gòu)體的指針;
      參數(shù) dev 是設(shè)備響應(yīng)的第一個(gè)設(shè)備號(hào);
      參數(shù) count 和設(shè)備相關(guān)聯(lián)的設(shè)備號(hào)的數(shù)目。
      一般的,count 的值為 1,但是有些情形也可能是大于 1 的數(shù)。比如 SCSI 磁帶機(jī),它通過給每個(gè)物理設(shè)備安排多個(gè)此設(shè)備號(hào)來允許用戶在應(yīng)用程序里選擇操作模式(比如密度)。

      cdev_add 如果失敗了,那么返回一個(gè)負(fù)值,表明驅(qū)動(dòng)無法加載到系統(tǒng)中。然而它一般情況下都會(huì)成功,一旦 cdev_add 返回,設(shè)備也就 “活” 了起來,于是所對(duì)應(yīng)的操作方法(file_operations 結(jié)構(gòu)里所定義的各種函數(shù))也就能為內(nèi)核所調(diào)用。

      從系統(tǒng)中移除一個(gè)字符設(shè)備,可以調(diào)用:
      引用
      void cdev_del(struct cdev *p)

       

      老版本的字符設(shè)備注冊(cè)與注銷
      在許多驅(qū)動(dòng)程序代碼里,會(huì)看到許多字符設(shè)備驅(qū)動(dòng)并沒有用 cdev 這個(gè)接口。這是一種老式的方法,但新寫的代碼應(yīng)該使用 cdev 接口。

      用于注冊(cè)字符設(shè)備驅(qū)動(dòng)程序的老式函數(shù) register_chrdev() 函數(shù)定義如下:
      引用
      int register_chardev (unsigned int major, const char *name, struct file_operations *fops)

      利用該函數(shù)注冊(cè)時(shí),應(yīng)先定義好主設(shè)備號(hào)、設(shè)備驅(qū)動(dòng)程序的名稱、file_operations 結(jié)構(gòu)體的變量。

      應(yīng)用程序中利用設(shè)備文件搜索設(shè)備驅(qū)動(dòng)程序的時(shí)候使用主設(shè)備號(hào) (major) 。

      在內(nèi)核中表示 proc 文件系統(tǒng)或錯(cuò)誤代碼時(shí),使用設(shè)備驅(qū)動(dòng)程序名稱。

      另外,利用 unregister_chrdev() 函數(shù)注銷字符設(shè)備驅(qū)動(dòng)程序時(shí),可以作為區(qū)分標(biāo)志。注冊(cè)函數(shù)中關(guān)鍵的地方是定義 file_operations 結(jié)構(gòu)體變量的地址。

      所謂注冊(cè)字符設(shè)備驅(qū)動(dòng)程序,應(yīng)理解為在內(nèi)核中注冊(cè)與主設(shè)備號(hào)相關(guān)的 file_operations 結(jié)構(gòu)體。

      register_chrdev() 函數(shù)注冊(cè)完設(shè)備驅(qū)動(dòng)程序,把定義主設(shè)備號(hào)的 major 設(shè)置為 0,返回注冊(cè)的主設(shè)備號(hào)(動(dòng)態(tài)分配),把已知的主設(shè)備號(hào)設(shè)為 major 值時(shí),返回 0 (人工指定)。注冊(cè)失敗時(shí),返回負(fù)值

      從內(nèi)核中注銷字符設(shè)備驅(qū)動(dòng)程序的 unregister_chrdev() 函數(shù)形式如下:
      引用
      int unregister_chrdev (unsigned int major, const char *name)

      該函數(shù)中使用主設(shè)備號(hào)(major) 和設(shè)備驅(qū)動(dòng)程序名稱 (name) 與 register_chrdev 函數(shù)中使用的值相同,因?yàn)閮?nèi)核會(huì)把這些參數(shù)作為注銷字符設(shè)備驅(qū)動(dòng)程序的基準(zhǔn)對(duì)比兩個(gè)設(shè)定內(nèi)容。從內(nèi)核成功注銷了字符設(shè)備驅(qū)動(dòng)程序時(shí),返回 0 ,失敗則返回負(fù)值。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多