本文分析了Linux下的串口驱动程序。由顶级c库提供。封装到操作系统的系统调用层。然后到tty子系统的核心。然后是一系列的行规。然后到最底层的硬件操作。

简要介绍了Linux中的tty子系统。从理论到实践。以便读者对OS原理有更深入的理解和更具体的把握。

具体分析之前。我们必须检查串行端口。开车。和Linux操作系统。在这个阶段,我们有三个问题要解决:

1.什么是Linux操作系统。

2.什么是Linux设备驱动程序。

3.各种串口。

来理解这些概念。下面我介绍一下这方面的小知识。不幸的是,有些概念不可避免地会被向前引用。

在这个过程中我会尽量忽略次要因素。以这次调查的主要目的为主线。读者们,如果你们对这些概念有深刻的理解。可以直接阅读下面的代码分析:

1、什么是Linux操作系统?Linux是一种类似Unix的操作系统,可以免费使用和自由传播。它是一个基于POSIX和UNIX的多用户、多任务、多线程、多CPU的操作系统。

它可以运行主要的UNIX工具、应用程序和网络协议。它支持32位和64位硬件。Linux是一个性能稳定的多用户网络操作系统,继承了Unix以网络为核心的设计思想。

Linux操作系统诞生于1991年10月5日(这是第一次官方公布时间)。Linux有很多不同的版本,但都使用Linux内核。

Linux的可移植性令人惊讶。它可以安装在各种计算机硬件设备中,如手机、平板电脑、路由器、文章游戏机、台式电脑、大型机和超级计算机。

严格来说,Linux这个词本身只是指Linux内核,但实际上,人们已经习惯于用Linux来描述整个基于Linux内核的操作系统,用GNU来投射各种工具和数据库。

在这些简短的段落中。引入了许多新术语。下面我将描述几个重要的概念。

一、关于类UNIX系统

类Unix系统(英文:Unix-like)是指各种传统的Unix系统(如SUN公司的FreeBSD、OpenBSD、Solaris)和各种类似于传统Unix系统的系统(如Minix、Linux、QNX等)。).

虽然它们有些是自由软件,有些是商业软件,但它们都在相当程度上继承了原UNIX的特点,有许多相似之处,并且都在一定程度上符合POSIX规范。

这一点在一些经典的操作系统教材中已经有过解释。我们只想知道。和我们熟悉的Windows系列操作系统是一样的。这是一个现代化的操作系统。抽象底层计算机资源。为上层用户提供调用接口。完成电脑应该完成的功能。

b、关于便携性

可移植性是指将软件从一个环境转移到另一个环境的难度。为了获得高的可移植性,在设计过程中经常使用通用编程语言和运行支持环境。尽量不要使用与系统底层有强烈关联的语言。

可移植性是软件的质量之一,良好的可移植性可以提高软件的生命周期。代码可移植性的话题是软件;可移植性是软件产品的一种能力属性,其行为表现出一个度,这个度与环境密切相关。

操作系统的可移植性通常表明它可以在不同的架构上运行。感性的理解就是可以支持的设备很多。例如,如前所述,Linux可以在大型服务器上运行。在各种平板电脑上。

前段时间,有黑客成功将Linux移植到佳能相机上。而且这款相机上运行的是一些主流软件。可以说。只要有足够的可用硬件资源。可以把Linux移植到这个硬件平台上。这种资源的最低要求通常很低。这可以与Windows形成鲜明对比,后者需要很高的硬件资源。举个例子。当电脑右下角弹出Windows 10的升级提示时。

你能点击立即升级不假思索?我认为大多数人这个问题的答案是否定的。为什么?因为大多数情况下。升级后会变得更卡。延迟更大。一些无用而庞大的软件疯狂地占用你有限的电脑资源。如果你选择Linux。几乎可以随意在电脑上安装软件。运行程序(如果你的内存不算太小。并且硬盘交换分区足够)。

Linux将其有限的硬件资源发挥到了极致。开源软件良好的模块化设计充分利用了各级程序局部性原则。(当然,这是在损失一些可用性的前提下。)。抱歉,我跑题了。这些都不是本文的重点。

因为我不没有土豪,我有很多电脑。所以我选择了更便宜的ARM9开发板作为开发平台。它的CPU是三星生产的S3C2440。核心是ARM920T。

c,关于Linux的基本思想

Linux的基本思想有两点:

第一,一切都是文档。系统中的一切都归结为一个文件,包括命令、硬件和软件设备、操作系统、进程等。对于操作系统内核来说,它们都被看作是具有各自特点或类型的文件。至于基于Unix的Linux,很大程度上是因为两者的基本思想非常相似。

第二,每个软件都有明确的用途。

d、关于Linux的特点

完全免费。

Linux是一个免费的操作系统。用户可以通过网络或其他渠道免费获得,并可以随意修改其源代码。这是其他操作系统可以做到的不做。

正因为如此,无数来自世界各地的程序员参与了Linux的修改和编写,程序员可以根据自己的兴趣和灵感对其进行修改,这使得Linux吸收了无数程序员的精华而发展壮大。

完全兼容POSIX1.0标准

这使得在Linux下通过相应的模拟器运行常用的DOS和Windows程序成为可能。这为用户从Windows转到Linux奠定了基础。

很多用户在考虑使用Linux的时候,都想着Windows下的常用程序是否能正常运行,消除了他们的疑虑。

多用户、多任务

