tft每日頭條

 > 科技

 > linux内核驅動開發

linux内核驅動開發

科技 更新时间:2024-08-30 09:22:43

字符設備的驅動程序開發步驟大緻都是差不多的,這裡繪制了一張圖來形象的反應字符設備驅動程序的關鍵步驟:

linux内核驅動開發(Linux内核與驅動學習記錄-字符設備驅動程序框架)1

我們創建一個字符設備的時候,首先要得到一個設備号,分配設備号的途徑有靜态分配和動态分配;拿到設備的唯一 ID,我們需要實現 file_operation 并保存到 cdev 中,實現 cdev 的初始化;然後我們需要将我們所做的工作告訴内核,使用 cdev_add() 注冊 cdev;最後我們還需要創建設備節點,以便我們後面調用 file_operation接口。 注銷設備時我們需釋放内核中的 cdev,歸還申請的設備号,删除創建的設備節點。

1.字符設備的定義

Linux 内核提供了兩種方式來定義字符設備:

//第一種方式 static struct cdev chrdev; //第二種方式 struct cdev *cdev_alloc(void); struct cdev *p_cdev = cdev_alloc();

第一種方式,就是我們常見的變量定義;第二種方式,是内核提供的動态分配方式,調用該函數之後,會返回一個 struct cdev 類型的指針,用于描述字符設備。

第二種方式定義的字符設備,可以通過cdev_del函數來釋放占用的内存。

2.設備号的申請和歸還2.1.設備号的靜态申請

register_chrdev_region 函數用于靜态地為一個字符設備申請一個或多個設備編号。

int register_chrdev_region(dev_t from, unsigned count, const char *name);

參數:

  • from:dev_t 類型的變量,用于指定字符設備的起始設備号,如果要注冊的設備号已經被其他的設備注冊了,那麼就會導緻注冊失敗;
  • count:指定要申請的設備号個數, count 的值不可以太大,否則會與下一個主設備号重疊;
  • name:用于指定該設備的名稱,我們可以在/proc/devices 中看到該設備。

返回值:返回 0 表示申請成功,失敗則返回錯誤碼。

2.2.設備号的動态申請

使用 register_chrdev_region 函數時,都需要去查閱内核源碼的 Documentation/devices.txt 文件,這就十分不方便。因此,内核又為我們提供了一種能夠動态分配設備編号的方式: alloc_chrdev_region。

調用 alloc_chrdev_region 函數,内核會自動給我們分配一個尚未使用的主設備号。我們可以通過命令“cat /proc/devices”查詢内核分配的主設備号。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

參數:

  • dev:指向 dev_t 類型數據的指針變量,用于存放分配到的設備編号的起始值;
  • baseminor:次設備号的起始值,通常情況下,設置為 0;
  • count:指定要申請的設備号個數, count 的值不可以太大,否則會與下一個主設備号重疊;
  • name:用于指定該設備的名稱,我們可以在/proc/devices 中看到該設備。

返回值:返回 0 表示申請成功,失敗則返回錯誤碼。

2.3.設備号的申請(靜态和動态都支持)

除了register_chrdev_region函數能夠靜态申請設備号,alloc_chrdev_region函數能夠動态申請設備号之外,内核還提供了register_chrdev 函數用于分配設備号。該函數是一個内聯函數,它不僅支持靜态申請設備号,也支持動态申請設備号,并将主設備号返回。register_chrdev 函數原型如下:

static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops) { return __register_chrdev(major, 0, 256, name, fops); }

參數:

  • major:用于指定要申請的字符設備的主設備号,等價于 register_chrdev_region 函數,當設置為 0 時,内核會自動分配一個未使用的主設備号;
  • name:用于指定字符設備的名稱;
  • fops:用于操作該設備的函數接口指針。

返回值:主設備号。

我們從以上代碼中可以看到,使用 register_chrdev 函數向内核申請設備号,同一類字符設備(即主設備号相同),會在内核中申請了256 個,通常情況下,我們不需要用到這麼多個設備,這就造成了極大的資源浪費。因此通常情況下,并不使用該函數。

