Подсистема ввода/вывода

Подсистема ввода/вывода, слишком объемная тема, что-бы могла быть рассмотрена в рамках статьи,тем более, что полно и доходчиво изложена в --->> 

А.Робачевский OS UNIX ст. 322-382, Таненбаум "Современные операционные системы" ст. 304-416 --> Ввод-вывод_базовые понятия --->> PDF Колесниченко - Аппаратные средства <<------PDF Маршал Кирк МакКузик FreeBSD - Архитектура и реализация <<---PDF ст. 259

http://cs.mipt.ru   Ввод/вывод часть-1

11:50 ---> шины, 22:02  ---> адр.пространство ввода/вывода     Регистр

Ввод/вывод часть-2

14:23  ---> Polling, прерывания  32:23  ---> Программные прерывания [1]   34:39 --> DMA



        

 https://www.youtube.com/

          Таненбаум <----Ввод_вывод глава 5 ст.304

Одна из важнейших функций операционной системы состоит в управлении всеми устройствами ввода/вывода компьютера. Операционная система должна давать этим устройствам команды, перехватывать прерывания и обрабатывать ошибки. Она должна также обеспечить простой и удобный интерфейс между устройствами и остальной частью системы. Интерфейс (команды, принимаемые аппаратурой, выполняемые ею функции и ошибки, о которых аппаратура может сообщить), насколько это возможно, должен быть одинаковым для всех устройств (для достижения независимости от применяемых устройств). Программное обеспечение ввода-вывода составляет существенную часть операционной системы.

Фактическая архитектура ввода/вывода скрыта от прикладных процессов несколькими интерфейсами,

Один из них - интерфейс файловой системы, взаимодействие с удаленными ресурсами обеспечивается по средствам - сетевых интерфейсов сокетов или Transport Layer Interface.

в определенных ситуациях, прикладному процессу требуется взаимодействие с периферийными устройствами на более низком уровне. Хотя в этом случае роль файловой подсистемы не столь велика, как при работе с обычными файлами, все равно ядро предоставляет процессу унифицированную схему, скрывающую истинную архитектуру того или иного устройства.

В конечном итоге работа всех этих интерфейсов, как высокого уровня, (файловая система), так и более низкого (взаимодействие с физическим устройством), обеспечивается подсистемой ввода/вывода ядра операционной системы.

UNIX использует два основных типа драйверов — символьные и блочные. Как следует из названия, драйверы первого типа обеспечивают обмен сравнительно небольшими объемами данных с устройством, что имеет место при работе, например, с терминалами или принтерами. Драйверы второго типа производят передачу данных блоками, что характерно для дисковых носителей данных. Эти типы драйверов входят в традиционную подсистему ввода/вывода и присутствуют во всех версиях UNIX.

Устройства

Анализ оборудования

Устройства ввода-вывода можно грубо разделить на две категории: блочные устройства и символьные устройства, следует заметить, что касается интерфейса устройств, то одно и то же физическое устройство может иметь как блочный, так и символьный интерфейсы. Для блочных устройств такой интерфейс также называют интерфейсом доступа низкого уровня (raw interface).

Блочные устройства

Устройства, хранящие информацию в виде блоков фиксированного размера, причем у каждого блока имеется адрес. Обычно размеры блоков варьируются от 521 до 32 768 байт. Важное свойство блочного устройства состоит в том, что каждый его блок может быть прочитан независимо от остальных блоков. Наиболее распространенными блочными устройствами являются диски. Если приглядеться внимательнее, то окажется, что граница между блок-адресуемыми устройствами и устройствами, к отдельным блокам которых нельзя адресоваться напрямую, не определена строго. Все согласны с тем, что диск является блок-адресуемым устройством, так как вне зависимости от текущего положения головки дисковода всегда можно переместить ее на определенный цилиндр и затем считать или записать отдельный блок с нужной дорожки. 