Linux支持多用户,每个用户对自己的文件设备都有自己的特殊权限,保证了每个用户之间互不影响。多任务处理是当今计算机最重要的特征。Linux可以让多个程序同时独立运行。

良好的界面

Linux既有字符界面又有图形界面。在字符界面中,用户可以通过键盘输入相应的指令进行操作。同时还提供了类似Windows图形界面的X-Window系统,用户可以用鼠标进行操作。X-Window环境类似于Windows,可以说是Windows的Linux版。

支持多种平台

Linux可以运行在多种硬件平台上,例如采用x86、680x0、SPARC、Alpha等处理器的平台。另外,Linux是嵌入式操作系统,可以在掌上电脑、机顶盒或者游戏机上运行。2001年1月发布的Linux版内核已经能够完全支持Intel 64位芯片架构。Linux也支持多处理器技术。多个处理器同时工作,大大提高了系统性能。

列出文件类型

常规文件:通常被访问的文件。ls-al显示的属性中,第一个属性是[-],例如[-rwxrwxrwx]。另外,根据文件的内容,大致可以分为:

1、纯文本文件(ASCII):这是Unix系统中最常见的文件类型。之所以称之为纯文本文件,是因为其内容可以直接读取的数据,如数字、字母等。几乎所有的设置文件都属于这种文件类型。例如,您可以使用命令猫~/。bashrc (cat读出文件的内容)。

2、二进制文件:系统只知道并能执行二进制文件。Linux中的可执行文件(脚本,文本形式的批处理文件不算)都是这种格式。例如,命令cat是一个二进制文件。

3、数据格式文件(data):有些程序在运行过程中会读取一些特定格式的文件,那些特定格式的文件可以称为数据文件。例如,当用户登录时,Linux将登录数据记录在/var/log/wtmp文件中,这是一个可以由最后一个命令读出的数据文件。但是使用cat时,会读出乱码。因为它属于特殊格式文件。

4、目录文件:是目录,第一个属性是[d],例如[[drwxrwxrwx]]。

文件(链接):类似Windows下的快捷方式。第一个属性是[l],例如[lrwxrwx]。

5、设备和设备文件:一些与系统外设和存储相关的文件通常集中在/dev目录中。通常分为两种类型:

块文件:指存储数据供系统访问的接口设备。简单来说,就是硬盘。比如1号硬盘的代码是/dev/hda1等文件。第一个属性是[b]。

字符文件:串口的接口设备,如键盘、鼠标等。第一个属性是[c]。

6、 sockets:这种文件通常用于网络数据连接。你可以启动一个程序来监控客户端客户端可以通过socket进行数据通信。第一个属性是[s],这种文件类型最常见于/var/run目录中。

7、管道):FIFO,管道):FIFO也是一种特殊的文件类型。它的主要目的是解决多个程序同时访问一个文件造成的错误。FIFO是先进先出的缩写。第一个属性是[p]

文件结构

/:根目录,所有目录、文件、设备都在/,/是Linux文件系统的组织者,也是最高层的领导者。

/bin: bin是binary的缩写。在一般系统中,您可以在这个目录中找到linux命令。系统所需的命令位于该目录中。

/boot:内核/boot:Linux和引导系统程序所需的文件目录,比如vmlinuz initrd.img文件,都位于这个目录下。通常,GRUB或LILO系统引导管理器也位于这个目录中。

/cdrom:刚安装系统时,此目录为空。你可以把光盘文件系统挂在这个目录下。示例:mount /dev/cdrom /cdrom

/dev: dev是device的缩写。这个目录对所有用户都非常重要。因为这个目录包含了linux系统中使用的所有外部设备。但这不是外接设备的驱动。这与常用的windows和dos操作系统不同。它实际上是一个访问这些外部设备的端口。访问这些外部设备非常方便,和访问一个文件或者一个目录没什么区别。

/etc: etc这个目录是linux系统中最重要的目录之一。系统管理中用到的各种配置文件和子目录都存放在这个目录中。网络配置文件、文件系统、X系统配置文件、设备配置信息、设置用户信息等。要用的都在这个目录里。

/home:如果您创建一个用户名为xx ,那么/home目录下就有对应的/home/xx路径来存储用户的主目录。

/lib: lib是library的缩写。该目录用于存储系统动态连接共享库。几乎所有的应用程序都会使用这个目录中的共享库。因此,唐不要轻易用这个目录做任何事情。一旦出了问题,系统就赢了不工作。

/lost found:在ext2或ext3文件系统中,当系统意外崩溃或机器意外关机时,会将一些文件碎片放在这里。当系统启动时,fsck工具将检查此处并修复损坏的文件系统。有时候系统出现问题,很多文件被移到这个目录,可能是手动修复,也可能是移到原来的位置。

/mnt:这个目录一般用来存放挂载存储设备的挂载目录,比如cdrom等目录。请参见/etc/fstab的定义。

/media:Linux的一些发行版使用这个目录来挂载那些可移动硬盘(包括usb闪存驱动器)、CD/DVD驱动器等等。

/opt:以下是可选程序。

/proc:您可以在这个目录中获得系统信息。这些信息存在于内存中,由系统本身生成。

/root:主目录/root:Linux超级特权用户root。

/sbin:该目录用于存储系统管理员的系统管理程序。大部分是系统管理相关命令的存储,是超级特权用户root可执行命令的存储场所。普通用户无权执行这个目录、这个目录和/usr/sbin中的命令;/usr/X11R6/sbin或/usr/local/sbin目录是相似的,sbin目录中包含的所有内容都只能以root权限执行。

