Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 18.1. A Small TTY Driver

Оглавление
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

18.1. Маленький tty-драйвер

hardorsoft 26.10.10 в 06:05

0

Чтобы объяснить работу ядра tty-устройств, мы создадим маленький
tty-драйвер который может быть загружен и выгружен, и из которого
может производится чтение и запись. Основной структурой данных
любого tty-драйвера является struct tty_driver. Она используется для
регистрации и отмены регистрации драйвера в ядре tty-устройств и
описана в <"linux/tty_driver.h">.

hardorsoft 26.10.10 в 06:06

0

Для создания структуры struct tty_driver используется функция
alloc_tty_driver. В качестве параметра передается количество
tty-устройств, которое поддерживается драйвером. Выполняется это,
например, таким кодом:

hardorsoft 26.10.10 в 06:06

0

/* определение tty-драйвера */
tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS);
if (!tiny_tty_driver)
return -ENOMEM;
После успешного выполнения функции, структура должна быть
инициализирована данными, необходимыми для tty-драйвера. Структура
состоит из различных полей, но не все они инициализируются при работе
драйвера. В приведенном примере показывается, как и какие поля
должны быть инициализированы, чтобы получился работоспособный
драйвер. Для копирования в структуру struct tty_driver множества
функций драйвера, используется вызов tty_set_operations:

hardorsoft 26.10.10 в 06:07

0

static struct tty_operations serial_ops = {
.open = tiny_open,
.close = tiny_close,
.write = tiny_write,
.write_room = tiny_write_room,
.set_termios = tiny_set_termios,
};

hardorsoft 26.10.10 в 06:07

0

/* initialize the tty driver */
tiny_tty_driver->owner = THIS_MODULE;
tiny_tty_driver->driver_name = "tiny_tty";
tiny_tty_driver->name = "ttty";
tiny_tty_driver->devfs_name = "tts/ttty%d";
tiny_tty_driver->major = TINY_TTY_MAJOR,
tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL,
tiny_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
tiny_tty_driver->init_termios = tty_std_termios;
tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tiny_tty_driver, &serial_ops);

В этой главе рассмотрены перечисленные выше переменные и
функции, а так же использование структуры struct tty_driver.

hardorsoft 26.10.10 в 06:07

0

Для регистрации драйвера в ядре tty-устройств, структура struct
tty_driver должна быть передана в функцию tty_register_driver:

hardorsoft 26.10.10 в 06:07

0

/* register the tty driver */
retval = tty_register_driver(tiny_tty_driver);
if (retval) {
printk(KERN_ERR "failed to register tiny tty driver");
put_tty_driver(tiny_tty_driver);
return retval;
}

hardorsoft 26.10.10 в 06:08

0

Когда вызывается tty_register_driver, ядро создает все файлы
последовательных устройств, которые драйвер может обслуживать, в
sysfs. Если вы используете devfs (не описанный в этой книги) и не
указываете флаг TTY_DRIVER_NO_DEVFS, файлы devfs так же создаются.
Флаг может быть указан, если вы хотите вызывать tty_register_device
только для устройств фактически присутствующих в системе. Таким
образом, пользователь всегда имеет своевременное представление об
имеющихся устройствах, что и требуется при использовании devfs.

hardorsoft 26.10.10 в 06:08

0

После своей регистрации, драйвер регистрирует устройства
функцией tty_register_device. Эта функция имеет три аргумента:

hardorsoft 26.10.10 в 06:08

0

Указатель на структуру struct tty_driver принадлежащую
устройству.

hardorsoft 26.10.10 в 06:08

0

Младший номер устройства.

hardorsoft 26.10.10 в 06:09

0

Указатель на структуру struct device связанную с этим
устройством. Если tty-устройство не связано с какой-либо struct
device, этот аргумент устанавливается в NULL.

hardorsoft 26.10.10 в 06:09

0

