t113-c字符型驱动复盘(自动创建设备文件)

发布时间 2023-07-08 10:21:07作者: 悠闲的小莫

整个代码

// #include "linux/module.h"
// #include "linux/fs.h"
// //#include "linux/stddef.h"
// #include "linux/types.h"
// //#include "crypto/if_alg.h"

#include "chabasemo.h"


#define number 1										//设备数量

//注册字符型设备
uint8_t databuffer[1000];
char *st="nibuhao";
int major,ma=0,mi=0;						   		   //设备号,朱设备号,次设备号
static struct cdev chadv;					   	//初始化一个cdev的句柄,主要是在init时候用来初始化


struct class *chabases;						//创建一个类
struct device *chabasedev;//创建类下的一个设备

static const struct file_operations chabase = {
	.owner		= THIS_MODULE,
	.open		= chabase_open,
	.read		= chabase_read,
	.release	= chabase_release,
	.write		= chabase_write,
};

//节点和文件,不详细解说
static int chabase_open(struct inode *inode, struct file *file)
{
    //printk(KERN_EMERG,"chabase_open!\r\n");//最高级输出
	return 0;
}
//节点和文件,不详细解说
static int chabase_release(struct inode *inode, struct file *file)
{
    //printk(KERN_EMERG,"chabase_release!\r\n");//最高级输出
	return 0;
}
//节点和文件,不详细解说,buffer和count三常用的
static ssize_t chabase_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
    //printk(KERN_EMERG,"chabase_read!\r\n");//最高级输出
	if(copy_to_user(buffer,st,strlen(st)))
	{
		return -EHWPOISON;
	}
	return 0;
}
//节点和文件,不详细解说
static ssize_t chabase_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    //printk(KERN_EMERG,"chabase_write!\r\n");//最高级输出
	if(copy_from_user(databuffer,buffer,sizeof(buffer)))
	{
		return -EHWPOISON;
	}
	return 0;
}


static int __init chabase_init(void)
{
	int err;
	memset(databuffer,'\0',1000);
	printk("chabase init \r\n");
    // major=register_chrdev(0,"chabase",&chabase);//如果用这个作为设备号的分配将会一次占完此设备号下的所有子设备号节点
	// //因此我们不用这个
	//注册字符型设备,并且设备号为200,子设备号(后20位)在此默认为0,网上说设备号设为0为自动获取
	//返回的的好像是主设备号字段


	if(!ma)
	{
		printk("allocing\r\n");
		err=alloc_chrdev_region(&ma,mi,number,"chabasedev");//如果未定义设备号用,主设备号内和给,次是设备号自己定,返回值是朱设备号
	 	printk("allocing %d",err);
		printk("ma is %d,mi is %d",ma,mi);
		if(err<0)
		{
			printk("failed to alloc chidev");
			return err;
		}
	}
	else{
		printk("registering");
		err=register_chrdev_region(MKDEV(ma,mi),number,"chabasedev");
		if(err<0){
			printk("failed to alloc chidev");
			return err;
		}
	}
	ma = MAJOR(ma);
	major=MKDEV(ma,mi);

	//创建字符型设备
	//先初始化在创建
	printk("cdev_initing");
	chadv.owner=THIS_MODULE;
	cdev_init(&chadv,&chabase);


	printk("ading cdev_initing");
	cdev_add(&chadv, major,number);									//创建

	printk("majior is %d \r\n",major);
	chabases=class_create(THIS_MODULE,"chabase");//自动创建类
	if(IS_ERR(chabases))															   //由于返回的是指针,所以药用iserr来检查是否出错
		return PTR_ERR(chabases);											  //如果出错则用ptrerr返回错误类型

	chabasedev=device_create(chabases,NULL, MKDEV(ma,mi),NULL,"chabase");//创建的类,父节点一般为null,设备号
	//	节点可能用到的数据,节点的名字
	if(IS_ERR(chabasedev))
		return PTR_ERR(chabasedev);

	//firstdrv_class_devs[0] = class_device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"leds"); 
	//firstdrv_class_devs[minor] = class_device_create(firstdrv_class,NULL,MKDEV(major,minor),NULL,"led%d",minor);

    return 0;
}

static void __exit chabase_out(void)
{

	
	//unregister_chrdev(200,"chabase");//注销

	unregister_chrdev_region(major,1);

	//注销字符型设备
	cdev_del(&chadv);

	//退出后要进行注销
	//先注销节点再注销类
	device_destroy(chabases,MKDEV(ma, mi));
    class_destroy(chabases);



}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiaomo <2712767798@qq.com>");
MODULE_DESCRIPTION("testting");
// MODULE_ALIAS("ipt_limit");
// MODULE_ALIAS("ip6t_limit");

module_init(chabase_init);
module_exit(chabase_out);

细节注意

1.这些要使用的变量需要定义成能够赋予内存的变量,不要定义成指针,如果定义指针那么其内存只包含一个指针而不是内容,那么这时候使用会导致内存泄漏

2.在使用时,如果判断对错的返回值是一个指针使用以下函数来判断是否成功

3.自动分配函数会把ma赋予主设备号,但是也会往前推进二十位,因此用的时候注意先把ma退后20位

链接:

Linux驱动device_create创建字符设备文件

cdev_alloc与cdev_init区别

字符设备驱动-使用alloc_chrdev_region+cdev注册设备驱动

顺带标明以下调试时候常用的函数

dev_info()/dev_dbg()/dev_err()

Linux内核之 printk 打印