/SElinux:对于SElinux的一些配置文件目录,SElinux可以让linux更加安全。

/srv服务启动后,需要访问的数据目录,比如www服务读取的网页数据,可以放在/srv/www中。

/tmp:临时文件目录,用于存储执行不同程序时生成的临时文件。有时当用户运行一个程序时,会产生一个临时文件。/tmp用于存储临时文件。/var/tmp目录类似于这个目录。

/usr:这是linux系统中占用硬盘空间最多的目录。用户的许多应用程序和文件都存储在这个目录中。在这个目录中,您可以找到不支持不适合放在/bin或/etc目录中。

/usr/local:这里主要存储手动安装的软件,也就是没有通过新立或apt-get。它的目录结构类似于/usr目录。让包管理器管理/usr目录,并将自定义脚本放在/usr/local目录下。

/usr/share:存储系统共享的东西的地方。例如,/usr/share/fonts是字体目录,/usr/share/doc和/usr/share/man帮助文件。

/var:这个目录的内容是不断变化的。看名字就知道了,可以理解为vary的缩写。/var下有/var/log。这是用于存储系统日志的目录。/var/www目录是定义Apache服务器站点的目录。/var/lib用于存储一些库文件,比如MySQL s和MySQL 的数据库。

如上。相信读者对Linux操作系统有个大概的了解。对于一些特定的命令。决定用的时候我会解释的。现在让让我们看看第二个概念:

2、什么是Linux设备驱动程序?设备驱动最通俗的解释就是驱动硬件设备动作。驱动程序直接处理底层硬件,根据硬件设备的具体工作模式读写硬件设备的寄存器,完成设备的轮询、中断处理和DMA通信,将物理内存映射到虚拟内存等。最终使通信设备能够发送和接收数据,显示设备能够显示文字和图片,存储设备能够记录文件和数据。

Linux设备驱动程序是底层硬件资源的抽象。为上层操作系统的其他服务提供良好的接口。让其他服务放置一个特定的硬件。或用作文档的机制。使用通用系统调用进行调用。

3、各种串口都是众所周知的。现在我们的电脑上有很多界面。例如USB。网嘴。并口等。串行总线就是其中之一。串行接口简称串行口,也称为串行通信接口或串行通信接口(通常指COM接口),是利用串行通信的扩展接口。

串行接口是指数据逐位顺序传输,特点是通信线路简单。只需要一对传输线就可以实现双向通信(电话线可以直接作为传输线),大大降低了成本。特别适合远距离通信,但传输速度较慢。串行通信是一条信息的比特位按顺序逐比特传输的通信方式。

串行通信的特点是:数据位按位序传输,至少只需要一条传输线;成本低但传输速度慢。串行通信的距离可以从几米到几公里;根据信息传输的方向,串行通信可以进一步分为单工、半双工和全双工。

串行通信的两种基本方式:同步串行通信和异步串行通信。

Serial指SPI(串行外设接口)的缩写,顾名思义就是串行外设接口。SPI总线系统是一种同步串行外设接口,它使MCU能够以串行方式与各种外设进行通信,以交换信息。TRM450是SPI接口。

异步是指UART(通用异步接收器/发送器),通用异步接收/发送。UART是并行输入变成串行输出的芯片,通常集成在主板上。UART包括TTL级串口和RS232级串口。

TTL电平为3.3V,RS232为负逻辑电平,定义5~ 12V为低电平,-12~-5V为高电平。MDS 2710、 MSD4、 El 805等。都是RS232接口,EL806有TTL接口。

串行接口包括RS-232-C、RS-422、RS485等。根据电气标准和协议。

RS-232

也称为标准串口,是最常用的串行通信接口。它是由美国电子工业协会(EIA)联合贝尔系统公司、调制解调器制造商和计算机终端制造商于1970年制定的,作为串行通信的标准。

它的全名是数据终端设备(DTE)和数据通信设备(DCE)之间串行二进制数据交换接口技术标准。传统的RS-232-C接口标准有22根线,采用标准的25芯D-socket (DB25)。后来简化为9芯D-socket (DB9),但现在应用中很少使用25芯的socket。

RS-232采用非平衡传输方式,即所谓的单端通信。因为发送电平和接收电平之间的差只有大约2V到3V,所以它的共模抑制能力很差。再加上双绞线上的分布电容,其最大传输距离约为15m,最高速率为20kB/s,RS-232是为点对点通信而设计的(即只有一对收发器件),其驱动负载为3 ~ 7 k。因此,RS-232适用于本地设备之间的通信。

RS-422

标准的全称是平衡电压数字接口电路的电气特性,它定义了接口电路的特性。典型的RS-422是一个四线接口。其实还有一根信号地线,一共五根线。其DB9连接器引脚定义。由于接收端采用高输入阻抗,发送驱动器比RS232具有更强的驱动能力,所以允许在同一条传输线上连接多个接收节点,最多10个节点。

即一个主设备和其余的从设备不能相互通信,因此RS-422支持一点对多的双向通信。接收机的输入阻抗为4k,因此发射机的最大负载能力为104k 100(终端电阻)。

由于RS-422四线接口采用独立的发送和接收通道,因此不需要控制数据的方向。设备之间任何必要的信号交换都可以通过软件(XON/XOFF握手)或硬件(一对单独的双绞线)来实现。

