原文: http://liu1227787871.blog.163.com/blog/static/20536319720128901736417/
#include <linux/fs.h>
#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