一些主设备编号是静态分派给最普通的设备的. 一个这些设备的列表在内核源码树的 Documentation/devices.txt 中. 分配给你的新驱动使用一个已经分配的静态编号的机会 很小, 但是, 并且新编号没在分配. 因此, 作为一个驱动编写者, 你有一个选择: 你可以 简单地捡一个看来没有用的编号, 或者你以动态方式分配主编号. 只要你是你的驱动的唯 一用户就可以捡一个编号用; 一旦你的驱动更广泛的被使用了, 一个随机捡来的主编号将 导致冲突和麻烦.

因此, 对于新驱动, 我们强烈建议你使用动态分配来获取你的主设备编号, 而不是随机选 取一个当前空闲的编号. 换句话说, 你的驱动应当几乎肯定地使用 alloc_chrdev_region, 不是 register_chrdev_region.

动态分配的缺点是你无法提前创建设备节点, 因为分配给你的模块的主编号会变化. 对于 驱动的正常使用, 这不是问题, 因为一旦编号分配了, 你可从 /proc/devices 中读取 它.[6]6

为使用动态主编号来加载一个驱动, 因此, 可使用一个简单的脚本来代替调用 insmod, 在 调用 insmod 后, 读取 /proc/devices 来创建特殊文件.

一个典型的 /proc/devices 文件看来如下:

Character devices: 1 mem

2  pty

3  ttyp

4  ttyS

6  lp

7  vcs

10 misc

13  input

14  sound

21 sg

180 usb

Block devices: 2 fd

8 sd

11 sr

65  sd

66  sd

6  [6]

从 sysfs 中能获取更好的设备信息, 在基于 2.6 的系统通常加载于 /sys. 但是使 scull 通过 sysfs 输出信息超

出了本章的范围; 我们在 14 章中回到这个主题.

因此加载一个已经安排了一个动态编号的模块的脚本, 可以使用一个工具来编写, 如 awk , 来从 /proc/devices 获取信息以创建 /dev 中的文件.

下面的脚本, snull_load, 是 scull 发布的一部分. 以模块发布的驱动的用户可以从系统 的 rc.local 文件中调用这样一个脚本, 或者在需要模块时手工调用它.

#!/bin/sh module="scull" device="scull" mode="664"

# invoke insmod with all arguments we got

# and use a pathname, as newer modutils don't look in . by default

/sbin/insmod ./$module.ko $* || exit 1

# remove stale nodes

rm -f /dev/${device}[0-3]

major=$(awk "\\$2==\"$module\" {print \\$1}" /proc/devices) mknod /dev/${device}0 c $major 0

mknod /dev/${device}1 c $major 1 mknod /dev/${device}2 c $major 2

mknod /dev/${device}3 c $major 3

# give appropriate group/permissions, and change the group.

# Not all distributions have staff, some have "wheel" instead. group="staff"

grep -q '^staff:' /etc/group || group="wheel"

chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3]

这个脚本可以通过重定义变量和调整 mknod 行来适用于另外的驱动. 这个脚本仅仅展示了 创建 4 个设备, 因为 4 是 scull 源码中缺省的.

脚本的最后几行可能有些模糊:为什么改变设备的组和模式? 理由是这个脚本必须由超级用 户运行, 因此新建的特殊文件由 root 拥有. 许可位缺省的是只有 root 有写权限, 而任 何人可以读. 通常, 一个设备节点需要一个不同的存取策略, 因此在某些方面别人的存取 权限必须改变. 我们的脚本缺省是给一个用户组存取, 但是你的需求可能不同. 在第 6 章 的"设备文件的存取控制"一节中, sculluid 的代码演示了驱动如何能够强制它自己的对设 备存取的授权.

还有一个 scull_unload 脚本来清理 /dev 目录并去除模块.

作为对使用一对脚本来加载和卸载的另外选择, 你可以编写一个 init 脚本, 准备好放在 你的发布使用这些脚本的目录中. [7] 7作为 scull 源码的一部分, 我们提供了一个相当完整

和可配置的 init 脚本例子, 称为 scull.init; 它接受传统的参数 -- start, stop, 和 restart -- 并且完成 scull_load 和 scull_unload 的角色.

如果反复创建和销毁 /dev 节点, 听来过分了, 有一个有用的办法. 如果你在加载和卸载 单个驱动, 你可以在你第一次使用你的脚本创建特殊文件之后, 只使用 rmmod 和 insmod: 这样动态编号不是随机的. [8]8并且你每次都可以使用所选的同一个编号, 如果你不加载任 何别的动态模块. 在开发中避免长脚本是有用的. 但是这个技巧, 显然不能扩展到一次多 于一个驱动.

