精华内容
下载资源
问答
  • linux用户空间和kernel...现在介绍3种驱动生成文件节点的方法:1、在/dev下面创建节点2、在/proc下面创建节点上图中建的节点是/proc/onekey_recovery/last_pressed,如果不用proc_mkdir而只用proc_create的话,则...

    linux用户空间和kernel空间是分开,所以上层需要和某个模块驱动交流的时候,就需要驱动来创建一个文件节点,当然input设备除外,已有非常成熟的上报流程。现在介绍3种驱动生成文件节点的方法:

    1、在/dev下面创建节点


    2、在/proc下面创建节点



    上图中建的节点是/proc/onekey_recovery/last_pressed,如果不用proc_mkdir而只用proc_create的话,则生成的节点是/proc/last_pressed

    3、在/sys下面创建节点

    重点参考md_gpiox_write,md_gpiox_read,DEVICE_ATTR,device_create_file,这里生成的节点在/sys/devices/...

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/interrupt.h>
    #include <linux/platform_device.h>
    #include <linux/slab.h>
    #include <linux/switch.h>
    #include <linux/workqueue.h>
    #include <linux/gpio.h>
    #include <linux/fs.h>
    #include <linux/sysfs.h>
    #include <linux/seq_file.h>
    #include <linux/proc_fs.h>
    #include <asm/uaccess.h>
    #ifdef CONFIG_OF
    #include <linux/of_irq.h>
    #include <linux/of_address.h>
    #endif
    #include <linux/delay.h>
    //#include <linux/kthread.h>
    //#include <linux/reboot.h>
    
    #define USE_INTERRUPT 1
    
    #define D1_RST_PIN 84
    struct md_gpio_eint_data {
    	struct switch_dev sdev84;
    	unsigned gpio84; //alarm输入
    	const char *state_on;
    	const char *state_off;
    	int irq84;
    	struct work_struct work84;
    #ifdef CONFIG_OF
    	struct device_node *irq_node84;
    #endif
    };
    static char last_pressed =0;
    
    #ifdef USE_INTERRUPT
    static void md_gpio_eint_work84(struct work_struct *work)
    {
    	int state;
    	struct md_gpio_eint_data	*data =
    		container_of(work, struct md_gpio_eint_data, work84);
    
    	msleep(3000);	//3s
    
    	state = gpio_get_value(data->gpio84);
    	pr_err("%s: state=%d\n", __FUNCTION__, state);
    	switch_set_state(&data->sdev84, state);
    
    	/*
    	if(state)
    		irq_set_irq_type(data->irq84, IRQF_TRIGGER_LOW);
    	else
    		irq_set_irq_type(data->irq84, IRQF_TRIGGER_HIGH);
    	 */
    
    	enable_irq(data->irq84);
    }
    
    static irqreturn_t gpio_irq_handler84(int irq, void *dev_id)
    {
    	struct md_gpio_eint_data *switch_data =
    	    (struct md_gpio_eint_data *)dev_id;
    	
    	disable_irq_nosync(switch_data->irq84);
    	printk(KERN_ERR "vision_d:RST-KEY work84 irq handler \n");
    	last_pressed =1;
    	schedule_work(&switch_data->work84);
    	return IRQ_HANDLED;
    }
    
    #endif
    /*
    static int d1_reset_thread(void *x)
    {
    	int gpio84;
    	msleep(2000);		//2s
    
    	do{
    		//printk("vision_d:%s \n",__func__);
    		gpio84 = gpio_get_value(D1_RST_PIN);
    		if(gpio84 ==0){
    			msleep(2000);	//2s
    			gpio84 = gpio_get_value(D1_RST_PIN);
    			if(gpio84 ==0)
    				kernel_restart(NULL);
    		}else
    			msleep(100);	//100ms
    	}while (!kthread_should_stop());
    	
    	return 0;
    }
    */
    static int rgpio = -1;
    static ssize_t md_gpiox_write(struct device *dev, struct device_attribute *attr, char *buffer, size_t count)
    {
    	int ret;
    	int gpio_num = -1;
    	int gpio_val = -1;
    	int value;
    	int n =0;
    	
    	ret = sscanf(buffer, "%d", &value);
    	if(!ret) {
    		pr_err("%s: intput error!\n", __FUNCTION__);
    		return -1;
    	}
    	gpio_num = value;
    	//printk(KERN_ERR "vision_d %s: gpio num %d\n", __FUNCTION__, gpio_num);
    	while(value)
    	{
    		value = value / 10;
    		n++;
    	}
    	buffer +=n;	
    	if(*buffer ==32){
    		ret = sscanf(buffer, "%d", &value);
    		if(!ret) {
    			pr_err("%s: intput error!\n", __FUNCTION__);
    			return -1;
    		}
    		gpio_val = value;	
    		//printk(KERN_ERR "vision_d %s: gpio set value %d\n", __FUNCTION__, gpio_val);
    	}
    	printk(KERN_ERR "vision_d %s:set gpio%d  %d\n", __FUNCTION__, gpio_num,gpio_val);
    	
    	if(gpio_val ==0)
    		gpio_set_value(gpio_num, 0);
    	else if(gpio_val ==1)
    		gpio_set_value(gpio_num, 1);
    	else
    		rgpio = gpio_num;
    	
    	//gpio_free(gpio);
    		
    	return count;
    
    }
    
    static ssize_t md_gpiox_read(struct device *dev, struct device_attribute *attr, char *buffer)
    {
    	if(rgpio > 0)
    		return snprintf(buffer,PAGE_SIZE,"gpio%d=%d\n",rgpio,gpio_get_value(rgpio));
    	else
    		return -1;
    }
    static DEVICE_ATTR(pinctl, S_IWUSR | S_IRUGO, md_gpiox_read, md_gpiox_write);
    
    static ssize_t rst_key_status_r(struct device *dev, struct device_attribute *attr, char *buff)
    {
    	return snprintf(buff,PAGE_SIZE,"%d\n",last_pressed);
    }
    static ssize_t rst_key_status_w(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
    {
    	last_pressed =0;
    	return count;
    }
    
    static DEVICE_ATTR(RstKeyStatus, S_IWUSR | S_IRUGO, rst_key_status_r, rst_key_status_w);
    
    static int md_gpio_eint_probe(struct platform_device *pdev)
    {
    	struct md_gpio_eint_data *switch_data;
    	int ret = 0;
    #if defined(CONFIG_OF)
    	u32 ints[2] = { 0, 0 };
    #endif
    
    	ret = device_create_file(&pdev->dev,&dev_attr_RstKeyStatus);
    	if(ret)
    		printk(KERN_ERR "vision_d:create attr failed \n");
    	ret = device_create_file(&pdev->dev,&dev_attr_pinctl);
    	if(ret)
    		printk(KERN_ERR "vision_d:create attr failed \n");
    	
    	pr_err("%s: start!\n", __FUNCTION__);
    	switch_data = kzalloc(sizeof(struct md_gpio_eint_data), GFP_KERNEL);
    	if (!switch_data) {
    		pr_err("%s: kzalloc error!\n", __FUNCTION__);
    		return -ENOMEM;
    	}
    	
    	platform_set_drvdata(pdev, switch_data);
    
    	switch_data->sdev84.name = "onekey_recovery"; //gpio84
    	
    	switch_data->sdev84.index = 0;
    	switch_data->sdev84.state = 0;
    	
    	switch_data->gpio84 = D1_RST_PIN; 
    	switch_data->state_on = "on";
    	switch_data->state_off = "off";
    
    	ret = switch_dev_register(&switch_data->sdev84);
    	if (ret < 0) {
    		pr_err("%s: fail to register sdev84!\n", __FUNCTION__);
    		goto err_switch_dev_register;
    	}
    	
    	ret = gpio_request(switch_data->gpio84, "gpio84");
    	if (ret < 0) {
    		pr_err("%s: fail gpio_request 84!\n", __FUNCTION__);
    		goto err_request_gpio;
    	}
    
    /*	ret = gpio_request(D1_RST_PIN, "gpio84");
    	if (ret < 0) {
    		pr_err("%s: fail gpio_request 84!\n", __FUNCTION__);
    		goto err_request_gpio;
    	}
    */
    	ret = gpio_direction_input(switch_data->gpio84);
    	if (ret < 0) {
    		pr_err("%s: fail gpio_direction_input 84!\n", __FUNCTION__);
    		goto err_set_gpio_input;
    	}
    	gpio_set_debounce(switch_data->gpio84, 100);
    /*	
    	ret = gpio_direction_input(D1_RST_PIN);
    	if (ret < 0) {
    		pr_err("%s: fail gpio_direction_input 84!\n", __FUNCTION__);
    		goto err_set_gpio_input;
    	}
    	gpio_set_debounce(D1_RST_PIN, 100);
    */
    #ifdef USE_INTERRUPT
    	INIT_WORK(&switch_data->work84, md_gpio_eint_work84);
    #ifdef CONFIG_OF
    	printk(KERN_ERR "vision_d:md_gpio_eint find node from dts \n");
    	switch_data->irq_node84 = of_find_compatible_node(NULL, NULL, "mediatek, gpio84-eint");
    	if(switch_data->irq_node84)
    		switch_data->irq84 = irq_of_parse_and_map(switch_data->irq_node84, 0);
    #else
    	switch_data->irq84 = gpio_to_irq(switch_data->gpio84);
    	if (switch_data->irq84 < 0) {
    		pr_err("%s: fail gpio_to_irq 84!\n", __FUNCTION__);
    		ret = switch_data->irq84;
    		goto err_detect_irq_num_failed;
    	}
    	
    #endif
    	ret = request_irq(switch_data->irq84, gpio_irq_handler84,
    			  IRQF_TRIGGER_LOW |IRQF_ONESHOT, "gpio84_eint", switch_data);
    	if (ret < 0) {
    		pr_err("%s: fail request_irq 84!\n", __FUNCTION__);
    		goto err_request_irq;
    	}
    	//irq_set_irq_type(switch_data->irq84, IRQF_TRIGGER_LOW |IRQF_ONESHOT);
    	
    #endif
    //#ifndef USE_INTERRUPT
    //	kthread_run(d1_reset_thread, NULL, "d1_reset_thread");
    //#endif
    	switch_set_state(&switch_data->sdev84, 1);	//init state status
    	pr_err("%s: ok\n", __FUNCTION__);
    	return 0;
    
    err_request_irq:
    err_detect_irq_num_failed:
    err_set_gpio_input:
    	gpio_free(switch_data->gpio84);
    	//gpio_free(D1_RST_PIN);
    err_request_gpio:
    	switch_dev_unregister(&switch_data->sdev84);
    err_switch_dev_register:
    	kfree(switch_data);
    	
    	pr_err("%s: fail, ret=%d\n", __FUNCTION__, ret);
    	return ret;
    }
    
    static int md_gpio_eint_remove(struct platform_device *pdev)
    {
    	struct md_gpio_eint_data *switch_data = platform_get_drvdata(pdev);
    
    	//cancel_work_sync(&switch_data->work84);
    	gpio_free(switch_data->gpio84);
    	switch_dev_unregister(&switch_data->sdev84);
    	
    	kfree(switch_data);
    
    	return 0;
    }
    
    
    static const struct of_device_id md_gpio_eint_ids[] = {
    	{.compatible = "mediatek,md_gpio_eint",},
    	{},
    };
    static struct platform_driver md_gpio_eint_driver = {
    	.probe		= md_gpio_eint_probe,
    	.remove		= md_gpio_eint_remove,
    	.driver		= {
    		.name	= "md-gpio-eint",
    		.owner	= THIS_MODULE,
    #ifdef CONFIG_OF
    		.of_match_table = md_gpio_eint_ids,
    #endif
    	},
    };
    
    static int __init md_gpio_eint_init(void)
    {
    	pr_err("%s: start!\n", __FUNCTION__);
    	return platform_driver_register(&md_gpio_eint_driver);
    }
    
    static void __exit md_gpio_eint_exit(void)
    {
    	platform_driver_unregister(&md_gpio_eint_driver);
    }
    
    module_init(md_gpio_eint_init);
    module_exit(md_gpio_eint_exit);
    
    MODULE_AUTHOR("deli.sun <8434149@qq.com>");
    MODULE_DESCRIPTION("md gpio eint driver");
    MODULE_LICENSE("GPL");
    

    上述三种方法,第一种和第二种方法使用时一般流程就是open、read/write、ioctl等,第三种方法则可以通过echo/cat命令来读写。另外以上方法具体实现时可以在kernel目录下grep相关关键字,看看手中原代码是如何实现的,必须能搜到大量的使用例程的。

    展开全文
  • 如何在驱动中自动生成设备文件节点? 一、自动生成设备文件的必要性     在我们初学驱动开发的时候,我们的设备文件需要我们在知道设备号之后,使用命令 “mknod c|b dev_name major minor” 来生成,这样的...

    linux驱动中如何自动生成设备文件节点?


    一、自动生成设备文件的必要性

        在我们初学驱动开发的时候,我们的设备文件需要我们在知道设备号之后,使用命令 “mknod c|b dev_name major minor” 来生成,这样的设备文件生成方法在实际项目中显然是不行的,当驱动程序过多的时候,我们很难有精力来管理这么多的设备文件。因此,在驱动中,使得设备文件能够自动生成非常有必要。下面,将介绍在两种不同目录下生成设备文件的方法。

    二、如何自动生成设备文件节点

    1. mdev机制

        udev 是一个用户程序,在 Linux 下通过 udev 来实现设备文件的创建与删除,udev 可以检测系统中硬件设备状态,可以根据系统中硬件设备状态来创建或者删除设备文件。比如使用insmod或modprobe 命令成功加载驱动模块以后就自动在/dev 目录下创建对应的设备节点文件,使用rmmod 命令卸载驱动模块以后就删除掉/dev 目录下的设备节点文件。使用 busybox 构建根文件系统的时候,busybox 会创建一个 udev的简化版本—mdev,所以在嵌入式 Linux 中我们使用mdev 来实现设备节点文件的自动创建与删除,Linux 系统的热插拔事件也由 mdev 管理,在/etc/init.d/rcS 文件中如下语句:

    echo /sbin/mdev > /proc/sys/kernel/hotplug
    

        上述命令设置热插拔事件由 mdev 来管理,关于 udev 或 mdev 更加详细的工作原理这里就不详细探讨了,我们重点来学习一下如何通过 mdev 来实现设备文件节点的自动创建与删除。

    2. 在/dev下生成设备文件节点
    2.1 创建和删除类

        自动创建设备节点的工作是在驱动程序的入口函数中完成的,一般在 cdev_add 函数后面添加自动创建设备节点相关代码。首先要创建一个 class 类,class 是个结构体,定义在文件include/linux/device.h 里面。class_create 是类创建函数,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 展开以后内容如下:

    struct class *class_create (struct module *owner, const char *name)
    

        class_create 一共有两个参数,参数 owner 一般为 THIS_MODULE,参数 name 是类名字。返回值是个指向结构体 class 的指针,也就是创建的类。
        卸载驱动程序的时候需要删除掉类,类删除函数为 class_destroy,函数原型如下:

    void class_destroy(struct class *cls);
    

        参数 cls 就是要删除的类。

    2.2 创建和删除设备

        一小节创建好类以后还不能实现自动创建设备节点,我们还需要在这个类下创建一个设备。使用 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 是要删除的设备号。

    2.3 参考示例
    struct user_dev_t {
    	struct class *class; /* 类 */
    	struct device *device; /* 设备 */
        dev_t devid;
    };
    struct user_dev_t user_dev;
    
    #define DEV_CLASS_NAME "yyy"
    #define DEV_NAME	"xxx"
    
    /* 驱动入口函数 */
    static int __init xxx_init(void)
    {
    	/* 创建类 */
    	user_dev.class = class_create(THIS_MODULE, DEV_CLASS_NAME);
    	/* 创建设备 */
    	user_dev.device = device_create(user_dev.class, NULL, user_dev.devid, NULL, DEV_NAME);
    	return 0;
    }
    
    /* 驱动出口函数 */
    static void __exit xxx_exit(void)
    {
    	/* 删除设备 */
    	device_destroy(user_dev.class, user_dev.devid);
    	/* 删除类 */
    	class_destroy(user_dev.class);
    }
    
    module_init(xxx_init);
    module_exit(xxx_exit);
    
    3. 在/sys/class中生成设备文件节点

        有时候,我们会采取在 /sys/class 中生成设备文件节点,而不是 /dev 中。

    3.1 创建、删除类和设备

        首先,我们需要使用结构struct class_attribute创建一个属性数组,来组织设备文件的读写函数,struct class_attribute定义如下:

    struct class_attribute {
    	struct attribute attr;
    	ssize_t (*show)(struct class *class, struct class_attribute *attr, 
        		char *buf);
    	ssize_t (*store)(struct class *class, struct class_attribute *attr,
    			const char *buf, size_t count);
    };
    

        attr为属性,show函数为读文件操作函数,store函数为写文件操作函数。
    其中,结构struct attribute结构定义如下:

    struct attribute {
    	const char		*name;
    	umode_t			mode;
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    	bool			ignore_lockdep:1;
    	struct lock_class_key	*key;
    	struct lock_class_key	skey;
    #endif
    };
    

        name为设备文件名称,mode为模式。
        然后,需要定义一个struct class结构,为其成员class_attrs指定为上述结构。结构全部定义完毕之后,便可以使用函数class_register将class注册到系统。class_register定义如下:

    #define class_register(class)			\
    ({						\
    	static struct lock_class_key __key;	\
    	__class_register(class, &__key);	\
    })
    
    int __class_register(struct class *cls, struct lock_class_key *key)
    

    其为一个宏,其中, 参数class为上述定义的struct class。我们将其展开后得到如下接口:

    int class_register(struct class *cls);
    

    在驱动卸载的时候,需要删除这个class,使用函数class_unregister,其定义如下:

    void class_unregister(struct class *cls);
    
    3.2 参考示例

        在下面的参考示例中,会生成设备文件 /sys/class/eurphan/xxx

    /*
     * @description		: sysfs文件节点读函数
     * @param - class	: 传递给驱动的class
     * @param - attr	: sysfs文件节点属性
     * @param - buff	: 接收数据的缓存
     * @return			: 读取到的数据个数
     */
    static ssize_t xxx_show(struct class *class, struct class_attribute *attr, char *buff)
    {
    	return 0;
    }
    
    /*
     * @description		: sysfs文件节点写函数
     * @param - class	: 传递给驱动的class
     * @param - attr	: sysfs文件节点属性
     * @param - buff	: 写入的数据缓存
     * @param - count	: 写入的数据个数
     * @return			: 实际写入的数据个数
     */
    static ssize_t xxx_store(struct class *class, struct class_attribute *attr, const char *buff, size_t count)
    {
    	return count;
    }
    /* class属性结构 */
    static struct class_attribute xxx_class_attr[] = {
    	__ATTR(xxx, 0644, xxx_show, xxx_store),
    	__ATTR_NULL,
    };
    
    /* class结构 */
    static struct class xxx_class = {
    	.name = "eurphan",
    	.owner = THIS_MODULE,
    	.class_attrs = xxx_class_attr,
    };
    
    /*
     * @description		: 驱动卸载函数
     * @param			: 无
     * @return			: 加载是否成功
     */
    static __init int xxx_init(void)
    {
    	class_register(&xxx_class);
    	return 0;
    }
    
    /*
     * @description		: 驱动卸载函数
     * @param			: 无
     * @return			: 无
     */
    static __exit void xxx_exit(void)
    {
    	class_unregister(&xxx_class);
    }
    
    module_init(xxx_init);
    module_exit(xxx_exit);
    
    
    展开全文
  • 加载驱动的指令是:insmod xx.ko 查看驱动的指令是: lsmod 卸载驱动的指令是:rmmod xx 在include/linux/platform_device.h这个文件中定义了平台驱动注册和卸载文件函数 platform_driver_register 和 platform_...

    加载驱动的指令是:insmod xx.ko
    查看驱动的指令是: lsmod
    卸载驱动的指令是:rmmod xx

    在include/linux/platform_device.h这个文件中定义了平台驱动注册和卸载文件函数
    platform_driver_register 和 platform_driver_unregister 函数
    在这里插入图片描述
    这个两个函数参数调用了结构体platform_driver
    在这里插入图片描述

    该结构中包含了一组操作函数和一个 struct device_driver 的对像。在驱动中首先要做的
    就是定义 platform_driver 中的函数,并创建这个结构的一个对象实例, 然后在 init()函数中调用
    platform_driver_register()向系统注册驱动。

    1. 函数 int (*probe)(struct platform_device *);
      主要是进行设备的探测和初始化。例如想调用一个 GPIO,那么首先需要探测这个 GPIO 是
      否被占用了,如果被占用了那么初始化失败,驱动注册也就失败了;如果没有被占用,那么就
      申明要占用它。该函数中一般还会添加生成设备节点的函数,如果初始化成功,那么就会需要添加设备节点。
    2. 函数 int (*remove)(struct platform_device *);
      移除驱动,该函数中一般用于去掉设备节点或者释放软硬件资源
    3. void (*shutdown)(struct platform_device *);
      int (*suspend)(struct platform_device *, pm_message_t state);
      int (*resume)(struct platform_device *);
      从字面上就很好理解了,关闭驱动,悬挂(休眠)驱动以及恢复的时候该驱动要做什么

    接着的结构体 struct device_driver driver;
    主要包含两个参数,一个是 name 参数,驱动名称(需要和设备驱动结构体中的 name 参
    数一样,这点很重要);一个是 owner,一般是 THIS_MODULE。

    接下来编写驱动代码:

    #include <linux/init.h>
    #include <linux/module.h>
    
    /*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
    #include <linux/platform_device.h>
    
    #define DRIVER_NAME "hello_ctl"  //这个和前面设备的注册的hello结构体里面的名字相同
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("TOPEET");
    
    static int hello_probe(struct platform_device *pdv){
    	
    	printk(KERN_EMERG "\tinitialized\n");
    	
    	return 0;
    }
    
    static int hello_remove(struct platform_device *pdv){
    	
    	return 0;
    }
    
    static void hello_shutdown(struct platform_device *pdv){
    	
    	;
    }
    
    static int hello_suspend(struct platform_device *pdv){
    	
    	return 0;
    }
    
    static int hello_resume(struct platform_device *pdv){
    	
    	return 0;
    }
    
    struct platform_driver hello_driver = {
    	.probe = hello_probe,
    	.remove = hello_remove,
    	.shutdown = hello_shutdown,
    	.suspend = hello_suspend,
    	.resume = hello_resume,
    	.driver = {
    		.name = DRIVER_NAME,      //和devices名称相同
    		.owner = THIS_MODULE,
    	}
    };
    
    
    static int hello_init(void)
    {
    	int DriverState;
    	
    	printk(KERN_EMERG "HELLO WORLD enter!\n");
    	DriverState = platform_driver_register(&hello_driver); //然后在模块入口调用platform_driver_register
    	
    	printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
    	return 0;
    }
    
    static void hello_exit(void)
    {
    	printk(KERN_EMERG "HELLO WORLD exit!\n");
    	
    	platform_driver_unregister(&hello_driver);	//在函数的出口调用platform_driver_unregister
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    

    如果设备和驱动匹配成功就会进入函数 hello_probe 打印“initialized
    接着需要编写一下 Makefile 文件

    #!/bin/bash
    obj-m += probe_linux_module.o    //文件名
    
    #源码目录变量,这里用户需要根据实际情况选择路径
    
    KDIR := /home/birate/topeet/iTop4412_Kernel_3.0  #linux源码目录
    
    #当前目录变量
    PWD ?= $(shell pwd)
    
    #make命名默认寻找第一个目标
    #make -C就是指调用执行的路径
    #$(KDIR)Linux源码目录
    #$(PWD)当前目录变量
    #modules要执行的操作
    all:
    	make -C $(KDIR) M=$(PWD) modules
    		
    #make clean执行的操作是删除后缀为o的文件
    clean:
    	rm -rf *.o
    
    

    使用make编译,生成模块文件probe_linux_module.ko
    然后使用adb push probe_linux_module.ko /data 放到arm系统的/data目录下

    之后加载insmod probe_linux_module.ko
    如果没有错误将会打印initialized等内容
    在这里插入图片描述
    之后查看设备
    在这里插入图片描述
    卸载设备
    在这里插入图片描述

    后面我们生成杂项设备节点

    杂项设备节点在include/linux/miscdevice.h这个文件中,我们也可以使用cat /proc/misc查看对应的杂项设备

    在这里插入图片描述
    extern int misc_register(struct miscdevice * misc);
    杂项设备注册函数;一般在 probe 中调用,参数是 miscdevice
    extern int misc_deregister(struct miscdevice *misc);
    杂项设备卸载函数;一般是在 hello_remove 中用于卸载驱动

    结构体 miscdevice 中参数很多,下面几个是常用的。
    int .minor;设备号,赋值为 MISC_DYNAMIC_MINOR,这个宏定义可以查到为 10
    const char *name;设备名称
    const struct file_operations *fops

    file_operations 结构体在头文件“include/linux/fs.h”中,如下图所示,使用命令“vim
    include/linux/fs.h”打开头文件。
    查找file_operations
    在这里插入图片描述
    struct module *owner;一般是 THIS_MODULE。
    int (*open) (struct inode *, struct file *);对应上层的 open 函数,打开文件。
    int (*release) (struct inode *, struct file *);对应上层的 close 函数,打开文件操作之后一
    般需要关闭。
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);读函数,上层应用从底层读取
    函数。
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);写函数,上层应用向底
    层传输数据。
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);这个函数功能和写
    函数稍微有点重合,但是这个函数占用的内存非常小,主要针对 IO 口的控制

    #include <linux/init.h>
    #include <linux/module.h>
    
    /*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
    #include <linux/platform_device.h>
    /*注册杂项设备头文件*/
    #include <linux/miscdevice.h>
    /*注册设备节点的文件结构体*/
    #include <linux/fs.h>
    
    #define DRIVER_NAME "hello_ctl"
    #define DEVICE_NAME "hello_ctl123"  //杂项节点名称
    MODULE_LICENSE("Dual BSD/GPL");
    
    static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
    
    	
    	printk("cmd is %d,arg is %d\n",cmd,arg);
    	return 0;
    }
    
    static int hello_release(struct inode *inode, struct file *file){
    	printk(KERN_EMERG "hello release\n");
    	return 0;
    }
    
    static int hello_open(struct inode *inode, struct file *file){
    	printk(KERN_EMERG "hello open\n");
    	return 0;
    }
    
    static struct file_operations hello_ops = {   //定义file_operations 参数
    	.owner = THIS_MODULE,
    	.open = hello_open,
    	.release = hello_release,
    	.unlocked_ioctl = hello_ioctl,
    };
    
    static  struct miscdevice hello_dev = {
    	.minor = MISC_DYNAMIC_MINOR,  //参数 minor 为 MISC_DYNAMIC_MINOR,也就是 10																													
    	.name = DEVICE_NAME,					//参数 name 为 DEVICE_NAME,也就是 hello_ctl123	
    	.fops = &hello_ops,								//参数 fops 为“hello_ops”
    };
    
    
    static int hello_probe(struct platform_device *pdv){
    	
    	printk(KERN_EMERG "\tinitialized\n"); 
    	misc_register(&hello_dev); 向添加 hello_probe 中添加注册杂项设备的函数 misc_register,如下图所示,
    将 miscdevice 参数定义为 hello_dev
    	
    	return 0;
    }
    
    static int hello_remove(struct platform_device *pdv){
    	
    	printk(KERN_EMERG "\tremove\n");
    	misc_deregister(&hello_dev);
    	return 0;
    }
    
    static void hello_shutdown(struct platform_device *pdv){
    	
    	;
    }
    
    static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
    	
    	return 0;
    }
    
    static int hello_resume(struct platform_device *pdv){
    	
    	return 0;
    }
    
    struct platform_driver hello_driver = {
    	.probe = hello_probe,
    	.remove = hello_remove,
    	.shutdown = hello_shutdown,
    	.suspend = hello_suspend,
    	.resume = hello_resume,
    	.driver = {
    		.name = DRIVER_NAME,
    		.owner = THIS_MODULE,
    	}
    };
    
    
    static int hello_init(void)
    {
    	int DriverState;
    	
    	printk(KERN_EMERG "HELLO WORLD enter!\n");
    	DriverState = platform_driver_register(&hello_driver);
    	
    	printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
    	return 0;
    }
    
    
    static void hello_exit(void)
    {
    	printk(KERN_EMERG "HELLO WORLD exit!\n");
    	
    	platform_driver_unregister(&hello_driver);	
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    

    修改makefile函数

    #!/bin/bash
    obj-m += devicenode_linux_module.o 
    #源码目录变量,这里用户需要根据实际情况选择路径
    KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0
    
    #当前目录变量
    PWD ?= $(shell pwd)
    
    #make命名默认寻找第一个目标
    #make -C就是指调用执行的路径
    #$(PWD)当前目录变量
    #modules要执行的操作
    all:
    	make -C $(KDIR) M=$(PWD) modules
    		
    #make clean执行的操作是删除后缀为o的文件
    clean:
    	rm -rf *.o
    
    

    生成.ko文件
    传到 /data目录中
    在这里插入图片描述
    加载驱动 在/dev查看设备节点
    在这里插入图片描述
    已经生成了设备节点

    卸载 完成

    展开全文
  • linux驱动--设备节点生成

    千次阅读 2016-07-07 17:26:29
    linux驱动–设备节点生成关于设备注册于驱动注册,参考前一篇文章http://blog.csdn.net/cole10540316/article/details/51848272linux驱动一般分为三类:字符设备、块设备、网络设备,但是这三类设备并不能完全包含...

    linux驱动–设备节点生成

    关于设备注册于驱动注册,参考前一篇文章http://blog.csdn.net/cole10540316/article/details/51848272

    linux驱动一般分为三类:字符设备、块设备、网络设备,但是这三类设备并不能完全包含所有的设备,所以引入了杂项设备。linux下采用杂项设备可能包含字符设备、块设备、网络设备中的一项或者多项设备。本文是在杂项设备下生成设备节点,杂项设备,在内核编译时强制编译进内核。linux下的设备号为主设备号0-255,每个主设备号下又分为256个子设备号,杂项设备的主设备号为10.

    设备节点生成代码

    #include <linux/module.h>//与module相关的信息
    #include <linux/kernel.h>
    #include <linux/init.h>      //与init相关的函数
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h> //杂项设备头文件
    #include <linux/fs.h>
    /***************用到的函数******************
    extern int platform_driver_register(struct platform_driver *);
    extern void platform_driver_unregister(struct platform_driver *);
    
            int (*probe)(struct platform_device *);
            int (*remove)(struct platform_device *);
            void (*shutdown)(struct platform_device *);
            int (*suspend)(struct platform_device *, pm_message_t state);
            int (*resume)(struct platform_device *);
    杂项设备结构体
    struct miscdevice  {
            int minor;      //MISC_DYNAMIC_MINOR,由宏定义给定,一般就为10
            const char *name;
            const struct file_operations *fops;
            struct list_head list;
            struct device *parent;
            struct device *this_device;
            const char *nodename;
            mode_t mode;
    };
    //杂项设备注册于解除函数  一般在 probe函数 中调用
    extern int misc_register(struct miscdevice * misc);
    extern int misc_deregister(struct miscdevice *misc);
    
    struct file_operations {
            struct module *owner;
             long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
            long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
            int (*mmap) (struct file *, struct vm_area_struct *);
            int (*open) (struct inode *, struct file *);
            int (*flush) (struct file *, fl_owner_t id);
            int (*release) (struct inode *, struct file *);
            int (*fsync) (struct file *, int datasync);
            int (*aio_fsync) (struct kiocb *, int datasync);
            int (*fasync) (int, struct file *, int);
            int (*lock) (struct file *, int, struct file_lock *);
    
    
    **********************************/
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("zhangsan");
    
    #define DRIVER_NAME "hello_ctl"
    #define DEVICE_NAME "hello_ctldevice"
    //file ops结构体的内容实现
    static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
        printk(KERN_INFO "The cmd is %d,arg is %d\n",cmd,arg);
        return 0;
    }
    static int hello_release(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "hello_release\n");    
        return 0;
    }
    static int hello_open(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "hello_open\n");   
        return 0;
    }
    //
    static struct file_operations hello_ops={
    
        .owner=THIS_MODULE, //THIS_MODULE
        .open=hello_open,   //对应上层的open函数
        .release=hello_release,
        .unlocked_ioctl=hello_ioctl,
    };
    //杂项设备结构体
    static struct miscdevice hello_dev={
        .minor=MISC_DYNAMIC_MINOR,  //宏定义为10
        .name=DEVICE_NAME,     //设备名
        .fops=&hello_ops,       // 驱动需要实现的主体内容,在include/linux/fs.h头文件中有定义  
    };
    
    static int hello_probe(struct platform_device *pdv)
    {
        misc_register(&hello_dev);//杂项设备注册
        return 0;
    }
    static int hello_remove(struct platform_device *pdv)
    {
        misc_deregister(&hello_dev);//杂项设备解除
        return 0;
    }
    static void hello_shutdown(struct platform_device *pdv)
    {
        printk(KERN_INFO "hello_shutdown\n");   
    }
    static int hello_suspend(struct platform_device *pdv)
    {
        printk(KERN_INFO "Hello_suspend\n");
        return 0;
    }
    static int hello_resume(struct platform_device *pdv)
    {
        printk(KERN_INFO "Hello_resume\n");
        return 0;
    }
    // 注册设备结构体
    struct  platform_driver hello_driver={
        .probe=hello_probe,
        .remove=hello_remove,
        .shutdown=hello_shutdown,
        .suspend=hello_suspend,
        .resume=hello_resume,
        .driver={
            .name=DRIVER_NAME,
            .owner=THIS_MODULE,
        }
    };
    
    static int hellodriver_init()
    {
        int Driverstate;
        printk(KERN_INFO "Hello_init\n");
        Driverstate=platform_driver_register(&hello_driver);
        printk(KERN_INFO "Driverstate is %d\n",Driverstate);
        return 0;
    }
    
    static void hellodriver_exit()
    {
    
        printk(KERN_INFO "Hello_exit\n");
        platform_driver_unregister(&hello_driver);
    }
    module_init(hellodriver_init);
    module_exit(hellodriver_exit);
    
    展开全文
  • 生成设备节点以及编写简单应用调用驱动生成设备节点关于杂项设备杂项设备内核文件结构体如何生成设备节点代码代码分析结果演示编写简单应用调用驱动基本原理写代码前应知道的需要的头文件调用的函数编译代码实验代码...
  • android驱动生成设备节点的方法

    千次阅读 2013-09-10 18:57:39
    echo 1 > /sys/devices/platform/s3c2440-i2c.2/i2c-2/2-0055/bqfs_update static ssize_t set_bqfs_update(struct device *dev,  struct device_attribute *attr, const char *buf,  
  • linux驱动:自动创建设备节点

    千次阅读 2018-11-03 09:05:28
    在加载驱动模块后,就要自己使用mknod创建设备节点,这样虽然是可行的,但是比较麻烦。我们可以在__init()函数里面添加一些函数,自动创建设备节点。创建设备节点使用了两个函数 class_create()和device_create(),...
  • 生成设备节点1. 生成设备节点1.1 杂项设备1.2 注册文件1.3 生成设备节点源代码1.4 生成设备节点步骤1.5 需要注意的问题2. 调用设备节点 1. 生成设备节点 1.1 杂项设备 所有的设备都有自己的设备号,我们可以利用命令...
  • 注册设备 –> 注册驱动 –> 生成设备节点 1、注册设备 目的:注册完后可在虚拟平台总线下可以查到注册的设备 (ls /sys/devices/platform/) 结构体文件:include/linux/platform_device.h 使用结构体 platform_...
  • 前言:本篇没有解决什么大问题,不神秘也不高深...在未调整为module加载方式之前,系统启动后可以正常在dev下正常生成驱动节点 driver_test0,driver_test1 将驱动编译为module后,在系统完全启动后,使用insmod 加载
  • 了解注册设备、注册驱动生成设备节点这些概念。 其实学到现在,很多东西我们都似懂非懂,而我也是刚学,也感觉很多东西似是而非,但好在代码过程和结果都是对的。 我们再次整理一下这些概念。 无论是设备...
  • 在之前一篇博文讨论Linux内核空间与应用空间数据交流的几种方式提到了如下几种方式: ...3.sys文件系统,也就是属性节点,同样也是双向的。通常用于读取或者修改驱动程序的配置,比如在一个由pwm控制的LED程序中设
  • 上一篇我们介绍到创建设备文件的方法,...第二种是自动创建设备节点:利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。在驱动初始化代码里调用class_create为该设备创建一个
  • 最近在用tq2440做移动物体监控系统,用了zc3xxUSB摄像头,驱动...摄像头驱动应该是自动产生设备节点的,无需手动mknod 的,手动产生也是没有用的,试了很多办法,最终终于找到了问题所在 在编译内核之前要先编译内
  • 本节背景:已经编写好驱动,并生成驱动节点驱动在启动时加载,并且通过串口调试,进入dev目录下,可查看到自己的驱动。 Android的APP,通过so库调用驱动时,如果不给驱动节点权限,则在打开设备时,会出现...
  • Linux字符设备驱动自动创建设备节点

    千次阅读 2016-11-29 14:38:46
    Linux可使用udev、mdev的机制来自动创建设备节点。在驱动层面,我们需要首先调用class_create创建一个class类,然后在class类下,调用device_create来创建一个class_device,即类下面创建类的设备。(此方法仅适用于...
  • linux内核驱动---创建设备节点文件

    千次阅读 2017-09-15 23:22:44
    Linux下生成驱动设备节点文件的方法有3个:1、手动mknod;2、利用devfs;3、利用udev 在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以...
  • 驱动中动态创建设备号、设备节点

    千次阅读 2018-01-06 14:44:41
    在Linux驱动(三)字符设备驱动框架中,我们简要介绍了如何编写一个简单的驱动框架,并总结了步骤 1、生成设备号 2、向内核注册该设备号 3、初始化设备对象,完成操作方法集 4、向内核注册该设备对象 5、生成...
  • 生成jni 高用的c的so文件,并通过java调用该接口,实现能/dev/下的设备驱动的操作
  • 设备驱动-----自动创建节点

    千次阅读 2013-06-21 00:25:12
    以字符设备char_dev为例,在驱动初始化的代码里调用class_create为该设备创建一个class,再为每个设备调用 class_device_create创建对应的设备,这样的module被加载时,undev daemon就会自动在/dev下创建char_dev...
  • 驱动添加设备节点/sys/class/

    千次阅读 2017-06-05 12:22:36
    现在我有一个驱动文件xxx.c 编译加载后可以在 /dev/ 看到已经加载ok ,现在想要添加 sys/class/ 的设备节点 ,就是想做这件事情而已 假如 现在需要添加一个 gpio节点,配置gpio_control的属性文件接口 比如 echo 1...
  • Linux内核驱动自动创建设备节点文件

    千次阅读 2016-03-06 08:28:51
    Linux下生成驱动设备节点文件的方法有3个:1、手动mknod;2、利用devfs;3、利用udev 在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,...
  • //如果剩下读的数据长度少于len,则只复制出剩下读部分 len_copy = strlen ( data ) - file -> f_pos ; else len_copy = len ; //如果剩下的数据长度超出len,则本次复制len字节 ret = ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 110,934
精华内容 44,373
关键字:

驱动没生成节点