RS-422的最大传输距离为1219m,最大传输速率为10mb/s,平衡双绞线的长度与传输速率成反比,只有在传输速率低于100 KB/s时才能达到最大传输距离,只有在很短的距离内才能达到最高速率传输。通常,在100米长的双绞线上可以获得的最大传输速率仅为1 MB/s。

RS-485

它是由RS-422发展而来的,所以RS-485的许多电气规定与RS-422相似。比如采用平衡传输方式,需要在传输线上连接端接电阻。RS-485可以采用两线和四线模式。双线模式可以实现真正的多点双向通信。采用四线模式时,像RS-422一样,只能实现一点对多的通信,即只能有一个主设备,其余都是从设备。不过,它比RS-422有所改进,无论是四线模式还是两线模式,总线上都可以连接32个以上的器件。

RS-485与RS-422的不同之处在于其共模输出电压不同。RS-485在-7V到12V之间,RS-422在-7V到7V之间。RS-485接收器的最小输入阻抗为12k,RS-422为4k。因为RS-485符合所有RS-422规范,所以RS-485驱动程序可以在RS-422网络中应用。

RS-485和RS-422一样,最大传输距离约为1219米,最大传输速率为10 MB/s,平衡双绞线的长度与传输速率成反比。只有当传输速率低于100kb/s时,才能使用最长的电缆长度。最高速率的传输只能在短距离内实现。一般100米长的双绞线最大传输速率只有1 MB/s。

作者采用的RS-232串行通信协议。下面简单介绍一下它的通讯接线方式。目前常用的串口有9针串口(DB9)和25针串口(DB25)。当通信距离短时(12m ),标准的RS232口(RS422,RS485比较远)可以直接用线缆连接。如果距离较远,应连接调制解调器或其他相关设备。最简单也是最常用的方法是三线连接法,即地面、接收数据和发送数据相互连接。这是最基本的连接方式,直接用RS232连接。

以上是针对微机标准串口,还有很多非标准设备,就不解释了。

好吧。到目前为止,我们已经解决了前三个问题。让让我们进入实际的代码。用于分析的实际硬件。

在硬件平台上。硬件可用。我们必须将适当的软件写入平台的RAM中。以便CPU可以跳到第一条指令。然后慢慢加载各种资源。来完成系统的引导。

通常,我们使用BootLoader来初始化硬件。并引导至操作系统核心。

作者采用的BootLoader是u-Boot-1.1.16。Uboot是一款知名的开源软件。读者只需要知道它充当的是引导加载程序。这里不多解释。只简单描述串口的连接和程序的下载:

从UBOOT目录下载u-boot.bin到开发平台。在Windows中打开设备管理器。选择端口。从而找到正确的com口号。在此之前,确保开发板的串口与笔记本的USB口连接。(因为现在笔记本都没有并口。所以只能用USB串口线。匹配开发板上的电平转换芯片,完成串口连接。)

然后我们使用另一个工具。安全。找到相应的com号。完成快速链接。选择波特率115200。取消流量控制。

如果一切顺利。在笔记本上,你可以看到类似下面的串口输出。这就是传说中的串口控制台。

这个串口的指令功能是Uboot自己完成的。不是linux下的串口驱动。

此图旨在让读者了解串行控制台的功能。

让开始打开串口。发送。接收函数分析。这是一个函数的前向引用。就是linux内核中几个2440芯片通用的串口发送函数s3c24xx_serial_start_tx。函数声明为static voices 3c 24 xx _ serial _ start _ tx(struct UART _ port * port):函数定义在。/Linux/driver/tty/serial/Samsung . c。

好吧。我们从这个目录结构开始。解释大致的tty子系统驱动程序模型。

目前为止。我们面临一个问题。什么是linux内核。

Linux内核是什么?Linux是一个开源的计算机操作系统内核。它是一个用C语言编写的,符合POSIX标准的类Unix操作系统。

Linux最初是由芬兰黑客Linus Torvalds开发的,试图在英特尔x86架构上提供一个免费的类似Unix的操作系统。该项目始于1991年。在该计划的早期,一些Minix黑客提供了帮助。今天,全世界无数的程序员都在免费帮助这个程序。

Linux是一个单片内核系统。"内核指一种提供硬件抽象层、磁盘和文件系统控制、多任务等功能的系统软件。内核不是一个完整的操作系统。

一个完整的基于Linux内核的操作系统称为Linux操作系统,简称GNU/Linux。设备驱动程序可以完全访问硬件。Linux中的设备驱动程序可以方便地以模块化的形式设置,并且可以在系统运行时直接加载或卸载。

操作系统是用于处理硬件并为用户程序提供有限服务集的底层支持软件。计算机系统是硬件和软件的共生体,两者相互依存,不可分割。计算机硬件,包括外围设备、处理器、内存、硬盘和其他电子设备,构成了计算机的引擎。但它可以没有操作和控制它的软件就不能工作。

完成这种控制工作的软件称为操作系统,称为内核在Linux术语中,也可以称为核心。Linux内核的主要模块(或组件)分为以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信、系统初始化(boot)、系统调用等。

系统调用接口

SCI层提供了一些机制来执行从用户空间到内核的函数调用。正如前面所讨论的,这个接口依赖于架构,即使是在同一个处理器家族中。SCI其实是一个非常有用的函数调用复用和解复用服务。是的。你可以在/linux/kernel中找到SCI的实现,在。与架构相关的部分可以在/linux/arch中找到。

进程管理

流程管理的重点是流程的实施。在内核中,这些进程称为线程,代表单个处理器虚拟化(线程代码、数据、堆栈和CPU寄存器)。在用户空间中,通常使用术语进程,但是Linux实现没有区分这两个概念(进程和线程)。

