Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
18.3. Параметры настройки tty-линии
hardorsoft
26.10.10 в 06:30
|
|
Когда пользователь хочет изменить настройки линии tty-устройства, или восстановить прежние настройки, он выполняет одну из функций какой-нибудь пользовательской бибилиотеки для работы с termios, или производит вызов ioctrl для node устройства. Ядро tty-устройств конвертирует оба этих действия в вызов соответствующей функции tty- драйвера.
hardorsoft
26.10.10 в 06:30
|
|
|
|
|
Большинство функций пользовательской библиотеки для termios, использует вызов ioctrl для node устройства. Многие вызовы ioctrl, затем передается в функцию tty-драйвера set_termios. Функция определяет, какие настройки для линии запрашиваются, и производит требуемые изменения в tty-устройстве. Tty-драйвер должен декодировать все настройки в структуре termios, и отреагировать на требуемые изменения. Это сложная задача, т.к. структура termios содержит настройки линии в разнообразных форматах.
hardorsoft
26.10.10 в 06:31
|
|
В первую очередь функция set_termios должна определить, какие изменения нужно произвести. Это может быть выполнено следующим кодом:
hardorsoft
26.10.10 в 06:31
|
|
unsigned int cflag; cflag = tty->termios->c_cflag; /* проверяем, требуется ли действительно что-либо изменять*/ if (old_termios) { if ((cflag = = old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) = = RELEVANT_IFLAG(old_termios->c_iflag))) { printk(KERN_DEBUG " - nothing to change...\n"); return; } }
hardorsoft
26.10.10 в 06:31
|
|
Макрос RELEVANT_IFLAG определен так:
hardorsoft
26.10.10 в 06:31
|
|
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
hardorsoft
26.10.10 в 06:32
|
|
Макрос использует наиболее важные биты переменной cflags, он сравнивает их со старым значением. Если отличий нет, функция закачивает работу. Обратите внимание, что в начале проверяется корректность указателя old_termios. Это необходимо, т.к. переменная может иметь значение NULL. Доступ по нулевому указателю приведет к ошибке.
hardorsoft
26.10.10 в 06:38
|
|
Для определения запрашиваемого размера байта используется битовая маска CSIZE. Если размер не может быть определен, то обычно используется восемь бит. Это реализуется таким образом:
hardorsoft
26.10.10 в 06:38
|
|
/* получим размер байта */ switch (cflag & CSIZE) { case CS5: printk(KERN_DEBUG " break; case CS6: printk(KERN_DEBUG " break; case CS7: printk(KERN_DEBUG " break; default: case CS8: printk(KERN_DEBUG " break; }
hardorsoft
26.10.10 в 06:39
|
|
Для определения требуется ли паритет, используется битовая маска PARENB. Если паритет – используется, то битовая маска PARODD позволяет определить запрашиваемый тип паритета: четный (even) или не четный (odd).
hardorsoft
26.10.10 в 06:39
|
|
/* определяем паритет */ if (cflag & PARENB) if (cflag & PARODD) printk(KERN_DEBUG " - parity = odd\n"); else printk(KERN_DEBUG " - parity = even\n"); else printk(KERN_DEBUG " - parity = none\n"); запрашиваемые стоп-биты определяются битовой маской CSTOPB: /* Выводим запрашиваемые стоп-биты */ if (cflag & CSTOPB) printk(KERN_DEBUG " - stop bits = 2\n"); else printk(KERN_DEBUG " - stop bits = 1\n");
hardorsoft
26.10.10 в 06:40
|
|
Имеется два основных типа управления потоком: аппаратный и программный. Для определения используется ли аппаратное управление, служит битовая маска CRTSCTS: /* Выводим настройки аппаратного управления потоком */ if (cflag & CRTSCTS) printk(KERN_DEBUG " - RTS/CTS is enabled\n"); else printk(KERN_DEBUG " - RTS/CTS is disabled\n"); Определение различных режимов программного управления потоком и различных старт- и стоп-символов более запутано:
hardorsoft
26.10.10 в 06:41
|
|
/* определяем програмное управление потоком */ /* если мы реализуем XON/XOFF, устанавливаем старт- * и стоп-символы в устройстве */ if (I_IXOFF(tty) || I_IXON(tty)) { unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); /* если мы реализуем INBOUND XON/XOFF */ if (I_IXOFF(tty)) printk(KERN_DEBUG " - INBOUND XON/XOFF is enabled, " "XON = %2x, XOFF = %2x", start_char, stop_char); else printk(KERN_DEBUG" - INBOUND XON/XOFF is disabled"); /* если мы реализуем OUTBOUND XON/XOFF */ if (I_IXON(tty)) printk(KERN_DEBUG" - OUTBOUND XON/XOFF is enabled, " "XON = %2x, XOFF = %2x", start_char, stop_char); else printk(KERN_DEBUG" - OUTBOUND XON/XOFF is disabled"); }
hardorsoft
26.10.10 в 06:41
|
|
В заключении нужно определить скорость передачи. Для помощи в этом вопросе ядро tty-устройств предоставляет функцию tty_get_baud_rate. Функция возвращает целое число, показывающее зарегистрированную скорость передачи устройства
hardorsoft
26.10.10 в 06:41
|
|
/* получаем требуемую скорость передачи */ printk(KERN_DEBUG " - baud rate = %d", tty_get_baud_rate(tty));
hardorsoft
26.10.10 в 06:41
|
|
Теперь tty-драйвер определил все параметры линии, и может соответственно настроить аппаратное обеспечение. 18.3.2. tiocmget и tiocmset
hardorsoft
26.10.10 в 06:41
|
|
В ядре 2.4 и более старых, для установки и получения различных параметров линии, применялись вызовы ioctl. При этом использовались константы TIOCMGET, TIOCMBIS, TIOCMBIC, и TIOCMSET. Константа TIOCMGET применялась для получения параметров настройки линиии, и так же как в ядре 2.6, этот вызов ioctl передавал управление функции tty-драйвера tiocmget. Другие три вызова были упрощены, и теперь они заменены одной функцией tty-драйвера tiocmset.
hardorsoft
26.10.10 в 06:42
|
|
Функция tty-драйвера tiocmget вызывается ядром tty-устройств, когда ему требуется узнать текущие настройки линии устройства. Обычно это значения линий DTR и RTS последовательного порта. Если устройство не предоставляет возможность tty-драйверу прочитать значения регистров последовательного порта MSR или MCR, то драйвер использует их локально сохраненную копию. Некоторые драйверы преобразователя USB-последовательный порт реализуют такой подход. Приведем пример функции, локально сохраняющей копии этих значений:
hardorsoft
26.10.10 в 06:42
|
|
static int tiny_tiocmget(struct tty_struct *tty, struct file *file) { struct tiny_serial *tiny = tty->driver_data; unsigned int result = 0; unsigned int msr = tiny->msr; unsigned int mcr = tiny->mcr; result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | /* DTR is set */ ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | /* RTS is set */ ((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) | /* LOOP is set */ ((msr & MSR_CTS) ? TIOCM_CTS : 0) | /* CTS is set */ ((msr & MSR_CD) ? TIOCM_CAR : 0) | /* Carrier detect is set*/ ((msr & MSR_RI) ? TIOCM_RI : 0) | /* Ring Indicator is set */ ((msr & MSR_DSR) ? TIOCM_DSR : 0); /* DSR is set */ return result; }
hardorsoft
26.10.10 в 06:43
|
|
Функция tiocmset вызывается ядром tty-устройств, когда ему требуется установить значения управляющие линией устройства. Ядро tty-устройств говорит драйверу, какие значения установить, а какие очистить, передавая их в двух переменных: set и clear. Эти переменные содержат битовую маску изменяемых настроек линии. Функция ioctl никогда не передает запрос драйверу на установки и очистку одного и того же бита одновременно. Таким образом, не имеет значение, какая из операций будет выполнена первой. Приведем пример того, как эту функцию можно реализовать в драйвере:
hardorsoft
26.10.10 в 06:43
|
|
static int tiny_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct tiny_serial *tiny = tty->driver_data; unsigned int mcr = tiny->mcr; if (set & TIOCM_RTS) mcr |= MCR_RTS; if (set & TIOCM_DTR) mcr |= MCR_RTS; if (clear & TIOCM_RTS) mcr &= ~MCR_RTS; if (clear & TIOCM_DTR) mcr &= ~MCR_RTS; /* установим новое значение MCR в устройстве */ tiny->mcr = mcr; return 0; }
hardorsoft
26.10.10 в 06:43
|
|