Настройки на TTY линия

Предишно съдържание Следващо

Когато потребителят иска да промени настройките на tty низа на устройството или да получи текущите настройки на низа, той прави едно от многото различни termios извиквания към функцията на библиотеката на потребителското пространство или директно прави ioctl извикване към tty възела на устройството. Ядрото на tty преобразува и двата интерфейса в редица различни функции за обратно извикване на tty драйвер и ioctl извикване.

set_termios

Повечето функции termios на потребителското пространство се превеждат от библиотеката в ioctl извикване към хоста на драйвера. След това голям брой различни извиквания на tty ioctl се преобразуват от ядрото на tty в едно извикване към функцията set_termios на драйвера tty. Обратното извикване set_termios трябва да определи кои настройки на линията се иска да промени и след това да направи тези промени в tty устройството. Tty драйверът трябва да може да декодира всички различни настройки в структурата на termios и да реагира на всички необходими промени. Това е трудна задача, тъй като всички настройки на линията са опаковани в структурата на termios по голям брой начини.

Първото нещо, което функцията set_termios трябва да направи, е да определи дали нещо наистина трябва да се промени. Това може да стане със следния код:

неподписан int cflag;

/* проверете какво наистина искат да променим */

if ((cflag == old_termios->c_cflag) &&

printk(KERN_DEBUG "- нищо за промяна.\n");

Макросът RELEVANT_IFLAG се дефинира като:

#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRKBRKINTIGNPARPARMRKINPCK))

и се използва за маскиране на важни битове в променливата cflags. След това се сравнява със старата стойност и се вижда дали има промени. Ако не, тогава нищо не трябва да бъдепроменени, значи се върнахме. Имайте предвид, че първо проверява дали променливата old_termios сочи към валидна структура, преди да осъществи достъп до нея. Това е необходимо, защото в някои случаи тази променлива е NULL. Опитът за достъп до поле чрез NULL указател води до паника в ядрото.

За да видите искания размер в байтове, битовата маска CSIZE може да се използва за извличане на необходимите битове от променливата cflag. Ако размерът не може да бъде определен, тогава той обикновено се задава по подразбиране на осем бита данни. Това може да се приложи по следния начин:

/* получава размер в байтове */

превключвател (cflag & CSIZE)

printk(KERN_DEBUG "-битове данни = 5\n");

printk(KERN_DEBUG "- битове данни = 6\n");

printk(KERN_DEBUG "- битове данни = 7\n");

printk(KERN_DEBUG "-битове данни = 8\n");

За да се определи исканата стойност за паритет, битовата маска PARENB може да се приложи към cflag, за да се определи дали паритетът изобщо трябва да бъде зададен. Ако е така, битовата маска PARODD може да се използва, за да се определи дали трябва да се използва паритет, нечетен или четен. Изпълнение на това:

ако (cflag & PARENB)

ако (cflag & PARODD)

printk(KERN_DEBUG "- паритет = нечетно\n");

printk(KERN_DEBUG "- паритет = дори\n");

printk(KERN_DEBUG "- паритет = няма\n");

Исканите стоп битове могат също да бъдат зададени с променливата cflag, като се използва маската CSTOPB. Изпълнение на това:

/* намиране на необходимите стоп битове */

ако (cflag & CSTOPB)

printk(KERN_DEBUG "- стоп битове = 2\n");

printk(KERN_DEBUG " - стоп битове = 1\n");

Има два основни типа контрол на потока от данни:хардуер и софтуер. За да се определи дали потребителят иска хардуерен контрол на потока, битовата маска CRTSCTS може да се приложи към променливата cflag. Пример за това:

/* разберете настройките за управление на хардуерния трансфер */

ако (cflag & CRTSCTS)

printk(KERN_DEBUG "-RTS/CTS е активиран\n");

printk(KERN_DEBUG " - RTS/CTS е деактивиран\n");

Дефинирането на различните видове програмно управление на потока и различните знаци за спиране и стартиране е малко по-сложно:

/* дефиниране на софтуерен контрол на потока */

/* ако имплементираме XON/XOFF, задайте начало и

* знак за спиране в устройството */

ако (I_IXOFF(tty) I_IXON(tty))

unsigned char stop_char = STOP_CHAR(tty);

unsigned char start_char = START_CHAR(tty);

/* ако внедрим INPUT XON/XOFF */

printk(KERN_DEBUG " - INBOUND XON/XOFF е активиран, "

"XON = %2x, XOFF = %2x", start_char, stop_char);

printk(KERN_DEBUG" - INBOUND XON/XOFF е деактивиран");

/* ако внедрим OUTPUT XON/XOFF */

printk(KERN_DEBUG" - OUTBOUND XON/XOFF е активиран, "

"XON = %2x, XOFF = %2x", start_char, stop_char);

printk(KERN_DEBUG" - ИЗХОДЯЩ XON/XOFF е деактивиран");

Накрая трябва да се определи скоростта на предаване на данни. За да помогне за това, tty ядрото предоставя основната функция tty_get_baud_rate. Функцията връща цяло число, указващо исканата скорост на предаване за даденото tty устройство:

/* получава скорост на предаване */

printk(KERN_DEBUG " - скорост на предаване = %d", tty_get_baud_rate(tty));

Сега, след като tty драйверът е определил всички различни параметри на линията, е възможно правилно да се инициализира въз основа на тези стойности.оборудване.

tiocmget и tiocmset

Във версия 2.4 и по-стари ядра бяха използвани множество tty ioctl извиквания за получаване и задаване на различни опции за контрол на линията. Те са обозначени с константите TIOCMGET, TIOCMBIS, TIOCMBIC и TIOCMSET. TIOCMGET се използва за получаване на стойности за настройка на низ в ядрото и от версия 2.6 това ioctl извикване е превърнато във функция за обратно извикване на tty драйвер, наречена tiocmget. Другите три ioctl са опростени и сега са представени от една функция за обратно извикване на tty драйвер, наречена tiocmset.

Функцията tiocmget в tty драйвера се извиква от tty ядрото, когато ядрото иска да знае текущите физически стойности на контролните линии на конкретно tty устройство. Това обикновено се прави, за да получите стойностите на DTR и RTS линиите на серийния порт. Ако tty драйверът не може директно да прочете MCR или MSR на серийния порт, защото хардуерът не го позволява, копие трябва да се съхранява локално. Редица драйвери за USB към сериен порт трябва да прилагат този вид променлива "сянка". Ето как може да се приложи тази функция, ако се пазят локални копия на тези променливи:

static int tiny_tiocmget(struct tty_struct *tty, struct file *file)

struct tiny_serial *tiny = tty->driver_data;

unsigned int резултат = 0;

unsigned int msr = tiny->msr;

unsigned int mcr = tiny->mcr;

резултат = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* DTR набор */

((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* RTS набор */

((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) /* LOOP е зададен */

((msr & MSR_CTS) ? TIOCM_CTS : 0) /* CTS набор */

((msr & MSR_CD) ? TIOCM_CAR : 0) /* Зададено откриване на носеща(откриване на носител) */

((msr & MSR_RI) ? TIOCM_RI : 0) /* Индикатор за звънене е зададен */

Когато ядрото иска да зададе контролните линии на конкретно tty устройство, tty ядрото извиква функцията tiocmset в tty драйвера. Ядрото tty казва на tty драйвера кои стойности да зададе и кои да изчисти, като ги предава в две променливи: set и clear. Тези променливи съдържат битова маска на настройките на линията, които трябва да бъдат променени. Извикването на ioctl никога не изисква от драйвера да зададе и изчисти един и същ бит едновременно, така че няма значение коя операция се случва първа. Ето пример за това как тази функция може да бъде реализирана от tty драйвера:

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;

ако (set & TIOCM_RTS)

ако (set & TIOCM_DTR)

ако (изчистване и TIOCM_RTS)

ако (изчистване & TIOCM_DTR)

/* задава на устройството нова стойност за MCR */