内核SCI提供了一个应用编程接口(API)来创建一个新的进程(fork,exec或可移植操作系统接口[POS ]函数),停止进程(kill,exit),并进行通信和同步(signal或POS 机制)。

进程管理还包括处理活动进程之间共享CPU的需求。内核实现了新的调度算法,无论多少个线程争夺CPU,都可以在固定的时间内运行。这种算法被称为O (1) scheduler,这意味着它调度多个线程所用的时间与调度一个线程所用的时间相同。

o调度程序也可以支持多处理器(称为对称多处理器或SMP)。您可以访问。进程管理的源代码可以在/linux/kernel中找到,也可以在。依赖于架构的源代码可以在/linux/arch中找到。

内存管理

内核管理的另一个重要资源是内存。为了提高效率,如果用硬内存管理虚拟内存,那么内存就按照所谓的内存分页法(大多数架构是4KB)来管理。Linux包括管理可用内存的方式和用于物理和虚拟映射的硬件机制。

但是,内存管理需要管理4KB以上的缓冲区。Linux提供了4KB缓冲区的抽象,比如slab分配器。这种内存管理模式以4KB缓冲区为基数,然后从中分配结构,并跟踪内存页面的使用情况,比如哪些页面已满,哪些页面未完全使用,哪些页面为空。这允许该模式根据系统需求动态调整内存使用。

为了支持多个用户使用内存,有时会耗尽可用内存。因此,可以将页面移出内存,放入磁盘。这个过程称为交换,因为页面是从内存交换到硬盘的。内存管理的源代码可以在。/linux/mm.

虚拟文件系统

虚拟文件系统(VFS)是Linux内核的一个非常有用的方面,因为它为文件系统提供了一个通用的接口抽象。VFS在SCI和内核支持的文件系统之间提供了一个交换层。

VFS在用户和文件系统之间提供了一个交换层。

在VFS之上,它是对诸如打开、关闭、读写等功能的通用API抽象。VFS下面是文件系统抽象,它定义了上层功能的实现。它们是给定文件系统(超过50个)的插件。该文件的源代码可以在。在/linux/fs中找到。

文件系统层下面是缓冲区缓存,它为文件系统层提供了一个通用的函数集(不考虑具体的文件系统)。该缓存层通过将数据保留一段时间(或在需要时预读数据)来优化对物理设备的访问。缓冲区缓存下面是设备驱动程序,它实现特定物理设备的接口。

好吧。相信读者对linuxkernel有个大概的了解。让让我们继续分析这条道路背后的模型结构。(。/Linux/驱动程序/tty/串行/samsung.c)

Driver是驱动程序的目录。如图所示:

有一个linux设备驱动程序的一般描述。让让我们具体看看linux下的驱动程序。

查看linux/drivers目录,可能有超过35个子目录。每个子目录基本代表一个设备驱动,包括atm、block、char、misc、input、net、usb、sound、video等。本文只介绍嵌入式系统中应用最广泛的三种器件。

1.字符设备(充电设备)

字符是Linux中最简单的设备,可以像文件一样被访问。当字符设备被初始化时,它的设备驱动程序被注册到Linux,并且一个device_struct数据结构条目被添加到字符设备向量表中。该设备的主设备标识符被用作该向量表的索引。

设备的主设备标识符是固定的。chrdevs向量表(device_struct数据结构)中的每个条目包括两个元素:注册设备驱动程序名称的指针和指向一组文件操作的指针。可以参考的代码是include/linux/major.h

一般来说,鼠标、串口、键盘等设备都属于字符设备。

2.闭塞设备

块是文件系统的物质基础,也可以像文件一样被访问。Linux blkdevs向量表用于维护注册的块设备文件。和chrdevs向量表一样,它使用设备的主设备号作为索引。它的条目也是device_struct数据结构。与字符设备不同,块设备分为SCSI类和IDE类。

向Linux内核注册,并向内核提供文件操作。块设备类的设备驱动程序向该类提供与该类相关的接口。参考代码是fs/devices.c.

每个块设备驱动程序必须提供一个通用的文件操作接口和一个缓冲区缓存接口。每个块设备驱动程序填充BLK _开发向量表中的blk_dev _ STRUCT数据结构。该向量表的索引是设备的主设备号。blk_dev_struct数据结构包括请求例程的地址和指向请求数据结构列表的指针,每个请求数据结构表示缓冲区高速缓存对设备读/写一条数据的请求。

可用的源代码有drivers/block/ll_rw_blk.c和include/Linux/blkdev.h。

当buffer cache从一个注册的设备中读取/写入一段数据,或者想要从另一个位置读取/写入一段数据时,它会在blk_dev_struct中添加一个请求数据结构。每个请求数据结构都有一个指向一个或多个buffer_head数据结构的指针,每个buffer _ head数据结构都是一个读/写数据的请求。

如果buffer_head数据结构被锁定(buffer_cache),可能会有一个进程等待这个缓冲区的阻塞进程完成。每个请求数据结构都是从all_request表中分配的。如果请求被添加到空请求列表,调用驱动的请求函数来处理请求队列,否则,驱动程序只处理请求队列中的每个请求。

块设备驱动程序和字符设备驱动程序之间的主要区别在于,实际的硬件I/O通常在字符设备被读写后立即发生,而块设备不会。它使用一块系统内存作为缓冲区。当用户的进程请求设备满足用户如果没有,它就调用请求函数来执行实际的I/O操作。Block主要是针对磁盘等速度较慢的设备,以免花费太多的CPU时间等待。

