在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何在Linux系統下自動創建設備節點

嵌入式開發愛好者 ? 來源:嵌入式開發愛好者 ? 作者:嵌入式開發愛好者 ? 2022-11-06 20:18 ? 次閱讀

第一:自動創建設備節點方法

1、使用 class_create 函數創建一個類。

2、使用 device_create 函數在我們創建的類下面創建一個設備。

第二:自動創建設備節點簡介

Linux驅動實驗中,通過使用insmod命令加載模塊后,需要通過mknod命令手動創建設備節點,這樣使用起來比較麻煩,并且不可能每個設備都這樣操作, Linux 系統的存在就是為了方便使用, 所以我們來看一下如何實現自動創建設備節點, 當加載模塊時, 在/dev 目錄下自動創建相應的設備文件。怎么自動創建一個設備節點呢?在嵌入式 Linux 中使用 mdev 來實現設備節點文件的自動創建和刪除。

udev 是一種工具, 它能夠根據系統中的硬件設備的狀態動態更新設備文件, 包括設備文件的創建, 刪除等。設備文件通常放在/dev 目錄下。使用 udev 后, 在/dev 目錄下就只包含系統中真正存在的設備。而mdev 是 udev 的簡化版本,是 busybox 中所帶的程序,最適合用在嵌入式系統,而 udev 一般用在 PC 上的linux 中,相對 mdev 來說要復雜些, 所以在嵌入式 Linux 中使用 mdev 來實現設備節點文件的自動創建和刪除。

第三:創建和刪除類函數

內核中定義了struct class結構體,一個struct class結構體類型變量對應一個類,內核同時提供了class_create用來創建一個類,這個類存放于 sysfs 下面, 一旦創建好了這個類, 再調用 device_create來在/dev 目錄下創建相應的設備節點。這樣, 加載模塊的時候, 用戶空間中的 udev 會自動響應 device_create,去/sysfs 下尋找對應的類從而創建設備節點。

在 Linux 驅動程序中一般通過 class_create 和 class_destroy 來完成設備節點的創建和刪除。首先要創建一個 class 類結構體, class 結構體定義在 include/linux/device.h 里面。class_create 是個宏, 宏定義如下:#define class_create(owner, name)

({ 
static struct lock_class_key __key; 
__class_create(owner, name, &__key); 
})
 
struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key)

class_create一共有兩個參數,參數owner 一般為 THIS_MODULE, 參數 name 是類名字。返回值是個指向結構體 class 的指針, 也就是創建的類。

卸載驅動程序的時候需要刪除掉類,類刪除函數為class_destroy, 函數原型如下:
void class_destroy(struct class *cls);//參數 cls 就是要刪除的類。
第四:創建設備函數

當使用上節的函數創建完成一個類后,使用device_create 函數在這個類下創建一個設備。

device_create函數原型如下:
struct device *device_create(struct class *class,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)

device_create是個可變參數函數,參數class就是設備要創建哪個類下面;參數parent是父設備,一般為NULL,也就是沒有父設備;參數devt是設備號;參數drvdata是設備可能會使用的一些數據,一般為NULL;參數fmt是設備名字,如果設置fmt=xxx的話,就會生成/dev/xxx這個設備文件。返回值就是創建好的設備。同樣的, 卸載驅動的時候需要刪除掉創建的設備, 設備刪除函數為 device_destroy, 函數原型如下:

void device_destroy(struct class *class, dev_t devt)
參數class是要刪除的設備所處的類,參數devt是要刪除的設備號。

第五:創建類函數

chrdev.c文件完整代碼如下所示:

#include  //初始化頭文件
#include  //最基本的文件, 支持動態添加和卸載模塊。
#include  //包含了文件操作相關 struct 的定義, 例如大名鼎鼎的struct file_operations
#include 
#include  //對字符設備結構 cdev 以及一系列的操作函數的定義。 
                        //包含了 cdev 結構及相關函數的定義。
 
