日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 字符设备驱动结构(二)—— 自动创建设备节点

發(fā)布時間:2023/12/9 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 字符设备驱动结构(二)—— 自动创建设备节点 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇我們介紹到創(chuàng)建設備文件的方法,利用cat /proc/devices查看申請到的設備名,設備號。

第一種是使用mknod手工創(chuàng)建:mknod filename type major minor

第二種是自動創(chuàng)建設備節(jié)點:利用udev(mdev)來實現設備文件的自動創(chuàng)建,首先應保證支持udev(mdev),由busybox配置。

? ? ? 具體udev相關知識這里不詳細闡述,可以移步Linux 文件系統(tǒng)與設備文件系統(tǒng) —— udev 設備文件系統(tǒng),這里主要講使用方法。

? ? ?

? ? 在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼里調用class_create(...)為該設備創(chuàng)建一個class,再為每個設備調用device_create(...)創(chuàng)建對應的設備

? ? 內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創(chuàng)建一個類,這個類存放于sysfs下面,一旦創(chuàng)建好了這個類,再調用 device_create(…)函數來在/dev目錄下創(chuàng)建相應的設備節(jié)點。

? ? ?這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創(chuàng)建設備節(jié)點。


下面是兩個函數的解析:

1、class_create(...) 函數

功能:創(chuàng)建一個類;

下面是具體定義:

[cpp]?view plaincopy
  • #define?class_create(owner,?name)???????\??
  • ({??????????????????????\??
  • ????static?struct?lock_class_key?__key;?\??
  • ????__class_create(owner,?name,?&__key);????\??
  • })??
  • owner:THIS_MODULE
    name ?: 名字

    __class_create(owner, name, &__key)源代碼如下:

    [cpp]?view plaincopy
  • struct?class?*__class_create(struct?module?*owner,?const?char?*name,??
  • ?????????????????struct?lock_class_key?*key)??
  • {??
  • ????struct?class?*cls;??
  • ????int?retval;??
  • ??
  • ????cls?=?kzalloc(sizeof(*cls),?GFP_KERNEL);??
  • ????if?(!cls)?{??
  • ????????retval?=?-ENOMEM;??
  • ????????goto?error;??
  • ????}??
  • ??
  • ????cls->name?=?name;??
  • ????cls->owner?=?owner;??
  • ????cls->class_release?=?class_create_release;??
  • ??
  • ????retval?=?__class_register(cls,?key);??
  • ????if?(retval)??
  • ????????goto?error;??
  • ??
  • ????return?cls;??
  • ??
  • error:??
  • ????kfree(cls);??
  • ????return?ERR_PTR(retval);??
  • }??
  • EXPORT_SYMBOL_GPL(__class_create);??
  • 銷毀函數:void class_destroy(struct class *cls)

    [cpp]?view plaincopy
  • void?class_destroy(struct?class?*cls)??
  • {??
  • ????if?((cls?==?NULL)?||?(IS_ERR(cls)))??
  • ????????return;??
  • ??
  • ????class_unregister(cls);??
  • }??


  • 2、device_create(...) 函數

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

    功能:創(chuàng)建一個字符設備文件

    參數:

    ? ? ? struct class *class ?:類
    ? ? ? struct device *parent:NULL
    ? ? ?dev_t devt ?:設備號
    ? ? ?void *drvdata ?:null、
    ? ? ?const char *fmt ?:名字

    返回:

    ? ??struct device *

    下面是源碼解析:

    [cpp]?view plaincopy
  • struct?device?*device_create(struct?class?*class,?struct?device?*parent,??
  • ?????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,?...)??
  • {??
  • ????va_list?vargs;??
  • ????struct?device?*dev;??
  • ??
  • ????va_start(vargs,?fmt);??
  • ????dev?=?device_create_vargs(class,?parent,?devt,?drvdata,?fmt,?vargs);??
  • ????va_end(vargs);??
  • ????return?dev;??
  • }??
  • device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:

    [cpp]?view plaincopy
  • struct?device?*device_create_vargs(struct?class?*class,?struct?device?*parent,??
  • ???????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,??
  • ???????????????????va_list?args)??
  • {??
  • ????return?device_create_groups_vargs(class,?parent,?devt,?drvdata,?NULL,??
  • ??????????????????????fmt,?args);??
  • }??
  • 現在就不繼續(xù)往下跟了,大家可以繼續(xù)往下跟;


    下面是一個實例:

    hello.c

    [cpp]?view plaincopy
  • #include?<linux/module.h>??
  • #include?<linux/fs.h>??
  • #include?<linux/cdev.h>??
  • #include?<linux/device.h>??
  • ??
  • static?int?major?=?250;??
  • static?int?minor=0;??
  • static?dev_t?devno;??
  • static?struct?class?*cls;??
  • static?struct?device?*test_device;??
  • ??
  • static?int?hello_open?(struct?inode?*inode,?struct?file?*filep)??
  • {??
  • ????printk("hello_open?\n");??
  • ????return?0;??
  • }??
  • static?struct?file_operations?hello_ops=??
  • {??
  • ????.open?=?hello_open,??
  • };??
  • ??
  • static?int?hello_init(void)??
  • {??
  • ????int?ret;??????
  • ????printk("hello_init?\n");??
  • ??
  • ??
  • ????devno?=?MKDEV(major,minor);??
  • ????ret?=?register_chrdev(major,"hello",&hello_ops);??
  • ??
  • ????cls?=?class_create(THIS_MODULE,?"myclass");??
  • ????if(IS_ERR(cls))??
  • ????{??
  • ????????unregister_chrdev(major,"hello");??
  • ????????return?-EBUSY;??
  • ????}??
  • ????test_device?=?device_create(cls,NULL,devno,NULL,"hello");//mknod?/dev/hello??
  • ????if(IS_ERR(test_device))??
  • ????{??
  • ????????class_destroy(cls);??
  • ????????unregister_chrdev(major,"hello");??
  • ????????return?-EBUSY;??
  • ????}?????
  • ????return?0;??
  • }??
  • static?void?hello_exit(void)??
  • {??
  • ????device_destroy(cls,devno);??
  • ????class_destroy(cls);???
  • ????unregister_chrdev(major,"hello");??
  • ????printk("hello_exit?\n");??
  • }??
  • MODULE_LICENSE("GPL");??
  • module_init(hello_init);??
  • module_exit(hello_exit);??
  • test.c

    [cpp]?view plaincopy
  • #include?<sys/types.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<stdio.h>??
  • ??
  • ??
  • main()??
  • {??
  • ????int?fd;??
  • ??
  • ??
  • ????fd?=?open("/dev/hello",O_RDWR);??
  • ????if(fd<0)??
  • ????{??
  • ????????perror("open?fail?\n");??
  • ????????return?;??
  • ????}??
  • ??
  • ??
  • ????close(fd);??
  • }??
  • makefile

    [cpp]?view plaincopy
  • ifneq??($(KERNELRELEASE),)??
  • obj-m:=hello.o??
  • $(info?"2nd")??
  • else??
  • KDIR?:=?/lib/modules/$(shell?uname?-r)/build??
  • PWD:=$(shell?pwd)??
  • all:??
  • ????$(info?"1st")??
  • ????make?-C?$(KDIR)?M=$(PWD)?modules??
  • clean:??
  • ????rm?-f?*.ko?*.o?*.symvers?*.mod.c?*.mod.o?*.order??
  • endif??

  • 下面可以看幾個class幾個名字的對應關系:




    上一篇我們介紹到創(chuàng)建設備文件的方法,利用cat /proc/devices查看申請到的設備名,設備號。

    第一種是使用mknod手工創(chuàng)建:mknod filename type major minor

    第二種是自動創(chuàng)建設備節(jié)點:利用udev(mdev)來實現設備文件的自動創(chuàng)建,首先應保證支持udev(mdev),由busybox配置。

    ? ? ? 具體udev相關知識這里不詳細闡述,可以移步Linux 文件系統(tǒng)與設備文件系統(tǒng) —— udev 設備文件系統(tǒng),這里主要講使用方法。

    ? ? ?

    ? ? 在驅動用加入對udev 的支持主要做的就是:在驅動初始化的代碼里調用class_create(...)為該設備創(chuàng)建一個class,再為每個設備調用device_create(...)創(chuàng)建對應的設備

    ? ? 內核中定義的struct class結構體,顧名思義,一個struct class結構體類型變量對應一個類,內核同時提供了class_create(…)函數,可以用它來創(chuàng)建一個類,這個類存放于sysfs下面,一旦創(chuàng)建好了這個類,再調用 device_create(…)函數來在/dev目錄下創(chuàng)建相應的設備節(jié)點。

    ? ? ?這樣,加載模塊的時候,用戶空間中的udev會自動響應 device_create()函數,去/sysfs下尋找對應的類從而創(chuàng)建設備節(jié)點。


    下面是兩個函數的解析:

    1、class_create(...) 函數

    功能:創(chuàng)建一個類;

    下面是具體定義:

    [cpp]?view plaincopy
  • #define?class_create(owner,?name)???????\??
  • ({??????????????????????\??
  • ????static?struct?lock_class_key?__key;?\??
  • ????__class_create(owner,?name,?&__key);????\??
  • })??
  • owner:THIS_MODULE
    name ?: 名字

    __class_create(owner, name, &__key)源代碼如下:

    [cpp]?view plaincopy
  • struct?class?*__class_create(struct?module?*owner,?const?char?*name,??
  • ?????????????????struct?lock_class_key?*key)??
  • {??
  • ????struct?class?*cls;??
  • ????int?retval;??
  • ??
  • ????cls?=?kzalloc(sizeof(*cls),?GFP_KERNEL);??
  • ????if?(!cls)?{??
  • ????????retval?=?-ENOMEM;??
  • ????????goto?error;??
  • ????}??
  • ??
  • ????cls->name?=?name;??
  • ????cls->owner?=?owner;??
  • ????cls->class_release?=?class_create_release;??
  • ??
  • ????retval?=?__class_register(cls,?key);??
  • ????if?(retval)??
  • ????????goto?error;??
  • ??
  • ????return?cls;??
  • ??
  • error:??
  • ????kfree(cls);??
  • ????return?ERR_PTR(retval);??
  • }??
  • EXPORT_SYMBOL_GPL(__class_create);??
  • 銷毀函數:void class_destroy(struct class *cls)

    [cpp]?view plaincopy
  • void?class_destroy(struct?class?*cls)??
  • {??
  • ????if?((cls?==?NULL)?||?(IS_ERR(cls)))??
  • ????????return;??
  • ??
  • ????class_unregister(cls);??
  • }??


  • 2、device_create(...) 函數

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

    功能:創(chuàng)建一個字符設備文件

    參數:

    ? ? ? struct class *class ?:類
    ? ? ? struct device *parent:NULL
    ? ? ?dev_t devt ?:設備號
    ? ? ?void *drvdata ?:null、
    ? ? ?const char *fmt ?:名字

    返回:

    ? ??struct device *

    下面是源碼解析:

    [cpp]?view plaincopy
  • struct?device?*device_create(struct?class?*class,?struct?device?*parent,??
  • ?????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,?...)??
  • {??
  • ????va_list?vargs;??
  • ????struct?device?*dev;??
  • ??
  • ????va_start(vargs,?fmt);??
  • ????dev?=?device_create_vargs(class,?parent,?devt,?drvdata,?fmt,?vargs);??
  • ????va_end(vargs);??
  • ????return?dev;??
  • }??
  • device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:

    [cpp]?view plaincopy
  • struct?device?*device_create_vargs(struct?class?*class,?struct?device?*parent,??
  • ???????????????????dev_t?devt,?void?*drvdata,?const?char?*fmt,??
  • ???????????????????va_list?args)??
  • {??
  • ????return?device_create_groups_vargs(class,?parent,?devt,?drvdata,?NULL,??
  • ??????????????????????fmt,?args);??
  • }??
  • 現在就不繼續(xù)往下跟了,大家可以繼續(xù)往下跟;


    下面是一個實例:

    hello.c

    [cpp]?view plaincopy
  • #include?<linux/module.h>??
  • #include?<linux/fs.h>??
  • #include?<linux/cdev.h>??
  • #include?<linux/device.h>??
  • ??
  • static?int?major?=?250;??
  • static?int?minor=0;??
  • static?dev_t?devno;??
  • static?struct?class?*cls;??
  • static?struct?device?*test_device;??
  • ??
  • static?int?hello_open?(struct?inode?*inode,?struct?file?*filep)??
  • {??
  • ????printk("hello_open?\n");??
  • ????return?0;??
  • }??
  • static?struct?file_operations?hello_ops=??
  • {??
  • ????.open?=?hello_open,??
  • };??
  • ??
  • static?int?hello_init(void)??
  • {??
  • ????int?ret;??????
  • ????printk("hello_init?\n");??
  • ??
  • ??
  • ????devno?=?MKDEV(major,minor);??
  • ????ret?=?register_chrdev(major,"hello",&hello_ops);??
  • ??
  • ????cls?=?class_create(THIS_MODULE,?"myclass");??
  • ????if(IS_ERR(cls))??
  • ????{??
  • ????????unregister_chrdev(major,"hello");??
  • ????????return?-EBUSY;??
  • ????}??
  • ????test_device?=?device_create(cls,NULL,devno,NULL,"hello");//mknod?/dev/hello??
  • ????if(IS_ERR(test_device))??
  • ????{??
  • ????????class_destroy(cls);??
  • ????????unregister_chrdev(major,"hello");??
  • ????????return?-EBUSY;??
  • ????}?????
  • ????return?0;??
  • }??
  • static?void?hello_exit(void)??
  • {??
  • ????device_destroy(cls,devno);??
  • ????class_destroy(cls);???
  • ????unregister_chrdev(major,"hello");??
  • ????printk("hello_exit?\n");??
  • }??
  • MODULE_LICENSE("GPL");??
  • module_init(hello_init);??
  • module_exit(hello_exit);??
  • test.c

    [cpp]?view plaincopy
  • #include?<sys/types.h>??
  • #include?<sys/stat.h>??
  • #include?<fcntl.h>??
  • #include?<stdio.h>??
  • ??
  • ??
  • main()??
  • {??
  • ????int?fd;??
  • ??
  • ??
  • ????fd?=?open("/dev/hello",O_RDWR);??
  • ????if(fd<0)??
  • ????{??
  • ????????perror("open?fail?\n");??
  • ????????return?;??
  • ????}??
  • ??
  • ??
  • ????close(fd);??
  • }??
  • makefile

    [cpp]?view plaincopy
  • ifneq??($(KERNELRELEASE),)??
  • obj-m:=hello.o??
  • $(info?"2nd")??
  • else??
  • KDIR?:=?/lib/modules/$(shell?uname?-r)/build??
  • PWD:=$(shell?pwd)??
  • all:??
  • ????$(info?"1st")??
  • ????make?-C?$(KDIR)?M=$(PWD)?modules??
  • clean:??
  • ????rm?-f?*.ko?*.o?*.symvers?*.mod.c?*.mod.o?*.order??
  • endif??

  • 下面可以看幾個class幾個名字的對應關系:




    總結

    以上是生活随笔為你收集整理的Linux 字符设备驱动结构(二)—— 自动创建设备节点的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。