Наш драйвер регистрирует сразу все tty-устройства т.к. они –
виртуальные и не связаны с физическим оборудованием:

hardorsoft 26.10.10 в 06:09

0

for (i = 0; i < TINY_TTY_MINORS; ++i)
tty_register_device(tiny_tty_driver, i, NULL);

Для отмены регистрации драйвера в tty-ядре, необходимо отменить
регистрацию устройств, выполнив tty_unregister_device. Затем
отменяется регистрация структуры struct tty_driver, с помощью
функции tty_unregister_driver:

hardorsoft 26.10.10 в 06:10

0

for (i = 0; i < TINY_TTY_MINORS; ++i)
tty_unregister_device(tiny_tty_driver, i);
tty_unregister_driver(tiny_tty_driver);

hardorsoft 26.10.10 в 06:10

0

18.1.1. Структура struct termios

hardorsoft 26.10.10 в 06:11

0

Переменная init_termios в структуре struct device имеет тип
struct termios. Она используется для предоставления параметров
настройки линии, если пользователь обращается к порту, не
инициализируя его. Драйвер инициализирует переменную init_termios
стандартным набором значений, который копируется из tty_std_termios.
Переменная tty_std_termios определена следующим образом:

hardorsoft 26.10.10 в 06:11

0

struct termios tty_std_termios = {
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC
};

hardorsoft 26.10.10 в 06:11

0

Структура используется для хранения текущих параметров линии
для соответствующего порта tty-устройства. Эти параметры управляют
скоростью, размером данных, потоком данных, и многим другим. Поля
структуры struct termios:

hardorsoft 26.10.10 в 06:12

0

tcflag_t c_iflag;
Флаги режима ввода.

hardorsoft 26.10.10 в 06:12

0

tcflag_t c_oflag;
Флаги режима вывода.

hardorsoft 26.10.10 в 06:12

0

tcflag_t c_cflag;
Флаги управления.

hardorsoft 26.10.10 в 06:12

0

tcflag_t c_lflag;
Флаги локального режима.

hardorsoft 26.10.10 в 06:12

0

cc_t c_line;
Тип line discipline.

hardorsoft 26.10.10 в 06:12

0

cc_t c_cc[NCCS];
Массив управляющих символов.

hardorsoft 26.10.10 в 06:13

0

Все флаги режима являются битовыми полями. Различные значения
режимов и их назначение, можно найти на странице «termios» утилиты
man, в любом дистрибутиве Linux. Ядро предоставляет множество
макросов для получения значений битов. Эти макросы определены в
заголовочном файле <"include/linux/tty.h">.

hardorsoft 26.10.10 в 06:13

0

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

hardorsoft 26.10.10 в 06:13

0

Поля driver_name и name выглядят очень похоже, тем не менее
используются для различных целей. Переменной driver_name должно
быть присвоено короткое, выразительное и уникальное значение
относительно остальных tty-драйверов. Это сделано, потому что в файле
/proc/tty/drivers и каталоге классов tty-устройств sysfs, для
пользователя, описываются все загруженные драйверы. Поле name
используется для определения имени индивидуального node,
назначенному данному tty-драйверу в дереве каталогов /dev. Эта строка,
дополненная в конце номером используемого устройства, применяется
для создания tty-устройства. Так же она используется в качестве имени
устройства в каталоге sysfs /sys/class/tty/. Если в ядре используется
devfs, это имя будет использовано для размещения tty-драйвера в его
подкаталоге. На пример, драйвер последовательного порта в ядре
устанавливает поле имени в значение tts/, если devfs – резрешен, и в
ttyS если нет. Эта строка так же присутствует в файле
/proc/tty/drivers.

hardorsoft 26.10.10 в 06:13

0

Как мы говорили, в файле /proc/tty/drivers показываются все
зарегистрированные драйверы. После регистрации в ядре драйвера
tiny_tty, и при условии, что devfs не используется, файл выглядит
примерно так:

hardorsoft 26.10.10 в 06:14

