linux创建的设备号,指定子设备号创建字符设备

本文介绍了在Linux内核中如何指定子设备号创建字符设备,包括使用register_chrdev_region和alloc_chrdev_region注册设备号,通过cdev结构体管理驱动,并创建设备文件。详细讲解了流程和示例代码,展示了如何为不同的file_operations分配不同的子设备号。
摘要由CSDN通过智能技术生成

目录

title: 指定子设备号创建字符设备

tags: linux

date: 2018/12/28 19:57:24

toc: true

---

指定子设备号字符设备

流程

内核中设备号分为主设备号和次设备号,以前注册字符设备驱动的时候,直接占用了主设备号包含了255个子设备号,也就是内核最多支持255个设备驱动(如果主设备号占据8位)

在Linux2.6中内核可以指定主设备号和对应的子设备号给一个fileoperation,如下图所示

97aeba530c1e81fc1059dfff5536f2d2.png

流程如下:

确认需要得到几个子设备号使用

如果指定主设备号使用register_chrdev_region,当返回值小于0,表示注册失败

dev_t devid;

devid = MKDEV(major, 0);

/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */

register_chrdev_region(devid, HELLO_CNT, "hello");

如果需要系统分配主设备号,alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");当返回值小于0,表示注册失败

/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */

alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello");

major = MAJOR(devid);

这里使用 cdev管理驱动,并将file_operations结构体放入cdev-> ops 里

cdev_init(&hello_cdev, &hello_fops);

cdev_add(&hello_cdev, devid, HELLO_CNT);

struct cdev {

struct kobject kobj; // 内嵌的kobject对象

struct module *owner; //所属模块

const struct file_operations *ops; //操作方法结构体

struct list_head list; //与 cdev 对应的字符设备文件inode->i_devices 的链表头

dev_t dev;          //起始设备编号,可以通过MAJOR(),MINOR()来提取主次设备号

unsigned int count;  //连续注册的次设备号个数

};

创建设备文件是与以前一样的,使用class_create创建类和class_device_create创建设备文件

卸载

/*将系统中的cdev结构体删除掉*/

void cdev_del(struct cdev *p);

/*注销字符设备*/

void unregister_chrdev_region(dev_t from, unsigned count);

实例程序

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

/* 1. 确定主设备号 */

static int major;

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. 构造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,

};

#define HELLO_CNT 2

static struct cdev hello_cdev;

static struct cdev hello2_cdev;

static struct class *cls;

static int hello_init(void)

{

dev_t devid;

/* 3. 告诉内核 */

#if 0

major = register_chrdev(0, "hello", &hello_fops); /* (major, 0), (major, 1), ..., (major, 255)都对应hello_fops */

#else

if (major) {

devid = MKDEV(major, 0);

register_chrdev_region(devid, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */

} else {

alloc_chrdev_region(&devid, 0, HELLO_CNT, "hello"); /* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */

major = MAJOR(devid);

}

cdev_init(&hello_cdev, &hello_fops);

cdev_add(&hello_cdev, devid, HELLO_CNT);

devid = MKDEV(major, 2);

register_chrdev_region(devid, 1, "hello2");

cdev_init(&hello2_cdev, &hello2_fops);

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/hello3 */

return 0;

}

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_del(&hello_cdev);

unregister_chrdev_region(MKDEV(major, 0), HELLO_CNT);

cdev_del(&hello2_cdev);

unregister_chrdev_region(MKDEV(major, 2), 1);

}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("GPL");

测试

查看到只是用了同一个主设备号

cat /proc/devices

# cat /proc/devices

Character devices:

252 hello #同一个主设备号

252 hello2 #同一个主设备号

查看设备文件

# ls /dev/hello* -l

crw-rw---- 1 0 0 252, 0 Jan 1 04:18 /dev/hello0

crw-rw---- 1 0 0 252, 1 Jan 1 04:18 /dev/hello1

crw-rw---- 1 0 0 252, 2 Jan 1 04:18 /dev/hello2

crw-rw---- 1 0 0 252, 3 Jan 1 04:18 /dev/hello3

驱动fileopration

次设备号

hello_fops

0,1

hello2_fops

2

也就是对应设备文件的驱动如下

设备文件

/dev/hello0

hello_fops

/dev/hello1

hello_fops

/dev/hello2

hello2_fops

/dev/hello3

没有

使用测试文件去打开文件如下结果

# ./test /dev/hello0

hello_open #驱动1打开的

can open /dev/hello0

# ./test /dev/hello1

hello_open #驱动1打开的

can open /dev/hello1

# ./test /dev/hello2

hello2_open #驱动2打开的

can open /dev/hello2

# ./test /dev/hello3

can‘t open /dev/hello3 #无法打开

测试程序如下

//arm-linux-gcc -o test test.c

#include

#include

#include

#include

#include

#include

/*

* test /dev/hello0

*/

void print_usage(char *file)

{

printf("%s \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;

}

原文:https://www.cnblogs.com/zongzi10010/p/10192518.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值