博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
指定子设备号创建字符设备
阅读量:6614 次
发布时间:2019-06-24

本文共 5050 字,大约阅读时间需要 16 分钟。

目录


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

tags: linux
date: 2018/12/28 19:57:24
toc: true
---

指定子设备号字符设备

流程

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

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

mark

流程如下:

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

  2. 如果指定主设备号使用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");
  3. 如果需要系统分配主设备号,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);
  4. 这里使用 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;               //连续注册的次设备号个数};
  5. 创建设备文件是与以前一样的,使用class_create创建类和class_device_create创建设备文件

  6. 卸载

    /*将系统中的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 2static 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/devicesCharacter devices:252 hello               #同一个主设备号252 hello2              #同一个主设备号

查看设备文件

# ls /dev/hello* -lcrw-rw----    1 0        0        252,   0 Jan  1 04:18 /dev/hello0crw-rw----    1 0        0        252,   1 Jan  1 04:18 /dev/hello1crw-rw----    1 0        0        252,   2 Jan  1 04:18 /dev/hello2crw-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/hello0hello_open                  #驱动1打开的can open /dev/hello0# ./test  /dev/hello1hello_open                  #驱动1打开的can open /dev/hello1# ./test  /dev/hello2hello2_open                 #驱动2打开的can open /dev/hello2# ./test  /dev/hello3can'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

你可能感兴趣的文章
黑马程序员——内部类
查看>>
校园的早晨
查看>>
单例模式的5种实现方式,以及在多线程环境下5种创建单例模式的效率
查看>>
oracle取前几行|中间几行|后几行
查看>>
16.1 Tomcat介绍
查看>>
QuickBI助你成为分析师——数据源FAQ小结
查看>>
十周三次课
查看>>
S/4HANA服务订单Service Order的批量创建
查看>>
2008 AD 复制有防火墙要开什么端口
查看>>
IT服务管理中的知识库建设
查看>>
【Lucene】Lucene通过CustomScoreQuery实现自定义评分
查看>>
我的友情链接
查看>>
Android应用程序组件Content Provider的共享数据更新通知机制分析(3)
查看>>
敏友的【敏捷个人】有感(11): 敏捷个人线下活动有感
查看>>
刺激用户危机意识,实现快速盈利的营销思维
查看>>
英特尔嵌入式突围
查看>>
JUnit单元测试
查看>>
[logstash-input-file]插件使用详解
查看>>
植物大战僵尸
查看>>
原创文章
查看>>