www.label.pl | LAB-EL Elektronika Laboratoryjna
Elektronika Laboratoryjna

Konfiguracja Linuxa do współpracy z kartami wieloportowymi LB-240, LB-280 produkcji LAB-EL


  • dla Linuxa w dystrybucji RedHat 6.0 Hedwig
Karty wieloportowe - konfiguracja linux



UWAGA: Karty LB-240 i LB-280 wycofano z oferty, zastąpione kartą C104H/PCI lub podobną.

  • dokument powstał po instalacji karty LB-280 na komputerze z Linuxem w dystrybucji RedHat6.0 z jądrem 2.2.5 - istnieją różnice w konfiguracji portów szeregowych w różnych instalacjach Linuxa, więc nie jest to stuprocentowo dobry opis - w szczególności mogą wystąpić rożnice w sposobie wywołania programu setserial oraz sposobie konfigurowania jądra przed kompilacją
  • pisząc ten dokument autor działał w dobrej wierze i nie ponosi odpowiedzialności za żadne szkody wynikłe w skutek działalności Użytkownika zainspirowanego lekturą niniejszego dokumentu - w interesie Użytkownika jest więc zapoznanie się z dokumentacją do Jego instalacji i potraktowanie tego tekstu jako jednej z możliwych dróg osiągnięcia celu
  • wykorzystany został program setserial w wersji 2.15
  • w przykładach odwołuję się do karty skonfigurowanej na adres 0x280, irq 5 i posiadającej 8 portów szeregowych bez bufora FIFO czyli 16450
  • karty LB-240 i LB-280 są zgodne z kartami Hostess 550(TM) produkcji Comtrol Corporation

OPIS

1. Pierwszym krokiem przy konfigurowaniu linuksowego komputera do współpracy z kartą wieloportową LB240 albo LB-280 (zwaną dalej kartą) jest sprawdzenie, czy jądro systemu posiada wkompilowaną obsługę dla takiego urządzenia. Konieczne jest zawarcie następujących opcji kompilacji jądra:
  • CONFIG_SERIAL_EXTENDED - opcja aktywująca obsługę niestandardowych funkcji portów szeregowych, takich jak dzielenie przerwania przez kilka UARTów albo obsługę dodatkowych rejestrów zawartych na karcie. Opcja ta otwiera możliwość wybrania kolejnych szczegółowych opcji konfiguracji i jest aktywowana poprzez zaznaczenie pozycji Extended dumb serial driver options w programie konfiguracji jądra.
  • CONFIG_SERIAL_MANY_PORTS - konieczna dla obsługi wiecej niż 4 standardowych portów PC - aktywowana poprzez zaznaczenie Support more than 4 serial ports.
  • CONFIG_SERIAL_SHARE_IRQ - konieczna dla obsługi współdzielenia przerwania przez wszystkie UARTy karty - aktywowana przez zaznaczenie Support for sharing serial interrupts.
  • CONFIG_SERIAL_MULTIPORT - konieczna dla obsługi specjalnego rejestru umożliwiającego identyfikację UARTa zgłaszającego przerwanie - aktywowana przez zaznaczenie Support special multiport boards.
Jeśli aktualne jądro nie zostało skompilowane z ww. opcjami to należy wygenerować nowe i zainstalować je - opisu tych czynności niniejszy dokument nie zawiera.

2. Drugi krok instalacji karty wieloportowej to stworzenie w systemie plików - plików urządzeń przez które możliwa będzie komunikacja oprogramowania użytkownika z procedurami jądra. Pliki urządzeń znajdują sie w katalogu /dev a ich nazwę (dotyczy urządzeń dla portów szeregowych)  przez konwencję konstruuje sie z ttyS i unikalnego numeru, przy czym ttyS0 do ttyS3 przydzielane są zazwyczaj dla standardowych portów PC (oznaczanych niekiedy jako COM1..COM4). Dla każdego portu karty należy stworzyć odrębny plik urządzenia, i niech to, w tym przykładzie, będą pliki od ttyS16 do ttyS23 (przykład dla karty 8-portowej). Posługujemy się programem mknod, który generuje pliki urządzeń - jako parametry podajemy: nazwę specjalnego pliku urządzenia, c (urządzenie znakowe), oraz dwie liczby: major i minor - pozwalające na identyfikację urządzenia z zasobach jądra. Liczba major dla portu szeregowego (typu ttyS) jest równa 4, liczbę minor uzyskujemy jako sumę 64+numer_przy_ttyS, czyli dla ttyS16 będzie to 80. Można więc wykonać serię poleceń:
      mknod /dev/ttyS16 c 4 80
        
mknod /dev/ttyS17 c 4 81
mknod /dev/ttyS18 c 4 82
mknod /dev/ttyS19 c 4 83
mknod /dev/ttyS20 c 4 84
mknod /dev/ttyS21 c 4 85
mknod /dev/ttyS22 c 4 86
mknod /dev/ttyS23 c 4 87
albo skorzystać ze skryptu dołączonego na końcu dokumentu.

