首页>>科技 >>内容

从串口驱动到linux驱动模型怎么设置,从串口驱动到Linux驱动模型

发布时间:2024-01-10 23:26:05编辑:温柔的背包来源:

很多朋友对从串口驱动到linux驱动模型怎么设置,从串口驱动到Linux驱动模型不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。

从串口驱动到linux驱动模型怎么设置,从串口驱动到Linux驱动模型

本文分析了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系统(如FreeBSD、OpenBSD、SUN Solaris)和各种类似于传统Unix的系统(如Minix、Linux、QNX等)。).虽然它们有些是自由软件,有些是商业软件,但它们都在相当程度上继承了原UNIX的特点,有许多相似之处,并且都在一定程度上遵守POSIX规范。

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

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

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

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

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

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

Linux内核将有限的硬件资源发挥到了极致。开源软件良好的模块化设计充分利用了各级程序局部性原则。(当然,这是在损失一些可用性的前提下。)。抱歉我跑题了。这些都不是本文的重点。因为作者没有土豪,所以电脑很多。所以我选择了更便宜的ARM9开发板作为开发平台。它的CPU是三星生产的S3C2440。核心是ARM920T。c .关于Linux的基本想法

Linux的基本思想有两点:第一,一切都是文件。系统中的一切都归结为一个文件,包括命令、硬件和软件设备、操作系统、进程等。对于操作系统内核来说,它被视为一个具有自己特征或类型的文件。至于说Linux基于Unix,很大程度上是因为两者的基本思想非常相似。第二,每个软件都有明确的用途。d、Linux的特性完全免费。

Linux是一个免费的操作系统,用户可以通过网络或其他渠道免费获得,并且可以随意修改其源代码。这是其他操作系统无法企及的。也正因为如此,无数来自世界各地的程序员参与了Linux的修改和编写,程序员可以根据自己的兴趣和灵感进行修改,这使得Linux吸收了无数程序员的精华,不断成长。完全兼容POSIX1.0标准

这使得在Linux下通过相应的模拟器运行常用的DOS和Windows程序成为可能。这为用户从Windows转到Linux奠定了基础。很多用户在考虑使用Linux的时候,都想着Windows下的常用程序是否能正常运行,消除了他们的疑虑。多用户、多任务

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

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

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

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

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

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

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

4、目录:是目录,第一个属性是[d],例如[[drwxrwxrwx]]。链接:类似Windows下的快捷方式。第一个属性是[l],比如[[lrwxrwxrwx]]。5、设备:一些与系统外设和存储相关的文件通常集中在/dev目录中。通常分为两种类型:

块设备文件:存储系统访问数据的接口设备,它只是一个硬盘。比如1号硬盘的代码就是/dev/hda1之类的文件。第一个属性是[b]。字符设备文件:串口的接口设备,如键盘、鼠标等。第一个属性是[c]。

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

7、管道(FIFO): FIFO也是一种特殊的文件类型,其主要目的是解决多个程序同时访问一个文件而导致的错误。FIFO是先进先出的缩写。第一个属性是[p]文件结构/:根目录,所有的目录、文件、设备都在/,是Linux文件系统的组织者,也是最高领导。

/bin: bin是binary的缩写。在通用系统中,可以在这个目录中找到linux常用命令。系统所需的命令位于该目录中。/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接口的移动硬盘(包括u盘)、CD/DVD驱动器等等。/opt:可选程序主要存放在这里。/proc:您可以在这个目录中获得系统信息。这些信息存在于内存中,由系统本身生成。/root:主目录/root:Linux超级用户root。

/sbin:该目录用于存储系统管理员的系统管理程序。大部分是系统管理相关命令的存储,是超级特权用户root可执行命令的存储场所。普通用户无权执行这个目录、这个目录和/usr/sbin中的命令;/usr/X11R6/sbin或/usr/local/sbin目录类似,sbin包含的所有目录都只能用root权限执行。/selinux: selinux可以让linux对SElinux的一些配置文件目录更加安全。

/srv服务启动后,要访问的数据目录,例如www服务读取的网页数据,可以放在/srv/www /tmp: temporary file目录下,用来存储执行不同程序时产生的临时文件。有时当用户运行程序时,会生成一个临时文件。/tmp用于存储临时文件。/var/tmp目录类似于这个目录。

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