Рассмотрим теперь накопитель на магнитной ленте. На ленте хранится последовательность блоков. Если магнитофону дать команду прочитать блок N, он всегда может перемотать ленту и начать читать блоки, пока не дойдет до запрашиваемого блока N. Эта операция подобна поиску блока на диске с той лишь разницей, что она занимает значительно больше времени, в отличии от современных дисковых накопителей где головка перемещается на блок за малый момент времени. Кроме того, в зависимости от накопителя и формата хранящихся на нем данных, может оказаться возможной или невозможной запись отдельного произвольного блока в середине ленты. Даже если и было бы возможно использовать магнитные ленты в качестве блочных устройств произвольного доступа, это являлось бы в какой-то степени натяжкой и никто их не использует таким образом.

Другой тип устройств ввода-вывода — символьные устройства. 

Символьные устройства 

Символьные устройства представляют собой значительную часть периферийного оборудования системы, включая терминалы, манипуляторы (например, мышь), клавиатуру и локальные принтеры. Основное отличие этих устройств от блочных заключается в том, что они, как правило, передают небольшие объемы данных. Обмен данными с символьными устройствами происходит непосредственно через драйвер, минуя буферный кэш. При этом данные обычно копируются в драйвер из адресного пространства процесса, запросившего операцию ввода/вывода.

Символьное устройство принимает или предоставляет поток символов без какой-либо блочной структуры. Оно не является адресуемым и не выполняет операцию поиска. Принтеры, сетевые интерфейсные карты, и большинство других устройств, не похожих на диски, можно рассматривать как символьные устройства. Такая схема классификации не совершенна. Некоторые устройства просто не попадают ни в одну из категорий. Например, часы не являются блок-адресуемы- ми. Они также не формируют и не принимают символьных потоков. Вся их работа состоит в инициировании прерываний в строго определенные моменты времени. Экраны отображения памяти также не втискиваются в рамки этой модели. И все же модель блочных и символьных устройств является настолько общей, что может использоваться в качестве основы для достижения независимости от устройств некоторого программного обеспечения операционных систем, имеющего дело с вводом-выводом. Например, файловая система имеет дело с абстрактными блочными устройствами. 

Устройства ввода-вывода покрывают огромный диапазон скоростей, что создает определенные трудности для программного обеспечения, которому приходится обеспечивать хорошую производительность на скоростях передачи данных, различающихся несколькими порядками.

Контроллеры устройств 

Устройства ввода-вывода обычно состоят из механической части и электронной части. Часто эти части можно разделить для придания модели более модульного и общего вида. Электронный компонент устройства называется контроллером устройства или адаптером. В персональных компьютерах он часто принимает форму печатной платы, вставляемой в слот расширения. "Механический" компонент находится в самом устройстве.

Плата контроллера обычно снабжается разъемом, к которому может быть подключен кабель, ведущий к самому устройству. Многие контроллеры способны управлять двумя, четырьмя или даже восемью идентичными устройствами. Если интерфейс между контроллером и устройством является стандартным, то есть официальным стандартом ANSI, IEEE или ISO либо фактическим стандартом, тогда различные компании могут выпускать отдельно контроллеры и устройства, удовлетворяющие данному интерфейсу. Так, многие компании производят жесткие диски, соответствующие интерфейсу IDE или SCSI. Интерфейс между устройством и контроллером часто является интерфейсом очень низкого уровня. Например, какой-нибудь жесткий диск может быть отформатирован по 256 секторов на дорожку, с размером секторов по 512 байт. В действительности с диска в контроллер поступает последовательный поток битов, начинающийся с заголовка сектора (преамбулы-prefix), за которым следует 4096 бит в секторе, и, наконец, контрольная сумма (suffix), также называемая кодом исправления ошибок (ЕСС, Error-Correcting Code). Заголовок сектора записывается на диск во время форматирования. Он содержит номера цилиндра и сектора, размер сектора, информацию синхронизации и т. п.

