字符设备驱动程序
platform模型驱动和字符设备模型驱动

platform模型驱动和字符设备模型驱动字符设备驱动模型:1、申请设备号:动态申请(alloc_chrdev_region()),动态申请(register_chrdev_region())struct cdev btn_cdev;//申请设备号if(major){//静态申请设备号dev_id = MKDEV(major, 0);register_chrdev_region(dev_id, 1, "button");}else{//动态申请设备号alloc_chardev_region(&dev_id, 0, 1, "button");major = MAJOR(dev_id);}在Linux中以主设备号用来标识与设备文件相连的驱动程序。
次编号被驱动程序用来辨别操作的是哪个设备。
cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中高 12 位为主设备号,低20 位为次设备号。
设备号的获得与生成:获得:主设备号:MAJOR(dev_t dev);次设备号:MINOR(dev_t dev);生成:MKDEV(int major,int minor);2、初始化设备:void cdev_init(struct cdev *, struct file_operations *);cdev_init()函数用于初始化cdev 的成员,并建立cdev 和file_operations 之间的连接。
3、注册设备int cdev_add(struct cdev *, dev_t, unsigned);cdev_add()函数向系统添加一个 cdev,完成字符设备的注册。
4、创建设备节点手动创建设备节点:mknod 的标准形式为:mknod DEVNAME {b | c} MAJOR MINOR1,DEVNAME是要创建的设备文件名,如果想将设备文件放在一个特定的文件夹下,就需要先用mkdir在dev目录下新建一个目录;2, b和c 分别表示块设备和字符设备:b表示系统从块设备中读取数据的时候,直接从内存的buffer中读取数据,而不经过磁盘;c表示字符设备文件与设备传送数据的时候是以字符的形式传送,一次传送一个字符,比如打印机、终端都是以字符的形式传送数据;3,MAJOR和MINOR分别表示主设备号和次设备号:为了管理设备,系统为每个设备分配一个编号,一个设备号由主设备号和次设备号组成。
VxWorks下字符设备的驱动开发

( 国飞 行 试 验 研究 院 , 西 西 安 7 0 8 ) 中 陕 10 9
摘 要 : 着 V W o k 操 作 系统 在 嵌入 式 系统 中的应 用 , x ok 下 产 品 的 开发 和 应 用也 越 来 越 广 泛 。 发 嵌 入 式 设备 经 常遇 到 的 一 随 x rs V W rs 开
Ab ta t s r c :W ih t W or sopeai yse n mbe de yse .Vx or de h r uc e l p e n a pl ai s r n c he Vx k rt ng s t m i e d d s tm W ksun rt e p od td veo m nta d p i ton ae i — c c e sn l wi epr a r aigy d s e d.D e l pm e t o m be de v c s i o l m o n nc un e e n w t w rt f ce t nd r l be de ie veo n fe d d de i e s a pr b e e e o t r d i ho o i e e in a ei l vc i a drv m.I t sp pe .VxW o k e c rve v l pm e tu i e n hi a r r sd vie d i rde eo n nde h an ape t a rt e m i s cs nd how O c fg e t t on ur he PCIb e i e r s rb d i usd v c sae dec e i i d ti f rt ee ntde l pesago ee e c n eal o he rlva veo r od r fr n e. Ke y wor :Vx or s ha a trde i e rve veo ds W k ;c rce v c ;d i rde l pm e t n ;PCIde c ;slc u t vie ee tf nc on i
设备驱动程序简介