#define DEVICE_NUMBER 1 //定義次設備號的個數
#define DEVICE_SNAME "schrdev" //定義靜態注冊設備的名稱
#define DEVICE_ANAME "achrdev" //定義動態注冊設備的名稱
#define DEVICE_MINOR_NUMBER 0 //定義次設備號的起始地址
 
#include  //包含了 device、 class 等結構的定義
 
#define DEVICE_CLASS_NAME "chrdev_class" //宏定義類名
 
static int major_num, minor_num; //定義主設備號和次設備號
struct class *class; //定義類
struct cdev cdev;//定義一個 cdev 結構體
 
module_param(major_num, int, S_IRUSR); //驅動模塊傳入普通參數 major_num
module_param(minor_num, int, S_IRUSR); //驅動模塊傳入普通參數 minor_num
 
dev_t dev_num;
 
int chrdev_open(struct inode *inode, struct file *file)
{
    printk("chrdev_open
");
    return 0;
} 
 
struct file_operations chrdev_ops = {
.owner = THIS_MODULE,
.open = chrdev_open
};
 
static int hello_init(void)
{
    int ret; //函數返回值
    if (major_num)
    {
         /*靜態注冊設備號*/
         printk("major_num = %d
", major_num); //打印傳入進來的主設備號
         printk("minor_num = %d
", minor_num); //打印傳入進來的次設備號
         //MKDEV 將主設備號和次設備號合并為一個設備號
         dev_num = MKDEV(major_num, minor_num);
         ret = register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME); //注冊設備號
         if (ret < 0)
         {
              printk("register_chrdev_region error
");
         } 
         printk("register_chrdev_region ok
"); //靜態注冊設備號成功
    } 
    else
    {
         /*動態注冊設備號*/
         ret = alloc_chrdev_region(&dev_num, DEVICE_MINOR_NUMBER, 1, DEVICE_ANAME);
         if (ret < 0)
         {
             printk("alloc_chrdev_region error
");
         } 
         printk("alloc_chrdev_region ok
"); //動態注冊設備號成功
         major_num = MAJOR(dev_num); //將主設備號取出來
         minor_num = MINOR(dev_num); //將次設備號取出來
         printk("major_num = %d
", major_num); //打印傳入進來的主設備號
         printk("minor_num = %d
", minor_num); //打印傳入進來的次設備號
    } 
    cdev.owner = THIS_MODULE;
    //cdev_init 函數初始化 cdev 結構體成員變量
    cdev_init(&cdev, &chrdev_ops);
    //完成字符設備注冊到內核
    cdev_add(&cdev, dev_num, DEVICE_NUMBER);
    //創建類
    class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
    return 0;
}
 
static void hello_exit(void)
{
    unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);
    //注銷設備號
    cdev_del(&cdev);
    //刪除類
    class_destroy(class);
   printk("gooodbye! 
");
}
 
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

將代碼編譯成模塊,利用驅動程序里面的Makefile文件。

編譯并加載,如果創建類成功以后,會在開發板的/sys/class/下面生成一個名為“chrdev_class”的類。現在沒有加載驅動的情況,如下圖所示:ls /sys/class

第六:創建設備函數

在前面代碼的基礎上添加創建設備的代碼,如下所示:

#include  //初始化頭文件
#include  //最基本的文件, 支持動態添加和卸載模塊。
#include  //包含了文件操作相關 struct 的定義, 例如struct file_operations
#include 
 
#include  //對字符設備結構 cdev 以及一系列的操作函數的定義。
                        //包含了 cdev 結構及相關函數的定義。
 
#define DEVICE_NUMBER 1 //定義次設備號的個數
#define DEVICE_SNAME "schrdev" //定義靜態注冊設備的名稱
#define DEVICE_ANAME "achrdev" //定義動態注冊設備的名稱
#define DEVICE_MINOR_NUMBER 0 //定義次設備號的起始地址
 
#include  //包含了 device、 class 等結構的定義
 
#define DEVICE_CLASS_NAME "chrdev_class"
#define DEVICE_NODE_NAME "chrdev_test" //宏定義設備節點的名字
 
static int major_num, minor_num; //定義主設備號和次設備號
struct class *class; /* 類 */
struct device *device; /* 設備 */
struct cdev cdev; //定義一個 cdev 結構體
 
module_param(major_num, int, S_IRUSR); //驅動模塊傳入普通參數 major_num
module_param(minor_num, int, S_IRUSR); //驅動模塊傳入普通參數 minor_num
dev_t dev_num; /* 設備號 */
 
/***
* @description: 打開設備
* @param {structinode} *inode:傳遞給驅動的 inode
* @param {structfile} *file:設備文件, file 結構體有個叫做 private_data 的成員變量,
* 一般在 open 的時候將 private_data 指向設備結構體。
* @return: 0 成功;其他 失敗
*/
int chrdev_open(struct inode *inode, struct file *file)
{
    printk("chrdev_open
");
    return 0;
}
 
// 設備操作函數結構體
struct file_operations chrdev_ops = {
.owner = THIS_MODULE,
.open = chrdev_open
};
 
/**
* @description: 驅動入口函數
* @param {*}無
* @return {*} 0 成功;其他 失敗
*/
static int hello_init(void)
{
    int ret; //函數返回值
    if (major_num)
    {
        /*靜態注冊設備號*/
        printk("major_num = %d
", major_num); //打印傳入進來的主設備號
        printk("minor_num = %d
", minor_num); //打印傳入進來的次設備號
        dev_num = MKDEV(major_num, minor_num); 
        //MKDEV 將主設備號和次設備號合并為一個設備號
        ret = register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME); //注冊設備號
        if (ret < 0)
        {
            printk("register_chrdev_region error
");
        } 
        printk("register_chrdev_region ok
"); //靜態注冊設備號成功
    } 
    else
    {
        /*動態注冊設備號*/
        ret = alloc_chrdev_region(&dev_num, DEVICE_MINOR_NUMBER, 1, DEVICE_ANAME);
        if (ret < 0)
        {
            printk("alloc_chrdev_region error
");
        }
        printk("alloc_chrdev_region ok
"); //動態注冊設備號成功
        major_num = MAJOR(dev_num); //將主設備號取出來
        minor_num = MINOR(dev_num); //將次設備號取出來
        printk("major_num = %d
", major_num); //打印傳入進來的主設備號
        printk("minor_num = %d
", minor_num); //打印傳入進來的次設備號
    } 
    // 初始化 cdev
    cdev.owner = THIS_MODULE;
    cdev_init(&cdev, &chrdev_ops);
    // 向系統注冊設備
    cdev_add(&cdev, dev_num, DEVICE_NUMBER);
    // 創建 class 類
    class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
    // 在 class 類下創建設備
    device = device_create(class, NULL, dev_num, NULL, DEVICE_NODE_NAME);
    return 0;
} 
 
/**
* @description: 驅動出口函數
* @param {*}無
* @return {*}無
*/
static void hello_exit(void)
{
    //注銷設備號
    unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);
    //刪除設備
    cdev_del(&cdev);
    //注銷設備
    device_destroy(class, dev_num);
    //刪除類
    class_destroy(class);
    printk("gooodbye! 
");
} 
 
// 將上面兩個函數指定為驅動的入口和出口函數
module_init(hello_init);
module_exit(hello_exit);
// LICENSE 和作者信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuomu");

編寫應用測試程序如下所示:

#include 
#include 
#include 
#include 
#include 
int main(int argc,char *argv[])
{
    int fd;
    char buf[64] = {0};
    fd = open("/dev/chrdev_test",O_RDWR); //打開設備節點
    if(fd < 0)
    {
         perror("open error 
");
         return fd;
    } 
    close(fd);
    return 0;
}

輸入命令編譯app.c ,利用驅動里面的Makefile文件實現。

第七:具體效果如下:

將前面加載的驅動卸載掉,再加載新編譯好的的驅動, 如下圖所示:
rmmod chrdev
insmod chrdev.ko

c2a2be98-5d1f-11ed-a3b6-dac502259ad0.png

輸入以下命令查看/sys/class 下面是否生成類, 如下圖所示:ls /sys/class/chrdev_class/

輸入以下命令查看下是否生成了設備節點ls /dev/chrdev_test

c2beedca-5d1f-11ed-a3b6-dac502259ad0.png

總結:利用標準字符驅動模型,自動生成設備節點,在開發過程具有重要意義。

審核編輯:郭婷


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5125

    文章

    19438

    瀏覽量

    313053
  • Linux
    +關注

    關注

    87

    文章

    11420

    瀏覽量

    212315

原文標題:Linux系統下自動創建設備節點方法

文章出處:【微信號:嵌入式開發愛好者,微信公眾號:嵌入式開發愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    飛凌嵌入式ElfBoard ELF 1板卡-字符驅動之自動創建節點

    節點,本節講解如何讓驅動自動在/dev目錄下生成設備節點。想要實現自動創建
    發表于 03-18 09:48

    何在RakSmart服務器上用Linux系統部署DeepSeek

    Linux系統 DeepSeek 部署方案,結合RakSmart 服務器硬件推薦及多場景適配建議,主機推薦小編為您整理發布如何在RakSmart服務器上用Linux
    的頭像 發表于 03-14 11:53 ?274次閱讀

    Linux中的用戶與創建

    Linux中的用戶與創建 用戶的類型 超級管理用戶: 權限最高的用戶(uid:0) #uid:是用戶的身份證號,Linux系統只認uid 普通用戶: 權限受限的用戶(uid:1000-
    的頭像 發表于 12-20 14:24 ?539次閱讀
    <b class='flag-5'>Linux</b>中的用戶與<b class='flag-5'>創建</b>

    何在Linux系統上設置站群服務器IP地址

    Linux系統上設置站群服務器的IP地址,可以通過以下步驟進行,主機推薦小編為您整理發布如何在Linux系統上設置站群服務器IP地址。
    的頭像 發表于 12-11 10:05 ?387次閱讀

    何在TMS320C6727 DSP上創建基于延遲的音頻效果

    電子發燒友網站提供《如何在TMS320C6727 DSP上創建基于延遲的音頻效果.pdf》資料免費下載
    發表于 10-16 10:35 ?0次下載
    如<b class='flag-5'>何在</b>TMS320C6727 DSP上<b class='flag-5'>創建</b>基于延遲的音頻效果

    自動節點位置檢測(SNPD)

    電子發燒友網站提供《自動節點位置檢測(SNPD).pdf》資料免費下載
    發表于 09-30 09:35 ?3次下載
    <b class='flag-5'>自動</b>從<b class='flag-5'>節點</b>位置檢測(SNPD)

    何在DRA821U上使用Linux實現快速引導

    電子發燒友網站提供《如何在DRA821U上使用Linux實現快速引導.pdf》資料免費下載
    發表于 09-03 10:11 ?0次下載
    如<b class='flag-5'>何在</b>DRA821U上使用<b class='flag-5'>Linux</b>實現快速引導

    linux系統設備驅動一般分幾類

    Linux系統設備驅動是操作系統與硬件設備之間的橋梁,負責實現操作系統與硬件
    的頭像 發表于 08-30 15:13 ?785次閱讀

    Linux設備驅動程序分類有哪些

    Linux設備驅動程序是操作系統與硬件設備之間的橋梁,負責實現硬件設備與操作系統之間的通信和控制
    的頭像 發表于 08-30 15:11 ?970次閱讀

    Linux操作系統運行參數自動調整技術

    Linux操作系統運行參數的自動調整是一個復雜而關鍵的技術,它可以顯著提高系統性能、穩定性和資源利用率。通過使用自適應算法特別是內核態的機器學習框架、性能監控工具和配置管理工具,能夠在
    的頭像 發表于 08-22 09:53 ?629次閱讀
    <b class='flag-5'>Linux</b>操作<b class='flag-5'>系統</b>運行參數<b class='flag-5'>自動</b>調整技術

    Alphabet向旗下自動駕駛企業Waymo注資50億美元

    7月24日,科技巨頭谷歌的母公司Alphabet宣布了一項重大投資決策,即向旗下自動駕駛領域的先鋒企業Waymo注資50億美元,此舉標志著Alphabet對自動駕駛技術未來發展的堅定承諾。
    的頭像 發表于 07-24 16:13 ?1499次閱讀

    何在SQL中創建觸發器

    的業務邏輯,以及執行審計和記錄更改歷史等功能。下面,我將詳細解釋如何在SQL中創建觸發器,并附帶示例代碼。
    的頭像 發表于 07-18 16:01 ?2769次閱讀

    節點電壓法自動滿足KCL還是KVL?

    。KVL是描述電路中電壓環路的定律,而基爾霍夫電流定律(Kirchhoff's Current Law,簡稱KCL)則是描述電路中電流節點的定律。節點電壓法自動滿足KVL,但并不自動滿
    的頭像 發表于 07-12 09:23 ?3080次閱讀

    虹科干貨 |?多設備協同無憂:Linux環境下PCAN固定設備ID/通道分配指南

    在車輛網絡系統和工業自動化等多設備環境中,確保設備識別的一致性對于維護系統穩定性至關重要。虹科PCAN適配器提供了一種解決方案,允許用戶在
    的頭像 發表于 06-11 15:03 ?676次閱讀
    虹科干貨 |?多<b class='flag-5'>設備</b>協同無憂:<b class='flag-5'>Linux</b>環境下PCAN固定<b class='flag-5'>設備</b>ID/通道分配指南

    請問ESP Wroom 32板如何在LInux下使用?

    ESP Wroom 32板如何在LInux下使用。 我用的系統是統信UOS,如何使用ESP32板,開發Micropython啊 簡單來說就是在ESP32上刷上micropython固件,然后編寫micropython代碼。 在
    發表于 06-05 06:22
    主站蜘蛛池模板: 3344在线观看永久免费 | 好紧好爽太大了h视频 | 日韩一级欧美一级一级国产 | 扛着高跟鞋丝袜腿呻吟视频 | 婷婷综合久久中文字幕蜜桃三 | 国产全黄三级三级 | 国产精品午夜剧场 | 日本不卡视频在线视频观看 | 四虎影院免费在线 | 五月婷婷在线播放 | 免费播放一区二区三区 | 美女黄网站 | 激情欧美一区二区三区中文字幕 | 免费看吻胸亲嘴激烈网站 | 亚洲 欧洲 日韩 | 色多多视频在线观看 | 国产一区二区丁香婷婷 | 午夜黄色| 色综合久久综合欧美综合图片 | 成人在线视频网 | 日本bbxx| 奇米影视7777 | 在线免费看片a | 国产精品女人在线观看 | 好吊妞视频988在线播放 | 国产女同在线观看 | 男人j桶进女人j的视频 | 丁香花在线影院观看在线播放 | 明日花绮罗snis-862在线播放 | 刺激一区 | 国产精品久久久久久影院 | 亚洲天堂免费在线 | 操插干| 四虎成人免费网站在线 | 拍拍拍无挡视频免费全程1000 | 亚洲香蕉毛片久久网站老妇人 | 男人的天堂免费网站 | 久青草国产手机视频免费观看 | 美女性色| 国产欧美一级片 | free chinese 国产精品 |