Wcześniejsze wersje systemu wykorzystywały urządzenia typu /dev/cua, dla których liczba major ma wartość 5 - obecnie autorzy systemu zalecają zaprzestanie korzystania z tych plików urządzeń.

3. Trzecim krokiem jest stworzenie skryptów inicjujących tablice jądra wartościami odpowiednimi dla zainstalowanej karty - adres w przestrzeni I/O, przerwanie, typ UARTów. W tym celu posługujemy się programem setserial. Inicjacja tablic (w odróżnieniu od poprzednich kroków) jest konieczna przy każdym uruchomieniu systemu, należy więc, wykonywać ją ze skryptów uruchamianych automatycznie przy starcie. Program setserial wykonujemy oddzielnie dla każdego portu karty, jako parametry podajemy: nazwę pliku urządzenia, adres bazowy poru, numer linii przerwań, typ UARTa oraz prędkość transmisji. Adres bazowy kolejnego portu jest sumą adresu bazowego karty (ustawionego na zworkach) plus 8*numer_portu. Numer linii przerwań (również ustawiony na zworkach karty) jest taki sam we wszystkich wywołaniach. Typ UARTa zależy w jakie układy wyposażona jest karta, zazwyczaj jest to: albo 16450 (niebuforowany), albo 16550 (bufor FIFO 16to bajtowy). Parametr określający prędkość transmisji ma znaczenie jedynie wtedy, gdy oprogramowanie ustawia sobie transmisję 38400bps, faktyczna predkość zależy od parametru który podamy setserialowi, i jeśli to będzie spd_normal, to uzyskamy faktyczną prędkość 38400bps, dla spd_hi uzyskamy 57600bps a dla spd_vhi
115200bps. Dla połączeń przy pomocy pętli prądowych nie zaleca się korzystania z transmisji szybszej niż 38400bps, ze względu na ograniczenia układów separacji galwanicznej kart LB-2?0. Przykładowy ciąg poleceń ustawiających paramerty tablic jądra:
      setserial /dev/ttyS16 port 0x280 irq 5 uart 16450 spd_normal
        
setserial /dev/ttyS17 port 0x288 irq 5 uart 16450 spd_normal
setserial /dev/ttyS18 port 0x290 irq 5 uart 16450 spd_normal
setserial /dev/ttyS19 port 0x298 irq 5 uart 16450 spd_normal
setserial /dev/ttyS20 port 0x2a0 irq 5 uart 16450 spd_normal
setserial /dev/ttyS21 port 0x2a8 irq 5 uart 16450 spd_normal
setserial /dev/ttyS22 port 0x2b0 irq 5 uart 16450 spd_normal
setserial /dev/ttyS23 port 0x2b8 irq 5 uart 16450 spd_normal
Po ustawieniu parametrów dla poszczególnych portów należy poinformować procedury jądra o istnieniu specjalnego rejestru ułatwiającego identyfikację UARTa zgłaszającego przerwanie. Rejestr ten znajduje się w przestrzeni I/O pod adresem przesuniętym o 7 w stosunku do adresu bazowego karty. Posługujemy się znowu programem setserial.
      setserial /dev/ttyS16 set_multiport port1 0x287 mask1 0xff match1 0x00
Polecenia tego nie trzeba wykonywać dla każdego portu z osobna, ponieważ już wcześniej ustalono, że wszystkie posługują się wspólną linią przerwań, a to wystarcza aby to samo ustawienie dotyczyło innych portów karty. Wyjaśnienia wymagają pozostałe parametry: port1 0x287 - jest to adres portu (rejestru) identyfikacji przerwania o którym napisane jest powyżej, mask1 0xff - jest to wartość maski przykładanej do wartości wyczytanej z rejestru, dla każdego UARTa przydzielony jest 1 bit - jeśli więc korzystamy z karty 8mio portowej, to maska powinna być ustawiona na 0xff czyli de facto nie maskujemy nic. Dla karty 4ro portowej maska powinna mieć wartość 0x0f. Parametr: match1 0x00 - ustala zawartość rejestru po ustaniu żądania obsługi, czyli wartość jaką będzie zawierał rejestr po obsłużeniu żądań wszystkich UARTów karty.

Po wykonaniu ustawień można je skontrolować wywołując program:
    setserial /dev/ttyS16	# wypisuje ustawienia dla konkretnego portu, tu ttyS16 setserial /dev/ttyS16
      
get_multiport # wypisuje ustawienia dla rejestru identyfikacji przerwania
4. Typowym zastosowaniem kart wieloportowych jest łączenie przy ich pomocy terminali znakowych z hostem. Niezbędna konfiguracja obejmuje wypełnienie pozycji pliku /etc/inittab nakazujących procesowi init uruchamianie procesu getty dla każdej skonfigurowanej linii tty. Typowo wystarczy dodanie dla każdego nowego terminala jednej linii w inittabie tak jak w następującym przykładzie:
      16:2345:respawn:/sbin/getty ttyS16 DT19200 vt100
        
