如何创建设备文件

1.杂项设备

1.mknod 命令创建设备文件
安装驱动后不会自动在/dev/目录下创建设备文件,可以使用mknod 命令创建设备文件。
mknod命令格式:

mknod /dev/drive_name { b | c } Major Minor

/dev/drive_name:要创建的设备节点路径文件名;例如:/dev/myearly
{ b | c }:设备类型,b表示块设备,c表示字符设备;例如:c
Major:主设备号;
Minor:次设备号;
注意:一个主设备号只能被注册一次。一次注册 0~255 的次设备号就占用了。注销早期典型字符设备之后,对应的设备节点文件还是存在的。
例子:

[root@Sue /home]mknod /dev/myearly c 250 0

2.在驱动中创建设备文件
1.创建设备类

#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})

参数:
owner:类的所有者, 固定是 THIS_MODULE 。
name:类名,随便,能有含义最好
返回值:返回struct class 指针,所以要先定义好

2.创建设备文件

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

参数;
class:杂项设备注册函数中设备文件的类,上面class_create的返回值
parent:就是用户定义的杂项设备核心结构中的 parent 成员。如果没有,则为 NULL。
dev_t devt:杂项设备注册函数中实际参数是 dev, dev的值如下:

devt = MKDEV(MISC_MAJOR, misc->minor); //把主设备号的次设备号合成设备号

drvdata:这个是驱动数据,传递给设备回调使用,一般情况下没有,为 NULL。
fmt:杂项设备注册函数中实际参数是:"%s", misc->name,表示可变参数 ,和printf 语句一样的使用方式,可以使用%d,%s 这种方式格式一个字符串。
返回值:
成功: 返回有效 struct device * 指针;
失败:返回错误指针,可以使用 ERR_PTR()宏转换成错误代码。

例子;

#include <linux/kernel.h>
#include <linux/module.h>

//包含必须的头文件
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>            /*kfree ,kmalloc */
#include <linux/device.h>

//以下是文件操作方法的具体实现代码
static int xxx_open (struct inode *pinode, struct file *pfile)
{
	printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);
	return 0;
}

static int xxx_release (struct inode *pinode, struct file *pfile)
{
	printk("line:%d,%s is call\n",__LINE__,__FUNCTION__);
	return 0;
}

//文件操作方法集合指针
static const struct file_operations char_dev_fops={
	.open            =   xxx_open,
	.release         =   xxx_release,
};

//定义核心数据结构
static struct cdev *p_cdv;
//定义第一个设备号(包含主和次)
static dev_t dev_no;
//定义设备主设备号
static unsigned int major=0;
//定义设备名
#define MYCHAR_DEV  "auto_linux26"

#define CLASS_NAME  "chardev26"
static struct class *linux26_class = NULL;
static struct device *this_device = NULL;

static int __init chrdev_test_init(void)
{
	int ret = -1;
	//1.使用cdev_alloc函数分配p_cdv空间
	p_cdv=cdev_alloc();
	if(p_cdv == NULL)
	{
		printk("cdev_alloc error!\n");
		ret = -ENOMEM;/* 分配失败一般是内存不足导致的  */
		goto cdev_alloc_error;
	}
	
	//2.申请设备号:动态或者静态
	ret = alloc_chrdev_region(&dev_no, 0, 2,MYCHAR_DEV);
	if(ret < 0)
	{
		printk("alloc_chrdev_region error!\n");	
		goto alloc_chrdev_region_error;
	}

	//3.初始化p_cdv结构
	cdev_init(p_cdv, &char_dev_fops);
	//4.注册已经初始化好的c_dev结构
	ret = cdev_add(p_cdv, dev_no, 2);
    if ( ret < 0 ) 
	{	
		printk(KERN_EMERG "cdev_add  error\n");
        goto cdev_add_error;
    }
	
	/* 增加自动创建设备文件功能 */
    //5.创建一个设备类
    // linux26_class = class_create(THIS_MODULE,MYCHAR_DEV);//可以和设备名相同
    linux26_class = class_create(THIS_MODULE, CLASS_NAME); //取一个不同于设备名的类名
    if ( IS_ERR(linux26_class) ) {   
        ret = PTR_ERR(linux26_class);
        goto class_create_err;
    }
	
	//6.创建一个设备,报告设备信息
    this_device =  device_create(linux26_class,NULL ,dev_no,NULL, "%s", MYCHAR_DEV);
    if ( IS_ERR(this_device) ) {
        ret = PTR_ERR(this_device);
        goto device_create_err;
    }
	major=MAJOR(dev_no);
	printk(KERN_EMERG "major = %d \n",major);
    return 0;
	
	device_create_err:
		class_destroy(linux26_class);
		
	class_create_err:
		cdev_del(p_cdv);
	
	cdev_add_error:
		unregister_chrdev_region(dev_no, 2);

	alloc_chrdev_region_error:
	
		kfree(p_cdv);/*释放p_cdv结构空间*/
	
	cdev_alloc_error:
		return ret;
}

static void __exit chrdev_test_exit(void)
{
	device_destroy(linux26_class, dev_no);
	class_destroy(linux26_class);

	//1.注销p_cdv结构
   	cdev_del(p_cdv);
	//2.释放设备号
    unregister_chrdev_region(dev_no, 2);
	//3.释放p_cdv结构空间
    kfree(p_cdv);
}

module_init(chrdev_test_init);
module_exit(chrdev_test_exit);

MODULE_LICENSE("GPL");
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小坚学Linux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值