一些主设备编号是静态分派给最普通的设备的. 一个这些设备的列表在内核源码树的 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. C++ 浮点数 为 0 的判断

  2. 使用Fiddler抓取到的“姐夫酷”API接口

    下午本来准备抓取些网页视频地址,做一个小的视频app,用来学习ijkplayer,无意中发现了一个app--姐夫酷,这是一个很简单的网页,它也有相应的一个比较简单的android app. 于是心血来 ...

  3. Android AbsListView子类反复调用getView()和getCount()问题分析

    对于AbsListView子类,假设它的宽高是自适应的,你会发现getView()和getCount()会被疯狂的反复调用.即使在AbsListView子类设置完adapter后,getView()和 ...

  4. 每天一个linux命令(1): which命令

    0.学习时间: 2014-05-15 which命令用来在PATH指定的路径中查找特定的文件, 并返回第一个找到的结果. 1. 命令格式:  which 文件名 2.命令功能 一般使用which命令来 ...

  5. Git同步Python代码

    之前我们都是将代码保存到本地目录, 然后再上传到Git中,但如果针对在pycharm中的代码,就要换另一种方式了,下面简单介绍一下. 1.打开pycharm主界面,选择菜单栏VCS---checkou ...

  6. 一维数组的求平均成绩 Day06

    package com.sxt.arraytest1; /* * 求班里学生的平均成绩,以及成绩的综合 输出每个同学的成绩 */ import java.util.Arrays; import jav ...

  7. TreeSet的运用之使用内部比较器实现自定义有序(重要)

    Student.java package com.sxt.set3; /* * TreeSet:有序 * implements Comparable<Student> * 如果用内部比较器 ...

  8. 基于Qt框架的GUI控制台——qtconsole

  9. qt painter多个点的曲线

    plot.h #ifndef PLOT_H #define PLOT_H #include<QTimer> #include <QWidget> class pathplot ...

  10. CH1401 兔子与兔子

    #include<bits/stdc++.h> using namespace std; ,p=; typedef unsigned long long ULL;//自然溢出 ULL f[ ...