自动创建设备节点
使用udev或mdev来实现自动创建设备节点。
使用mknod
手动创建设备节点不够灵活,如果是动态分配的设备号怎么办,难道每次加载驱动后去查看/proc/devices
文件中查看它的主设备号,利用**udev(mdev)**来实现设备节点的自动创建,**udev(mdev)**存在于应用层。
包含头文件
#include<linux/device.h>
新建一个class结构体指针
static struct class *my_class;
在初始化函数中调用class_create()
函数创建一个类,参数分别为模块所有者和class结构name字段,在/sys/class/
下体现。在/sys/class/
下创建类目录。
my_class= class_create(THIS_MODULE, "my_class");
if(IS_ERR(my_class))
{
printk("Err: failed increating class.\n");
return -1;
}
调用device_create()
函数创建设备节点,参数分别为所从属类,这个设备的父设备,没有就制定NULL,设备号,设备的私有数据,最后一组参数指定设备节点名,比如这里的名为hello。在驱动模块初始化函数中实现设备节点的自动创建设备节点。
函数原型:
extern struct device *device_create(struct class *cls, structdevice *parent, dev_t devt, void *drvdata,const char *fmt, ...)
例:
device_create(my_class,NULL,dev_n,NULL,"%s","hello");
或者
device_create(my_class,NULL,dev_n,NULL,"hello");
设备卸载删除类和设备节点
device_destroy(my_class,dev_n);
class_destroy(my_class);
字符驱动框架
1. 现将头文件加进来
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
###b 2. 写open,write,read等函数
static int seconds_drv_open(struct inode *inode,struct file *file)
{
//printk("seconds_drv_open\n");
/* 配置gpf4,5,6引脚为输出 */
return 0;
}
static ssize_t seconds_drv_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
//printk("seconds_drv_write\n");
return 0;
}
3. 写file_operations结构,然后将上面的open,write函数填充到相应函数指针处
static struct file_operations seconds_drv_fops={
.owner = THIS_MODULE,
.open = seconds_drv_open,
.write = seconds_drv_write,
};
4. 在入口函数中注册驱动程序
int char01_dev_init(void)
{
int result;
//自动分配主次设备号
result = alloc_chrdev_region(&devno, 0, 1, "char01");
if (result != 0)
{
printk("alloc_chrdev_region failed!/n");
goto ERR1;
}
//设备初始化
cdev_init(&dev, &fops);
dev.owner = THIS_MODULE;
dev.ops = &fops;
//添加设备
result = cdev_add(&dev, devno, 1);
if (result != 0)
{
printk("cdev_add failed!/n");
goto ERR2;
}
//创建类
pclass = class_create(THIS_MODULE, "char01");
if (IS_ERR(pclass))
{
printk("class_create failed!/n");
goto ERR3;
}
//创建设备节点
device_create(pclass, NULL, devno, NULL, "char01");
return 0;
ERR3:
cdev_del(&dev);
ERR2:
unregister_chrdev_region(devno, 1);
ERR1:
return -1;
}
static int __init char01_init(void)
{
printk("module char01 init!/n");
return char01_dev_init();
}
5. 在出口函数中卸载驱动
static void __exit char01_exit(void)
{
printk("module char01 exit!/n");
class_destroy(pclass);
device_destroy(pclass,devno);
cdev_del(&dev);
unregister_chrdev_region(devno, 1);
}
6. 修饰入口函数和出口函数
module_init(seconds_drv_init);
module_exit(seconds_drv_exit);
MODULE_LICENSE("GPL");
7. 内核传参数,主次设备号
//内核模块传参数
//让内核传进来空闲的主、次设备号
module_param(major_num, int, S_IRUSR);
module_param(minor_num, int, S_IRUSR);
## 总结
使用`class_create()`和`device_create()`函数可以自动创建节点。
```c
class_create //创建class ,在/sys/class下创建类
class_destroy //销毁class
device_create //创建device ,在/sys/class的类下面创建设备节点
device_destroy //销毁device
示例程序
chrdev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
int char01_open(struct inode *inode, struct file *filp)
{
printk("char01 open!/n");
return 0;
}
int char01_release(struct inode *inode, struct file *filp)
{
printk("char01 release!/n");
return 0;
}
ssize_t char01_read(struct file *filp, char *buf,
size_t count, loff_t *fpos)
{
printk("char01 read!/n");
return 0;
}
ssize_t char01_write(struct file *filp, const char *buf,
size_t count, loff_t *fpos)
{
printk("char01 write!/n");
return 0;
}
int char01_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param)
{
printk("char01 ioctl!/n");
printk("cmd:%d param:%ld/n", cmd, param);
return 0;
}
struct file_operations fops =
{
.owner = THIS_MODULE,
.open = char01_open,
.release = char01_release,
.read = char01_read,
.write = char01_write,
.ioctl = char01_ioctl
};
dev_t devno;
struct class *pclass;
struct cdev dev;
int char01_dev_init(void)
{
int result;
result = alloc_chrdev_region(&devno, 0, 1, "char01");
if (result != 0)
{
printk("alloc_chrdev_region failed!/n");
goto ERR1;
}
cdev_init(&dev, &fops);
dev.owner = THIS_MODULE;
dev.ops = &fops;
result = cdev_add(&dev, devno, 1);
if (result != 0)
{
printk("cdev_add failed!/n");
goto ERR2;
}
pclass = class_create(THIS_MODULE, "char01");
if (IS_ERR(pclass))
{
printk("class_create failed!/n");
goto ERR3;
}
device_create(pclass, NULL, devno, NULL, "char01");
return 0;
ERR3:
cdev_del(&dev);
ERR2:
unregister_chrdev_region(devno, 1);
ERR1:
return -1;
}
static int __init char01_init(void)
{
printk("module char01 init!/n");
return char01_dev_init();
}
static void __exit char01_exit(void)
{
printk("module char01 exit!/n");
class_destroy(pclass);
device_destroy(pclass,devno);
cdev_del(&dev);
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Yao.GUET");
module_init(char01_init);
module_exit(char01_exit);
chrdev_test.c
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
/////////////////////////////////////////////////
int main(int argc, char *argv)
{
int fd;
fd = open("/dev/char01", O_RDWR);
if (fd<0)
{
printf("open /dev/char01 failed!/n");
printf("%s/n", strerror(errno));
return -1;
}
printf("open /dev/char01 ok!/n");
ioctl(fd, 0);
close(fd);
}