/usr/local:手动安装的软件主要存放在这里,也就是没有通过“Xinli”或者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,MySQL数据库的存放处。如上。相信读者已经对Linux操作系统有了一个大概的了解。对于一些特定的命令。我决定在需要的时候解释。现在让我们看看第二个概念:

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

Linux设备驱动程序是底层硬件资源的抽象。为上层操作系统的其他服务提供良好的接口。以便其他服务可以将特定的硬件。或者用作文件的机制。使用公共系统调用进行调用。

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

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

串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。

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

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

异步串行是指UART(UniversalAsynchronous Receiver/Transmitter),通用异步接收/发送。UART是一个并行输入成为串行输出的芯片,通常集成在主板上。UART包含TTL电平的串口和RS232电平的串口。

TTL电平是3.3V的,而RS232是负逻辑电平,它定义+5~+12V为低电平,而-12~-5V为高电平,MDS2710、MDS SD4、EL805等是RS232接口,EL806有TTL接口。

串行接口按电气标准及协议来分包括RS-232-C、RS-422、RS485等。

RS-232

也称标准串口,最常用的一种串行通讯接口。它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。

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

RS-232采取不平衡传输方式,即所谓单端通讯。由于其发送电平与接收电平的差仅为2V至3V左右,所以其共模抑制能力差,再加上双绞线上的分布电容,其传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其驱动器负载为37k。所以RS-232适合本地设备之间的通信。

RS-422

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

即一个主设备(Master),其余为从设备(Slave),从设备之间不能通信,所以RS-422支持点对多的双向通信。接收器输入阻抗为4k,故发端最大负载能力是104k+100(终接电阻)。

RS-422四线接口由于采用单独的发送和接收通道,因此不必控制数据方向,各装置之间任何必须的信号交换均可以按软件方式(XON/XOFF握手)或硬件方式(一对单独的双绞线)实现。

RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。其平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能达到最大传输距离。只有在很短的距离下才能获得最高速率传输。一般100米长的双绞线上所能获得的最大传输速率仅为1Mb/s。

RS-485

是从RS-422基础上发展而来的,所以RS-485许多电气规定与RS-422相仿。如都采用平衡传输方式、都需要在传输线上接终接电阻等。RS-485可以采用二线与四线方式,二线制可实现真正的多点双向通信,而采用四线连接时,与RS-422一样只能实现点对多的通信,即只能有一个主(Master)设备,其余为从设备,但它比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米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比,在100kb/s速率以下,才可能使用规定最长的电缆长度。只有在很短的距离下才能获得最高速率传输。一般100米长双绞线最大传输速率仅为1Mb/s。

笔者采用的RS-232串口通信协议。下面对其通信接线方法做简要说明。目前较为常用的串口有9针串口(DB9)和25针串口(DB25),通信距离较近时(《12m),可以用电缆线直接连接标准RS232端口(RS422,RS485较远),若距离较远,需附加调制解调器(MODEM)或其他相关设备。

最为简单且常用的是三线制接法,即地、接收数据和发送数据三脚相连,这是最为基本的接法,且直接用RS232相连。

上面是对微机标准串行口而言的,还有许多非标准设备,不做说明。

好了。到此为止我们已经解决了一开始的三个问题。让我们进入实际的代码。实际的硬件来进行分析。

在一个硬件平台上。硬件是可用的。我们必须要烧写适当的软体到平台的RAM中。这样CPU才能跳转到最先的指令。然后慢慢加载各种资源。才能完成系统的自举。

一般我们采用BootLoader进行硬件的初始化。并引导至操作系统核心。

笔者采用的BootLoader是u-Boot-1.1.16。Uboot是一个众所周知的开源软件。读者仅需了解它起到了BootLoader的作用即可。这里不多做解释。仅对串口的连接和程序的下载作简要说明:

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

然后我们再使用一个工具。即SecureCRT。找到对应的com号。完成快速链接。波特率选择115200。取消流控。

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

这个串口的指令功能是由Uboot本身完成的。并不是linux下的串口驱动。

引入此图旨在让读者感性的认识到串口控制台的功能是什么。

下面正式开始对串口打开。发送。接收函数的分析。这里向前引用一个函数。就是linux内核中几种2440芯片通用的串口发送函数s3c24xx_serial_start_tx。函数声明为static voids3c24xx_serial_start_tx(struct uart_port *port):函数定义在。/linux/driver/tty/serial/samsung.c中。

好了。我们从这个目录结构开始。说明大概的tty子系统驱动模型。

首先。最前面的linux是内核代码的根目录。如图所示。

