现在的位置: 首页 > 综合 > 正文

字符设备驱动程序之自动创建设备节点

2013年10月08日 ⁄ 综合 ⁄ 共 4139字 ⁄ 字号 评论关闭
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/device.h>
static struct class *led_class;

int led_open(struct inode *inode, struct file *file)
{
    printk("led_open\n");
    return 0;
}
ssize_t led_write(struct file *file, const char __user *user, size_t size, loff_t *off)
{
    printk("led_write\n");
    return 0;
}

static struct file_operations led_operation = {
    .owner=THIS_MODULE,
    .open=led_open,
    .write=led_write,   
};
int major;
int led_init(void)
{
    major=register_chrdev(0,"led",&led_operation);

    led_class = class_create(THIS_MODULE, "led_class");

    device_create(led_class, NULL, MKDEV(major, 0), NULL,"led_device");
    return 0;
}

void led_exit(void)
{
    unregister_chrdev(major,"led");
    device_destroy(led_class,MKDEV(major, 0));
    class_destroy(led_class);
    
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

主要思路:先创建一个类,在类下创建设备!这样我们就不需要在开发板上查看主设备号,然后手动创建设备节点了!在开发板上:ls /sys/class/会看到我们创建的类,ls /sys/class/led_class/会看到我们在类下创建的设备!不过真正的设备节点在/dev目录下面,通过命令:ls /dev/led_device可以查看到!
需要注意的是,我们在编写应用程序的时候,open函数里面的设备名字要跟驱动里面device_create指定的设备名字相一致!

但是,系统做了什么呢?在开发板的/etc/init.d/rcS文件里面有如下的信息:

echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
这两行信息就是说,一旦发生了热插拔事件(比如创建了类,在类下创建了设备),就会调用/sbin/mdev命令,mdev命令会通过环境变量中的 ACTION 和 DEVPATH来判断此次热插拔事件影响了/sys目录下的那个文件,一旦发现了这个文件,就会进入这个文件里面去查找dev的属性文件,并根据属性创建设备节点!比如我们加载驱动的的时候,会在 /sys/class/目录下创建类,在 /sys/class/led_class目录下创建设备,在

/sys/class/led_class目录下有个dev文件,dev文件里面就有设备的主次设备号,mdev就会根据主次设备号在/dev/目录下创建设备节点!

============================分割线===========================================

问题: cannot create duplicate filename xxxxx

我遇到的问题是: 在模块卸载的时候我已经调用了

    unregister_chrdev_region(devno, 1); //release dev number
    cdev_del(&firstcdev); //del char device
    class_destroy(myclass); //del class
    device_destroy(myclass, devno); //del device


可是在重新加载模块的时候还是会提示cannot create duplicate filename xxxxx
然后认真想了一下,发现有可能是释放的顺序,改成了下面的顺序之后就可以了。

    unregister_chrdev_region(devno, 1); //release dev number
    device_destroy(myclass, devno); //del device
    class_destroy(myclass); //del class
    cdev_del(&firstcdev); //del char device

上我自己写的代码:

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/device.h>

//device name
#define DEVNAME "ledctl"

//cdev
struct cdev firstcdev;
dev_t devno;

//for auto creata device file
struct class *myclass;


static int first_drv_open(struct inode *inode, struct file *file)
{
	printk("first_cdrv_open\n");

	s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPIO_OUTPUT); //GPB5 out mode
	s3c2410_gpio_setpin(S3C2410_GPB(5), 0);			  //led1 on
	return 0;
}

static int first_drv_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
{
	printk("first_cdrv_write\n");

	int val;

	copy_from_user(&val, (int *)buf, sizeof(int));
	printk("val from user is %d\n", val);
	s3c2410_gpio_setpin(S3C2410_GPB(5), (val == 0 ? 1 : 0)); //val=1 led1 on

	return 0;
}


static struct file_operations first_drv_fops = {
    	.owner  =   THIS_MODULE,    
    	.open   =   first_drv_open,     
	.write	=   first_drv_write,	   
};


static int first_drv_init(void)
{
	cdev_init(&firstcdev, &first_drv_fops);	//init cdev
	alloc_chrdev_region(&devno, 0, 1, DEVNAME);	//alloc char device number
	cdev_add(&firstcdev, devno, 1); //register char device


	myclass = class_create(THIS_MODULE, "ctlled"); //create /sys/class/ctlled
	device_create(myclass, NULL, devno, NULL, DEVNAME); //auto create /dev/ledctl

	printk("firstdrvcdev initialized.\n");
	
	return 0;
}


static void first_drv_exit(void)
{
	unregister_chrdev_region(devno, 1); //release dev number
	device_destroy(myclass, devno); //del device
	class_destroy(myclass); //del class
	cdev_del(&firstcdev); //del char device
}


module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");

其他参考资料: http://blog.csdn.net/garby2004/article/details/4603996
                             http://blog.csdn.net/jianchi88/article/details/6848035

抱歉!评论已关闭.