Работа контроллера заключается в конвертировании последовательного потока битов в блок байтов и выполнение коррекции ошибок, если это необходимо. Обычно байтовый блок собирается бит за битом в буфере контроллера. Затем проверяется контрольная сумма блока, и если она совпадает с указанной в заголовке сектора, блок объявляется считанным без ошибок, после чего он копируется в оперативную память. 

Контроллер монитора также работает как бит-последовательное устройство, на таком же низком уровне. Он считывает в памяти байты, содержащие символы, которые следует отобразить, и формирует сигналы, используемые для модуляции луча электронной трубки, заставляющие ее выводить изображение на экран. Видеоадаптер также формирует сигналы, управляющие горизонтальным и вертикальным возвратом электронного луча. Если бы не контроллер, программисту пришлось бы управлять перемещениями аналогового электронного луча. 

В действительности же операционная система всего лишь инициализирует контроллер, задавая небольшое число параметров, таких как количество символов или пикселов в строке и число строк на экране, а всю тяжелую работу по управлению передвижениями электронного луча по экрану выполняет контроллер.

Драйверы устройств

Таненбаум "Современные операционные системы" ст. 326

Драйверы устройств обеспечивают интерфейс между ядром UNIX и аппаратной частью компьютера. Благодаря этому от остальной части ядра скрыты архитектурные особенности компьютера, что значительно упрощает перенос системы и поддержку работы различных периферийных устройств. В UNIX существует большое количество драйверов. Часть из них обеспечивает доступ к физическим устройствам, например, жесткому диску, принтеру или терминалу, другие предоставляют услуги.

