簡單入門linux設備驅動之第四部分:字符設備驅動major號 & minor號


聲明:內容搬自阿三哥網站,只是翻譯了一下。侵刪。https://embetronicx.com/tutorials/linux/device-drivers/

正文如下:

 

這是“linux設備驅動系列”教程的續集,並且接着討論字符驅動程序及其實現。本系列的目的是提供簡單實用的示例,使每個人都能以簡單的方式理解這些概念。現在讓我們即將學習“linux設備驅動第四部分:字符設備驅動major號 & minor號”。

 在之前的教程中,我們討論了如何在加載時向Linux設備驅動程序傳遞參數。所以現在讓我們來學習有關major號和minor號的知識。

 

內容速覽

·1 簡介

·2 應用程序如何與硬件設備通信?

·3 字符設備驅動major號與minor號
·4 major號與minor號

  ·4.1 major號

  ·4.2 minor號
·5 分配major號與minor號

  ·5.1 靜態分配

  ·5.2 動態分配
  ·5.3 靜態和動態方法的區別
·6 注銷major號與minor號
·7 靜態分配major號程序示例
·8 動態分配minor號程序示例
 
 

·1 簡介

我們已經知道了什么是驅動程序,以及為什么我們需要驅動程序。字符驅動程序有什么特殊的嗎?如果我們編寫面向字節操作的驅動程序,我們就將其視為字符驅動程序。由於大多數設備都是面向字節的,大多數設備驅動程序都是字符設備驅動程序。例如,串行驅動程序,音頻驅動程序,視頻驅動程序,攝像頭驅動程序,以及基本I/O驅動程序。事實上,

設備驅動程序中,既不是存儲設備驅動程序,也不是網絡設備驅動程序的話,就屬於字符驅動程序啦。

 

·2 應用程序如何與硬件設備通信?

下圖展示了通信的完整路徑。

 

 ·首先,應用程序會打開設備文件。這個設備文件是設備驅動程序創建的。

 ·然后這個設備文件會根據major號和minor號來找到對應的設備驅動程序。

 ·然后找到的這個設備驅動程序就可以跟硬件設備交流。

 

·3 字符設備驅動major號與minor號

Linux內核的基本特性之一就是抽象對設備的處理。所有的硬件設備看起來都像是普通文件;可以使用相同的,標准的,用來操作文件的系統調用(system call)來打開(open),關閉(close),讀(read),寫(write)他們。對於Linux來說,一切皆文件。往硬盤寫入數據時,其實是往文件寫入。從鍵盤讀取數據時,其實是向文件讀取。保存磁帶設備的備份時,其實是往文件里寫入。甚至讀取內存數據時也是從文件中讀取。假如你想讀或寫的文件是一個普通文件,過程非常好理解:文件被打開,然后你讀取或者寫入數據。設備驅動程序與普通文件也差不多。驅動程序會為每個硬件設備創建一個特殊文件(與普通文件相對)。我們通過這些特殊文件(設備文件)與硬件溝通。

如果你想創建一個特殊文件,我們得了解設備驅動程序的major號與minor號相關的知識。在此節教程中我們會了解major和minor號。

 

·4 major號與minor號

 Linux內核用一對數字來表示字符和塊設備 <major> : <minor>

·4.1 major號

 傳統來說,major號用來標識與設備相關聯的驅動程序。一個major可以被許多設備驅動程序共享。在 /proc/devices 中我們可以看到,在一個運行中的Linux實例是怎么分配major號的。

 

 

 這些數字是major號。

 

·4.2 minor號

 major號用來標識相應的驅動程序。許多設備使用相同的major號。所以我們需要為使用相同major號的設備單獨再分配一個數字。這就是minor號啦。換句話說,設備驅動程序使用minor號<minor>來辨別單個物理或邏輯設備。

 

·5 分配major號與minor號

我們有兩種方法分配major號和minor號。

·靜態分配

·動態分配

 

·5.1 靜態分配

假如你想為你的驅動程序設置一個特別的major號,你可以使用這種方法。如果major號可用的話,這種方法會將major號分配給你。假如不可用,就分配失敗。

  int register_chardev_refion(dev_t first, unsigned int count, char *name);

 

first  是你想要分配設備號范圍的起始數字。 

count 是你請求的連續設備號的總數。請注意,如果count過大,你請求的范圍會溢出至下一個major號;但是只要你請求的數字范圍可用,一切都可以正常工作。

name 是與請求的設備號范圍([first, first+count])相關聯的設備名稱。它將會在 /proc/devices sysfs 目錄中出現。

 申請成功的話,函數 register_chrdev_region 的返回值為零。出錯的話,會返回一個負的錯誤碼,並且不能訪問所申請的設備號范圍。

 

dev_t 數據類型(在<linux/types.h>中定義)用來存儲設備號的major和minor部分。dev_t 是32位的數據,12bits用於表示major號,20bits用來表示minor號。

假如你想創建dev_t結構體變量表示你的major號和minor號,請使用下面這個函數。

MKDEV(int major, int minor);

 

假如你想從dev_t變量中獲取major號和minor號,請使用以下方法。

MAJOR(dev_t dev);

