• Linux内核模块具有自动创建设备模块的功能(需要应用层支持udev) 使用class_create()创建一个类,这个类可在/sys/class下找到对应目录,再用device_create()在类中创建设备。当模块被加载时udev会在类目录下发现...

    (本章基于:linux-4.4.0-37)

    Linux内核模块具有自动创建设备模块的功能(需要应用层支持udev)


    使用class_create()创建一个类,这个类可在/sys/class下找到对应目录,再用device_create()在类中创建设备。当模块被加载时udev会在类目录下发现此设备,并在/dev下创建相应的设备文件。

    (以下宏、函数均在linux/device.h中定义)


    创建类:
    class_create(owner, name)      

    owner:当前模块
    name:类名称
    返回一个struct class类型指针,返回值需要使用IS_ERR()检查,成功创建后可在/sys/class下找到相应的目录


    销毁类:

    void class_destroy(struct class *cls);


    创建设备节点:

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

    cls:类

    parent:父设备,没有为NULL

    devt:设备号

    drvdata:被添加到该设备回调的数据,不能为NULL

    fmt:设备名


    删除设备节点:

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


    例:

    hello.c

    #include <linux/device.h>
    
    static dev_t devId;
    static struct class *cls = NULL;
    
    static __init int hello_init(void)
    {
            int result;
    
            if(( result = alloc_chrdev_region(&devId, 0, 1, "stone-alloc-dev") ) != 0) {
                    printk(KERN_WARNING "register dev id error:%d\n", result);
                    goto err;
            } else {
                    printk(KERN_WARNING "register dev id success!\n");
            }
    
            cls = class_create(THIS_MODULE, "stone-class");
            if(IS_ERR(cls)) {
                    printk(KERN_WARNING "create class error!\n");
                    goto err;
            }
    
            if(device_create(cls, NULL, devId, "", "hello%d", 0) == NULL) {
                    printk(KERN_WARNING "create device error!\n");
                    goto err;
            }
    
            printk(KERN_ALERT "hello init success!\n");
            return 0;
    
    err:
            device_destroy(cls, devId);
            class_destroy(cls);
            unregister_chrdev_region(devId, 1);
            return -1;
    }
    
    static __exit void hello_exit(void)
    {
            device_destroy(cls, devId);
            class_destroy(cls);
            unregister_chrdev_region(devId, 1);
            printk(KERN_WARNING "helloworld exit!\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Stone");

    成功加载模块后可在/dev/下发现此设备

    # ls /dev/hello0 -l
    crw------- 1 root root 247, 0 Apr 18 21:22 /dev/hello0
    


    展开全文
  • udev的支持主要作用是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...); 内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应...

    udev的支持主要作用是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...);

    内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应 device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

    下面写一个字符设备测试程序:

    #include <linux/module.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <asm/uaccess.h> 
    
    #define HELLO_MAJOR 250
    #define HELLO_MINOR 0
    #define NUMBER_OF_DEVICES 2
    
    struct class *hello_class;
    static struct cdev cdev;
    dev_t devno;
    
    static ssize_t hello_read(struct file *file, char __user *buf, size_t count,
    				loff_t *ppos)
    {
    	char *str = "hello world";
    
    	copy_to_user(buf,str,strlen(str));
    	*(buf + strlen(str)) = '\n';
    	return count;
    }
    
    static ssize_t hello_open(struct inode *inode,struct file *file)
    {
    	return 0; 
    }
    
    static const struct file_operations hello_fops = {
    		.open = hello_open,
    		.read = hello_read,
    	    .owner = THIS_MODULE,
    };
    
    static int __init hello_init(void)
    {
    	int ret;
    	devno = MKDEV(HELLO_MAJOR,HELLO_MINOR);
    
    	if(HELLO_MAJOR){
    		ret = register_chrdev_region(devno,NUMBER_OF_DEVICES,"chrdev");
    	}else{
    		ret = alloc_chrdev_region(&devno, 0, NUMBER_OF_DEVICES, "chrdev");
    	}
    	if(ret < 0){
    		printk("%s register chrdev error\n",__func__);
    		return ret;
    	}
    
    	hello_class = class_create(THIS_MODULE,"hello_char_calss");
    	if(IS_ERR(hello_class)){
    		printk("%s create class error\n",__func__);
    		return -1;
    	}
    
    	device_create(hello_class, NULL, devno, NULL, "chrdev");
    	
    	
    	cdev_init(&cdev, &hello_fops);
    	cdev.owner = THIS_MODULE;
    	cdev_add(&cdev, devno, NUMBER_OF_DEVICES);
    
    	return 0;
    }
    
    
    static void __exit hello_exit(void)
    {
    	printk("%s",__func__);
    	cdev_del(&cdev);
    	device_destroy(hello_class,devno);
    	class_destroy(hello_class);
    	unregister_chrdev_region(devno,NUMBER_OF_DEVICES);
    
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("weed<weed_hz@126.com>");

    Makefile:

    ifeq ($(KERNELRELEASE),)
    #KERNEL_DIR:=/lib/modules/$(shell uname -r)/build/
    KERNEL_DIR:=/usr/src/linux-headers-3.2.0-29-generic-pae
    PWD:=$(shell pwd)
    modules:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
    modules_install:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
    clean:
    rm -rf  .*.cmd *.ko  *.o modules.order  Module.symvers *mod.c
    .PHONY: modules modules_install clean 
    else
    modules-objs := dev.o
    obj-m := dev.o
    endif

    编译模块安装之后会在/sys/class/看到hello_char_class 以及目录内的chrdev,同时也会在/dev下看到udev为我们建立的节点chrdev.

    测试程序:

    #include <stdio.h>
    #include <fcntl.h>
    
    int main(void)
    {
    	int fd;
    	int i;	
    	char buf[50];
    
    	fd = open("/dev/chrdev",O_RDWR);
    	if(fd < 0){
    		printf("can't open dev\n");
    		return -1;
    	}
    
    	read(fd,buf,11);
    	
    	printf("%s",buf);
    
    	return 0;
    }

    测试程序执行后会输出hello world.,

    展开全文
  • Linux设备分成三种基本类型: 字符设备块设备网络设备 设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。 设备节点相当于硬盘的inode一样的东西,立面记录了硬件设备的位置和...

    Linux设备分成三种基本类型:

    1. 字符设备
    2. 块设备
    3. 网络设备

    设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。

    设备节点被创建在/dev 下,是连接内核与用户层的枢纽,就是设备是接到对应哪种接口的哪个 ID 上。 相当于硬盘的inode一样的东西,立面记录了硬件设备的位置和信息

    在Linux中,所有设备都以文件的形式存放在/dev目录下,都是通过文件的方式进行访问,设备节点是Linux内核对设备的抽象,一个设备节点就是一个文件。应用程序通过一组标准化的调用执行访问设备,这些调用独立于任何特定的驱动程序。而驱动程序负责将这些标准调用映射到实际硬件的特有操作。

    设备节点,驱动,硬件设备是如何关联到一起的呢?

    这是通过设备号实现的,包括主设备号和次设备号。当我们创建一个设备节点时需要指定主设备号和次设备号。应用程序通过名称通过名称访问设备,而设备号指定了对应的驱动程序和对应的设备。主设备号标识设备对应的驱动程序,次设备号由内核使用,用于确定设备节点所指设备。

    设备号的分配

    在建立设备前,驱动首先要做的就是获得一个或者多个设备编号。一部分主设备号已经静态分配给了大部分常见设备,在Documentation/devices.txt文件中可以查到设备清单。设备号的分配有两种方式:1)简单选定一个未被使用的编号。调用intregister_chrdev_region(dev_t first, unsigned int count, char *name) 进行静态注册。这种方式选定的主设备号一旦驱动程序被广泛使用,可能造成冲突和麻烦。2)动态申请一个设备号。调用intalloc_chrdev_region(dev_t *dev, unsigned int -firstminor, unsigned int -count, char *name)动态申请,dev是仅用于输出的参数,保存已分配范围的第一个编号。动态分配的主设备不能始终保持一致,需要在调用insmod后从读取proc/devices文件以获取新分配的主设备号,然后再/dev目录中创建设备节点。【注:驱动程序加载后,驱动名称和对应的主设备号会添加到proc/devices文件中】

    不管使用哪种方式分配设备号,都应该在不再使用它们时调用unregister_chrdev_region(dev_t first, unsigned int count)释放这些设备编号。

    设备号的使用

    设备号的使用应该始终使用<linux/kdev_t.h>中定义的宏

    •  获取主次设备号:MAJOR(dev_t dev) 和 MINOR(dev_t dev)
    • 转换成dev_类型:MKDEV(int major,int minor)

     

    创建设备节点

    • 手动创建 

    使用mknode命令。命令格式为mknod name { b | c } Major Minor ,b表示块设备,c表示字符设备。

    • 自动创建

    使用自动创建的前提是用户空间移植了udev。在驱动的初始化代码里调用class_create为该设备创建一个class,再为每个设备调用device_create创建对应的设备。在移除模块时,要调用device_destroy 和class_destroy相应的删除自动创建的设备和类。

    展开全文
  • linux设备节点的理解

    2016-01-08 16:13:38
    linux设备节点是类似于硬盘inode一样的东西

    linux的设备节点

    在linux的驱动学习过程中,经常会碰到设备节点这一概念,什么主设备号,次设备号,可能都是一知半解的,只知道要想用户进程与内核下的硬件进行通信需要建立一个设备节点
    至于这个设备节点到底是怎样的一个存在,也许好多人并不清楚

    设备节点的作用

    设备节点使得用户可以与内核进行硬件的沟通,读写设备以及其他的操作
    在linux里面设备就像是普通文件一样的存在,访问一个设备就好像是访问一个文件一样
    主设备号代表着一类设备,次设备号代表着同一类设备的不同个体,说到这里也许并不知道设备节点的存在形式

    设备节点的存在形式

    另外在linux里面还有一个概念,就是inode与block,也就是硬盘一面的块与节点,硬盘里面的inode就相当于一个文件或者文件夹,它记录下此文件下面的文件位置所在,文件的位置是以block大小对齐的,例如有些系统就是4K的大小,而inode的大小是有限的,所以就有了单个文件不能超过4G的说法。而在linux的驱动程序里面的节点在我个人的理解也可以看做是一个类似于硬盘的inode一样的东西,里面可以记录硬件设备的位置以及别的一些信息,在用户需要进行访问的时候就参照到设备节点所记录的信息进行设备的访问
    展开全文
  • Linux设备分成三种基本类型: 字符设备块设备网络设备 设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。 在Linux中,所有设备都以文件的形式存放在/dev目录下,都是通过文件的...

    Linux设备分成三种基本类型:

    1. 字符设备
    2. 块设备
    3. 网络设备

    设备驱动程序也分为对应的三类:字符设备驱动程序、块设备驱动程序和网络设备驱动程序。

    在Linux中,所有设备都以文件的形式存放在/dev目录下,都是通过文件的方式进行访问,设备节点是Linux内核对设备的抽象,一个设备节点就是一个文件。应用程序通过一组标准化的调用执行访问设备,这些调用独立于任何特定的驱动程序。而驱动程序负责将这些标准调用映射到实际硬件的特有操作。

    设备节点,驱动,硬件设备是如何关联到一起的呢?

    这是通过设备号实现的,包括主设备号和次设备号。当我们创建一个设备节点时需要指定主设备号和次设备号。应用程序通过名称通过名称访问设备,而设备号指定了对应的驱动程序和对应的设备。主设备号标识设备对应的驱动程序,次设备号由内核使用,用于确定设备节点所指设备。

    设备号的分配

    在建立设备前,驱动首先要做的就是获得一个或者多个设备编号。一部分主设备号已经静态分配给了大部分常见设备,在Documentation/devices.txt文件中可以查到设备清单。设备号的分配有两种方式:1)简单选定一个未被使用的编号。调用intregister_chrdev_region(dev_t first, unsigned int count, char *name) 进行静态注册。这种方式选定的主设备号一旦驱动程序被广泛使用,可能造成冲突和麻烦。2)动态申请一个设备号。调用intalloc_chrdev_region(dev_t *dev, unsigned int -firstminor, unsigned int -count, char *name)动态申请,dev是仅用于输出的参数,保存已分配范围的第一个编号。动态分配的主设备不能始终保持一致,需要在调用insmod后从读取proc/devices文件以获取新分配的主设备号,然后再/dev目录中创建设备节点。【注:驱动程序加载后,驱动名称和对应的主设备号会添加到proc/devices文件中】

    不管使用哪种方式分配设备号,都应该在不再使用它们时调用unregister_chrdev_region(dev_t first, unsigned int count)释放这些设备编号。

    设备号的使用

    设备号的使用应该始终使用<linux/kdev_t.h>中定义的宏

    •  获取主次设备号:MAJOR(dev_t dev) 和 MINOR(dev_t dev)
    • 转换成dev_类型:MKDEV(int major,int minor)

     

    创建设备节点

    • 手动创建 

    使用mknode命令。命令格式为mknod name { b | c } Major Minor ,b表示块设备,c表示字符设备。

    • 自动创建

    使用自动创建的前提是用户空间移植了udev。在驱动的初始化代码里调用class_create为该设备创建一个class,再为每个设备调用device_create创建对应的设备。在移除模块时,要调用device_destroy 和class_destroy相应的删除自动创建的设备和类。

     


     

    展开全文
  • 在加载驱动模块后,就要自己使用mknod创建设备节点,这样虽然是可行的,但是比较麻烦。我们可以在__init()函数里面添加一些函数,自动创建设备节点。创建设备节点使用了两个函数 class_create()和device_create(),...
  • 一、手动创建 1.驱动模块 test_driver.c #include #include #include #include #include #include #include #define TEST_MAJOR 240 ...//动态设备节点 //struct class *mymodule_class; //结束 static i
  • linux设备节点

    2015-03-01 23:01:38
    设备节点的表示方法linux下的设备节点linux 2.6 内核中用32位值来表示,包含主设备号和从设备号。 主设备号码用到了32位中的12位,而剩下的20位作为从设备号。 root权限用户用以下命令创建设备结点:$mknod /dev...
  • 最近在学习Android下的LCD模块,在编写新需求时,要求底层提供节点给上层调用,这里我总结的三种Linux下如何创建设备节点的方法,而创建设备节点调用的函数都是Linux内核里面提供的函数接口,我们只需要调用这些函数...
  • Linux设备节点创建》手动与自动创建设备节点 本节是对上处链接的进一步研究。 一、Linux2.4之前手动mknod 驱动编写: static int __init test_drv_init(void) {  int rc;  printk("test_driver dev\n");  //...
  • struct device_attribute nable_attribute = __ATTR(enable,0664,enable_show,_enable_...以如上方式创建设备节点,开机后也没报错,怎么在设备里找到这个enable节点呢?网上写的在dev设备目录下,也没有看到这个enable
  • 在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点。...
  • 在宋宝华《Linux设备驱动开发详解》中我们能找到如下描述: devfs与udev的另一个显著区别在于:采用devfs,当一个并不存在的/dev节点被打开的时候,devfs能自动加载对应的驱动,而udev则不能。这是因为 udev的设计者...
  • 上一节中,我们是手工创建设备节点,大家肯定也会觉得这样做太麻烦了。...答:可以,linux有udev、mdev的机制,而我们的ARM开发板上移植的busybox有mdev机制,那么就使用mdev机制来自动创建设备节点。 问:
  • 通常我们在linux下看到的控制台(console)是由几个设备完成的。分别是/dev/ttyN(其中tty0就是/dev /console,tty1,tty2就是不同的虚拟终端(virtual console)).通常使用热键alt+Fn来在这些虚拟终端之间进行切换...
  • 上一篇我们介绍到创建设备文件的方法,...第二种是自动创建设备节点:利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。在驱动初始化代码里调用class_create为该设备创建一个
  • 1.设备 Linux下的设备通常分为三类,字符设备,块设备和网络设备。...在Linux里一个网络设备也可以叫做一个网络接口,如eth0,应用程序是通过Socket而不是设备节点来访问网络设备,在系统里根本就不存在网络...
  • linux中在/dev/下手动创建设备节点 /dev/目录下有许多设备节点文件,比如u盘的文件/dev/sda,mmc卡的文件/dev/mmcblk0,这些文件通常是由udev或mdev程序检测到uevent事件后自动创建的。我们也可以通过mknod命令手动...
  • !!   1. Linux下USB设备节点名不...以USB转串口设备为例,通常设备节点名为ttyUSBx(x为0~n),Linux内核会根据设备插入的先后顺序进行编号的分配,比如第一个插入的设备编号为ttyUSB0,然后依此加1,变为tty...
  • Linux驱动学习,手动创建设备节点并访问
1 2 3 4 5 ... 20
收藏数 55,090
精华内容 22,036
关键字:

linux 设备节点建立