Linux驱动学习:Linux文件系统与设备文件

基于宋宝华老师的《Linux设备驱动开发详解》

Linux文件操作

  1. 使用creat创建文件时,文件的存取权限要与umask一起决定
    1. int umask(int newmask);:只影响读写和执行权限
  2. DOSWindows系统中对于二进制文件和文本文件是有区分的,但Linux不区分二进制文件和文本文件

Linux文件系统

  1. /bin:包含基本命令,例如ls
  2. /sbin:包含系统命令,大多数是涉及系统管理的命令
  3. /dev:设备文件存储目录,应用程序通过对这些文件的读写和控制以访问实际的设备
  4. /etc:系统配置文件的所在地,一些服务器的配置文件也在这里。如用户账户和密码
  5. /lib:系统库文件存放目录
  6. /mnt:一般用于存放挂载储存设备的挂载目录,如cdrom等目录
  7. /opt:可选,有些软件包会被安装在这里
  8. /proc:操作系统运行时,进程及内核信息存放在这里。该目录为伪文件系统proc的挂载目录
  9. /tmp:存放临时文件
  10. /usr:系统存放程序的目录,如用户命令
  11. /var:存放经常变化的内容,如其下的/log就用来存放系统日志
  12. /sys:2.6以后的内核所支持的sysfs文件系统被映射在此目录上。Linux设备驱动模型中的总线、驱动和设备都可以在sysfs文件系统中找到对应的节点。当内核检测到在系统中出现了新设备后,内核会在sysfs文件系统中为该新设备生成一项新的记录

Linux文件系统与设备驱动

块设备访问方法

  1. 不通过文件系统直接访问裸设备,即通过Linux内核实现的def_blk_fops,即运行类似于dd if=/dev/sdb1 of=sdb1.img时,内核走的是该实现

image.png

  1. 通过文件系统来访问块设备,即通过通常的open等访问
    1. 因为文件系统会通过VFS统一的进行转化,不管访问的是ext2还是fat等文件系统,应用层都只需要通过openread等访问
    2. 因为在VFS中会自动的将其进行转化,类似于Java中的接口

file结构体

  1. 当打开文件后,由内核自动创建
  2. 当关闭文件后,由内核自动释放
  3. 通常被命名为filefilep:file pointer
  4. 设备驱动通常关心如下
    1. f_mode:文件读/写模式
    2. f_flags:文件标志,即是否阻塞式
    3. private_data:私有数据指针,通常用于指向设备驱动自定义以用于描述设备的结构体

inode结构体

  1. 该结构体是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁
  2. dev_t i_rdev:包含设备编号,高12位为主设备号,低20位为次设备号
    1. unsigned int iminor(struct inode *inode):获取次设备号
    2. unsigned int imajor(struct inode *inode):获取主设备号

/proc/devices:获知系统中注册的设备
/dev:查看系统中包含的设备文件
Documents目录下的devices.txt文件描述了Linux设备号的分配情况。

devfs(了解)

  1. 2.6以前可使用,2.6之后被抛弃
  2. 优点
    1. 在设备初始化和卸载时,自动的创建和删除设备文件
    2. 设备驱动程序可以指定设备名、所有者和权限位,用户空间程序依然可以修改所有者和权限为
    3. 可以自动的获得可用的主设备号,以及指定次设备号
      1. register_chrdev():传递0,自动获得可用的主设备号
      2. devfs_register():指定次设备号
  3. devfs_mk_dir():创建设备目录
  4. devfs_register():创建设备文件
  5. devfs_unregister():撤销设备文件

udev用户空间设备管理(位于用户空间)

  1. udev取代了devfs
    1. udev位于用户空间,而devfs位于内核空间
    2. 因为Linux设计中,内核只负责机制,不应该实现策略,说人话就是,内核只负责提供思想,而应用层负责把思想进行具体的应用
      1. 如,内核只负责提供一个加法机制,但不限制谁加谁,限制是应用层需要做的事情。
  2. udev是利用设备加入或移除时门内核所发送的热插拔时间来工作
    1. 热插拔时,设备的详细信息会由内核通过netlink套接字发送出来,发出的事件叫ueventudev的设备命名策略、权限控制和事件处理都是在用户态下完成的,它利用从内核收到的信息来进行创建设备文件节点等工作

示例代码,热插拔

#include <linux/netlink.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <poll.h>

static void die(char *s)
{
	write(2,s,strlen(s));
	exit(1);
}

int main(int argc,char* argv[])
{
	struct sockaddr_nl nls;
	struct pollfd pfd;

	char buf[512];

	memset(&nls,0,sizeof(struct sockaddr_nl));
	nls.nl_family = AF_NETLINK;
	nls.nl_pid = getpid();
	nls.nl_groups = -1;

	pfd.events = POLLIN;
	pfd.fd = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);

	if(pfd.fd == -1){
		die("Not root\n");
	}

	if(bind(pfd.fd,(void *)&nls,sizeof(struct sockaddr_nl))){
		die("Bind failed\n");
	}

	while(-1 != poll(&pfd,1,-1)){
		int i,len = recv(pfd.fd,buf,sizeof(buf),MSG_DONTWAIT);
		if(len == -1)
			die("recv\n");

		i=0;
		while(i<len){
			printf("%s\n",buf+i);
			i += strlen(buf+i) + 1;
		}
	}
	die("poll\n");
	return 0;
}

