Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Драйвер для 6 UART на PCI шине
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Linux
Hoodwin
Имеется плата PCI, где на ПЛИС сделаны 6 UART с драйверами RS-232. Написана PCI функция, которая управляет шестью UART 16550A, тоже самописными. Все это более менее проверялось раньше по отдельности, но теперь вот есть желание запустить порты из-под линукс. Особенность платы в том, что она позволяет делать резервирование RS-232, то есть кроме самого UART 16550 каждый порт имеет логику, которая управляет выключением микросхемы соответствующего драйвера RS-232. Эта логика имеет определенные настройки, которые определяют правила отключения драйвера в зависимости от состояния внешних сигналов.

Все UART представляют собой стандартные 8 регистров, которые расширены нулями до 32-битных слов и размещены в одном BAR по смежным адресам.

Собственно интересует наиболее простой путь подружить линукс со всеми 6 портами. Пока представляются следующие способы:
1) Писать с нуля PCI драйвер ос своими PID, VID.
2) Подсмотреть готовые конфигурации UART в исходниках драйверов линукс, и изменить PID, VID своего устройства в соответствии с подходящим профилем из поддержаных.
3) Написать свой минидрайвер, который будет находить устройство на шине PCI и регистрировать его UART'ы как serial8250 platfrom_device. После чего его и линукс сам подхватит.

Если делать свой драйвер (модуль), то можно в нем зарегистрировать атрибуты портов, чтобы можно было настраивать правила его резервирования. Не уверен, можно ли это сделать, если пытаться подстроиться под существующий драйвер для шины PCI.
Tarbal
Вот посмотрите:
http://www.sealevel.com/support/article/AA-00525
Hoodwin
Посмотрел. Пока ничего путного не вынес из документа. Пересобирать линукс не хотелось бы, так как у заказчика вообще что-то типа МСВС. И я не уверен, что он так просто сможет повторить его (пере)сборку. Зато есть свобода маневра с vendor id и device id. Можно на уровне устройства притвориться чем-то стандартным, для чего уже есть дескриптор в существующем драйвере PCI.

Кстати говоря, уже сейчас линукс пытается цапануть устройство как serial, видимо, на основе данных о классе устройства PCI. Но обламывается и выдает код -28 (ENOSPC?). Пока думаю, что причина в одном из:
1) Размер BAR не соответствует представлениям драйвера.
2) Размер регистра в PCI устройстве - 32 бита (сдвиг адреса 2), а по умолчанию драйвер ожидает 8 бит (сдвиг адреса 0).

Ну и собственно, остается открытым вопрос, как правильно сделать управление параметрами порта, не относящиеся непосредственно к UART? например, мне нужно для каждого порта делать некую настройку, какие внешние сигналы (из определенного набора) могут отключать сигнальный драйвер, чтобы резервный комплект не мешал основному. Явно надо какой-то модуль ядра писать. Например, был опыт с написанием мини-драйвера, который находил UART-ы на одной шине и регистрировал их на шине platform_bus. Вполне такая схема работает, и можно при регистрации определить заодно атрибуты устройства. В том проекте у меня были атрибуты для выбора дуплекса, и параметра управления передатчиком в RS-422/RS-485.

--
Да, так и есть, по умолчанию драйвер 8250_pci хочет регистрировать устройства с 8-битными регистрами. Отсюда и облом при регистрации устройства с 32-битными регистрами.
Tarbal
Но первый-то вариант без сборки кернела.

там вообще две команды с консоли на каждый интерфейс.
federal
жаль мне заказчика
xor.kruger
Естественно Вам придется писать свой драйвер, т.к. железка то нестандартная, "уровень" работы с PCI можно выдернуть из готовых, например для плат ST-Labs, исходники их драйверов можно скачать с офф.сайта.
Hoodwin
Да драйвер-то написать можно, есть и свои драйверы для PCI устройств с DSP, вполне пойдут в основу. Тем более что нужен то мини-драйвер, который выдернет из платы адреса и зарегистрирует стандартные порты 8250. Я надеялся, что линукс сам может определить мультипортовый контроллер на основе данных PCI BAR и т.п., но поглядев исходники 8250_pci.c понял, что особенных чудес ждать неоткуда. В той версии ядра, которая стоит на отладочном стенде, вообще нет 6-портовых конфигураций, только степени двойки.
xor.kruger
Цитата
Я надеялся, что линукс сам может определить мультипортовый контроллер

Он бы и определил, будь бы контроллер из семейства "стандартных", но Вы ведь сами указали что данный контроллер реализован на ПЛИС sm.gif
Hoodwin
Дык на ПЛИС я как раз могу довольно просто переделать архитектуру, чтобы прикинуться "стандартным" устройством, только вот как изобразить 6 стандартных портов в одном устройстве? Ну хотя бы чтобы компорты проверить.
Methane
Цитата(Hoodwin @ Nov 21 2013, 23:43) *
1) Писать с нуля PCI драйвер ос своими PID, VID.

Вот и напишите. Линух про резервирование ком портов не знает. Нет в модулях под линух совершенно ничего сложного.
Tarbal
lspci показывает ваше устройство?

Если да
lspci -v
Результат опубликуйте здесь.
Какое прерывание используется (номер) для вашего первого (из шести) последовательного интерфейса?
gerber
Цитата(Hoodwin @ Nov 22 2013, 22:07) *
Дык на ПЛИС я как раз могу довольно просто переделать архитектуру, чтобы прикинуться "стандартным" устройством, только вот как изобразить 6 стандартных портов в одном устройстве? Ну хотя бы чтобы компорты проверить.

Очень просто. Для этого Вам нужно, чтобы набор регистров каждого COM-порта вашей платы соответствовал набору стандартного 8250-контроллера, с байтовым смещением регистров. При этом не нужно "подделывать" VID/PID своей платы под другого производителя, достаточно вписать свои VID/PID в тот большой перечень PCI-UART плат, которые поддерживаются стандартным драйвером. Если правильно помню - этот список плат содержится в файле 8250_pci.c, там есть большой массив с описанием плат, для каждой платы задаётся VID/PID, номер BAR, адресный шаг между регистрами разных COM-портов, количество COM-портов, реализуемых PCI-платой.
Hoodwin
Да, в итоге действительно потратил полтора часа времени на изучение 8250_pci.c и написал модуль по мотивам оного. К сожалению, сам 8250_pci не подошел, так как в нем нет есть всего одна шестипортовая комбинация, а эвристика мультипортового устройства не цепляла мое устройство. Править стандартный 8250_pci не стал, так как 1) для этого потребуется все ядро пересобирать, что нежелательно; 2) требуется зарегистрировать дополнительные атрибуты устройства, позволяющие управлять внешним драйвером сигналов.

В итоге устройство поднялось и даже вчерне работает. Есть вопрос по поводу количества uart в драйвере 8250. Мой модуль регистрирует 6 портов, но регистрируются только первые два. В принципе это ожидаемо, если в ядре CONFIG_SERIAL_8250_RUNTIME_UARTS и CONFIG_SERIAL_8250_NR_UARTS слишком малы. Так вот:
1) можно ли как-то подсмотреть, с какими настройками собрано текущее ядро?
2) Можно ли как-то увеличить количество уартов без пересборки ядра? Нашел в сети, что можно в комстроке ядра писать 8250.nr_uarts=8, но вот тут http://forums.opensuse.org/english/get-tec...4-detected.html пишут, что это не помогло, и в итоге люди уродовались с пересборкой модуля UART.
Dron_Gus
Цитата(Hoodwin @ Nov 24 2013, 23:47) *
1) можно ли как-то подсмотреть, с какими настройками собрано текущее ядро?

cat /proc/config, если повезет.
zcat /proc/config.gz
Methane
Цитата(Dron_Gus @ Nov 25 2013, 14:08) *
cat /proc/config, если повезет.
zcat /proc/config.gz


Долго спали?

/boot/config-3.11.0-13-generic
версия - по аналогии.
Tarbal
Цитата(Methane @ Nov 25 2013, 15:20) *
Долго спали?

/boot/config-3.11.0-13-generic
версия - по аналогии.

Оба варианта годятся.
Dron_Gus
Цитата(Methane @ Nov 25 2013, 16:20) *
Долго спали?

/boot/config-3.11.0-13-generic
версия - по аналогии.

Это сильно зависит от дистрибьютива. Если он туда что-то кладет - повезло. Автор ничего про это не сказал.

В Генту вообще можно сделать
cd /usr/src/linux
cat .config
Hoodwin
В общем вот что имеем:
Цитата
# cat /boot/config-2.6.24-1-686 | grep 8250 | grep UART
CONFIG_SERIAL_8250_NR_UARTS=32
CONFIG_SERIAL_8250_RUNTIME_UARTS=4


а вот в /proc/ никакого намека на config нету.
Hoodwin
---
Да, вот попробовал написать в комстроку ядра 8250.nr_uarts=8. Даже сработало. Получился такой лог:
Код
ACPI: PCI Interrupt 0000:01:0b.0[A] -> GSI 23 (level, low) -> IRQ 22
0000:01:0b.0: Probing COMB6U PCI driver for 6 ports...
0000:01:0b.0: setup port df80, irq 22, type 0
0000:01:0b.0: ttyS4 at I/O 0xdf80 (irq = 22) is a 16550A
0000:01:0b.0: setup port df88, irq 22, type 0
0000:01:0b.0: ttyS5 at I/O 0xdf88 (irq = 22) is a 16550A
0000:01:0b.0: setup port df90, irq 22, type 0
0000:01:0b.0: ttyS6 at I/O 0xdf90 (irq = 22) is a 16550A
0000:01:0b.0: setup port df98, irq 22, type 0
0000:01:0b.0: ttyS7 at I/O 0xdf98 (irq = 22) is a 16550A
0000:01:0b.0: setup port dfa0, irq 22, type 0
0000:01:0b.0: ttyS2 at I/O 0xdfa0 (irq = 22) is a 16550A
0000:01:0b.0: setup port dfa8, irq 22, type 0
0000:01:0b.0: ttyS3 at I/O 0xdfa8 (irq = 22) is a 16550A


Видно, что все 6 UART-ов поднялись. Однако есть проблема с их порядком. Пока поднимались только первые два, то ttyS2 приходился на порт df80, а ttS3 - на порт df88. Теперь порядок другой, скажем прямо, не порядок. Вопрос: почему так? Регистрировал то я все это одним циклом тупо по порядку.


И еще вопрос. Существует ли в природе какой-нибудь тест для стандартного UART 16550 (для linux 2.6)? Интересен тест, который бы позволил по возможности наиболее полно протестировать UART. Можно даже с неким внешним loopback'ом для 9-контактного разъема D-Sub.

Есть один непонятный момент.
echo 123 > /dev/ttyS2
не выводит ничего, можно хоть 100 раз подряд такое выполнить.
echo 1234567890 > /dev/ttyS2
выводит все правильно.
cat Makefile > /dev/ttyS2
выводит все правильно и без потерь.
запуск bash </dev/ttyS2 >/dev/ttyS2 2>/dev/ttyS2 &
дает совершенно нормальную консоль, эхо идет на каждый введенный символ.

прямой вывод в обход драйвера - outb 0xdf80 0x21 - работает, как часы.
Однако
echo 123 > /dev/ttyS0 (порт на системной плате) все же работает.
В общем, хочется понять в чем тут дело.
sasamy
Цитата(Hoodwin @ Nov 26 2013, 12:35) *
Видно, что все 6 UART-ов поднялись. Однако есть проблема с их порядком.


Можно указать через setserial какой угодно
http://linux.die.net/man/8/setserial