至此。我们面临一个问题。linux内核是什么。

Linux内核是什么?Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。

Linux最早是由芬兰黑客Linus Torvalds为尝试在英特尔x86架构上提供自由免费的类Unix操作系统而开发的。该计划开始于1991年,在计划的早期有一些Minix 黑客提供了协助,而今天全球无数程序员正在为该计划无偿提供帮助。

Linux是一个一体化内核(monolithickernel)系统。“内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。

一套基于Linux内核的完整操作系统叫作Linux操作系统,或是GNU/Linux。设备驱动程序可以完全访问硬件。Linux内的设备驱动程序可以方便地以模块化(modularize)的形式设置,并在系统运行期间可直接装载或卸载。

操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。

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

系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在。/linux/kernel 中您可以找到SCI 的实现,并在。/linux/arch 中找到依赖于体系结构的部分。

进程管理

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

内核通过SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或Portable Operating System Interface POS 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者POS机制)。

进程管理还包括处理活动进程之间共享CPU的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争CPU,这种算法都可以在固定时间内进行操作。这种算法就称为O调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。

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

内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬管理虚拟内存,内存是按照所谓的内存页方式进行管理的(对于大部分体系结构来说都是4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。

不过内存管理要管理的可不止4KB缓冲区。Linux 提供了对4KB缓冲区的抽象,例如slab 分配器。这种内存管理模式使用4KB缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。

为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在。/linux/mm 中找到。

虚拟文件系统

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

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

在VFS 上面,是对诸如open、close、read 和write 之类的函数的一个通用API 抽象。在VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过50 个)的插件。文件系统的源代码可以在。/linux/fs 中找到。

文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

好了。相信读者已经对linuxkernel 有了一个概观。下面我们继续分析这个路径背后代表的模型结构。(。/linux/driver/tty/serial/samsung.c)

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

前文对linux设备驱动程序有了一个大概的描述。下面我们具体看一下linux下的驱动。

纵览linux/drivers目录,大概还有35个以上的子目录,每个子目录基本上就代表了一种设备驱动,有atm、block、char、misc、input、net、usb、sound、video等。这里只描述在嵌入式系统里面用得最为广泛的3种设备。

1字符设备(char device)

字符设备是Linux最简单的设备,可以像文件一样访问。初始化字符设备时,它的设备驱动程序向Linux登记,并在字符设备向量表中增加一个device_struct数据结构条目,这个设备的主设备标识符用做这个向量表的索引。

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

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

2块设备(block device)

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

向Linux内核登记并向核心提供文件操作。一种块设备类的设备驱动程序向这种类提供和类相关的接口。可以参考的代码是fs/devices.c。

每一个块设备驱动程序必须提供普通的文件操作接口和对于buffer cache的接口。每一个块设备驱动程序填充blk_dev向量表中的blk_dev_struct数据结构。此向量表的索引是设备的主设备号。其中blk_dev_struct数据结构包括一个请求例程的地址和一个指针,指向一个request数据结构的列表,每一个都表达buffer cache向设备读/写一块数据的一个请求。

可以参考的源代码是drivers/block/ll_rw_blk.c和include/linux/blkdev.h。

当buffer cache从一个已登记的设备读/写一块数据,或者希望读、写一块数据到其他位置时,就在blk_dev_struct中增加一个request数据结构。每个request数据结构都有一个指向一个或多个buffer_head数据结构的指针,每一个都是读/写一块数据的请求。

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

块设备驱动程序和字符设备驱动程序的主要区别是:在对字符设备发出读、写请求时,实际的硬件I/O一般紧接着就发生了,块设备则不然,它利用一块系统内存作为缓冲区,当用户进程对设备请求能满足用户的要求时,就返回请求的数据,如果不能就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备的,以免耗费过多的CPU时间来等待。

块设备主要有硬盘、光盘驱动器等。可以查看文件/proc/devices获得。

3网络设备(net device)

网络设备在系统中的作用类似于一个已挂载的块设备。块设备将自己注册到blk_dev数据及其他内核结构中,然后通过自己的request函数在发生请求时传输和接收数据块,同样网络设备也必须在特定的数据结构中注册自己,以便与外界交换数据包时被调用。网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD UNIX的Socket机制。

在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据的缓存,提供流量控制机制,提供对多协议的支持。

4杂项设备(misc device)

杂项设备也是在嵌入式系统中用得比较多的一种设备驱动,在第11章里面介绍的sub LCD和弦芯片的驱动等都是采用misc device 的驱动方式实现的。在Linux 内核的includelinux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。