设备驱动程序简介1.设备驱动程序的作⽤从⼀个⾓度看,设备驱动程序的作⽤在于提供机制,⽽不是策略。
在编写驱动程序时,程序猿应该特别注意以下这个基本概念:编写訪问硬件的内核代码时,不要给⽤户强加不论什么特定策略。
由于不同的⽤户有不同的需求,驱动程序应该处理如何使硬件可⽤的问题。
⽽将如何使⽤硬件的问题留给上层应⽤程序。
从还有⼀个⾓度来看驱动程序。
它还能够看作是应⽤程序和实际设备之间的⼀个软件层。
总的来说,驱动程序设计主要还是综合考虑以下三个⽅⾯的因素:提供给⽤户尽量多的选项、编写驱动程序要占⽤的时间以及尽量保持程序简单⽽不⾄于错误丛⽣。
2.内核功能划分Unix系统⽀持多进程并发执⾏。
每⼀个进程都请求系统资源。
内核负责处理全部这些请求,依据内核完毕任务的不同,可将内核功能分为例如以下⼏部分:1.进程管理:负责创建和销魂进程。
并处理它们和外部世界之间的连接。
内核进程管理活动就是在单个或多个CPU上实现了多个进程的抽象。
2.内存管理:内存是计算机的主要资源之中的⼀个,⽤来管理内存的策略是决定系统系能的⼀个关键因素。
3.⽂件系统:内核在没有结构的硬件上构造结构化的⽂件系统。
⽽⽂件抽象在整个系统中⼴泛使⽤。
4.设备控制:差点⼉每个系统操作终于都会映射到物理设备上。
5.⽹络功能:⽹络功能也必须由操作系统来管理,系统负责在应⽤程序和⽹络接⼝之间传递数据包,并依据⽹络活动控制程序的运⾏。
全部的路由和地址解析问题都由内核处理。
可装载模块:Linux有⼀个⾮常好的特性:内核提供的特性可在执⾏时进⾏扩展。
可在执⾏时加⼊到内核的代码被称为“模块”。
Linux内核⽀持⼏种模块类型。
包含但不限于设备驱动程序。
每⼀个模块由⽬标代码组成,能够使⽤insmod程序将模块连接到正在执⾏的内核,也能够使⽤rmmod程序移除连接。
3.设备和模块的分类Linux系统将设备分成三个基本类型:字符设备、块设备、⽹络接⼝。
1.字符设备:字符设备驱动程序通常⾄少要实现open、close、read和write系统调⽤。
C语言设备驱动编程入门

C语言设备驱动编程入门C语言设备驱动编程是一项常见的技术,用于编写操作系统的设备驱动程序。
设备驱动程序是操作系统与硬件设备之间的桥梁,它负责将用户操作转化为硬件设备能够理解和执行的指令。
本文将介绍C语言设备驱动编程的基本概念和入门知识,帮助读者了解并入门这一重要的编程技术。
一、设备驱动程序概述设备驱动程序是操作系统的一部分,它与操作系统内核紧密结合,用于实现对硬件设备的控制和管理。
设备驱动程序通常由硬件设备制造商提供,或者由操作系统开发者开发。
它负责处理硬件设备与操作系统之间的通信,使得用户能够方便地操作硬件设备。
设备驱动程序可以分为字符设备驱动和块设备驱动两种类型。
字符设备驱动用于处理流式数据的设备,如键盘、鼠标等;块设备驱动用于处理以块为单位的数据的设备,如硬盘、U盘等。
不同类型的设备驱动程序在实现上有所不同,但都需要用C语言编写。
二、设备驱动程序的基本结构设备驱动程序的基本结构包括设备初始化、设备打开、设备关闭和设备读写等函数。
下面我们逐步介绍这些函数的作用和实现方法。
1. 设备初始化函数设备初始化函数负责对设备进行初始化,包括设备的寄存器配置、中断设置等。
在这个函数中,我们需要了解硬件设备的相关规格和特性,并根据需要进行适当的配置。
2. 设备打开函数设备打开函数在设备被用户程序打开时被调用,它负责向操作系统申请资源,并进行相应的设置,例如打开文件、分配内存等。
3. 设备关闭函数设备关闭函数在设备被用户程序关闭时被调用,它负责释放设备所占用的资源,如释放文件占用的内存、关闭文件等。
4. 设备读写函数设备读写函数是设备驱动程序的核心部分,它负责设备与用户程序之间的数据交换。
设备读函数用于从设备中读取数据,设备写函数用于向设备中写入数据。
三、设备驱动程序的编写步骤编写设备驱动程序需要经过以下几个步骤:1. 了解硬件设备在编写设备驱动程序之前,我们需要详细了解硬件设备的规格和特性,包括硬件寄存器的地址、中断向量等。
块、字符、网络设备

write等。
指令 用途
# 空指令,无任何效果
#include 包含一个源代码文件
#define 定义宏
区特性的字符设备,访问它们时可前后移动访问位置。例如framebuffer就是这样的一个设
备,app可以用mmap或lseek访问抓取的整个图像。
块设备:
和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备(例如磁盘)
上能够容纳filesystem。在大多数的Unix系统中,进行I/O操作时块设备每次只能传输一个
用。字符终端(/dev/console)和串口(/dev/ttyS0以及类似设备)就是两个字符设备,
它们能很好的说明“流”这种抽象概念。字符设备可以通过FS节点来访问,比如/dev/tty1
和/dev/lp0等。这些设备文件和普通文件之间的唯一差别在于对普通文件的访问可以前后
移动访问位置,而大多数字符备是一个只能顺序访问的数据通道。然而,也存在具有数据
或多个完整的块,而每块包含512字节(或2的更高次幂字节的数据)。Linux可以让app像
字符设备一样地读写块设备,允许一次传递任意多字节的数据。因此,块设备和字符设备的
区别仅仅在于内核内部管理数据的方式,也就是内核及驱动程序之间的软件接口,而这些不
同对用户来讲是透明的。在内核中,和字符驱动程序相比,块驱动程序具有完全不同的接口。
#undef 取消已定义的宏
#if 如果给定条件为真,则编译下面代码
#ifdef 如果宏已经定义,则编译下面代码
#ifndef 如果宏没有定义,则编译下面代码
嵌入式Linux系统中字符设备驱动程序的开发

[ sr c!C mbnd w t ted vlp n fA d vro 3 41F b ad hspp rmany daswi eb i igo rs c mpl Abta t o ie i h eeo me to D r e f¥ C2 0 or,ti ae il el t t ul n fcos o i h i hh d e
实现、调试和 发布 方法进行 了详细的论述 。
关羹词 :嵌入式 系统 ;数据采 集 ;AD转换 ;驱动程序 /
De eo m e t f v lp n a v c i e so b d e y t m o Ch rDe ieDr v r f Em e d d S se Un e n x S se d rLi u y t m
中圈分类号: P9. T31 9
嵌入 式 Ln x系统 中字符设备 驱动程 序 的开发 iu
李胜朝 ,黄先祥 ,谢 建
( 第二炮兵工程学院二 系 ,西 安 7 0 2 ) 10 5
接
要: 结合嵌入式开 发板 ¥ C 40 3 2 1F的模数转换驱动程序 的开发 ,该文对 Lnx i 环境下交叉编译环境的建立 , u 字符设备驱动程序 的组成、
其它 文件一样对 此设备 文件进行 操作。Ln x系统驱动主要 iu
由字符设备、块设备和 网络设备的驱动程序组成 ,其 中字符 设备如 I / O、A / A设备和 US DD B设备 等应用最为广泛,下面 结合 2 1F开发板 中 A 40 D转换设备的驱动开发,对字符设备
的驱 动 开 发 流 程 进 行 深 入 讨 论 。
() 3通过 stp命 令选 配好主机 的 NF e u S功能 ,并建立一 NF 根 目录/fro, ec x ot文件中添]1 fro (wn S ns t t e p r o 在/ / s J/ s t r ,o [n o
添加简单的字符设备教程

编写简单的字符设备的驱动由于用户进程是通过设备文件同硬件打交道,对设备文件的操作方式不外乎就是一些系统调用,如open,read,write,close....而这些系统调用通过定义struct file_operations结构体和设备驱动程序相关联。
所以,编写设备驱动程序的主要工作就是编写子函数,并填充file_operations 的各个域。
具体步骤如下:①随便在一个目录下,新建一个目录叫mydev ,再在此目录下新建三个文件分别叫Makefile mydev.c main.c。
其中Makefile是编译文件,mydev.c是我们编写的字符设备驱动程序,main.c则是用于测试字符设备驱动的测试程序。
三个文件的源程序代码详见附录2.②打开终端使用su 命令,切换到super user 身份,然后写位到mydev 目录下。
③输入make 命令,编译驱动程序chardev.c。
④输入gcc main.c 命令,编译测试程序。
⑤输入insmod mydev.ko 加载驱动模块。
⑥输入gedit /proc/devices 查看mydev 驱动模块的主设备号。
⑦输入mknod /dev/mydev c 250 0 在/dev/目录下,创建设备mydev。
其中,c代码字符驱动,250是驱动主设备号,0是次设备号。
次设备号一般都为0。
⑧输入./a.out 运行测试程序。
⑨测试程序退出后,输入rmmod mydev 卸载驱动模块,并输入rm -rf /dev/mydev 删除/dev/目录下的mydev 设备。
其安装过程和运行结果如图3-1~图3-3所示。
图3-1 查看驱动模块主设备号图3-2 创建mydev源代码:Makefileobj-m:=mydev.oKDIR:=/lib/modules/$(shell uname -r)/buildSRCPWD:=$(shell pwd)all:make -C $(KDIR) M=$(SRCPWD) modulesclean:rm -rf chardev.omydev.c#include <linux/kernel.h>#include <linux/fs.h>#include <linux/module.h>#include <asm/uaccess.h>#include <linux/cdev.h>static int mydevread(struct file *filp,char __user *buffer,size_t,loff_t *);static int mydevopen(struct inode *,struct file *);static int mydevwrite(struct file *filp,const char __user *buffer,size_t ,loff_t*);static int mydevrelease(struct inode *,struct file *);static int major;static char buf[100]="Mydev is working!";static const struct file_operations file_ops = {.read = mydevread,.write = mydevwrite,.open = mydevopen,.release = mydevrelease};static int __init mydev_init(void){int result;major = 0;result = register_chrdev(major, "mydev", &file_ops);if (result < 0) {printk("register mydev failed!\n");return result;}if (major == 0)major = result;return 0;}static int mydevopen(struct inode *inode,struct file *file) {try_module_get(THIS_MODULE);printk("mydev open called!\n");return 0;}static int mydevrelease(struct inode *inode,struct file *file) {module_put(THIS_MODULE);printk("mydev clean called!\n");return 0;}static int mydevread(struct file *filp,char __user *buffer,size_t length,loff_t *offset){int rd;rd=copy_to_user(buffer,&buf,length);if(rd)return length;return -1;}static int mydevwrite(struct file *filp,const char __user *buffer,size_t length,loff_t *offset) {int wt;wt=copy_from_user(&buf,buffer,length);if(wt)return length;return -1;}static void __exit mydev_close(void){unregister_chrdev(major, "mydev");}module_init(mydev_init);module_exit(mydev_close);。
实验二:字符设备驱动实验

实验二:字符设备驱动实验一、实验目的通过本实验的学习,了解Linux操作系统中的字符设备驱动程序结构,并能编写简单的字符设备的驱动程序以及对所编写的设备驱动程序进行测试,最终了解Linux操作系统如何管理字符设备。
二、准备知识字符设备驱动程序主要包括初始化字符设备、字符设备的I/O调用和中断服务程序。
在字符设备驱动程序的file_operations结构中,需要定义字符设备的基本入口点。
open()函数;release()函数read()函数write()函数ioctl()函数select()函数。
另外,注册字符设备驱动程序的函数为register_chrdev()。
register_chrdev() 原型如下:int register_chrdev(unsigned int major, //主设备号const char *name, //设备名称struct file_operations *ops); //指向设备操作函数指针其中major是设备驱动程序向系统申请的主设备号。
如果major为0,则系统为该驱动程序动态分配一个空闲的主设备号。
name是设备名称,ops是指向设备操作函数的指针。
注销字符设备驱动程序的函数是unregister_chrdev(),原型如下:int unregister_chrdev(unsigned int major,const char *name);字符设备注册后,必须在文件系统中为其创建一个设备文件。
该设备文件可以在/dev目录中创建,每个设备文件代表一个具体的设备。
使用mknod命令来创建设备文件。
创建设备文件时需要使用设备的主设备号和从设备号作为参数。
阅读教材相关章节知识,了解字符设备的驱动程序结构。
三、实验内容根据教材提供的实例。
编写一个简单的字符设备驱动程序。
要求该字符设备包括open()、write()、read()、ioctl()和release()五个基本操作,并编写一个测试程序来测试所编写的字符设备驱动程序。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
字符设备驱动程序字符设备驱动程序与块设备不同。
所涉及的键盘驱动、控制台显示驱动和串口驱动以及与这些驱动有关的接口、算法程序都紧密相关。
他们共同协作实现控制台终端和串口终端功能。
下图反映了控制台键盘中断处理过程。
以上为总的处理流程,下面对每一个驱动分开分析。
首先是键盘驱动。
键盘驱动用汇编写的,比较难理解,牵涉内容较多,有键盘控制器804X的编程,还有扫描码(共3套,这里用第二套)和控制命令及控制序列(p209~210有讲解)。
由于键盘从XT发展到AT到现在PS/2,USB,无线键盘,发展较快,驱动各有不同,此版本驱动为兼容XT,将扫描码映射为XT再处理,因此仅供参考。
CNIX操作系统的键盘驱动实现为C语言,可读性更好。
键盘驱动键盘驱动就是上图键盘硬件中断的过程。
keyboard.S中的_keyboard_interrupt函数为中断主流程,文件中其他函数均被其调用。
以上打星处为键盘驱动的核心,即主要处理过程,针对不同扫描码分别处理,并最终将转换后所得ASCII 码或控制序列放入控制台tty 结构的读缓冲队列read_q 中。
键处理程序跳转表为key_table ,根据扫描码调用不同处理程序,对于“普通键”,即只有一个字符返回且没有含义变化的键,调用do_self 函数。
其他均为“特殊键”:1. crtrl 键的按下和释放 2. alt 键的按下和释放 3. shift 键的按下和释放 4. caps lock 键的按下和释放(释放直接返回,不作任何处理) 5. scroll lock 键的按下 6. num lock 的按下 7. 数字键盘的处理(包括alt-ctrl+delete 的处理,因为老式键盘delete 键在数字小键盘上。
还包括对光标移动键的分别处理) 8. 功能键(F1~F12)的处理 9. 减号的处理(老键盘’/’与’-’以0xe0加以区分,可能其中一键要按shift )do_self 是最常用的流程,即跳转表中使用频率最高的流程:控制台程序控制台程序分两部分:1. 控制台初始化 2. 控制台写函数控制台初始化函数根据EGA单色、MDA单色、EGA彩色、CGA各种显卡设置显卡类型、显存占用内存的起始地址、结束地址、显示索引寄存器端口和显示数据寄存器端口。
并将显卡类型打印在屏幕上。
初始化滚屏变量和光标位置,设置键盘中断陷阱门,复位键盘。
控制台写函数从终端对应的tty写缓冲队列中取字符,并显示在屏幕上。
思路是利用状态机原理对缓冲队列中的字符逐一处理(若是字符写在显存对应位置,若是光标,设置光标位置),最后向显示控制器发送光标显示位置。
上图中黑虚线表示不退出case循环读取下一字符,而是直接转到下一状态。
状态1的5、6与状态4的18、19相同。
(?)表示可能包含?串口程序一、串行通信原理通信方式:方向、连接、异步/同步;速度控制:波特率控制、收/发时钟、基准时钟; 差错控制:单/双端、信号重复、检错和纠错编码; 长距离传输:信号调制(调频、调幅、调相); 通道共享:时分多路、频分多路;通信协议:异步串行/同步串行通信协议;接口标准:类型(信号定义、逻辑特性、电气特性、机械特性)二、起止式异步串行通信协议通信前约定—波特率、字符(数据/校验/结束)格式;字符识别—空闲状态、字符开始、数据格式、字符结束、起点漂移解决; 抗干扰(信号重复)实现--起始位采样、数据采样; 字符正确性—校验码编码技术、检错与纠错三、串行通信接口标准标准类型:RS-232C 、RS-422A 、RS-423、RS-485 RS-232C 接口标准:信号定义:RxD、TxD、SG、DTR/DSR、RTS/CTS、DCD、RI逻辑特性:连接、信号使用/不使用MODEM时握手规则电气特性:信号电平、电平转换机械特性:连接器、有效传输距离四、INS8250内部结构内部总体结构中断控制逻辑LSRINTPRT端口定义和寄存器定义LCR—使用时,最后一次使D7=0并设置其它位;DLH/DLL—值为基准时钟频率÷(16×波特率);IIR—中断请求→IIR过程,对IIR读操作时其值的变化原理;与程序关系紧密的硬件是除数寄存器、接受缓冲、发送缓冲、中断允许寄存器、以及通信线路和Modem的控制和状态寄存器。
所谓的DLH/DLL值在除数寄存器中设定,即波特率因子。
同步控制时会以当前设定波特率的16倍频控制每一位信号的脉冲保持时间(即如果要求高信号必须是保持10ms,则同步控制会以10/16ms 的时间精度保证16次的10/16ms都为高脉冲),接收到信号以同样的原理检测信号。
(通常检测16倍频中的第7,8,9三个倍频处的脉冲,以少数服从多数原则判断脉冲的高低)。
中断的屏蔽与否取决于中断允许寄存器。
中断产生后都在中断标识寄存器中置位。
因此只要有中断标识在中断标识寄存器中置位且不屏蔽就会发出中断。
在实际处理中,在串口中断处理中循环判断是否在处理完上一中断后已产生下一中断,若有则直接处理,提高了效率。
串口程序分为初始化部分serial.c和中断处理部分rs_io.s。
串口初始化相当简单:串口中断处理程序也很简单:针对4个中断源的处理函数中两个函数:Modem状态改变的处理和接收状态有错处理都未作实际处理,只是复位相应寄存器。
另两个函数为已接收到数据处理和发送保持寄存器空的处理。
接收到数据中断的处理(read_char函数)(与读队列read_q 交互)发送保持寄存器空中断的处理(write_char函数)(与写队列write_q交互)字符设备(终端)的上层接口tty_io.c和tty_ioctl是终端(控制台和串口终端)的上层接口实现其实除了copy_to_cooked()函数提供完全供内核使用外。
字符设备接口函数(即与用户程序的接口)就三个:tty_read(),tty_write()和tty_ioctl()与用户程序的接口函数的特征是以设备号作为参数,而不会以某个内核数据结构作为参数。
tty_read函数实现用户接口从tty队列的secondary队列中读取字符。
读取的规则由p378的MIN和TIME机制决定。
tty_write函数将用户缓冲区的字符写入tty的write_q队列,未写完或write_q满了则睡眠,直到写完为止。
tty_iotcl是用户程序用来设置或取得tty设备(控制台终端或串口终端)参数的。
如设置或取得termios结构的属性、设置波特率。
获取或设置终端设备进程的组id等。
还有很多功能Linux0.11未实现,估计是为了兼容POSIX标准,已预留了接口。
tty_read(),tty_write()在系统中的位置如下图:值得一提的是tty_queue缓冲队列结构中缓冲区的算法,采用的是循环缓冲区的算法:tail指针处取字符,head指针处插字符。
tail取完一字符和head插完一字符,都将指针增1。
到了边界再转到缓冲区开头,详见p410 23~34行缓冲区操作宏函数。
缓冲区的数据结构如下图:tty_io.c和tty_ioctl.c两文件中与用户接口无关,只在内核中使用的函数是copy_to_cooked()函数。
它的功能是1. 将read_q中的字符复制成规范模式字符放在secondary队列中。
2. 对键盘中断符进行处理:向当前进程发送键盘中断信号,键盘退出信号。
3. 如果设置了回显标志,将相应字符放入write_q队列并调用tty->write直接输出到屏幕(con_write)或从串口输出(rs_write)4. 最后唤醒等待secondary的进程。
Linux0.11字符设备部分总结该部分尽管有键盘、显卡、串口的硬件驱动程序,但它们通过中断串联在了一起,即相互间紧密相关。
相关的方式是以功能为导向:1. 控制台终端 2. 串口终端1.控制台终端,见下面两图。
是以键盘中断触发的中断处理过程:键盘中断处理(扫描码转ASCII码或CSI)->行规则程序(copy_to_cooked)->屏幕显示(显卡驱动con_write,显示字符及光标位置和完成滚屏功能)2.串口驱动,与键盘只有一个中断源(按键)不同,串口有4个中断源,Linux0.11只对接收到数据中断和发送数据中断处理(其余2个只是复位寄存器,暂未处理)。
对于接收到数据中断:上图为串口中断接收到数据后的处理过程。
rs_write的作用是开启写保持空寄存器空中断,此中断会调用write_char中断处理程序。
因此此时是中断嵌套中断。
概括起来也是3步:串行口接收到字符中断->行规则程序(copy_to_cooked)->串口输出(开启写保持寄存器空中断,在中断中调用write_char将write_q中的字符全部输出)对于发送数据中断的处理上图为串口写保持寄存器空时的处理过程。
之前须调用rs_write开启发送保持寄存器空中断。
由上述分析可知,Linux0.11内核的字符设备驱动程序之间关系紧密相关,共同完成控制台终端或串口终端的功能。
管理它们的数据结构设计得也很巧妙:用户接口只能通过传入的设备号来索引tty_table数组从而查询或设置tty设备(控制台或串口终端)的参数。
核心数据结构即为tty_struct,其中又包含了termios结构用来管理控制台和三个tty_queue结构的队列(read_q、write_q、secondary)。
设计很巧妙。
tty_table中有3个tty_struct结构,用来支持控制台、串口1、串口2。
该数组在tty_io.c程序中被初始化,属内核全局数组。
因此只要键盘、串口、显卡被初始化后,字符设备的功能就可(通过中断)自动运行起来。