Цитата
И еще вопрос. Существует ли в природе какой-нибудь тест для стандартного UART 16550 ... Можно даже с неким внешним loopback'ом для 9-контактного разъема D-Sub.


А что там тестировать ?
http://linux.die.net/man/1/minicom
Tarbal
deleted by Tarbal
Hoodwin
sasamy

Ну, вот раньше в CheckIT были тесты ком-портов, которые проверяли правильность работы UART-а. Например:
1) Правильность логики установки статусов внешних сигналов
2) Правильность работы механизмов RTS-CTS
3) правильность работы флагов прерываний на передачу, прием данных и таймаут приема,
4) Правильную работу регистров MSR, LSR.
5) Правильную работу контроля четности.
6) Отсутствие пропадания прерываний при скоростном обмене.
7) Точность бодового генератора.

Короче говоря, интересен некий формальный тест, выдающий на выходе да или нет. И если нет, то какая именно проверка не прошла. Причем не нужно много кнопок давить, запустил программу с именем терминала и все, тест пошел.

К сожалению, я не смог найти внятного описания как правильно работать с FIFO в через драйвер 8250. Точнее, как управлять его настройками. Судя по коду, драйвер сам принимает решение об использовании FIFO, исходя из типа UART. Ну например, для стандртного UART 16550A выбирается FIFO threasholds 8 и все. Ни разу не видел, как через stty это скорректировать. И даже просто как посмотреть, то что есть по факту, не особо описано. В QNX и то куда более внятно было расписано.
sasamy
Цитата(Hoodwin @ Nov 26 2013, 19:56) *
Ну, вот раньше в CheckIT были тесты ком-портов, которые проверяли правильность работы UART-а. Например:


Таких тестов скорей всего не найдете - если только у производителей многопортовых плат на сайтах рыть

Цитата
7) Точность бодового генератора.


и типа можно верить этим измерениям ? лучше измерить осцилом - посылать в порт число 0x55 и смотреть частоту.

Цитата
драйвер сам принимает решение об использовании FIFO, исходя из типа UART.


зачем пользовательским программам управлять размерами аппаратного FIFO - чтобы отключить, указываете тип уарта без FIFO (16450) в setserial.
Hoodwin
Цитата(sasamy @ Nov 27 2013, 00:02) *
Таких тестов скорей всего не найдете - если только у производителей многопортовых плат на сайтах рыть

Жаль, я думал, в линуксе подобные вещи есть.

Цитата(sasamy)
и типа можно верить этим измерениям ? лучше измерить осцилом - посылать в порт число 0x55 и смотреть частоту.

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

Цитата(sasamy)
зачем пользовательским программам управлять размерами аппаратного FIFO - чтобы отключить, указываете тип уарта без FIFO (16450) в setserial.

Ну вот, например, у нас был один проект, где протокол был так устроен, что передавались посылки по два байта, с периодом в 20-30 байтовых интервалов. В протоколе не было никаких признаков первого байта, за исключением того, что он первый после паузы. И вот когда сели делать через /dev/ser* (дело было под QNX), то выяснилось, что никак нельзя гарантировать синхронизацию по первым байтам. Тогда включили FIFO с порогом 4, и стали ловить прерывания по таймауту данных. С помощью этого прерывания синхронизацию удалось восстановить. Таким образом, аппаратные особенности UART вполне могут играть ключевую роль при программировании решения. Конечно, можно сказать, что берите и пишите для такого случая специальный драйвер. Можно было бы согласиться, однако в случае многопортового устройства появляется нюанс. Как поределить какой порт к какому драйверу приписывать. Обычно все порты автотматически цепляются каким-то одним драйвером.
Tarbal
Цитата(Hoodwin @ Nov 28 2013, 00:27) *
Как поределить какой порт к какому драйверу приписывать. Обычно все порты автотматически цепляются каким-то одним драйвером.


Драйвер будет один, но устройства разные. Драйвер всегда знает с каким устройством он работает в данный момент.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.