MINOR(dev_t dev);

如果你將dev_t變量傳入MAJOR 或者MINOR函數,他會返回驅動程序的major號/minor號。

舉個栗子,

dev_t dev = MKDEV(235, 0);

register_chrdev_region(dev, 1, "Embetronicx_Dev");

 

·5.2 動態分配

 假如我們不想要固定的major號和minor號請使用這種方法。這種方法會為驅動程序動態分配可用的major號。

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

 

dev 是一個輸出參數,成功執行時會返回分配范圍的第一個值。

firstminor 應為請求使用的第一個minor號,通常為0。

count 為您請求的連續設備號總數。

name 時與分配的設備號相關聯的設備名稱。他會在 /proc/devices sysfs 中出現。

 

·5.3 靜態和動態方法的區別

 靜態方法只有在你提前知道你想從哪一個major號開始時真的有用。使用靜態方法時,你告訴內核你想要的設備號(起始major/minor號以及count)然后內核分配給你或不分配(取決於這些設備號是否可用)。

使用動態方法時,你告訴內核你需要多少設備號(起始minor號以及count)然后他會為你找到一個起始major號,如果他是可用的。

有些人為了避免與其他設備驅動程序產生沖突,會優先選擇使用動態方法函數,它會為你動態分配設備號。

 動態分配的缺點就是你不能提前創建設備節點,因為分配給你的major號可能會變化。對於驅動程序的正常使用來說,這不算是個問題。因為一旦分配了設備號,你可以從 /proc/devices 中讀取。

 

·6 注銷major號與minor號

不論你是怎樣分配你的設備號的,當你不再使用他們的時候應該釋放掉。設備號使用下面函數釋放:

 

void unregister_chrdev_region(dev_t first, unsigned int count);

 

通常將unregister_chrdev_region放在模塊的退出函數中。

 

 ·7 靜態分配major號程序示例

GitHub中獲取源代碼

在此程序中,我指定235作為major號。

/***************************************************************************//**
*  \file       driver.c
*
*  \details    Simple linux driver (Statically allocating the Major and Minor number)
*
*  \author     EmbeTronicX
*
* *******************************************************************************/
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include <linux/fs.h>

//creating the dev with our custom major and minor number
dev_t dev = MKDEV(235, 0);

/*
** Module Init function
*/
static int __init hello_world_init(void)
{
    register_chrdev_region(dev, 1, "Embetronicx_Dev");
    printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
    printk(KERN_INFO "Kernel Module Inserted Successfully...\n");
    return 0;
}

/*
** Module exit function
*/
static void __exit hello_world_exit(void)
{
    unregister_chrdev_region(dev, 1);
    printk(KERN_INFO "Kernel Module Removed Successfully...\n");
}
 
module_init(hello_world_init);
module_exit(hello_world_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx@gmail.com>");
MODULE_DESCRIPTION("Simple linux driver (Statically allocating the Major and Minor number)");
MODULE_VERSION("1.0");

 


·使用makefile生成驅動程序(sudo make)

·使用 sudo insmode 加載驅動程序

·使用 cat /proc/devices 檢查major號

linux@embetronicx-VirtualBox::/home/driver/driver$ cat /proc/devices | grep "Embetronicx_Dev"

235 Embetronicx_Dev

 

 

 ·8 動態分配major號程序示例

GitHub中獲取源代碼

此程序會動態分配一個major號。

/***************************************************************************//**
*  \file       driver.c
*
*  \details    Simple linux driver (Dynamically allocating the Major and Minor number)
*
*  \author     EmbeTronicX
*
* *******************************************************************************/
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kdev_t.h>
#include<linux/fs.h>
 
dev_t dev = 0;

/*
** Module Init function
*/
static int __init hello_world_init(void)
{
        /*Allocating Major number*/
        if((alloc_chrdev_region(&dev, 0, 1, "Embetronicx_Dev")) <0){
                printk(KERN_INFO "Cannot allocate major number for device 1\n");
                return -1;
        }
        printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
        printk(KERN_INFO "Kernel Module Inserted Successfully...\n");
        
        return 0;
}

/*
** Module exit function
*/
static void __exit hello_world_exit(void)
{
        unregister_chrdev_region(dev, 1);
        printk(KERN_INFO "Kernel Module Removed Successfully...\n");
}
 
module_init(hello_world_init);
module_exit(hello_world_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx@gmail.com>");
MODULE_DESCRIPTION("Simple linux driver (Dynamically allocating the Major and Minor number)");
MODULE_VERSION("1.1");

 

·使用makefile生成驅動程序(sudo make)

·使用 sudo insmode 加載驅動程序

·使用 cat /proc/devices 檢查major號

linux@embetronicx-VirtualBox::/home/driver/driver$ cat /proc/devices | grep "Embetronicx_Dev"

243 Embetronicx_Dev

 

函數分配的major號243給這個驅動程序。

 

在卸載驅動程序之前使用 ls /dev/ 檢查下/dev下的文件。你找不到我們的驅動程序文件。因為我們現在還沒有創建它呢。在下一小節的教程里,我們會看到設備文件。

 

 

---------------------分割線-------------------

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM