Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
18.1. Маленький tty-драйвер
hardorsoft
26.10.10 в 06:05
|
|
Чтобы объяснить работу ядра tty-устройств, мы создадим маленький tty-драйвер который может быть загружен и выгружен, и из которого может производится чтение и запись. Основной структурой данных любого tty-драйвера является struct tty_driver. Она используется для регистрации и отмены регистрации драйвера в ядре tty-устройств и описана в <"linux/tty_driver.h">.
hardorsoft
26.10.10 в 06:06
|
|
Для создания структуры struct tty_driver используется функция alloc_tty_driver. В качестве параметра передается количество tty-устройств, которое поддерживается драйвером. Выполняется это, например, таким кодом:
hardorsoft
26.10.10 в 06:06
|
|
/* определение 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
|
|
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
|
|
/* 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
|
|
Для регистрации драйвера в ядре tty-устройств, структура struct tty_driver должна быть передана в функцию tty_register_driver:
hardorsoft
26.10.10 в 06:07
|
|
/* 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
|
|
Когда вызывается tty_register_driver, ядро создает все файлы последовательных устройств, которые драйвер может обслуживать, в sysfs. Если вы используете devfs (не описанный в этой книги) и не указываете флаг TTY_DRIVER_NO_DEVFS, файлы devfs так же создаются. Флаг может быть указан, если вы хотите вызывать tty_register_device только для устройств фактически присутствующих в системе. Таким образом, пользователь всегда имеет своевременное представление об имеющихся устройствах, что и требуется при использовании devfs.
hardorsoft
26.10.10 в 06:08
|
|
После своей регистрации, драйвер регистрирует устройства функцией tty_register_device. Эта функция имеет три аргумента:
hardorsoft
26.10.10 в 06:08
|
|
Указатель на структуру struct tty_driver принадлежащую устройству.
hardorsoft
26.10.10 в 06:08
|
|
Младший номер устройства.
hardorsoft
26.10.10 в 06:09
|
|
Указатель на структуру struct device связанную с этим устройством. Если tty-устройство не связано с какой-либо struct device, этот аргумент устанавливается в NULL.
hardorsoft
26.10.10 в 06:09
|
|
Наш драйвер регистрирует сразу все tty-устройства т.к. они – виртуальные и не связаны с физическим оборудованием:
hardorsoft
26.10.10 в 06:09
|
|
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
|
|
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
|
|
18.1.1. Структура struct termios
hardorsoft
26.10.10 в 06:11
|
|
Переменная init_termios в структуре struct device имеет тип struct termios. Она используется для предоставления параметров настройки линии, если пользователь обращается к порту, не инициализируя его. Драйвер инициализирует переменную init_termios стандартным набором значений, который копируется из tty_std_termios. Переменная tty_std_termios определена следующим образом:
hardorsoft
26.10.10 в 06:11
|
|
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
|
|
Структура используется для хранения текущих параметров линии для соответствующего порта tty-устройства. Эти параметры управляют скоростью, размером данных, потоком данных, и многим другим. Поля структуры struct termios:
hardorsoft
26.10.10 в 06:12
|
|
tcflag_t c_iflag; Флаги режима ввода.
hardorsoft
26.10.10 в 06:12
|
|
tcflag_t c_oflag; Флаги режима вывода.
hardorsoft
26.10.10 в 06:12
|
|
tcflag_t c_cflag; Флаги управления.
hardorsoft
26.10.10 в 06:12
|
|
tcflag_t c_lflag; Флаги локального режима.
hardorsoft
26.10.10 в 06:12
|
|
cc_t c_line; Тип line discipline.
hardorsoft
26.10.10 в 06:12
|
|
cc_t c_cc[NCCS]; Массив управляющих символов.
hardorsoft
26.10.10 в 06:13
|
|
Все флаги режима являются битовыми полями. Различные значения режимов и их назначение, можно найти на странице «termios» утилиты man, в любом дистрибутиве Linux. Ядро предоставляет множество макросов для получения значений битов. Эти макросы определены в заголовочном файле <"include/linux/tty.h">.
hardorsoft
26.10.10 в 06:13
|
|
Все поля переменной tiny_tty_driver нужны для работы tty- драйвера. Поле owner необходимо для предотвращения выгрузки драйвера в момент, когда tty-порт открыт. В предыдущих версиях ядра, драйвер самостоятельно отслеживал факт своего использования. Но разработчики ядра пришли к решению, что учитывать все возможные ситуации будет сложно, и теперь это делает ядро tty-устройств.
hardorsoft
26.10.10 в 06:13
|
|
Поля 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
|
|
Как мы говорили, в файле /proc/tty/drivers показываются все зарегистрированные драйверы. После регистрации в ядре драйвера tiny_tty, и при условии, что devfs не используется, файл выглядит примерно так:
hardorsoft
26.10.10 в 06:14
|
|
$ 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
|
|
Когда драйвер tiny_tty зарегистрировался в ядре tty-устройств, каталог sysfs /sys/class/tty выглядит примерно так:
hardorsoft
26.10.10 в 06:14
|
|
$ 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
|
|
Старшая переменная соответствует старшему номеру этого драйвера. Тип и подтип переменной информирует о типе tty-драйвера. В нашем примере, мы используем драйвер последовательного порта, стандартного типа «normal». Другие подтипа tty-драйвера могут иметь тип «callout». Callout-устройства традиционно используются для настройки линии. Данные посылаются или принимаются через один узел устройства, а настройки линии посылаются в другой узел, который и является callout-устройством. Такой подход требует использования двух младших номеров для одного tty-устройства.
hardorsoft
26.10.10 в 06:14
|
|
К счастью почти все драйвера, работают с данными и настройками через один и тот же узел, и тип «callout» редко используется в новых драйверах.
hardorsoft
26.10.10 в 06:15
|
|
TTY_DRIVER_RESET_TERMIOS
hardorsoft
26.10.10 в 06:15
|
|
Этот флаг указывает tty-ядру на необходимость сбрасывать все настройки, когда последний процесс закрывает устройство. Флаг используется для драйверов консоли и pty. Этот флаг может быть полезен, если пользователь может оставить терминал в неизвестном состоянии. Когда этот флаг установлен, терминал сбрасывается в нормальное состояние при завершении процесса контролирующего сессию, или когда пользователь выходит из системы.
hardorsoft
26.10.10 в 06:15
|
|
|
|
|
При установленном флаге, драйвер гарантирует, что пошлет уведомление о паритете или о символах остановки. Это позволяет намного быстрее принимать символы в процессе работы, т.к. не нужно анализировать каждый принимаемый от tty-драйвера символ. Из-за прироста скорости, этот флаг обычно устанавливается для всех tty-драйверов.
hardorsoft
26.10.10 в 06:15
|
|
|
|
|
Этот флаг используется, чтобы ядро tty-устройств не создавало точки входа devfs для tty-устройства, после выполнения вызова tty_register_driver. Этот флаг полезен для драйверов, которые создают и удаляют устройства динамически. Примером такого драйвера может быть преобразователь USB-последовательный порт, драйвер USB-модема, USB Bluetooth tty-драйвер, и драйверы для стандартного последовательного порта.
hardorsoft
26.10.10 в 06:16
|
|
Когда драйверу необходимо зарегистрировать tty-устройство, он должен выполнить функцию tty_register_device, передав в нее указатель на структуру struct tty_driver и младший номер создаваемого устройства. Если этого не сделать, то tty-ядро будет передавать все вызовы драйверу, но некоторые возможности tty- устройства будут не доступны. Такие как извещение /sbin/hotplug о новых tty-устройствах, и sysfs-представление tty-устройств. Когда зарегистрированное устройство удаляется из машины, tty-драйвер должен вызвать tty_unregister_device.
hardorsoft
26.10.10 в 06:16
|
|
Существует еще один бит TTY_DRIVER_INSTALLED, им управляет ядро tty-устройств. Этот флаг устанавливается после регистрации драйвера, и никогда не меняется непосредственно tty-драйвером.
hardorsoft
26.10.10 в 06:16
|
|