这些设备主要包括硬盘、光驱等。它可以通过查看文件/proc/devices获得。

3.网络设备(网络设备)

网络设备就像系统中安装的块设备。设备在blk_dev数据和其他内核结构中注册自己,然后通过自己的请求函数在请求发生时发送和接收数据块。类似地,网络设备必须在特定的数据结构中注册自己,以便在与外界交换数据包时可以调用它。网络是在Linux下专门处理的。Linux的网络系统主要基于BSD UNIX的Socket机制。在系统和驱动程序之间定义了一个特殊的数据结构(sk_buff)来传输数据。系统支持发送数据和接收数据的缓存,提供流量控制机制,支持多种协议。

4.杂项设备(杂项装置)

杂项设备也是嵌入式系统中广泛使用的一种设备驱动程序。第十一章介绍的子LCD和chord芯片的驱动都是用misc设备驱动实现的。linux内核的includelinux目录下有Miscdevice.h文件,所以要在这里定义自己的Miscdevice从设备。实际上,它因为这些字符设备不不符合预先确定的字符设备类别。所有这些设备都采用主编号10,同属于misc设备。实际上,misc_register调用的是主号码为10的register_chrdev()。

这是驱动目录下的类别。我们主要研究串口驱动程序。属于TTY子系统。所以我们cd到tty目录。Ls显示里面的文件。如图所示:

下面简单介绍一下linux内核中的tty设备。

tty一词来源于Teletypes,即电传打字机,是最早的终端设备,类似于电传打字机,由Teletype公司生产。起初,tty指的是连接到Unix系统的物理或虚拟终端。终端是一种字符型设备,tty通常用来统称各种类型的终端设备。随着时间的推移,当终端连接可以通过串口建立时,这个名称也被用来指代任何串行设备。

有很多种,比如串口(ttySn,ttyscn,ttyOn),USB转串口(ttyUSBn),需要特殊处理才能正常工作的调制解调器(比如传统的WinModem设备)。Tty虚拟设备支持虚拟控制台,它可以通过键盘和网络连接或xterm会话登录到计算机。

其实一开始,终端和主机都不是个人电脑的概念,而是很多人共用的小、中、大型电脑的概念。它为终端主机提供了人机界面,每个人都使用主机的资源。有两种终端:字符终端和图形终端。一台主机可以连接到许多终端。控制台是一种特殊的人机界面,是人们控制主机的第一个人机界面。

并且主机对控制台的信任度高于其他终端。这也可以结合init进程在内核启动代码中打开/dev/console并执行sys_dup(0)两次,以及进程fork后的标准输入、标准输出、标准错误、标准输入输出的副本来理解。而个人电脑只有控制台,没有终端。如果您愿意,可以在串行端口上连接一个或两个哑终端。

但是,linux根据POSIX标准将个人计算机作为小型机使用。在控制台上,六个虚拟终端(或虚拟控制台终端tty1-tty6)(数量可在/etc/inittab中自行调整)和一个图形终端被getty软件虚拟化。在虚拟图形终端中,无限数量的伪终端(pts/0等。)可以通过软件虚拟化(比如rxvt)。

但是它都是虚拟的。虽然它用同样的方式,有它实际上没有物理实体。所以在个人电脑上,只有一个真正的控制台,而没有终端。所有终端都由控制台上的软件模拟。也可以使用个人电脑作为主机,然后通过串口或网卡连接真实的物理终端。论成本,呵呵。谁来做?

根据终端自身的功能,终端可以分为:

1、智能终端(瘦客户端)

早期的计算机终端通过串行RS-232进行通信,它只能解释有限数量的控制代码(CR、LF等。),但它不能处理和执行特殊的转义序列功能(如行清除、屏幕清除或光标位置控制)。简单来说就是处理能力有限的终端。一般来说,它们只具有类似于机械电传打字机的有限功能。这种类型的终端称为哑终端。

通过设置环境变量TERM=dumb,在现代类Unix系统上仍然支持它。哑终端有时用来指通过RS-232连接的任何类型的传统计算机终端,它是一种串行通信终端,不在本地处理数据或在本地执行用户程序。哑终端有时指功能有限,只有单色文本处理能力或不等待主机轮询而直接传输每个键入字符的公用计算机终端。

2、智能终端(胖客户端)

智能终端是具有处理转义序列能力的终端,也就是说,具有很强处理能力的终端。

一般来说,Linux系统的终端设备如下:

1、控制台

系统控制台/开发/控制台

/dev/console是系统控制台,是与操作系统交互的设备。系统生成的信息将被发送到设备。通常我们看到的PC只有屏幕和键盘,其实就是一个控制台。目前,仅允许用户在单用户模式下登录控制台/开发/控制台。(可以在单用户模式下输入tty命令进行确认)。

控制台有缓冲的概念,并为内核提供打印输出。内核把要打印的内容加载到缓冲区__log_buff,然后控制台决定打印到哪里(比如tty0或者ttySn等。).控制台指向活动终端。历史上,控制台指的是主机本身的屏幕和键盘,而tty指的是通过线缆链接的其他位置的控制台。

在某些情况下,console和tty0是一致的,即使用当前的虚拟终端,并且虚拟终端也被激活。所以有资料说/dev/console是/dev/tty0的符号链接,现在看来是错误的:根据内核文档,在2.1.71之前,/dev/console是根据不同的系统设置,符号链接到/dev/tty0或者其他TTY *,2.1.71之后,其映射完全由内核代码控制。