冷插拔

  1. 冷插拔:在udev启动前就已经插入的设备。
  2. /sys/module/psmouse/uevent写一个add,就会导致内核重新发送netlink
    1. uevent节点位于sysfs下面

sysfs文件系统与Linux设备模型

  1. sysfs是一个虚拟的文件系统,可以产生一个包括所有系统硬件的层级视图,与proc文件系统类似
  2. sysfs:把连接在系统上的设备和总线组织成一个分级的文件,可以被用户空间存取,向用户空间导出内核数据结构以及他们的属性。
    1. 可以通过sysfs知晓设备驱动模型中各组件的层次关系
    2. /sys/block:包含所有的块设备
    3. /sys/devices:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构
    4. /sys/bus:包含系统中所有的总线类型
      1. ./pci等子目录下,会分出driversdevices目录,而devices中是对/sys/devices目录中文件的符号链接
    5. /sys/class:包含系统中的设备类型,如网卡设备
  3. 在Linux内核中:
    1. bus_type:描述总线
    2. device_driver:描述设备驱动
    3. device:描述设备
    4. 这三个结构体定义在:include/linux/device.h
      1. 由于驱动和设备都必须依附于总线,故都包含struct bus_typezhiz
    5. 在Linux内核中,设备和驱动是分开注册的。
      1. 通过bus_typematch()成员函数进行匹配
    6. 总线、驱动和设备实际上都可以认为是kobject的派生类,一个kobject对应sysfs中的一个目录
    7. 总线、设备和驱动中的各个attribute都会成为sysfs中的一个文件,读写attribute使用对应结构体中的show()store()函数
遍历sysfs,找出所有的设备,并分析出来设备名和主次设备号
#!/bin/bash

  # Populate block devices

  for i in /sys/block/*/dev /sys/block/*/*/dev
  do
    if [ -f $i ]
    then
      MAJOR=$(sed 's/:.*//' < $i)
      MINOR=$(sed 's/.*://' < $i)
      DEVNAME=$(echo $i | sed -e 's@/dev@@' -e 's@.*/@@')
      echo /dev/$DEVNAME b $MAJOR $MINOR
      #mknod /dev/$DEVNAME b $MAJOR $MINOR
    fi
  done

  # Populate char devices

  for i in /sys/bus/*/devices/*/dev /sys/class/*/*/dev
  do
    if [ -f $i ]
    then
      MAJOR=$(sed 's/:.*//' < $i)
      MINOR=$(sed 's/.*://' < $i)
      DEVNAME=$(echo $i | sed -e 's@/dev@@' -e 's@.*/@@')
      echo /dev/$DEVNAME c $MAJOR $MINOR
      #mknod /dev/$DEVNAME c $MAJOR $MINOR #为整个系统中的设备建立/dev/下面的节点
    fi
  done

sed 's/:.*//'sed -e 's@/dev@@'中,第一个的/和第二个的@作用一直,都是用于分割命令的,第一个命令是指:匹配:后面的序列,并删除;第二个命令是指:匹配/dev,并删除/dev

udev的组成

  1. udev目前和systemd项目合并
    1. 文档:https://lwn.net/Articles/490413/
    2. 下载最新代码:http://cgit.freedesktop.org/systemd/https://github.com/systemd/systemd
  2. 工作过程
    1. 内核检测到系统中出现了新设备,内核就通过netlink套接字发送uevent
    2. udev获取到内核发送的信息,进行规则的匹配。匹配的事务包括SUBSYSTEMACTIONattribute、内核提供的名称以及其他的环境变量
  3. 捕获uevent包含的信息:udevadm monitor --kernel --property --udev
在U盘插入时,自动为该U盘创建一个/dev/kingstonUD的符号链接
#Kingston USB mass storage
SUBSYSTEM=="block",ACTION=="add",KERNEL=="*sd?",ENV{ID_TYPE}=="disk",
    ENV{ID_VENDOR}=="Kingston",ENV{ID_USB_DRIVER}=="usb-storage",SYMLINK+="kingstonUD"

  1. SYMLINK+="kingstonUD":自动创建一个kingstonUD符号链接
  2. 文件应当放置在/etc/udev/rules.d

udev规则文件

  1. 规则文件的关键字
    1. 匹配关键字
      1. ACTION:行为
      2. KERNEL:匹配内核设备名
      3. BUS:匹配总线类型
      4. SUBSYSTEM:匹配子系统名
      5. ATTR:属性等
    2. 赋值关键字
      1. NAME:创建的设备文件名
      2. SYMLINK:符号创建链接名
      3. OWNER:设置设备的所有者
      4. GROUP:设置设备的组
      5. IMPORT:调用外部程序
      6. MODE:节点访问权限等
    3. 也可以使用正则表达式,如
      1. *:通配符
      2. :代替一个字符
      3. %k:代表KERNEL
      4. %n:代表设备的KERNEL序号
  2. 查看内核信息和sysfs属性信息
    1. udevadm info -a -p 指定的设备名,如
      1. udevadm info -a -p /sys/devices/platform/serial8250/tty/ttyS1
    2. 查看/dev节点对应于/sys的具体节点路径
      1. udevadm info -a -p $(udevadm info -q path -n /dev/ttyS1)
      2. 输出的信息中:紧随looking at device其后的便是

udev的轻量级版本:mdev;
android中的是vold

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值