Porty szeregowe i równoległe

Niektórym programom nie wystarcza działanie na samym procesorze czy sprzęcie znajdującym się w komputerze. Czasem trzeba połączyć się z jakimś urządzeniem zewnętrznym, takim jak modem zewnętrzny czy drukarka. Celem tego artykułu jest właśnie pokazanie, jak to zrobić.


Porty równoległe


(przeskocz porty równoległe)

Tutaj sprawa jest dość prosta. Porty równoległe nie wymagają żadnych ustawień, ewentualnie tylko tryb pracy, ustawiany w BIOSie. Praca z portem równoległym pod Linuksem sprowadza się do czytania i zapisu do specjalnych plików - /dev/parportN (N - liczba), które reprezentują porty równoległe. O tym, jak obsługiwać pliki, napisałem w kursie.


Porty szeregowe

Porty szeregowe są trudniejsze w obsłudze. Czasem wystarczy, podobnie jak dla portów równoległych, po prostu czytać i zapisywać do specjalnych plików, ale to nie zawsze może wystarczyć. Jest tak, gdyż porty szeregowe mają swoje ustawienia:

Pierwszym krokiem jest otwarcie specjalnego pliku urządzenia, zazwyczaj /dev/ttySx (x - liczba). O tym, jak otwierać pliki, zapisywać i odczytywać z nich dane, napisałem w kursie.

Jeśli trzeba ustawić parametry portu, wykonuje się to funkcją systemową sys_ioctl (numer 54). Przyjmuje ona w tym przypadku 3 argumenty:

Najpierw należy pobrać bieżące parametry portu, potem zmienić te, które chcemy i wysłać je do portu. Poniżej przedstawiam przykładowy kod w składni NASMa. Najpierw otwiera on plik portu, potem odczytuje bieżące argumenty, i ustawia nowe:

Wszystkie wykorzystane stałe można znaleźć w pliku /usr/include/bits/termios.h. Polecam zapoznanie się, gdyż można tam znaleźć wiele ciekawych opcji, na przykład automatyczne tłumaczenie znaków CR na LF i na odwrót.

	mov	eax, 5		; otwieranie pliku
	mov	ebx, port	; nazwa
	mov	ecx, 402o	; odczyt i zapis, nie terminal kontrolujący
	mov	edx, 777o	; rwx dla wszystkich
	int	80h

	cmp	eax, 0
	jl	koniec
	mov	ebx, eax	; EBX = deskryptor

	; pobieranie i ustawianie parametrów portu
%define TCGETS 0x00005401
%define TCSETS 0x00005402

	mov	eax, 54		; sys_ioctl
	;ebx = deskryptor
	mov	ecx, TCGETS	; pobierz parametry
	mov	edx, termios
	int	80h

	cmp	eax, 0
	jl	koniec

%define B115200  0010002o
%define CS8   0000060o
%define CLOCAL  0004000o
%define CREAD   0000200o
	mov dword [termios+__kernel_termios.c_cflag],B115200|CS8|CLOCAL|CREAD
%define INPCK   0000020o
	mov	dword [termios+__kernel_termios.c_iflag], INPCK
	mov	dword [termios+__kernel_termios.c_oflag], 0
%define ICANON  0000002o
	mov	dword [termios+__kernel_termios.c_lflag], ICANON
%define VKILL 3
%define VMIN 6
	mov	byte [termios+__kernel_termios.c_cc+VKILL], 0
	mov	byte [termios+__kernel_termios.c_cc+VMIN], 1

	mov	eax, 54		; sys_ioctl
	;ebx = deskryptor
	mov	ecx, TCSETS	; ustaw parametry
	mov	edx, termios
	int	80h

	cmp	eax, 0
	jnl	ioctl_set_ok
...
section .data
port		db	"/dev/ttyS0", 0
termios		istruc	__kernel_termios

Po wykonaniu tego kodu można normalnie czytać z urządzenia i zapisywać do niego jak do zwykłego pliku.

Na uwagę zasługuje wartość 402o wpisana do ECX przed otwarciem pliku. Mówi ona, że chcemy dostęp do odczytu i zapisu, ale dodatkowo włączona jest opcja O_NOCTTY (400o). Sprawi ona, że otwarte przez nas urządzenie znakowe NIE stanie się terminalem kontrolującym programu. W innym przypadku czytanie ze standardowego wejścia kończyłoby się czytaniem z wybranego portu szeregowego, a próba wyświetlenia napisu wysyłałaby bajty na ten port.

Polecam lekturę Serial Programming HOWTO.


Spis treści off-line (Alt+1)
Spis treści on-line (Alt+2)
Ułatwienia dla niepełnosprawnych (Alt+0)