如果终端设备想要实现控制台功能,它必须向内核注册一个struct控制台结构,这在串口驱动程序中很常见。如果设备想要实现tty功能,就必须在内核的tty子系统中注册一个struct tty _ driver结构。注册的函数在drivers/tty/tty _ io.c中,一个设备可以同时实现console和tty_driver。一般串口都是这样做的。

当前控制台:/dev/tty

这是应用中的一个概念。如果当前进程有一个控制终端,那么/dev/tty就是当前进程控制台的设备文件。对于您登录的shell,/dev/tty是您使用的控制台,设备号是(5,0)。但是,它不引用任何物理控制台,并且/dev/tty将被映射到当前设备(使用命令tty 以查看它对应于哪个实际的物理控制台设备)。/dev/tty的输出将只显示在当前工作的终端上(无论是登录ttyn还是pty)。

如果你在控制台界面(即字符界面),那么dev/tty映射到dev/tty1-6中的一个(取决于你当前的控制台号),但是如果你在图形界面(Xwindows),那么你会发现当前的/dev/tty映射到/dev/pts的伪终端。/dev/tty有点类似于实际使用的终端设备的连接。

您可以输入命令tty ,将显示当前映射终端,如/dev/tty1或/dev/pts/0。您也可以使用命令PS-ax 检查其它进程连接到哪个控制终端。

输入echo 铁拳侠/dev/tty,它会直接显示在当前终端中。

虚拟控制台/开发/ttyn

/dev/ttyn是一个进程虚拟控制台,它们共享同一个真实的物理控制台。如果这样的文件是在一个进程中打开的,并且它不是其他进程的控制台,那么它就是这个进程的控制台。

过程printf数据将在此处输出。在PC上,用户可以使用alt Fn来切换控制台。现在我不不知道什么这是怎么回事。我用Ctrl Alt Fn切换。我还没有我没具体见过这个。为什么?也许Linux没有不要继承UNIX的传统。好像有多个屏幕,这个虚拟控制台对应的是tty1~n,其中:

/dev/tty1等代表第一个虚拟控制台。

比如ALT F2用于切换时,系统的虚拟控制台是/dev/tty2,当前控制台(/dev/tty2)指向/dev/tty2。

在UNIX系统中,计算机显示器通常称为控制台。它模拟了一个Linux类型的终端,有一些特殊的文件与之关联:tty0,tty1、tty2等。登录控制台时,使用tty1。使用Alt [F1—F6]组合键时,我们可以切换到tty2、tty3等。

读者可以登录到不同的虚拟控制台,从而允许系统同时有几个不同的会话。

什么比较特殊的是/dev/tty0,代表当前虚拟控制台,实际上是当前使用的虚拟控制台的别名。因此,无论当前使用的是哪个虚拟控制台(注意:这是虚拟控制台,不包括伪终端),系统信息都会被重定位到/dev/tty0。

只有系统或超级用户root可以写入/dev/tty0。Tty0由系统自动打开,但不用于用户登录。在未启用Framebuffer设备的系统中,可以使用/dev/tty0来访问显卡。

2、伪终端pty(伪tty)

伪终端是终端的发展,为了满足当前的需求(比如网络登录,xwindow管理)。它是成对出现的逻辑终端设备(即主设备和从设备,主设备的操作会反映在从设备上)。它主要用于模拟终端程序,是在远程登录(telnet、ssh、xterm等)后创建的控制台设备。).

历史上,有两套伪终端软件接口:

BSD接口:比较简单,有master/dev/pty[p-za-e][0-9a-f];Slave是/dev/tty [p-za-e] [0-9a-f],都是成对出现的。例如/dev/ptyp3和/dev/ttyp3。但由于在编程中需要一个一个尝试才能找到合适的终端,所以逐渐被放弃。

Unix 98接口:使用a /dev/ptmx作为主设备,每次打开操作都会得到一个主设备fd,在/dev/pts/目录下有一个从设备(比如/dev/pts/3和/dev/ptmx),避免了一个一个试的麻烦。

