14_字符设备另一种写法

14_字符设备另一种写法

1、字符设备框架对比

之前的字符设备驱动框架:
在这里插入图片描述
缺点:
在这里插入图片描述
修改后的框架:
在这里插入图片描述
修改后:程序按照主设备号、次设备号来打开设备,这样同一个主设备号下可以对应多个file_operation结构体,对应多个次设备号。

2、新的字符设备驱动程序编写

2.1、在hello.c中

2.1.1、确定主设备号

/* 1. 分配主设备号 */
static int major;

2.1.5、定义测试所用的open函数

static int hello_open(struct inode *inode, struct file *file)
{
	printk("hello_open\n");
	return 0;
}

static int hello2_open(struct inode *inode, struct file *file)
{
	printk("hello2_open\n");
	return 0;
}

2.1.2、构造file_operations

static struct file_operations hello_fops = {
	.owner = THIS_MODULE,
	.open  = hello_open, 
};

static struct file_operations hello2_fops = {
	.owner = THIS_MODULE,
	.open  = hello2_open, 
};

2.1.3、告诉内核

#define HELLO_CNT  2

/* 3.1 定义一个cdev结构体 */
static struct cdev hello_cdev;
static struct cdev hello2_cdev;

/* 4.1 定义一个类 */
static struct class *cls;

/* 在入口函数中告诉内核 */
static int hello_init(void)
{
	dev_t devid;

	/* 3. 告诉内核 */
#if 0	
	/* 以前是这样 	
	 * (major, 0), (major, 1), ...(major, 255)都对应hello_fops 
	 */
	major = register_chrdev(0, "hello", &hello_fops);
#else
	/* 3.2 分配主次设备号 */
	if(major) {	/* 若自己指定主设备号 */
		/* 参一:主设备号 
		 * 参二:次设备号开始的下标
		 */
		devid = MKDEV(major, 0);

		/* (major, 0~1)对应hello_fops, (major, 2~255)d都不对应hello_fops 
		 * 参二:次设备号个数
		 */
		register_chrdev_region(devid, HELLO_CNT, "hello");
	} else {	/* 若由系统自动分配主设备号 */

		/* (major, 0~1)对应hello_fops, (major, 2~255)d都不对应hello_fops 
		 * 参二:次设备号开始的下标
		 * 参三:次设备号个数
		 */
		alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");
		major = MAJOR(devid);
	}

	/* 3.3 初始化cdev,绑定fops结构体 */
	cdev_init(&hello_cdev, &hello_fops);

	/* 3.4 注册cdev */
	cdev_add(&hello_cdev, devid, HELLO_CNT);

    /* 3.5 分配第二个fops对应设备的次设备号 */
	devid = MKDEV(major, 2);
    
    /* (major, 2)对应hello2_fops, (major, 0、1;3~255)都不对应hello2_fops 
     * 注册第二个fops对应的设备
     */ 
	register_chrdev_region(devid, 1, "hello2");

    /* 初始化cdev,绑定第二个fops结构体 */
	cdev_init(&hello2_cdev, &hello2_fops);

    /* 注册第二个cdev */
	cdev_add(&hello2_cdev, devid, 1);
#endif

	cls = class_create(THIS_MODULE, "hello");
	class_device_create(cls, NULL, MKDEV(major, 0), NULL, "hello0");	/* /dev/hello0 */
	class_device_create(cls, NULL, MKDEV(major, 1), NULL, "hello1");	/* /dev/hello1 */
	class_device_create(cls, NULL, MKDEV(major, 2), NULL, "hello2");	/* /dev/hello2 */
	class_device_create(cls, NULL, MKDEV(major, 3), NULL, "hello3");	/* /dev/hello2 */

	return 0;
}

2.1.4、在出口函数hello_exit中

static void hello_exit(void)
{
	/* 删除类下面的设备 */
	class_device_destroy(cls, MKDEV(major, 0));	
	class_device_destroy(cls, MKDEV(major, 1));	
	class_device_destroy(cls, MKDEV(major, 2));
	class_device_destroy(cls, MKDEV(major, 3));
	
	/* 删除类 */
	class_destroy(cls);

	/* 卸载cdev */
	cdev_del(&hello_cdev);
	
	/* 删除创建的区域 */
	unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);

	cdev_del(&hello2_cdev);
	unregister_chrdev_region(MKDEV(major, 2), 1);
}

2.2、在hello_test中

/* hello_test <dev> */
void print_usage(char *file)
{
	printf("%s <dev>\n", file);
}
int main(int argc, char **argv)
{
	int fd;
	if(argc != 2)
	{
		print_usage(argv[0]);
		return 0;
	}
	fd = open(argv[1], O_RDWR);
	if(fd < 0)
		printf("can't open %s\n", argv[1]);
	else
		printf("can open %s\n", argv[1]);
	return 0;
}

2.3、修饰

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");

3、测试

1th:

测试驱动程序
在这里插入图片描述

2th:

加上测试程序hello_test
在这里插入图片描述
打开hello0、1、2都能打开,都有对应的file_operations结构体;
打不开hello3,缺少对应的file_operations结构体。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

「已注销」

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

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

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

打赏作者

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

抵扣说明:

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

余额充值