其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。

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

下面对linux内核tty设备做一点简要说明。

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

它还有多种类,例如串口(ttySn、ttySACn、ttyOn)、USB到串口的转换器(ttyUSBn),还有需要特殊处理才能正常工作的调制解调器(比如传统的WinModem类设备)等。tty虚拟设备支持虚拟控制台,它能通过键盘及网络连接或者通过xterm会话登录到计算机上。

其实起初终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念。终端为主机提供了人机接口,每个人都通过终端使用主机的资源。终端有字符终端和图形终端两种。一台主机可以连很多终端。控制台是一种特殊的人机接口, 是人控制主机的第一人机接口。

而主机对于控制台的信任度高于其他终端。对此还可以结合内核启动代码中init进程打开/dev/console和执行两次sys_dup(0),以及标准输入、标准输出、标准出错,还有就是进程fork后的标准输入输出的复制情况来一起理解。而个人计算机只有控制台,没有终端。当然愿意的话,可以在串口上连一两台字符哑终端。

但是linux按POSIX标准把个人计算机当成小型机来用,在控制台上通过getty软件虚拟了六个字符哑终端(或者叫虚拟控制台终端tty1-tty6)(数量可以在/etc/inittab里自己调整)和一个图型终端, 在虚拟图形终端中又可以通过软件(如rxvt)再虚拟无限多个伪终端(pts/0等)。

但这全是虚拟的,虽然用起来一样,但实际上没有物理实体。所以在个人计算机上,只有一个实际的控制台,没有终端,所有终端都是在控制台上用软件模拟的。要把个人计算机当主机再通过串口或网卡外连真正的物理终端也可以,论成本,呵呵。谁会怎么做呢。

终端按照其自身能力分类,可以分为:

1、哑终端(瘦客户端)

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

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

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

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

Linux系统的终端设备一般有以下几种:

1、 控制台

系统控制台/dev/console

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

console有缓冲的概念,为内核提供打印输出。内核把要打印的内容装入缓冲区__log_buff,然后由console来决定打印到哪里(比如是tty0还是ttySn等)。console指向激活的终端。历史上,console指主机本身的屏幕和键盘,而tty指用电缆链接的其它位置的控制台。

某些情况下console和tty0是一致的,就是当前所使用的是虚拟终端,也是激活虚拟终端。所以有些资料中称/dev/console是到/dev/tty0的符号链接,但是这样说现在看来是不对的:根据内核文档,在2.1.71之前,/dev/console根据不同系统设定,符号链接到/dev/tty0或者其他tty上,在2.1.71版本之后则完全由内核代码内部控制它的映射。

如果一个终端设备要实现console功能,必须向内核注册一个struct console结构,一般的串口驱动中都会有。如果设备要实现tty功能,必须要内核的tty子系统注册一个struct tty_driver结构,注册函数在drivers/tty/tty_io.c中。一个设备可以同时实现console和tty_driver,一般串口都这么做。

当前控制台:/dev/tty

这是应用程序中的概念,如果当前进程有控制终端(Controlling Terminal),那么/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 “tekkaman”》 /dev/tty ,都会直接显示在当前的终端中。

虚拟控制台/dev/ttyn

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

进程printf数据会输出到这里。在PC上,用户可以使用alt+Fn切换控制台,现在不知道怎么回事我用Ctrl + Alt + Fn才能切换。这没具体看过为啥。可能是Linux没有继承UNIX这方面的传统罢了。看起来感觉存在多个屏幕,这种虚拟控制台对应tty1~n,其中:

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

例如当使用ALT+F2进行切换时,系统的虚拟控制台为/dev/tty2 ,当前控制台(/dev/tty)则指向/dev/tty2

在UNIX系统中,计算机显示器通常被称为控制台(Console)。它仿真了类型为Linux的一种终端,并且有一些设备特殊文件与之相关联:tty0、tty1、tty2等。当你在控制台上登录时,使用的是tty1。使用Alt+F1—F6组合键时,我们就可以切换到tty2、tty3等上面去。

读者可以登录到不同的虚拟控制台上去,因而可以让系统同时有几个不同的会话存在。

而比较特殊的是/dev/tty0,他代表当前虚拟控制台,其实就是当前所使用虚拟控制台的一个别名。因此不管当前正在使用哪个虚拟控制台(注意:这里是虚拟控制台,不包括伪终端),系统信息都会重定位到/dev/tty0上。