0

$ cat /proc/tty/drivers
tiny_tty /dev/ttty 240 0-3 serial
usbserial /dev/ttyUSB 188 0-254 serial
serial /dev/ttyS 4 64-107 serial
pty_slave /dev/pts 136 0-255 pty:slave
pty_master /dev/ptm 128 0-255 pty:master
pty_slave /dev/ttyp 3 0-255 pty:slave
pty_master /dev/pty 2 0-255 pty:master
unknown /dev/vc/ 4 1-63 console
/dev/vc/0 /dev/vc/0 4 0 system:vtmaster
/dev/ptmx /dev/ptmx 5 2 system
/dev/console /dev/console 5 1 system:console
/dev/tty /dev/tty 5 0 system:/dev/tty

hardorsoft 26.10.10 в 06:14

0

Когда драйвер tiny_tty зарегистрировался в ядре tty-устройств,
каталог sysfs /sys/class/tty выглядит примерно так:

hardorsoft 26.10.10 в 06:14

0

$ tree /sys/class/tty/ttty*
/sys/class/tty/ttty0
-- dev
/sys/class/tty/ttty1
-- dev
/sys/class/tty/ttty2
-- dev
/sys/class/tty/ttty3
-- dev
$ cat /sys/class/tty/ttty0/dev
240:0

hardorsoft 26.10.10 в 06:14

0

Старшая переменная соответствует старшему номеру этого
драйвера. Тип и подтип переменной информирует о типе tty-драйвера. В
нашем примере, мы используем драйвер последовательного порта,
стандартного типа «normal». Другие подтипа tty-драйвера могут иметь
тип «callout». Callout-устройства традиционно используются для
настройки линии. Данные посылаются или принимаются через один узел
устройства, а настройки линии посылаются в другой узел, который и
является callout-устройством. Такой подход требует использования двух
младших номеров для одного tty-устройства.

hardorsoft 26.10.10 в 06:14

0

К счастью почти все драйвера, работают с данными и настройками
через один и тот же узел, и тип «callout» редко используется в новых
драйверах.

hardorsoft 26.10.10 в 06:15

0

TTY_DRIVER_RESET_TERMIOS

hardorsoft 26.10.10 в 06:15

0

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

hardorsoft 26.10.10 в 06:15

0

TTY_DRIVER_REAL_RAW

hardorsoft 26.10.10 в 06:15

0

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

hardorsoft 26.10.10 в 06:15

0

TTY_DRIVER_NO_DEVFS

hardorsoft 26.10.10 в 06:15

0

Этот флаг используется, чтобы ядро tty-устройств не создавало
точки входа devfs для tty-устройства, после выполнения вызова
tty_register_driver. Этот флаг полезен для драйверов, которые
создают и удаляют устройства динамически. Примером такого
драйвера может быть преобразователь USB-последовательный порт,
драйвер USB-модема, USB Bluetooth tty-драйвер, и драйверы для
стандартного последовательного порта.

hardorsoft 26.10.10 в 06:16

0

Когда драйверу необходимо зарегистрировать tty-устройство, он
должен выполнить функцию tty_register_device, передав в нее
указатель на структуру struct tty_driver и младший номер
создаваемого устройства. Если этого не сделать, то tty-ядро будет
передавать все вызовы драйверу, но некоторые возможности tty-
устройства будут не доступны. Такие как извещение /sbin/hotplug
о новых tty-устройствах, и sysfs-представление tty-устройств. Когда
зарегистрированное устройство удаляется из машины, tty-драйвер
должен вызвать tty_unregister_device.

hardorsoft 26.10.10 в 06:16

0

Существует еще один бит TTY_DRIVER_INSTALLED, им управляет ядро
tty-устройств. Этот флаг устанавливается после регистрации драйвера, и
никогда не меняется непосредственно tty-драйвером.

hardorsoft 26.10.10 в 06:16

0
Минутку...