精华内容
下载资源
问答
  • Linux中各种设备及设备号

    千次阅读 2016-07-24 10:50:18
    Linux中所有一切都是文件,Linux中的各种设备,分类来说,可分为物理设备及特殊设备。前者是客观存在的设备,而后者则未必能在系统找到,又可以称为伪设备,下面按物理设备和特殊设备,对其进行系统归纳总结。

    Linux中所有一切都是文件,Linux中的各种设备,分类来说,可分为物理设备及特殊设备。前者是客观存在的设备,而后者则未必能在系统找到,又可以称为伪设备,下面按物理设备和特殊设备,对其进行系统归纳总结。


    备注:

    1) 上面分别为设备及在Linux内的对应的文件名,其中U盘的与SCSI/SATA/USB硬盘文件名一致;

    2)  每块硬盘只能有四个主分区和扩展分区(三个主分区+一个扩展分区,或者四个主分区)

    3)  对应SCSI盘,/dev/sda为其中一块硬盘,/dev/sda1则为其中一个分区

    4)  当前鼠标为/dev/mouse,如果接了USB鼠标,或者PS2鼠标,其设备文件不同



    备注:

    1) stdin,stdout,stderr 分别对应0,1,2


    2)  /dev/null 空洞设备,可以丢弃任何文件,数据流。主要用于dd硬盘读写速度,或清空文件等


    3)  /dev/zero 是一个特殊的文件,当你读它的时候,它会提供无限的空字符(NULL, ASCII NUL, 0x00)。其中的一个典型用法是用它提供的字符流来覆盖信息,另一个常见用法是产生一个特定大小的空白文件


    4)  /dev/full 是一个特殊设备文件,总是在向其写入时返回设备无剩余空间(错误码为ENOSPC),读取时则与/dev/zero相似,返回无限的空字符(NULL, ASCII NUL, 0x00)。


    5)  /dev/fd  记录用户打开的文件描述符


    6)  /dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。很多解密程序与安全应用程序(如SSH Keys,SSL Keys等)需要它们提供的随机数据流。这两个设备的差异在于:/dev/random的random pool依赖于系统中断,因此在系统的中断数不足时,/dev/random设备会一直封锁,尝试读取的进程就会进入等待状态,直到系统的中断数充分够用, /dev/random设备可以保证数据的随机性。/dev/urandom不依赖系统的中断,也就不会造成进程忙等待,但是数据的随机性也不高。


    展开全文
  • linux设备号详解

    万次阅读 2011-11-22 17:42:23
    每个字符设备和块设备都必须有主、次设备号,主设备号相同的设 备是同类设备(使用同一个驱动程序)。这些设备中,有些设备是对实际存在的物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,...
      
    

    linux 中的设备有2种类型:字符设备(无缓冲且只能顺序存取)、块设备(有缓冲且可以随机存取)。每个字符设备和块设备都必须有主、次设备号,主设备号相同的设 备是同类设备(使用同一个驱动程序)。这些设备中,有些设备是对实际存在的物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,又称为"虚拟设备")。每个设备在 /dev 目录下都有一个对应的文件(节点)。可以通过 cat /proc/devices 命令查看当前已经加载的设备驱动程序的主设备号。内核能够识别的所有设备都记录在原码树下的 documentation/devices.txt 文件中。在 /dev 目录下除了字符设备和块设备节点之外还通常还会存在:fifo管道、socket、软/硬连接、目录。这些东西没有主/次设备号。
    $ ls -l /dev/rfd0 /dev/fd0
    brw-r-----  9 root operator 2, 0 nov 12 13:32 /dev/fd0
    crw-r-----  9 root operator 9, 0 nov 12 13:32 /dev/rfd0
        可以看到原来显示文件大小的地方,现在改为显示两个用逗号分隔的数字。这是系统用来表示设备的两个重要的序号,第一个为主设备号(major number),用来表示设备使用的硬件驱动程序在系统中的序号;第二个为从设备号(minor number)。
    linux内核所能识别的所有 设备都记录在
    http://www.lanana.org/docs/device-list/
    而内核原码树中的 documentation/devices.txt 可能不是最新版本。
    了解这些设备的最基本要求就是对 每个设备文件的含义了如指掌,下面就医列表的形式列出常见的设备文件以及相应的含义(比较偏僻的就省略了):
    代 码:----------------------------------------------------------------------
    主 设备号        设备类型
                   次设备号=文件名          简要说明
    ----------------------------------------------------------------------
     0                未命名设备(例如:挂载的非设备)
                     0 = 未空设备号保留
     1 char        内存设备
                     1 = /dev/mem                直接存取物理内存
                     2 = /dev/kmem                存取经过内核虚拟之后的内存
                     3 = /dev/null                空设备。任何写入都将被直接丢弃,任何读取都将得到eof。
                     4 = /dev/port                存取 i/o 端口
                     5 = /dev/zero                零字节源,只能读取到无限多的零字节。
                     7 = /dev/full                满设备。任何写入都将失败,并把errno设为enospc以表示没有剩余空间。
                     8 = /dev/random        随机数发生器。完全由用户的输入来产生随机数。
                                           如果用户停止所有动作,则停止产生新的随机数。
                     9 = /dev/urandom        更快,但是不够安全的随机数发生器。尽可能由用户的输入来产生随机数,
                                           如果用户停止所有动作,则把已经产生的随机数做为种子来产生新的随机数。
                    10 = /dev/aio                异步 i/o 通知接口
                    11 = /dev/kmsg                任何对该文件的写入都将作为 printk 的输出
     1 block        ram disk
                     0 = /dev/ram0                第1个 ram disk (initrd只能使用ram0)
                     1 = /dev/ram1                第2个 ram disk
                       ...
                   200 = /dev/ram200        第200个 ram disk
     4 char        tty(终端)设备
                     0 = /dev/tty0                当前虚拟控制台
                     1 = /dev/tty1                第1个虚拟控制台
                       ...
                    63 = /dev/tty63        第63个虚拟控制台
     4 block        如果根文件系统以是以只读方式挂载的,那么就不可能创建真正的设备节点,
                   此时就使用该设备作为动态分配的主(major)设备的别名
                     0 = /dev/root
     5 char        其他 tty 设备
                     0 = /dev/tty                当前 tty 设备
                     1 = /dev/console        系统控制台
                     2 = /dev/ptmx                所有 pty master 的复用器
     7 char        虚拟控制台捕捉设备(这些设备既允许读也允许写)
                     0 = /dev/vcs                当前虚拟控制台(vc)的文本内容
                     1 = /dev/vcs1                tty1 的文本内容
                       ...
                    63 = /dev/vcs63        tty63 的文本内容
                   128 = /dev/vcsa                当前虚拟控制台(vc)的文本/属性内容
                   129 = /dev/vcsa1        tty1 的文本/属性内容
                       ...
                   191 = /dev/vcsa63        tty63 的文本/属性内容
    代码:  7 block        回环设备(用一个普通的磁盘文件来模拟一个块设备)
                   对回环设备的绑定由 mount(8) 或 losetup(8) 处理
                     0 = /dev/loop0        第1个回环设备
                     1 = /dev/loop1        第2个回环设备
                       ...
     8 block        scsi 磁盘(0-15)
                     0 = /dev/sda                第1个 scsi 磁盘(整个磁盘)
                    16 = /dev/sdb                第2个 scsi 磁盘(整个磁盘)
                    32 = /dev/sdc                第3个 scsi 磁盘(整个磁盘)
                       ...
                   240 = /dev/sdp                第16个 scsi 磁盘(整个磁盘)
                   分区表示方法如下(以第3个 scsi 磁盘为例)
                    33 = /dev/sdc1                第1个分区
                    34 = /dev/sdc2                第2个分区
                       ...
                    47 = /dev/sdc15        第15个分区
                   对于linux/i386来说,分区1-4是主分区,5-15是逻辑分区。
     9 block        metadisk(raid)设备
                     0 = /dev/md0                第1组 metadisk
                     1 = /dev/md1                第2组 metadisk
                       ...
                   metadisk 驱动用于将同一个文件系统分割到多个物理磁盘上。
    10 char        非串口鼠标,各种杂项设备和特性
                     1 = /dev/psaux        ps/2鼠标
                   131 = /dev/temperature        机器内部温度
                   134 = /dev/apm_bios        apm(高级电源管理) bios
                   135 = /dev/rtc                实时时钟(real time clock)
                   144 = /dev/nvram        非易失配置 ram
                   162 = /dev/smbus        系统管理总线(system management bus)
                   164 = /dev/ipmo                intel的智能平台管理(intelligent platform management)接口
                   173 = /dev/ipmikcs        智能平台管理(intelligent platform management)接口
                   175 = /dev/agpgart        agp图形地址重映射表(graphics address remapping table)
                   182 = /dev/perfctr        性能监视计数器
                   183 = /dev/hwrng        通用硬件随机数发生器
                   184 = /dev/cpu/microcode cpu微代码更新接口
                   186 = /dev/atomicps        进程状态数据的原子快照
                   188 = /dev/smbusbios        smbus(系统管理总线) bios
                   200 = /dev/net/tun        tap/tun 网络设备(tap/tun以软件的方式实现了网络设备)
                                           tap模拟了以太网帧(第二层),tun模拟了ip包(第三层)。
                   202 = /dev/emd/ctl        增强型 metadisk raid (emd) 控制器
                   220 = /dev/mptctl        message passing technology (mpt) control
                   223 = /dev/input/uinput        用户层输入设备驱动支持
                   227 = /dev/mcelog        x86_64 machine check exception driver
                   228 = /dev/hpet                hpet driver
                   229 = /dev/fuse                fuse(用户空间的虚拟文件系统)
                   231 = /dev/snapshot        系统内存快照
                   232 = /dev/kvm                基于内核的虚构机(基于amd svm和intel vt硬件虚拟技术)
    11 block        scsi cd-rom 设备
                     0 = /dev/scd0                第1个 scsi cd-rom
                     1 = /dev/scd1                第2个 scsi cd-rom
                       ...
    代码:
    13 char        核心输入设备
                    32 = /dev/input/mouse0                第1个鼠标
                    33 = /dev/input/mouse1                第2个鼠标
                       ...
                    62 = /dev/input/mouse30        第31个鼠标
                    63 = /dev/input/mice                所有鼠标的统一
                    64 = /dev/input/event0                第1个事件队列
                    65 = /dev/input/event1                第2个事件队列
                       ...
                    95 = /dev/input/event1                第32个事件队列
    21 char        通用 scsi 设备(通常是scsi光驱)
                     0 = /dev/sg0                第1个通用 scsi 设备
                     1 = /dev/sg1                第2个通用 scsi 设备
                       ...
    29 char        通用帧缓冲(frame buffer)设备
                     0 = /dev/fb0                第1个帧缓冲设备
                     1 = /dev/fb1                第2个帧缓冲设备
                       ...
                    31 = /dev/fb31                第32个帧缓冲设备
    30 char        ibcs-2 兼容设备
                     0 = /dev/socksys        套接字访问接口
                     1 = /dev/spx                svr3 本地 x 接口
                    32 = /dev/inet/ip        网络访问接口
                    33 = /dev/inet/icmp
                    34 = /dev/inet/ggp
                    35 = /dev/inet/ipip
                    36 = /dev/inet/tcp
                    37 = /dev/inet/egp
                    38 = /dev/inet/pup
                    39 = /dev/inet/udp
                    40 = /dev/inet/idp
                    41 = /dev/inet/rawip
                   此外,ibcs-2 还需要下面的连接必须存在
                   /dev/ip -> /dev/inet/ip
                   /dev/icmp -> /dev/inet/icmp
                   /dev/ggp -> /dev/inet/ggp
                   /dev/ipip -> /dev/inet/ipip
                   /dev/tcp -> /dev/inet/tcp
                   /dev/egp -> /dev/inet/egp
                   /dev/pup -> /dev/inet/pup
                   /dev/udp -> /dev/inet/udp
                   /dev/idp -> /dev/inet/idp
                   /dev/rawip -> /dev/inet/rawip
                   /dev/inet/arp -> /dev/inet/udp
                   /dev/inet/rip -> /dev/inet/udp
                   /dev/nfsd -> /dev/socksys
                   /dev/x0r -> /dev/null
    代码: 36 char        netlink 支持
                     0 = /dev/route        路由, 设备更新, kernel to user
                     3 = /dev/fwmonitor        firewall packet 复制
    59 char        sf 防火墙模块
                     0 = /dev/firewall        与 sf 内核模块通信
    65 block        scsi 磁盘(16-31)
                     0 = /dev/sdq                第17个 scsi 磁盘(整个磁盘)
                    16 = /dev/sdr                第18个 scsi 磁盘(整个磁盘)
                    32 = /dev/sds                第19个 scsi 磁盘(整个磁盘)
                       ...
                   240 = /dev/sdaf                第32个 scsi 磁盘(整个磁盘)
    66 block        scsi 磁盘(32-47)
                     0 = /dev/sdag                第33个 scsi 磁盘(整个磁盘)
                    16 = /dev/sdah                第34个 scsi 磁盘(整个磁盘)
                    32 = /dev/sdai                第35个 scsi 磁盘(整个磁盘)
                       ...
                   240 = /dev/sdav                第48个 scsi 磁盘(整个磁盘)
    89 char        i2c 总线接口
                     0 = /dev/i2c-0        第1个 i2c 适配器
                     1 = /dev/i2c-1        第2个 i2c 适配器
                       ...
    98 block        用户模式下的虚拟块设备(分区处理方式与 scsi 磁盘相同)
                     0 = /dev/ubda                第1个用户模式块设备
                    16 = /dev/udbb                第2个用户模式块设备
                       ...
    103 block        审计(audit)设备
                     0 = /dev/audit        审计(audit)设备
    128-135 char        unix98 pty master
                   这些设备不应当存在设备节点,而应当通过 /dev/ptmx 接口访问。
    136-143 char        unix98 pty slave
                   这些设备节点是自动生成的(伴有适当的权限和模式),不能手动创建。
                   方法是通过使用适当的 mount 选项(通常是:mode=0620,gid=)
                   将 devpts 文件系统挂载到 /dev/pts 目录即可。
                     0 = /dev/pts/0        第1个 unix98 pty slave
                     1 = /dev/pts/1        第2个 unix98 pty slave
                       ...
    代码:153 block        enhanced metadisk raid (emd) 存储单元(分区处理方式与 scsi 磁盘相同)
                     0 = /dev/emd/0        第1个存储单元
                     1 = /dev/emd/0p1        第1个存储单元的第1个分区
                     2 = /dev/emd/0p2        第1个存储单元的第2个分区
                       ...
                    15 = /dev/emd/0p15        第1个存储单元的第15个分区
                    16 = /dev/emd/1        第2个存储单元
                    32 = /dev/emd/2        第3个存储单元
                       ...
                   240 = /dev/emd/15        第16个存储单元
    180 char        usb 字符设备
                    96 = /dev/usb/hiddev0        第1个usb人机界面设备(鼠标/键盘/游戏杆/手写版等人操作计算机的设备)
                       ...
                   111 = /dev/usb/hiddev15        第16个usb人机界面设备
    180 block        usb 块设备(u盘之类)
                     0 = /dev/uba                第1个usb 块设备
                     8 = /dev/ubb                第2个usb 块设备
                    16 = /dev/ubc                第3个usb 块设备
                        ...
    192 char        内核 profiling 接口
                     0 = /dev/profile        profiling 控制设备
                     1 = /dev/profile0        cpu 0 的 profiling 设备
                     2 = /dev/profile1        cpu 1 的 profiling 设备
                       ...
    193 char        内核事件跟踪接口
                     0 = /dev/trace        跟踪控制设备
                     1 = /dev/trace0        cpu 0 的跟踪设备
                     2 = /dev/trace1        cpu 1 的跟踪设备
                       ...
    195 char        nvidia 图形设备(比如显卡)
                     0 = /dev/nvidia0                第1个 nvidia 卡
                     1 = /dev/nvidia1                第2个 nvidia 卡
                       ...
                   255 = /dev/nvidiactl                nvidia 卡控制设备
    202 char        特定于cpu模式的寄存器(model-specific register,msr)
                     0 = /dev/cpu/0/msr                cpu 0 的 msrs
                     1 = /dev/cpu/1/msr                cpu 1 的 msrs
                       ...
    203 char        cpu cpuid 信息
                     0 = /dev/cpu/0/cpuid                cpu 0 的 cpuid
                     1 = /dev/cpu/1/cpuid                cpu 1 的 cpuid
                       ...
    代 码:===================================================================
    这 部分详细说明一些应该或可能存在于 /dev 目录之外的文件。
    链接最好使用与这里完全相同的格式(绝对路径或相对路径)。
    究竟是使用硬 链接(hard)还是软连接(symbolic)取决于不同的设备。
           必须的链接
    必须在所有的系统上都存在这些连接:
    链 接                目标                链接类型        简要说明
    /dev/fd                /proc/self/fd        symbolic        文件描述府
    /dev/stdin        fd/0                symbolic        标准输入文件描述府
    /dev/stdout        fd/1                symbolic        标准输出文件描述符
    /dev/stderr        fd/2                symbolic        标准错误文件描述符
    /dev/nfsd        socksys                symbolic        仅为 ibcs-2 所必须
    /dev/x0r        null                symbolic        仅为 ibcs-2 所必须
    [注意] /dev/x0r 是 --
           推荐的链接
    推荐在所有的系统上都存在这些连接:
    链接                目标                链接类型        简要说明
    /dev/core        /proc/kcore        symbolic        为了向后兼容
    /dev/ramdisk        ram0                symbolic        为了向后兼容
    /dev/ftape        qft0                symbolic        为了向后兼容
    /dev/bttv0        video0                symbolic        为了向后兼容
    /dev/radio        radio0                symbolic        为了向后兼容
    /dev/i2o*        /dev/i2o/*        symbolic        为了向后兼容
    /dev/scd?        sr?                hard                代替 scsi cd-rom 的名字
           本地定义的链接
    下面的 链接很可能需要根据机器的实际硬件配置创建其中的一部分甚至全部。
    这些链接仅仅是为了迎合习惯用法,它们既非必须也非推荐。
    链接                目标                链接类型        简要说明
    /dev/mouse        mouse port        symbolic        当前鼠标
    /dev/tape        tape device        symbolic        当前磁带
    /dev/cdrom        cd-rom device        symbolic        当前cd-rom
    /dev/cdwriter        cd-writer        symbolic        当前cd-writer
    /dev/scanner        scanner                symbolic        当前扫描仪
    /dev/modem        modem port        symbolic        当前调制解调器
    /dev/root        root device        symbolic        当前根文件系统所在设备
    /dev/swap        swap device        symbolic        当前swap所在设备
    /dev/modem 不应当用于能够同时支持呼入和呼出的modem,因为往往会导致锁文件问题。
    如果存在 /dev/modem ,那么它应当指向一个恰当的主 tty 设备。
    对于scsi设备,
    /dev/tape 和 /dev/cdrom 应该分别指向"cooked"设备 /dev/st* 和 /dev/sr* ;
    而 /dev/cdwriter 和 /dev/scanner 应当分别指向恰当的 /dev/sg* 。
    /dev/mouse 可以指向一个主串行 tty 设备、一个硬件鼠标、
    或 者一个对应鼠标驱动程序的套接字(例如 /dev/gpmdata)。
           套接字和管道
    持久套接字和命名管道可以存在于 /dev 中。常见的有:
    /dev/printer        socket                lpd 本地套接字
    /dev/log        socket                syslog 本地套接字
    /dev/gpmdata        socket                gpm 鼠标多路复用器(multiplexer)
    /dev/gpmctl        socket                (lfs-livecd中出现)
    /dev/initctl        fifo pipe        init 监听它并从中获取信息(用户与 init 进程交互的通道)
           挂载点
    以下名称被保留用于挂载特殊的文件系统。
    这 些特殊的文件系统只提供内核界面而不提供标准的设备节点。
    /dev/pts        devpts                pty slave 文件系统
    /dev/shm        tmpfs                提供对 posix 共享内存的直接访问
    ===================================================================
    终 端(或tty)设备是一种特殊的字符设备。终端设备是可以在会话中扮演控制终端角色的任何设备,
    包括:虚拟控制台、串行接口(已废弃)、伪终端 (pty)。
    所有的终端设备共享一个通用的功能集合:line discipline,
    它既包含通用的终端 line discipline 也包含slip和ppp模式。
    所有的终端设备的命名都很相似。这部分内容将解释命名规则和各种类型的tty(终端)的使 用。
    需要注意的是这些命名习惯包含了几个历史遗留包袱。
    其中的一些是linux所特有的,另一些则是继承自其他系统,
    还有一些反 映了linux在成长过程中抛弃了原来借用自其它系统的一些习惯。
    井号(#)在设备名里表示一个无前导零的十进制数。
    虚拟控制台 (virtual console)和控制台设备(console device)
    虚拟控制台是在系统视频监视器上全屏显示的终端。
    虚拟 控制台被命名为编号从 /dev/tty1 开始的 /dev/tty# 。
    /dev/tty0 是当前虚拟控制台。
    /dev/tty0 用于在不能使用帧缓冲设备(/dev/fb*)的机器上存取系统视频卡,
    注意,不要将 /dev/console 用于此目的。
    /dev/console 由内核管理,系统消息将被发送到这里。
    单用户模式下必须允许 login 使用 /dev/console 。
    串行接口(已废弃)
    这 里所说的"串行接口"是指 rs-232 串行接口和任何模拟这种接口的设备,
    不管是在硬件(例如调制解调器)还是在软件(例如isdn驱动)中 模拟。
    在linux中的每一个串行接口都有两个设备名:
    主设备或呼入(callin)设备、交替设备或呼出(callout)设备。
    设 备类型之间使用字母的大小写进行区分。
    比如,对于任意字母x,"tty"设备名为 /dev/ttyx# ,而"cu"设备名则为 /dev/cux# 。
    由于历史原因,/dev/ttys# 和 /dev/ttyc# 分别等价于 /dev/cua# 和 /dev/cub# 。
    名称 /dev/ttyq# 和 /dev/cuq# 被保留为本地使用。
    伪终端(pty)
    伪终端用于创 建登陆会话或提供其它功能,
    比如通过 tty line discipline (包括slip或者ppp功能)来处理任意的数据生成。
    每 一个 pty 都有一个master端和一个slave端。按照 system v/unix98 的 pty 命名方案,
    所有master端共 享同一个 /dev/ptmx 设备节点(打开它内核将自动给出一个未分配的pty),
    所有slave端都位于 /dev/pts 目录下,名为 /dev/pts/# (内核会根据需要自动生成和删除它们)。
    一旦master端被打开,相应的slave设备就可以按照与 tty 设备完全相同的方式使用。
    master设备与slave设备之间通过内核进行连接,等价于拥有 tty 功能的双向管道(pipe)。
    ===============================
    你 可能会很奇怪,为什么没有 /dev/hda 这样的设备,难道不常用么?
    原因在于从 2.6.19 开始,内核引入了新的ata驱动,将sata/ide硬盘同意使用 /dev/sd? 来表示了,所以 /dev/hd? 就没有存在的必要了

    展开全文
  • 描述一个pci设备,就需要知道设备的厂商号(venderId)、设备号(devId)和class号。那么,在Linux系统中,如何获取这三个数据呢?  既然是一个pci设备,那么首先就得知道BDF——该pci设备在OS中的唯一标识符。...

      要描述一个pci设备,就需要知道设备的厂商号(venderId)、设备号(devId)和class号。那么,在Linux系统中,如何获取这三个数据呢?
      既然是一个pci设备,那么首先就得知道BDF——该pci设备在OS中的唯一标识符。以网卡举例,我们可以通过ethtool来得到BDF。其中,bus-info对应的信息就是BDF。

    # ethtool -i p12p1
    driver: ixgbe
    version: 4.0.1-k
    firmware-version: 0x800003e1
    bus-info: 0000:11:00.0
    supports-statistics: yes
    supports-test: yes
    supports-eeprom-access: yes
    supports-register-dump: yes
    supports-priv-flags: no

    厂商号和设备号

      可通过lspci命令获取pci设备的厂商号和设备号。

    # lspci -n -s 11:00.0
    11:00.0 0200: 8086:1528 (rev 01)

      其中,8086就是厂商号,1528就是设备号。

    # lspci | grep 11:00.0                                                            
    11:00.0 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)

      当然,也可以通过上面的方法直接使用lspci命令来查看该设备的基础信息。上面可以看出,这是一个intel的网卡设备,X540网卡。

    class号

      一个完整的class号应该包含三个部分:Device class、Device subclass和Program interface,每个部分占2个16进制数字,一个类型的设备,他们的class号是一样的。其实,在上面的lspci命令中已经获取到了部分的class号。下面实例的0200就是class号的前两部分Device class和Device subclass,只是没有Program interface这一部分。要查询完整的class号,可以通过在线网站pci-ids来查询。

    # lspci -n -s 11:00.0
    11:00.0 0200: 8086:1528 (rev 01)

    无Program interface情况

      还是以上面的网卡为例,我们已经知道这是个网卡控制器(Ethernet controller)。那么我们就在网页的Jump一栏中输入关键字“Ethernet controller”,就会直接跳转该项。由于该项没有Program interface,因此,最终的class号就是020000。

    有Program interface情况

      再以三星的ssd磁盘为例。

    # lspci | grep Samsung
    01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
    0c:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
    10:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
    # lspci -n -s 01:00.0
    01:00.0 0108: 144d:a802 (rev 01)

      在pci-ids查询关键字“Non-Volatile memory controller”,进入该项后,了解到该项的Device class和Device subclass为0108。同时,我们还发现该项有两个Program Interface。由于这个ssd是NVMe总线的,所以该ssd的最终class号就是010802。
    这里写图片描述
    ps:lspci -D:显示设备的厂商号、设备号、Class号。但这个Class号只是前半部分,还缺少后半部分。

    # lspci -Q -s 0c:00.1
    0c:00.1 Class 0200: Device 8086:1528 (rev 01)
    展开全文
  •  linux系统将设备分为3类:字符设备、块设备、网络设备。使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的...

    一、字符设备基础知识

    1、设备驱动分类

          linux系统将设备分为3类:字符设备、块设备、网络设备。使用驱动程序:



    字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。

    块设备:是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。

    每一个字符设备或块设备都在/dev目录下对应一个设备文件linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备


    2、字符设备、字符设备驱动与用户空间访问该设备的程序三者之间的关系


         如图,在Linux内核中:

    a -- 使用cdev结构体来描述字符设备;

    b -- 通过其成员dev_t来定义设备号(分为主、次设备号)以确定字符设备的唯一性;

    c -- 通过其成员file_operations来定义字符设备驱动提供给VFS的接口函数,如常见的open()、read()、write()等;


         在Linux字符设备驱动中:

    a -- 模块加载函数通过 register_chrdev_region( ) 或 alloc_chrdev_region( )来静态或者动态获取设备号;

    b -- 通过 cdev_init( ) 建立cdev与 file_operations之间的连接,通过 cdev_add( ) 向系统添加一个cdev以完成注册;

    c -- 模块卸载函数通过cdev_del( )来注销cdev,通过 unregister_chrdev_region( )来释放设备号;


         用户空间访问该设备的程序:

    a -- 通过Linux系统调用,如open( )、read( )、write( ),来“调用”file_operations来定义字符设备驱动提供给VFS的接口函数;


    3、字符设备驱动模型



    二、cdev 结构体解析

          在Linux内核中,使用cdev结构体来描述一个字符设备,cdev结构体的定义如下:

    <include/linux/cdev.h>
    
    struct cdev { 
    	struct kobject kobj;                  //内嵌的内核对象.
    	struct module *owner;                 //该字符设备所在的内核模块的对象指针.
    	const struct file_operations *ops;    //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.
    	struct list_head list;                //用来将已经向内核注册的所有字符设备形成链表.
    	dev_t dev;                            //字符设备的设备号,由主设备号和次设备号构成.
    	unsigned int count;                   //隶属于同一主设备号的次设备号的个数.
    };

    内核给出的操作struct cdev结构的接口主要有以下几个:

    a -- void cdev_init(struct cdev *, const struct file_operations *);

    其源代码如代码清单如下:

    void cdev_init(struct cdev *cdev, const struct file_operations *fops)
    {
    	memset(cdev, 0, sizeof *cdev);
    	INIT_LIST_HEAD(&cdev->list);
    	kobject_init(&cdev->kobj, &ktype_cdev_default);
    	cdev->ops = fops;
    }
    
          该函数主要对struct cdev结构体做初始化最重要的就是建立cdev 和 file_operations之间的连接:

    (1) 将整个结构体清零;

    (2) 初始化list成员使其指向自身;

    (3) 初始化kobj成员;

    (4) 初始化ops成员;


     b --struct cdev *cdev_alloc(void);

         该函数主要分配一个struct cdev结构动态申请一个cdev内存,并做了cdev_init中所做的前面3步初始化工作(第四步初始化工作需要在调用cdev_alloc后,显式的做初始化即: .ops=xxx_ops).

    其源代码清单如下:

    struct cdev *cdev_alloc(void)
    {
    	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
    	if (p) {
    		INIT_LIST_HEAD(&p->list);
    		kobject_init(&p->kobj, &ktype_cdev_dynamic);
    	}
    	return p;
    }

         在上面的两个初始化的函数中,我们没有看到关于owner成员、dev成员、count成员的初始化;其实,owner成员的存在体现了驱动程序与内核模块间的亲密关系,struct module是内核对于一个模块的抽象,该成员在字符设备中可以体现该设备隶属于哪个模块,在驱动程序的编写中一般由用户显式的初始化 .owner = THIS_MODULE, 该成员可以防止设备的方法正在被使用时,设备所在模块被卸载。而dev成员和count成员则在cdev_add中才会赋上有效的值。

     
    c -- int cdev_add(struct cdev *p, dev_t dev, unsigned count);

           该函数向内核注册一个struct cdev结构,即正式通知内核由struct cdev *p代表的字符设备已经可以使用了。

    当然这里还需提供两个参数:

    (1)第一个设备号 dev,

    (2)和该设备关联的设备编号的数量。

    这两个参数直接赋值给struct cdev 的dev成员和count成员。


    d -- void cdev_del(struct cdev *p);

         该函数向内核注销一个struct cdev结构,即正式通知内核由struct cdev *p代表的字符设备已经不可以使用了。

         从上述的接口讨论中,我们发现对于struct cdev的初始化和注册的过程中,我们需要提供几个东西

    (1) struct file_operations结构指针;

    (2) dev设备号;

    (3) count次设备号个数。

    但是我们依旧不明白这几个值到底代表着什么,而我们又该如何去构造这些值!



    三、设备号相应操作

    1 -- 主设备号和次设备号(二者一起为设备号):

          一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。

      linux内核中,设备号用dev_t来描述,2.6.28中定义如下:

      typedef u_long dev_t;

      在32位机中是4个字节,高12位表示主设备号,低20位表示次设备号。

    内核也为我们提供了几个方便操作的宏实现dev_t:

    1) -- 从设备号中提取major和minor

    MAJOR(dev_t dev);                              

    MINOR(dev_t dev);

    2) -- 通过major和minor构建设备号

    MKDEV(int major,int minor);

    注:这只是构建设备号。并未注册,需要调用 register_chrdev_region 静态申请;

    //宏定义:
    #define MINORBITS    20
    #define MINORMASK    ((1U << MINORBITS) - 1)
    #define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))
    #define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))
    #define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))</span>


    2、分配设备号(两种方法):

    a -- 静态申请

    int register_chrdev_region(dev_t from, unsigned count, const char *name);

    其源代码清单如下:

    int register_chrdev_region(dev_t from, unsigned count, const char *name)
    {
    	struct char_device_struct *cd;
    	dev_t to = from + count;
    	dev_t n, next;
    
    	for (n = from; n < to; n = next) {
    		next = MKDEV(MAJOR(n)+1, 0);
    		if (next > to)
    			next = to;
    		cd = __register_chrdev_region(MAJOR(n), MINOR(n),
    			       next - n, name);
    		if (IS_ERR(cd))
    			goto fail;
    	}
    	return 0;
    fail:
    	to = n;
    	for (n = from; n < to; n = next) {
    		next = MKDEV(MAJOR(n)+1, 0);
    		kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
    	}
    	return PTR_ERR(cd);
    }

    b -- 动态分配:

    int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);

    其源代码清单如下:

    int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
    			const char *name)
    {
    	struct char_device_struct *cd;
    	cd = __register_chrdev_region(0, baseminor, count, name);
    	if (IS_ERR(cd))
    		return PTR_ERR(cd);
    	*dev = MKDEV(cd->major, cd->baseminor);
    	return 0;
    }

    可以看到二者都是调用了__register_chrdev_region 函数,其源代码如下:

    static struct char_device_struct *
    __register_chrdev_region(unsigned int major, unsigned int baseminor,
    			   int minorct, const char *name)
    {
    	struct char_device_struct *cd, **cp;
    	int ret = 0;
    	int i;
    
    	cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
    	if (cd == NULL)
    		return ERR_PTR(-ENOMEM);
    
    	mutex_lock(&chrdevs_lock);
    
    	/* temporary */
    	if (major == 0) {
    		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
    			if (chrdevs[i] == NULL)
    				break;
    		}
    
    		if (i == 0) {
    			ret = -EBUSY;
    			goto out;
    		}
    		major = i;
    		ret = major;
    	}
    
    	cd->major = major;
    	cd->baseminor = baseminor;
    	cd->minorct = minorct;
    	strlcpy(cd->name, name, sizeof(cd->name));
    
    	i = major_to_index(major);
    
    	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
    		if ((*cp)->major > major ||
    		    ((*cp)->major == major &&
    		     (((*cp)->baseminor >= baseminor) ||
    		      ((*cp)->baseminor + (*cp)->minorct > baseminor))))
    			break;
    
    	/* Check for overlapping minor ranges.  */
    	if (*cp && (*cp)->major == major) {
    		int old_min = (*cp)->baseminor;
    		int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
    		int new_min = baseminor;
    		int new_max = baseminor + minorct - 1;
    
    		/* New driver overlaps from the left.  */
    		if (new_max >= old_min && new_max <= old_max) {
    			ret = -EBUSY;
    			goto out;
    		}
    
    		/* New driver overlaps from the right.  */
    		if (new_min <= old_max && new_min >= old_min) {
    			ret = -EBUSY;
    			goto out;
    		}
    	}
    
    	cd->next = *cp;
    	*cp = cd;
    	mutex_unlock(&chrdevs_lock);
    	return cd;
    out:
    	mutex_unlock(&chrdevs_lock);
    	kfree(cd);
    	return ERR_PTR(ret);
    }
     通过这个函数可以看出  register_chrdev_region  alloc_chrdev_region 的区别,register_chrdev_region直接将Major 注册进入,而 alloc_chrdev_region从Major = 0 开始,逐个查找设备号,直到找到一个闲置的设备号,并将其注册进去;

    二者应用可以简单总结如下:

                                         register_chrdev_region                                                alloc_chrdev_region 

        devno = MKDEV(major,minor);
        ret = register_chrdev_region(devno, 1, "hello"); 
        cdev_init(&cdev,&hello_ops);
        ret = cdev_add(&cdev,devno,1);
         alloc_chrdev_region(&devno, minor, 1, "hello");
        major = MAJOR(devno);
        cdev_init(&cdev,&hello_ops);
        ret = cdev_add(&cdev,devno,1)
    register_chrdev(major,"hello",&hello

         可以看到,除了前面两个函数,还加了一个register_chrdev 函数,可以发现这个函数的应用非常简单,只要一句就可以搞定前面函数所做之事;

    下面分析一下register_chrdev 函数,其源代码定义如下:

    static inline int register_chrdev(unsigned int major, const char *name,
    				  const struct file_operations *fops)
    {
    	return __register_chrdev(major, 0, 256, name, fops);
    }
    调用了 __register_chrdev(major, 0, 256, name, fops) 函数:
    int __register_chrdev(unsigned int major, unsigned int baseminor,
    		      unsigned int count, const char *name,
    		      const struct file_operations *fops)
    {
    	struct char_device_struct *cd;
    	struct cdev *cdev;
    	int err = -ENOMEM;
    
    	cd = __register_chrdev_region(major, baseminor, count, name);
    	if (IS_ERR(cd))
    		return PTR_ERR(cd);
    
    	cdev = cdev_alloc();
    	if (!cdev)
    		goto out2;
    
    	cdev->owner = fops->owner;
    	cdev->ops = fops;
    	kobject_set_name(&cdev->kobj, "%s", name);
    
    	err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
    	if (err)
    		goto out;
    
    	cd->cdev = cdev;
    
    	return major ? 0 : cd->major;
    out:
    	kobject_put(&cdev->kobj);
    out2:
    	kfree(__unregister_chrdev_region(cd->major, baseminor, count));
    	return err;
    }
    可以看到这个函数不只帮我们注册了设备号,还帮我们做了cdev 的初始化以及cdev 的注册;

    3、注销设备号:

    void unregister_chrdev_region(dev_t from, unsigned count);


    4、创建设备文件:

         利用cat /proc/devices查看申请到的设备名,设备号。

    1)使用mknod手工创建:mknod filename type major minor

    2)自动创建设备节点:

        利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。在驱动初始化代码里调用class_create为该设备创建一个class,再为每个设备调用device_create创建对应的设备。

        详细解析见:Linux 字符设备驱动开发 (二)—— 自动创建设备节点


    下面看一个实例,练习一下上面的操作:

    hello.c

    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    static int major = 250;
    static int minor = 0;
    static dev_t devno;
    static struct cdev cdev;
    static int hello_open (struct inode *inode, struct file *filep)
    {
    	printk("hello_open \n");
    	return 0;
    }
    static struct file_operations hello_ops=
    {
    	.open = hello_open,			
    };
    
    static int hello_init(void)
    {
    	int ret;	
    	printk("hello_init");
    	devno = MKDEV(major,minor);
    	ret = register_chrdev_region(devno, 1, "hello");
    	if(ret < 0)
    	{
    		printk("register_chrdev_region fail \n");
    		return ret;
    	}
    	cdev_init(&cdev,&hello_ops);
    	ret = cdev_add(&cdev,devno,1);
    	if(ret < 0)
    	{
    		printk("cdev_add fail \n");
    		return ret;
    	}	
    	return 0;
    }
    static void hello_exit(void)
    {
    	cdev_del(&cdev);
    	unregister_chrdev_region(devno,1);
    	printk("hello_exit \n");
    }
    MODULE_LICENSE("GPL");
    module_init(hello_init);
    module_exit(hello_exit);
    

    测试程序 test.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    main()
    {
    	int fd;
    
    	fd = open("/dev/hello",O_RDWR);
    	if(fd<0)
    	{
    		perror("open fail \n");
    		return ;
    	}
    
    	close(fd);
    }
    makefile:
    ifneq  ($(KERNELRELEASE),)
    obj-m:=hello.o
    $(info "2nd")
    else
    KDIR := /lib/modules/$(shell uname -r)/build
    PWD:=$(shell pwd)
    all:
    	$(info "1st")
    	make -C $(KDIR) M=$(PWD) modules
    clean:
    	rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order
    endif

    编译成功后,使用 insmod 命令加载:

    然后用cat /proc/devices 查看,会发现设备号已经申请成功;



    展开全文
  • Linux中的设备文件与设备号

    千次阅读 2014-08-29 15:49:35
    Linux下,一切皆文件,设备也不例外,为了管理这些设备,系统为它们各自都编了号,而每个设备号又分为主设备号和次设备号。主设备号用来区分不同类型的设备,而次设备号用来区分同一类型内的多个设备。 一个Linux...
  • Linux 设备驱动之 DTS 描述的资源

    千次阅读 2015-07-16 22:27:36
    linux使用platform_driver_register() 注册 platform_driver 时, 需要在 platform_driver 的probe() 里面知道设备的中断, 内存地址等资源。这些资源的描述信息存放在 resource 数据结构中, 相同的资源存放在...
  •  很久前接触linux驱动就知道主设备号找驱动,次设备号找设备。这句到底怎么理解呢,如何在驱动中实现呢,在介绍该实现之前先看下内核中主次设备号的管理:  二、Linux内核主次设备号的管理  Linux的设备...
  • linux使用platform_driver_register() 注册 platform_driver 时, 需要在 platform_driver 的probe() 里面知道设备的中断, 内存地址等资源。 这些资源的描述信息存放在 resource 数据结构中, 相同的资源存放...
  • 深入理解Linux字符设备驱动

    千次阅读 2016-03-20 11:09:13
    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次、组成框架和交互、如何编写驱动、设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解。
  • Linux杂项设备驱动

    千次阅读 2013-10-23 21:42:40
    Linux杂项驱动出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费。 所以对于这些简单的字符设备它们共用一个主设备号,不同的设备使用不同的次设备号. ...
  • 任何USB设备在连接到USB接口后,主机检测到有新设备接入,会利用不同的请求命令(Request)查询该设备的属性,设备通过不同的描述符向主机报告自己的情况。包括设备的种类,设备的功能,设备具有的端点数量以及其他...
  • 用sysfs查看linux下usb设备描述

    千次阅读 2019-06-14 09:27:12
    根hub-端口:设备-接口 一般,1-0是hub自身信息,当hub上有插入设备时,就会出现1-1:1了。 1.查看目录: ls /sys/bus/usb/devices/ 1-0:1.0 1-1.1:1.0 2-1 4-0:1.0 usb1 usb4 1-1 1-1:1.0 2...
  • Linux 设备树添加spi设备

    千次阅读 2018-12-16 22:38:38
    Linux:4.6 应用开发板:zynq系列 zc706、zedboard 文件系统:ubuntu12 参考帖子:...之前实验过spi控制器下面挂载spi设备,当时,关于spi设备树的节点描述如下...
  • 本博实时更新《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)的最新进展。 目前已经完成稿件。 2015年8月9日,china-pub开始上线预售: ... 2015年8月20日,各路朋友报喜...
  • linux 设备

    千次阅读 2017-09-01 22:19:36
    linux 设备树参考地址 http://blog.csdn.net/green1900/article/details/45646095 http://www.cnblogs.com/xiaojiang1025/p/6131381.html http://blog.csdn.net/21cnbao/article/details/84575461.为什么要使用...
  • Linux字符设备

    千次阅读 2016-10-04 14:02:48
    一.驱动程序的概念  所谓设备驱动程序就是控制与管理硬件设备数据...应用层通过系统调用进入内核层,内核层根据系统调用来调用驱动程序对应的接口函数。在linux中驱动程序运行的原理如下图1.1所示:  
  • linux设备管理

    千次阅读 2013-11-18 10:35:02
    Linux设备管理 Linux设备管理的主要任务是控制设备完成输入输出操作,所以又称输入输出(I/O)子系统。 它的任务是把各种设备硬件的复杂物理特性的细节屏蔽起来,提供一个对各种不同设备使用...
  • Linux 设备文件的创建和mdev

    千次阅读 2015-07-06 10:43:47
    本文是嵌入式企鹅圈开篇--《linux字符设备驱动剖析》的姐妹篇,在上述文章里面我们详细描述了字符设备驱动框架涉及的驱动注册、通过设备文件来访问驱动等知识,并明确通过device_create接口并结合mdev来创建设备文件...
  • Linux内核设备模型与总线 - 内核版本 Linux Kernel 2.6.34, 与 Robert.Love的《Linux Kernel Development》(第三版)所讲述的内核版本一样 - 源代码下载路径: ...
  • linux usb 描述

    千次阅读 2011-07-07 22:11:46
    设备描述linux内核使用struct usb_device来描述一个usb设备struct usb_device{int devnum}
  • 吃完饭了,那就继续USB吧,接下来那便是USB的设备描述符了。   每个USB设备内部都固化了一些数据,通过这些数据,USB主机就可以获取USB设备的类型、生产厂商等的信息。这组固定格式的数据,就是U
  • Linux设备分类

    千次阅读 2017-09-19 06:49:31
    纵览linux/drivers目录,大概...这里只描述在嵌入式系统里面用得最为广泛的3种设备。 1.字符设备(char device) 字符设备Linux最简单的设备,可以像文件一样访问。初始化字符设备时,它的设备驱动程序向Linux登记,
  • linux设备

    千次阅读 2018-05-31 01:00:56
    来自:https://www.cnblogs.com/xuyh/p/5333086.htmlhttp://www.cnblogs.com/xuyh/p/5333191.htmlhttp://www.cnblogs.com/xuyh/p/5340026.html 一: 块设备概念: 一种具有一定结构的随机存取设备,对这种设备的...
  • Linux设备驱动

    万次阅读 2008-01-29 21:50:00
    第十三章 Linux设备驱动本章导读块设备是与字符设备并列的概念,这两类设备Linux中驱动的结构有较大差异,总体而言,块设备驱动比字符设备驱动要复杂得多,在I/O操作上表现出极大的不同,缓冲、I/O调度、请求...
  • Linux从未停歇脚步。Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核。做技术,从来没有终南捷径,拼的就是坐冷板凳的傻劲。 这是一个连阅读都被...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 216,225
精华内容 86,490
关键字:

linux描述设备号

linux 订阅