2.4.設備号的歸還

當我們删除字符設備時候,我們需要把分配的設備編号交還給内核,對于使用 register_chrdev_region 函數以及 alloc_chrdev_region 函數分配得到的設備編号,可以使用 unregister_chrdev_region 函數将分配得到的設備号歸還給内核。

void unregister_chrdev_region(dev_t from, unsigned count);

參數:

  • from:指定需要注銷的字符設備的設備編号起始值,我們一般将定義的 dev_t 變量作為實參;
  • count:指定需要注銷的字符設備編号的個數,該值應與申請函數的 count 值相等,通常采用宏定義進行管理。
3.字符設備的初始化

cdev_init()函數主要将file_operations結構體和我們的字符設備結構體相關聯。

void cdev_init(struct cdev *cdev, const struct file_operations *fops);

參數:

  • cdev:struct cdev 類型的指針變量,指向需要關聯的字符設備結構體;
  • fops:file_operations 類型的結構體指針變量,一般将實現操作該設備的結構體 file_operations 結構體作為實參。
4.字符設備的注冊和移除4.1.字符設備的注冊

cdev_add 函數用于向内核的 cdev_map 散列表添加一個新的字符設備。

int cdev_add(struct cdev *p, dev_t dev, unsigned count);

參數:

  • p:struct cdev 類型的指針,用于指定需要添加的字符設備;
  • dev:dev_t 類型變量,用于指定設備的起始編号;
  • count:指定注冊多少個設備。

返回值:0或者錯誤碼。

4.2.字符設備的移除

從内核中移除某個字符設備,則需要調用 cdev_del 函數。從系統中删除 cdev, cdev 設備将無法再打開,但任何已經打開的 cdev 将保持不變,即使在 cdev_del 返回後,它們的 fops 仍然可以調用。

void cdev_del(struct cdev *p);

參數:

  • p:将已經注冊的字符設備結構體的地址作為實參傳遞進去,就可以從内核中移除該字符設備了。
5.設備節點的創建和銷毀5.1.設備節點的創建

可以在代碼中使用device_create函數創建設備節點。

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

參數:

  • class:指向這個設備應該注冊到的 struct 類的指針;
  • parent:指向此新設備的父結構設備(如果有)的指針;
  • devt:要添加的字符設備的設備号;
  • drvdata:要添加到設備進行回調的數據;
  • fmt:輸入設備名稱。

返回值:成功時返回 struct device 結構體指針, 錯誤時返回 ERR_PTR()。

5.2.設備節點的銷毀

可以使用device_destroy函數來删除 device_create 函數創建的設備節點。

void device_destroy(struct class *class, dev_t devt);

參數:

  • class:指向注冊此設備的 struct 類的指針;
  • devt:以前注冊設備時,使用的設備号。
5.3.使用mknod命令創建設備節點

除了使用代碼創建設備節點,還可以使用 mknod 命令創建設備節點。

用法: mknod 設備名 設備類型 主設備号 次設備号

當類型為”p”時可不指定主設備号和次設備号,否則它們是必須指定的。如果主設備号和次設備号以”0x”或”0X”開頭,它們會被視作十六進制數來解析;如果以”0”開頭,則被視作八進制數;其餘情況下被視作十進制數。可用的設備類型包括:

  • b:創建 (有緩沖的) 區塊特殊文件;
  • c,u:創建 (沒有緩沖的) 字符特殊文件;
  • p:創建先進先出 (FIFO) 特殊文件。

如: mkmod /dev/test c 2 0 創建一個字符設備/dev/test,其主設備号為 2,次設備号為 0。

當我們使用上述命令,創建了一個字符設備文件時,實際上就是創建了一個設備節點 inode 結構體,并且将該設備的設備編号記錄在成員i_rdev,将成員 f_op 指針指向了 def_chr_fops 結構體。這就是 mknod 負責的工作内容。

inode 上的 file_operation 并不是自己構造的 file_operation,而是字符設備通用的 def_chr_fops,那麼自己構建的 file_operation 等在應用程序調用 open 函數之後,才會綁定在文件上。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved