一些主设备编号是静态分派给最普通的设备的. 一个这些设备的列表在内核源码树的 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. typeof与js数据类型

    js有6种数据类型有null.undefied.string.number.boolean.object. 然而我之前的[误区]: typeof的返回值和JS的数据类型是一样的.但是并不是(⊙o⊙)哦 ...

  2. VC程序异常中断的原因

    自己编写的VC程序,编译调试通过,运行良好,然后关闭运行界面,就弹出一个“已经触发一个中断”的提示,然后断点就停在了下面这个中断处. _CRTIMP void _cdecl _CrtDbgBreak( ...

  3. 关于iOS7的一切相关的资料

    http://www.cocoachina.com/special/ios7/ PreviousNext 作为的用户,您可能需要了解 WWDC大会以及iOS 7的新界面 CocoaChina WWDC ...

  4. python 导入整个模块

  5. PHPCMS快速建站系列之在线留言

    有两种方法 第一种方法: 利用留言板插件,在后台模板中,安装留言板插件使用,这里先不展开. 第二种方法: 表单向导的适用场合: 如果一个前台页面只是为了提交表单数据,那么就非常适合适用表单向导的功能, ...

  6. JavaScript--天猫数量输入框

    <!DOCTYPE html> <head> <meta charset="utf-8" /> <title>无标题文档</t ...

  7. MySQL中使用LIMIT进行分页的方法

    一.分页需求: 客户端通过传递start(页码),pageSize(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和 ...

  8. swap function & copy-and-swap idiom

    在C++中,众所周知在一个资源管理类(例如含有指向堆内存的指针)中需要重新定义拷贝构造函数.赋值运算符以及析构函数(Big Three),在新标准下还可能需要定义移动构造函数和移动赋值运算符(Big ...

  9. android 数据存储----android短信发送器之文件的读写(手机+SD卡)

    本文实践知识点有有三: 1.布局文件,android布局有相对布局,线性布局,绝对布局,表格布局,标签布局等.各个布局能够嵌套的.本文的布局文件就是线性布局的嵌套 <LinearLayout x ...

  10. sql:mysql:函数:TIMESTAMPDIFF函数实现TimeStamp字段相减,求得时间差

    函数内指定是minute,则最终结果value值的单位是分钟,如果函数内指定为hours,则最终结果value值单位为小时. //UPLOAD_TIME 减去 CREATE_DTTM 求得时间差,以分 ...