安排主编号最好的方式, 我们认为, 是缺省使用动态分配, 而留给自己在加载时指定主编 号的选项权, 或者甚至在编译时. scull 实现以这种方式工作; 它使用一个全局变量, scull_major, 来持有选定的编号(还有一个 scull_minor 给次编号). 这个变量初始化为 SCULL_MAJOR, 定义在 scull.h. 发布的源码中的 SCULL_MAJOR 的缺省值是 0, 意思是"使 用动态分配". 用户可以接受缺省值或者选择一个特殊主编号, 或者在编译前修改宏定义或 者在 insmod 命令行指定一个值给 scull_major. 最后, 通过使用 scull_load 脚本, 用 户可以在 scull_load 的命令行传递参数给 insmod.[9]9

这是我们用在 scull 的源码中获取主编号的代码:

if (scull_major) {

dev = MKDEV(scull_major, scull_minor);

result = register_chrdev_region(dev, scull_nr_devs, "scull");

} else {

result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev);

}

if (result < 0) {

printk(KERN_WARNING "scull: can't get major %d\n", scull_major); return result;

}

本书使用的几乎所有例子驱动使用类似的代码来分配它们的主编号.

linux主编号的动态分配的更多相关文章

  1. 鸟哥的linux私房菜——第十三章学习(Linux 帐号管理与 ACLL 权限设置)

    第十三章.Linux 帐号管理与 ACLL 权限设置 1.0).使用者识别码: UID 与 GID UID :User ID GID :group ID [root@study ~]# ll -d / ...

  2. linux设备号分配

    参考:http://blog.chinaunix.net/uid-24460251-id-2606762.htmlhttp://blog.csdn.net/zjjyliuweijie/article/ ...

  3. Linux:主设备号和次设备号

    http://www.linuxidc.com/Linux/2011-03/33863.htm     Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备 ...

  4. Java,Python,前端,Linux,公众号等5T编程资源整理免费下载

    场景 我的CSDN: https://blog.csdn.net/BADAO_LIUMANG_QIZHI 实现 马士兵Java学习视频 方立勋JavaWeb 尚硅谷Python核心基础 数据分析 机器 ...

  5. Linux 单引号和双引号的区别

    1.单引号 单引号将其中的内容都作为了字符串来,忽略所有的命令和特殊字符,类似于一个字符串的用法 $echo 'This is a string' This is a string $echo 'ls ...

  6. 获取linux服务进程号

    ps -ef | grep "服务名" | grep -v "grep" | awk '{print $2}' # ps -ef|grep "被查询的 ...

  7. linux系统调用号查询(pwn)

    做pwn题时遇到程序使用了64位系统调用号:59和15,这里做一下记录 在线查询链接:https://syscalls.w3challs.com/ 分为32位和64位,链接中还有arm.mips等架构 ...

  8. Linux C--信号 sigaction函数

    使用 sigaction 函数: signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受 到了一定的限制.而 POSIX 标准定义的信号处 ...

  9. linux 系统调用号表

    位于 /usr/include/asm/unistd.h 由于我是64位系统,所以有一些额外的东西.我的这个文件为下文 #ifndef _ASM_X86_UNISTD_H #define _ASM_X ...

随机推荐

  1. python Match函数

  2. Leetcode3.Longest Substring Without Repeating Characters无重复字符的最长字串

    给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 ...

  3. ubuntu上将常用程序拖到左侧栏目

  4. 阿里工程师开发了一款免费工具,提升Kubernetes应用开发效率

    对于使用了Kubernetes作为应用运行环境的开发者而言,在同一个集群中我们可以使用命名空间(Namespace)快速创建多套隔离环境,在相同命名空间下,服务间使用Service的内部DNS域名进行 ...

  5. java 使用poi导出Excel,设置单元格保护不可编辑

    //sheet表加密:等效excel的审阅菜单下的保护工作表 sheet.protectSheet(new String("333"));//333是密码 更多设置请参考:http ...

  6. 如何利用 Webshell 诊断 EDAS Serverless 应用

    本文主要介绍 Serverless 应用的网络环境以及 Serverless 应用容器内的环境,了解背景知识以及基本的运维知识后可以利用 Webshell 完成基本的运维需求. Webshell 简介 ...

  7. 小爬爬5:重点回顾&&移动端数据爬取1

    1. ()什么是selenium - 基于浏览器自动化的一个模块 ()在爬虫中为什么使用selenium及其和爬虫之间的关联 - 可以便捷的获取动态加载的数据 - 实现模拟登陆 ()列举常见的sele ...

  8. 运行docker容器镜像

    docker容器可以理解为在盒中运行的进程. 这个盒包含了该进程运行所必须的资源,包括文件系统.系统类库.shell 环境等等. 但这个盒默认是不会运行任何程序的. 1.运行镜像之前,可以先查看本地有 ...

  9. BKDRhash

     哈希: 字符串(数字同理): 例如有100000个字符串,现在要插入一些字符串,插入前比较是否已经存在避免含有重复数据 用暴力计较的话会比较慢,在某字符串插入时,最好的情况是在第一个位置就遇见该字符 ...

  10. 创建我的flask第一个应用(一)

    本地python版本 (venv) dongge@dongge-PC:/data/webroot$ python --version Python 3.6.5 创建flask命令 $mkdir myp ...