17:2345:respawn:/sbin/getty ttyS17 DT19200 vt100
18:2345:respawn:/sbin/getty ttyS18 DT19200 vt100
19:2345:respawn:/sbin/getty ttyS19 DT19200 vt100
20:2345:respawn:/sbin/getty ttyS20 DT19200 vt100
21:2345:respawn:/sbin/getty ttyS21 DT19200 vt100
22:2345:respawn:/sbin/getty ttyS22 DT19200 vt100
23:2345:respawn:/sbin/getty ttyS23 DT19200 vt100
Opis składni poleceń znaleźć można w manualu do inittaba, ważne jest aby parametr definiujący parametry transmisji określał ją jako połączenie lokalne - nie wymagające synchronizacji (handshake) - w przykładzie określone jest to przez parametr DT19200 (wybrana prędkość 19200bps). Definicja parametru DT19200 podana jest w pliku /etc/gettydefs i powinna ona wyglądać (mniej-więcej) tak:
      DT19200# B19200 CS8 CLOCAL # B19200 SANE -ISTRIP CLOCAL #@S login: #DT19200
        
Ważne jest podanie flagi CLOCAL - określającej połączenie jako lokalne, opis formatu pliku znaleźć można w manualu do gettydefs, opis znaczenia flag w manualu do stty. Po wypełnieniu pliku inittab należy zasygnalizować procesowi init zmianę ustawień wydając komendę:
      init q
        
po czym na terminalach podłączonych do uruchamianej karty powinien pojawić się tekst zachęty do logowania.
Wyjaśnienia:
  • UART - universal asynchronius receiver/transmiter, czyli układ (zazwyczaj scalony) realizujący funkcję nadajnika/odbiornika asynchronicznej transmisji szeregowej
  • program konfiguracji jądra - program wywoływany poleceniem: make menuconfig, udostępniający użytkownikowi interfejs (zestaw menu) do ustawiania opcji kompilacji jądra

Bibliografia:
  • manual: setserial, stty, getty, gettydefs, inittab, init, mknod
  • HOWTO: Serial-HOWTO, Serial-Programming-HOWTO
  • źródła jądra (2.2.5): /usr/src/linux/drivers/char/serial.c,  /usr/src/linux/include/linux/serial.h
  • www.comtrol.com - dokument 6252d.pdf - Installation Reference Card for The Linux System with the Hostess 550(TM) Series

    #!/bin/bash
      
#
# skrypt ustawiajacy parametry jadra do wspolpracy z kartami LB-240 i LB-280
# produkcji LAB-EL, sprawdzony na jadrze 2.2.5, RedHat 6.0, z programem
# setserial 2.15
#
# JRS, 13.9.1999
#
# -- konfiguracja -----------------------------------------------------------
DEVSTART=16                     # numer pierwszego ttyS przydzielonego karcie
PORTNUMB=8                      # liczba uart-ow na karcie: 4 albo 8
BASE=0x280                      # adres bazowy -- czyli adres pierwszego uart-a
IRQ=5                           # numer linii irq
UART=16450                      # typ uart-a: 16450 albo 16550
SPEED=spd_normal                # spd_normal daje max bps=38400
# -- koniec konfiguracji ----------------------------------------------------

echo
echo -- tworzenie urzadzen --

PN=0 ; while (let $PN-$PORTNUMB) ; do
    DN=$[$[$DEVSTART]+$[$PN]]
    echo -n port $PN:
    if (test -e /dev/ttyS$DN) ; then
        echo /dev/ttyS$DN juz istnieje
    else
        echo /dev/ttyS$DN maj:4 min:$[64+$[$DN]]
        mknod /dev/ttyS$DN c 4 $[64+$[$DN]]
    fi

    echo -n port $PN:
    if (test -e /dev/cua$DN) ; then
        echo /dev/cua$DN juz istnieje
    else
        echo /dev/cua$DN maj:5 min:$[64+$[$DN]]
        mknod /dev/cua$DN c 5 $[64+$[$DN]]
    fi

    PN=$[$[$PN]+1]
done

echo
echo -- ustawienia portow --

PN=0 ; while (let $PN-$PORTNUMB) ; do
    DN=$[$[$DEVSTART]+$[$PN]]
    echo -n port $PN:
    setserial -v /dev/ttyS$DN port $[$[$BASE]+$[PN]*8] \
               irq $IRQ uart $UART $SPEED
    PN=$[$[$PN]+1]
done

echo
echo -- ustawienia karty wieloportowej --

setserial /dev/ttyS$DEVSTART set_multiport port1 $[$[$BASE]+7] \
           match1 0x00 \
           mask1 `if (let $PORTNUMB-4) ; then echo 0xff ; else echo 0xf; fi`
setserial /dev/ttyS$DEVSTART get_multiport

#
# -- koniec skryptu ---------------------------------------------------------