由于可能有成千上万的用户登录,/dev/pts/*是动态生成的,不像其他设备文件是系统构建时就已经生成的硬盘节点(如devfs、udev、mdev等。未被使用)。第一个用户登录,设备文件是/dev/pts/0,第二个是/dev/pts/1,依此类推。它们与实际的物理设备没有直接关系。目前大部分系统都是通过这个接口实现pty的。

当我们在X Window下打开终端或者使用telnet或者ssh登录Linux主机时,这个时候我们都使用pty设备。例如,如果有人在Internet上使用telnet程序连接到您的计算机,telnet程序可能会打开/dev/ptmx设备来获取fd。此时,一个getty程序应该运行在相应的/dev/pts/*上。当telnet从远端得到一个字符时,会通过ptmx,pts/*传递给getty程序,getty程序会返回登录:通过ptmx、PTMX和telnet程序将信息串到网络上。这样,登录程序和telnet程序通过一个伪终端。

telnet 《---》 /dev/ptmx(主)《---》 pts/*(从)《---》 getty

如果一个程序把pts/*当作串口设备,那么它对这个端口的读/写操作就会反映到逻辑终端设备对的另一个/dev/ptmx上,而/dev/ptmx是另一个程序用来进行读/写操作的逻辑设备。

这样,两个程序可以通过这个逻辑设备相互通信,这很像逻辑设备对之间的流水线操作。对于pts/*,任何设计为使用串口设备的程序都可以使用这个逻辑设备。但是,对于使用/dev/ptmx的程序,需要专门设计来使用/dev/ptmx逻辑设备。通过使用适当的软件,两个甚至更多的伪终端设备可以连接到同一个物理串行端口。

3、串行端口终端(/dev/ttySn)

串口终端是通过计算机串口连接的终端设备。计算机的每个串口都被视为一个字符设备。有一段时间,串行端口设备通常被称为终端设备。当时他们最大的目的就是连接终端,所以这些串口对应的设备名分别是/dev/tts/0(或者/dev/ttyS0)、/dev/tts/1(或者/dev /ttyS1),设备号分别是(4,0)和(4,1)。要向端口发送数据,您可以在命令行上将标准输出重定向到这些特殊的文件名。

我们可以输入:echo tekkaman /dev/ttys1在命令行提示符下发送铁拳侠连接到ttyS1(COM2)端口的设备。

在2.6的内核之后,部分三星芯片将串行终端设备节点命名为ttySACn。TI s Omap系列芯片从2.6.37开始对芯片上的uart设备使用专有的omap-uart驱动程序,所以设备节点命名为ttyOn,与设备名ttySn 使用8250驱动程序时。这其中就包括笔者使用的S3C2440。因此,我们需要在Uboot启动参数中设置console=ttySAC0。这句话的意思其实就是把ttySAC0作为我们的控制台终端。

4、其他类型的终端

对于许多不同的字符设备,还有许多其他种类的终端设备专用文件,例如/dev/ttyIn终端设备用于ISDN设备。

好吧。那就是它。相信读者对tty设备有一个大概的了解。

因为我们和开发板的人机界面是Windows下的串口控制台。这就是上面提到的控制台终端。但是我们使用console=ttySAC0。也就是说,串行终端被用作控制台终端。所以我们需要cd到serial子目录来研究具体的代码。串口终端目录。显示ls下的文件节点。如图所示:

我们主要是关门

我们得到的函数调用链是这样的(以发送函数。即文件的写操作为例。

write-》

sys_write-》

vfs_write-》

redirected_tty_write-》

tty_write-》

n_tty_write-》

uart_write-》

uart_start-》

s3c24xx_serial_start_tx

从具体代码上来看。这些函数基本上都是通过结构体中的函数指针调用。我们可以把这个调用链分为三个部分。即tty子系统核心。tty链路规程。tty驱动

tty核心。是对整个tty设备的抽象。对用户提供统一的接口。包括sys_write-》vfs_write

tty线路规程。是对传输数据的格式化。在tty_ldisc_N_TTY变量中描述。包括redirected_tty_write-》tty_write-》n_tty_write-》

tty驱动。是面向tty设备的硬件驱动。这里面真正的对硬件进行操作。包括uart_write-》uart_start-》s3c24xx_serial_start_tx

这是从具体函数的角度来看的调用链。下面为了从数据结构的角度来分析调用链。介绍linux内核中针对于这一个串口硬件的主要数据结构。对于具体的字段我们用到的时候再解释。

uart_driver。

就是uart驱动程序结构。封装了tty_driver,使得底层的UART驱动无需关心tty_driver具体定义如下。

uart_port

uart_port用于描述一个UART端口(直接对应于一个串口)的I/O端口或者IO内存地址等信息。

uart_ops定义了针对UART的一系列操作。注意这里不要把uart_ops结构和uart_ops变量混淆。uart_ops结构是我们这里的数据结构。而uart_ops变量则是一个tty_operations的变量。

在serial_core.c中定义了tty_operations的实例。即uart_ops变量,包含uart_open();uart_close();uart_send_xchar()等成员函数,这些函数借助uart_ops结构体中的成员函数来完成具体的操作:

uart_ops变量是tty_operations型的一个变量。如下图所示:

uart_state是uart的状态结构。

uart_info是uart的信息结构。在这个体系结构下定义为s3c24xx_uart_info:

所以很显然。用数据结构来描述函数调用链就是

uart_driver -》

uart_state-》

uart_port-》

uart_ops-》

特定的函数指针。

初始化过程比较复杂。不赘述。从函数指针的调用流程为主线。忽略一些入参检查和内核中的信号量代码。大致的初始化流程如下图所示:

打开设备和初始化流程类似。如图所示:

同理数据的发送和接收如图所示:

这里我们需要注意的是。使能发送并没有真正的发送过程。而只是使能发送中断

这一句:enable_irq(ourport-》tx_irq);

这是因为ARM9处理器上有一个循环缓冲。用户从write系统调用传下来的数据就会写入这个UTXH0寄存器。发送完事之后处理器会产生一个内部中断。我们通过这个内部中断就可以实现流控过程、我们打开芯片手册可以看到如下字样(拿ARM11举例也一样,。这是ARM11的):

如下才是发送中断的ISR(Interrupt Service Routine)中断服务例程。一个irqreturn_t类型的handler。

这个wr_regb(port, S3C2410_UTXH, port-》x_char);就是往特定寄存器写的过程。

至此我们的分析已经结束。相信读者对于Linux下的tty子系统已经有一个概观了。下面是这个uart驱动的总图。结合数据结构的调用链。Linux内核完成了驱动模型和特定硬件的分离:

串口驱动数据结构总图:

-END-

直接来源 | 嵌入式大杂烩

作者:Linkerist