Примером последних могут служить драйверы для работы с виртуальной памятью ядра представляющий "нулевое" устройство (Нулевое устройство — весь вывод на него уничтожается, а при попытке ввода с этого устройства возвращается Ø байтов /dev/null,....# /dev/zero - Нулевое устройство — весь вывод на него уничтожается, а ввод приводит к получению последовательности Ø).

В процессе запуска системы ядро вызывает соответствующие процедуры инициализации установленных драйверов. Во многих версиях UNIX эти процедуры выводят на консоль сообщение о том, что драйвер найден, и инициализация прошла успешно, а также параметры драйвера и устройства (...где-то в /var/log/messages....kern.log....syslog). Наиболее очевидная функция драйвера состоит в обработке абстрактных запросов чтения и записи независимого от устройств программного обеспечения, расположенного над ними. Но кроме этого они должны также выполнять еще несколько функций. Например, драйвер должен при необходимости инициализировать устройство. Ему также может понадобиться управлять энергопотреблением устройства и регистрацией событий.

Управление устройством подразумевает выдачу ему серии команд. Именно в драйвере определяется последовательность команд в зависимости от того, что должно быть сделано. Определившись с командами, драйвер начинает записывать их в регистры контроллера устройства. После записи каждой команды в контроллер может быть нужно проверить, принял ли контроллер эту команду и готов ли принять следующую. Такая последовательность действий продолжается до тех пор, пока контроллеру не будут даны все команды. Некоторые контроллеры способны принимать связные списки команд, находящихся в памяти. Они сами считывают и выполняют их без дальнейшей помощи операционной системы.

Драйверам не разрешается обращаться к системным вызовам, но им часто бывает необходимо взаимодействовать с остальным ядром. Обычно разрешаются обращения к некоторым системным процедурам. Например, драйверы обращаются к системным процедурам для выделения им аппаратно фиксированных страниц памяти в качестве буферов, а также затем, чтобы вернуть эти страницы обратно ядру. Кроме того, драйверы пользуются вызовами, управляющими MMU, таймерами, контроллером DMA, контроллером прерываний и т. п.

Типы драйверов 

Драйверы различаются по возможностям, которые они предоставляют, а также по тому, каким образом обеспечивается к ним доступ и управление. Можно рассматривать три основные типа драйверов -- символьные, блочные и драйверы низкого уровня, точнее два [2], если отнести драйверы низкого уровня к блочно-символьным устройствам,

В большинстве операционных систем определен стандартный интерфейс, который должны поддерживать все блочные драйверы, и второй стандартный интерфейс, поддерживающий все символьные драйверы. Эти интерфейсы включают наборы процедур, которые могут вызываться остальной операционной системой для обращения к драйверу. К этим процедурам относятся, например, процедуры чтения блока (блочного устройства) или записи символьной строки (для символьного устройства). В некоторых системах операционная система представляет собой единую двоичную программу, содержащую в себе, в откомпилированном вместе с ней виде, все необходимые ей драйверы. 

Такая схема в течение многих лет была нормой для систем UNIX, так как они предназначались для работы в компьютерных центрах, а устройства ввода-вывода менялись нечасто. При добавлении нового устройства системный администратор просто перекомпилировал ядро с новым драйвером, получая новый двоичный модуль. С появлением персональных компьютеров с их огромным разнообразием устройств ввода-вывода такая модель перестала работать.

Символьные драйверы

Этот тип драйверов обеспечивает работу с устройствами с побайтовым доступом и обменом данными. К таким устройствам можно отнести модемы, терминалы, принтеры, манипуляторы мышь и т. д. Доступ к таким драйверам не включает использование буферного кэша, таким образом ввод и вывод как правило не буферизуется. При необходимости буферизации для символьных драйверов обычно используется подход, основанный на структурах данных, называемых clist. 

Символьные драйверы обеспечивают доступ не только к символьным устройствам, например, к адаптеру последовательного или параллельного портов, манипулятору "мышь", монитору или терминалам. Часть символьных драйверов служит в качестве интерфейса доступа низкого уровня к блочным устройствам, таким как диски или накопители на магнитных лентах.

Блочные драйверы 

Драйверы блочных устройств предназначены для обслуживания периферийного оборудования, обеспечивающего обмен данными с помощью фрагментов фиксированной длины, называемыми блоками, размер которых значительно превышает один байт. В основном эти драйверы используются файловой подсистемой и подсистемой управления памятью. Например, свопинг характеризуется обменом данными с устройством вторичной памяти, размер которых обычно равен размеру страницы, что составляет 4 или 8 Кбайт. Файловая подсистема производит чтение и запись данных фрагментами, размер которых равен одному или нескольким блокам устройства. Типичными представителями блочных устройств являются жесткий и гибкий диски.

Этот тип драйверов позволяет производить обмен данными с устройством фиксированными порциями (блоками). На пример, для жесткого диска данные можно адресовать и, соответственно, читать только секторами, размер которых составляет несколько сотен байтов. Для блочных драйверов обычно используется буферный кэш, который и является интерфейсом между файловой системой и устройством. Хотя операции чтения и записи для процесса допускают обмен данными, размер которых меньше размера блока, на системном уровне это все равно приводит к считыванию всего блока, изменению части его данных и записи измененного блока обратно на диск.

Драйверы низкого уровня 

Этот тип интерфейса (raw drivers) блочных драйверов позволяет производить обмен данными с блочными устройствами, минуя буферный кэш. Это, в частности, означает, что устройство может быть адресовано элементами, размер которых не совпадает с размером блока. 

Обмен данными происходит независимо от файловой подсистемы и буферного кэша, что позволяет ядру производить передачу непосредственно между пользовательским процессом и устройством, без дополнительного копирования, драйверы доступа низкого уровня обеспечивают обмен данных непосредственно с адресным пространством процесса. Отсутствие посредника в виде буферного кэша устраняет необходимость в совершении дополнительных операций копирования (драйвер — буферный кэш -- буфер процесса), но в то же время лишает процесс услуг кэширования данных, предоставляемых операционной системой.

 Linux_Device_Drivers   PDF   ст.7

 Классы устройств и модулей

Способ видения устройств в Linux разделяется на три фундаментальных типа. Каждый модуль обычно реализован как один из этих типов и таким образом классифицируется как символьный модуль, блочный модуль, или сетевой модуль. Такое разделение модулей на разные типы или классы не является жёстким; программист может при желании создавать большие модули, содержащие разные драйверы в одном куске кода. Хорошие программисты, тем не менее, обычно создают разные модули для каждой новой функциональности, потому что декомпозиция является ключом к масштабируемости и расширяемости. Этими тремя классами являются:

Символьные устройства

Символьное устройство - это такое устройств, к которому можно обращаться как к потоку байтов (так же как к файлу); драйвер символьного устройства отвечает за реализацию такого поведения. Такой драйвер обычно, по крайней мере, поддерживает системные вызовы open, close, read и write. Текстовый экран (/dev/console) и последовательные порты (/dev/ttyS0 и подобные) являются примерами символьных устройств, так как они хорошо представлены абстракцией потока. Для обращения к символьным устройствам используют узлы (node) файловой системы, такие как /dev/tty1и /dev/lp0. Единственное важное отличие между символьными устройствами и обычными файлами - вы всегда можете двигаться вперед и назад в обычном файле, в то время как большинство символьных устройств - это только каналы данных, к которым вы можете обращаться только последовательно. Существуют, однако, символьные устройства, которые выглядят как области данных, и вы можете двигаться по ним назад и вперёд; к примеру, это обычно используется в грабберах экрана, где приложения могут получать доступ ко всему полученному изображению используя mmap или lseek.

Блочные устройства

Так же как символьные устройства, блочные устройства доступны через узлы файловой системы в директории /dev. Блочное устройство - это устройство (например, диск) который может содержать файловую систему. В большинстве систем Unix блочное устройство может поддерживать только операции ввода-вывода, которые передают один или более целых блоков, обычно равных 512 байт (или большей степени числа два). Linux, однако, разрешает приложению читать и писать в блочное устройство, так же как и в символьное устройство - это позволяет передавать любое число байт за раз. В результате, блочные и символьные устройства отличаются только способом управления данными внутри ядра и, соответственно, программным интерфейсом в ядре/драйвере. Как и символьное устройство, каждое блочное устройство доступно через узел файловой системы, так что различия между ними не видны пользователю. Блочные драйверы имеют интерфейс для ядра полностью отличный от символьных устройств.

Сетевые интерфейсы

Любой сетевой обмен данными делается через интерфейс, то есть устройство, которое в состоянии обменяться данными с другими узлами сети. Обычно, интерфейс - это аппаратное устройство, но также он может быть чисто программным устройством, наподобие интерфейса loopback (локальное петлевое устройство). Сетевой интерфейс отвечает за отсылку и приём пакетов данных, управляемых подсистемой сети в ядре, без знания кому предназначены передаваемые пакеты. Многие сетевые соединения (особенно использующие TCP) являются поточноориентированными, но сетевые устройства обычно разработаны для передачи и приёма пакетов. Сетевой драйвер ничего не знает об отдельных соединениях; он только обрабатывает пакеты. Не будучи поточно-ориентированным устройством, сетевой интерфейс нелегко представить как узел в файловой системе наподобие /dev/tty1. Unix всё же обеспечивает доступ к интерфейсам через назначение им уникальных имён (таких как eth0), но это имя не имеет соответствующего элемента в файловой системе. Обмен между ядром и сетевым устройством сильно отличается от используемого в символьных и блочных драйверах. Вместо read и write ядро вызывает функции, относящиеся к передаче пакетов.

Прерывания

    На аппаратном уровне прерывания (interrupt) работают следующим образом. Когда устройство ввода- вывода заканчивает свою работу, оно инициирует прерывание (при условии, что прерывания разрешены операционной системой). Для этого устройство выставляет сигнал на выделенную устройству специальную линию шины. Этот сигнал распознается микросхемой контроллера прерываний, расположенной на материнской плате. Контроллер прерываний принимает решение о дальнейших действиях.

    При отсутствии других необработанных запросов прерывания контроллер прерываний обрабатывает прерывание немедленно. Если прерывание уже обрабатывается, и в это время приходит запрос от другого устройства по линии с более низким приоритетом, то новый запрос просто игнорируется. В этом случае устройство продолжает удерживать сигнал прерывания на шине до тех пор, пока оно не будет обслужено центральным процессором.

    Для обработки прерывания контроллер выставляет на адресную шину номер устройства, требующего к себе внимания, и устанавливает сигнал прерывания на соответствующий контакт процессора.  Этот сигнал заставляет процессор приостановить текущую работу и начать выполнять обработку прерывания. Номер, выставленный на адресную шину, используется в качестве индекса в таблице, называемой вектором прерываний [1], из которой извлекается новое значение счетчика команд. Новый счетчик команд указывает на начало соответствующей процедуры обработки прерывания. Обычно с этого места аппаратные и эмулированные прерывания используют один и тот же механизм и часто пользуются одним и тем же вектором. Расположение вектора может быть либо жестко прошито на аппаратном уровне, либо, наоборот, располагаться в произвольном месте памяти, на которое указывает специальный регистр процессора, загружаемый операционной системой. Вскоре после начала своей работы процедура обработки прерываний подтверждает получение прерывания, записывая определенное значение в порт контроллера прерываний. Это подтверждение разрешает контроллеру издавать новые прерывания. Благодаря тому, что центральный процессор откладывает выдачу подтверждения до момента, когда он уже готов к обработке нового прерывания, удается избежать ситуации состязаний при появлении почти одновременных прерываний от нескольких устройств. Следует упомянуть, что на некоторых старых компьютерах нет микросхемы, централизованного контроллера прерываний, поэтому контроллер каждого устройства выставляет свое собственное прерывание. 

    Аппаратура всегда, прежде чем начать процедуру обработки прерывания, сохраняет определенную информацию. Сохраняемая информация и место ее хранения широко варьируются в зависимости от центрального процессора. Как минимум сохраняется счетчик команд, что позволяет продолжить выполнение прерванного процесса. Другая крайность представляет собой сохранение всех программно доступных регистров и большого количества внутренних регистров центрального процессора.

    Место сохранения этой информации также оказывается проблемой. Один из вариантов состоит в том, чтобы сохранять эти данные в неких внутренних регистрах, доступных операционной системе. Недостаток такого подхода — до тех пор, пока вся сохраненная информация не будет считана обработчиком прерываний, новые прерывания будет нельзя разрешать. В противном случае любое новое прерывание просто стерло бы всю сохраненную таким образом информацию, записав поверх нее новые данные. В результате прерывания оказываются запрещенными в течение довольно длительных интервалов времени, что приводит к возможному игнорированию некоторых сигналов прерывания от устройств и, соответственно, к возможной потере данных.

    Поэтому большинство центральных процессоров сохраняют информацию в стеке. Однако у этого подхода также имеются недостатки. Во-первых, в чьем стеке следует сохранять данные? Если использовать текущий стек, он может оказаться стеком процесса пользователя. При этом может даже выясниться, что пользователь использует указатель стека в своей программе весьма нестандартно, то есть стек может указывать на область памяти, в которой нельзя сохранять данные. Попытка записать несколько слов в стек в таком случае может привести к неисправимой ошибке. Также указатель стека может указывать на конец страницы памяти. После нескольких обращений к стеку указатель может достичь конца страницы памяти и вызвать соответствующую ошибку. Если во время обработки аппаратного прерывания произойдет обращение к отсутствующей странице, это станет еще большей проблемой: где сохранить состояние процедуры обработки прерывания для обработки данной ошибки?

    Использовать стек ядра гораздо проще, так как при этом больше шансов, что указатель стека указывает на область памяти, в которой можно сохранять данные. Однако переключение в режим ядра может потребовать изменения контекста MMU (Memory Management Unit) и, возможно, обесценит большую часть содержимого кэша и TLB (Тranslation Lookaside Buffer — буфер быстрого преобразования адреса). Перегрузка всех этих кэшей статически или динамически увеличит время обработки прерывания и вызовет растрату процессорного времени. 

    Другая проблема вызвана тем фактом, что большинство современных центральных процессоров широко используют конвейеры и часто являются суперскалярными (внутренне параллельными). В более старых системах после выполнения каждой команды процессора микропрограмма или аппаратура проверяли, нет ли прерывания, ждущего обработки. Если таковое было, счетчик команд и слово состояния процессора (PSW-Program Status Word) сохранялись в стеке и начиналась обработка прерывания. По завершении работы обработчика прерывания происходила обратная процедура: старые значения PSW и счетчика команд извлекались из стека, и прерванный процесс возобновлялся. 

    Такая модель явно предполагает, что к приходу прерывания все команды процессора до этого момента выполнены полностью и ни одна команда процессора после последней выполненной команды не начала выполняться. На старых машинах такое предположение было оправдано. Однако на современных компьютерах это не всегда так …...................

Таненбаум "Современные операционные системы"  ст.317 

Архитектура терминального доступа

Монитор и клавиатура --->> Алфавитно-цифровой терминал или проще "Терминал" исторически сложившееся название. Наиболее часто встречаются следующие три типа терминалов. 

Алфавитно-цифровой терминал — последовательное устройство (устройство с последовательной передачей данных), и операционная система производит обмен данными с терминалом через последовательный интерфейс, называемый терминальной линией.

Алфавитно-цифровые терминалы позволяют вводить специальные управляющие символы с клавиатуры, а вывод на дисплей алфавитно-цифрового терминала управляется  ESC-последовательностями - возможностью вводить отдельные символы не через них самих, а через специальные кодовые слова, обозначающие эти символы.

Драйвер клавиатуры может работать как в сыром режиме (raw), так и в режиме с обработкой (cooked), в зависимости от потребностей конкретной прикладной программы. ESC-последовательности при выводе на терминал управляют перемещением курсора, а также позволяют вводить и удалять текст с экрана.

С каждой терминальной линией в UNIX ассоциирован специальный файл символьного устройства /dev/tty[01..02..]

Терминальные драйверы выполняют ту же функцию, что и остальные драйверы: управление передачей данных от<=>на терминалы. Однако терминалы имеют одну особенность, связанную с тем, что они обеспечивают интерфейс пользователя с системой. Обеспечивая интерактивное использование системы UNIX, терминальные драйверы имеют свой внутренний интерфейс с модулями, интерпретирующими ввод и вывод строк. Модуль, отвечающий за такую обработку, называется дисциплина линии (line discipline -  слой абстракции подсистемы терминальных устройств UNIX- систем, необходимый для имитации соответствующих возможностей аппаратного терминала. Этот слой расположен между драйвером консоли и драйвером UART).

TTY-абстракция     tty

Существует два режима терминального ввода/вывода:

В каноническом режиме интерпретаторы строк преобразуют неструктурированные последовательности данных, введенные с клавиатуры, в каноническую форму (то есть в форму, соответствующую тому, что пользователь имел в виду на самом деле) прежде, чем послать эти данные принимающему процессу. Например, программисты работают на клавиатуре терминала довольно быстро, но иногда допускают ошибки. На этот случай имеется клавиша стирания, и пользователь имеет возможность удалять часть введенной строки и вводить коррективы. Драйвер терминала получает всю введенную последовательность, включая и символы стирания. В каноническом режиме модуль дисциплины линии буферизует информацию в строку (набор символов, заканчивающийся символом возврата каретки) и стирает символы в буфере, прежде чем переслать исправленную последовательность считывающему процессу. В таком режиме, например, работает командный интерпретатор shell. В режиме без обработки строковый интерфейс передает данные между процессами и терминалом без каких-либо преобразований. Например, текстовый редактор работает с драйвером в неканоническом режиме, благодаря чему любой символ, введенный пользователем интерпретируется самим процессом.

В функции модуля дисциплины линии входят:

Существует дополнительная возможность обработки данных, получаемых и передаваемых устройству - отображение вводимых и выводимых символов в символы, определенные таблицей отображения. Данную возможность поддерживает утилита mapchan.

Псевдотерминалы

Псевдотерминалы являются специальным устройством, эмулирующим стандартную терминальную линию. Псевдотерминалы напоминают каналы как средство межпроцессного взаимодействия, позволяющее двум процессам обмениваться данными. Однако в отличие от каналов, псевдотерминалы обеспечивают дополнительную функциональность, специфичную для терминальных линий. Схематически архитектура псевдотерминала представлена на рис ниже.

Ярким примером использования псевдотерминалов является регистрация в системе по сети с использованием серверов удаленного доступа rlogin или telnet ,или использование графического эмулятора терминала xterm в системе X Window System. Когда пользователь регистрируется в системе подобным образом, псевдотерминал эмулирует обычную терминальную линию, поэтому пользователь не видит различия между удаленной и локальной работой с помощью терминала, подключенного по последовательной линии. Например, пользователь может установить различные режимы обработки и использовать соответствующие комбинации клавиш для генерации сигналов, как он это делает в случае обычного терминала.

Псевдотерминал по существу представляет собой два отдельных драйвера. Один из них выглядит как обычный терминальный драйвер и носит название подчиненного устройства (slave). Второй драйвер называется основным (master) ptmx и pts - основной и подчиненный псевдотерминал. 

{stdout, stdin, stderr} <--- Стандартные потоки ввода/вывода в системах типа UNIX (и некоторых других) — потоки процесса, имеющие дескриптор, зарезервированный для выполнения некоторых «стандартных» функций. Как правило (хотя и не обязательно), эти дескрипторы открыты уже в момент запуска исполняемого файла.

Поскольку подчиненное устройство имеет все характеристики терминала, процесс может связать свои стандартные потоки ввода, вывода и вывода ошибок с этим устройством. Однако в отличие от обычного терминала, в случае которого запись процесса приводит к отображению данных на физическом устройстве, а ввод данных пользователем с клавиатуры может быть получен чтением терминальной линии, все данные, записанные в подчиненное устройство, передаются основному и наоборот — почти так, как работает канал. Однако модуль дисциплины линии позволяет обеспечить дополнительные возможности этого канала, которые могут потребоваться некоторым приложениям, например, командному интерпретатору shell.

В качестве иллюстрации использования псевдотерминала, рассмотрим схему работы в режиме командной строки пользователя, находящегося на некоторой удаленной системе в сети.

Пользователь удаленной системы запускает программу удаленного доступа rlogin, которая формирует запрос и передает его по сети на требуемый компьютер. Там этот запрос доставляется серверу удаленного доступа rlogind, который (после надлежащей проверки) запускает программу login. При этом стандартные потоки ввода, вывода и вывода ошибок программы login связываются не с терминальным файлом, как в случае входа в систему с помощью сервера getty а с подчиненным устройством псевдотерминала. Основное же устройство оказывается связанным с сервером rlogind. Программа login запрашивает имя пользователя и его пароль точно так же, как она это делает при входе через getty. Более того, login и "не представляет", что на самом деле работает с эмулятором терминала, а не с традиционной терминальной линией. Весь ввод login поступает серверу rlogind и затем передается по сети клиентской части rlogin на удаленном компьютере. Далее работа ничем не отличается от работы локального пользователя, подключенного к системе с помощью обыкновенного терминала или консоли. Если имя пользователя и пароль были введены правильно, программа login запустит требуемый командный интерпретатор (login shell), который также не заметит подмены. Действительно, по всем характеристикам терминал будет неотличим от традиционной последовательной линии, включая различные установки и генерацию сигналов при нажатии определенных клавиш клавиатуры. Следует, правда, оговориться, что поскольку псевдотерминал не является "полноценным" терминальным устройством, часть установок для него не имеют смысла (например, скорость передачи, четность и т. д.) и просто игнорируются.