只有系统或超级用户root可以向/dev/tty0进行写操作。tty0是系统自动打开的,但不用于用户登录。在Framebuffer设备没有启用的系统中,可以使用/dev/tty0访问显卡。

2、 伪终端pty(pseudo-tty)

伪终端(Pseudo Terminal)是终端的发展,为满足现在需求(比如网络登陆、xwindow窗口的管理)。它是成对出现的逻辑终端设备(即master和slave设备, 对master的操作会反映到slave上)。它多用于模拟终端程序,是远程登陆(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接口:使用一个/dev/ptmx作为master设备,在每次打开操作时会得到一个master设备fd,并在/dev/pts/目录下得到一个slave设备(如/dev/pts/3和/dev/ptmx),这样就避免了逐个尝试的麻烦。

由于可能有好几千个用户登陆,所以/dev/pts/* 是动态生成的,不象其他设备文件是构建系统时就已经产生的硬盘节点(如果未使用devfs、udev、mdev等) 。第一个用户登陆,设备文件为/dev/pts/0,第二个为/dev/pts/1,以此类推。它们并不与实际物理设备直接相关。现在大多数系统是通过此接口实现pty。

我们在X Window下打开的终端或使用telnet或ssh等方式登录Linux主机,此时均通过pty设备。例如,如果某人在网上使用telnet程序连接到你的计算机上,则telnet程序就可能会打开/dev/ptmx设备获取一个fd。此时一个getty程序就应该运行在对应的/dev/pts/* 上。

当telnet从远端获取了一个字符时,该字符就会通过ptmx、pts/* 传递给getty程序,而getty程序就会通过pts/* 、ptmx和telnet程序往网络上返回“login:”字符串信息。这样,登录程序与telnet程序就通过“伪终端”进行通信。

telnet 《---》 /dev/ptmx(master) 《---》 pts/*(slave) 《---》 getty

如果一个程序把pts/* 看作是一个串行端口设备,则它对该端口的读/写操作会反映在该逻辑终端设备对的另一个/dev/ptmx上,而/dev/ptmx则是另一个程序用于读写操作的逻辑设备。

这样,两个程序就可以通过这种逻辑设备进行互相交流,这很象是逻辑设备对之间的管道操作。对于pts/* ,任何设计成使用一个串行端口设备的程序都可以使用该逻辑设备。但对于使用/dev/ptmx的程序,则需要专门设计来使用/dev/ptmx逻辑设备。通过使用适当的软件,就可以把两个甚至多个伪终端设备连接到同一个物理串行端口上。

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

串行端口终端(Serial PortTerminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。有段时间串行端口设备通常被称为终端设备,那时它的最大用途就是用来连接终端,所以这些串行端口所对应的设备名称是/dev/tts/0(或/dev/ttyS0)、/dev/tts/1(或/dev /ttyS1)等,设备号分别是(4,0)、(4,1)等(对应于win系统下的COM1、COM2等)。

若要向一个端口发送数据,可以在命令行上把标准输出重定向到这些特殊文件名上即可。

我们可以在命令行提示符下键入:echotekkaman》 /dev/ttyS1会把“tekkaman”发送到连接在ttyS1(COM2)端口的设备上。

在2.6以后的内核后、一些三星的芯片将串口终端设备节点命名为ttySACn。TI的Omap系列芯片从2.6.37开始芯片自带的UART设备开始使用专有的的omap-uart驱动,故设备节点命名为ttyOn,以区别于使用8250驱动时的设备名“ttySn”。这其中包括笔者用到的这个S3C2440。所以我们在Uboot启动参数中要设置console=ttySAC0才可以。这一句的意思其实就是把ttySAC0当做我们的控制台终端。

4、 其它类型终端

还针对很多不同的字符设备存在有很多其它种类的终端设备特殊文件,例如针对ISDN设备的/dev/ttyIn终端设备等。

好了。到此为止。相信读者已经对tty设备有了一个概观。

因为我们和开发板的人机交互的接口是Windows下的串口控制台。这就是上面所说的控制台终端。但是我们用了console=ttySAC0.即把串口终端当做控制台终端。所以我们要研究具体的代码需要cd到serial子目录下。即串口终端目录。ls显示serial下的文件结点。如图所示:

我们主要关心的是两类文件。一类是与体系结构和板载资源无关的通

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

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

以上知识分享希望能够帮助到大家!