Jak działają urządzenia znakowe lub specjalne pliki znakowe?


22

Próbuję zrozumieć specjalne pliki postaci. Z wikipedii rozumiem, że pliki te „zapewniają interfejs” dla urządzeń, które przesyłają dane po jednym znaku na raz. Rozumiem, że system w jakiś sposób wywołuje urządzenie znakowe zamiast bezpośrednio wywoływać sterownik urządzenia. Ale w jaki sposób plik zapewnia ten interfejs? Czy jest to plik wykonywalny, który tłumaczy wywołanie systemowe? Czy ktoś może wyjaśnić, co jest grane.

Odpowiedzi:


19

Są tak naprawdę - interfejsy. Zakodowane przez „większą” i „mniejszą” liczbę, zapewniają zaczepienie do jądra.

Występują w dwóch odmianach (cóż, trzech, ale nazwane potoki są na razie poza zakresem tego wyjaśnienia): Urządzenia postaci i Urządzenia bloku.

Urządzenia blokowe są zwykle urządzeniami pamięci masowej, zdolnymi do buforowania danych wyjściowych i przechowywania danych do późniejszego pobrania.

Urządzenia znakowe to takie rzeczy, jak karty audio lub graficzne lub urządzenia wejściowe, takie jak klawiatura i mysz.

W każdym przypadku, gdy jądro ładuje poprawny sterownik (podczas uruchamiania lub za pomocą programów takich jak udev ), skanuje różne magistrale, aby sprawdzić, czy jakieś urządzenia obsługiwane przez ten sterownik są rzeczywiście obecne w systemie. Jeśli tak, konfiguruje urządzenie, które „nasłuchuje” na odpowiednim numerze głównym / podrzędnym.

(Na przykład cyfrowy procesor sygnałowy pierwszej karty dźwiękowej znalezionej przez system otrzymuje parę liczb głównych / podrzędnych wynoszącą 14/3; druga otrzymuje 14,35 itd.)

Udev musi utworzyć wpis o /devnazwie dspjako urządzenie znakowe oznaczone jako główne 14 drugorzędne 3.

(W wersjach systemu Linux o znacznie starszych lub minimalnej powierzchni /dev/może nie być ładowane dynamicznie, ale tylko statycznie zawierać wszystkie możliwe pliki urządzeń).

Następnie, gdy program przestrzeni użytkownika próbuje uzyskać dostęp do pliku oznaczonego jako „specjalny plik znakowy” z odpowiednim numerem głównym / dodatkowym (na przykład odtwarzacz audio próbuje wysłać cyfrowy dźwięk /dev/dsp), jądro wie, że dane te muszą być przekazywane za pośrednictwem kierowcy, do którego dołączony jest numer główny / pomocniczy; prawdopodobnie powiedział, że kierowca wie z kolei, co z tym zrobić.


1
1. Czy liczby główne / drobne są analogiczne do portów?
bernie2436

2. Więc kiedy programy uzyskują dostęp do dowolnego pliku, jądro czyta te specjalne interfejsy, aby dowiedzieć się, czy program powinien odbierać przerwania z określonego urządzenia? Np .: jeśli program otwiera plik słowa, odczytuje plik specjalny urządzenia znakowego, aby wiedzieć, że program powinien reagować na wprowadzanie z klawiatury?
bernie2436

1) Nieco . To analogia biednego człowieka, ale da radę.
Shadur

2
2) Brakuje tam około trzech lub czterech warstw abstrakcji. Program, w którym otwierasz plik tekstowy, nie zna ani nie obchodzi, czym jest klawiatura. Komunikacja z podstawowym sprzętem odbywa się albo za pomocą emulatora terminali (jeśli jesteś w trybie konsoli) lub poprzez warstwę zdarzeń X (jeśli jesteś w trybie graficznym), z których jeden będzie nasłuchiwał klawiatury i innych napędów i zdecyduje, co , jeśli w ogóle, aby przejść do programu. Podsumowuję tutaj dość złożony system wielowarstwowy; możesz dobrze przeczytać w systemie X Window.
Shadur

1
Zauważ też, że w niektórych wersjach UN * X istnieją specjalne znaki dla urządzeń pamięci masowej; odczyt lub zapis do specjalnego pliku zmienia się w odczyt lub zapis do sekwencji bloków w urządzeniu. (W ostatnich wersjach FreeBSD, to są tylko pliki specjalne dla urządzeń pamięci masowej, nie żadne specjalne pliki blokowe.)

10

Każdy plik, urządzenie lub w inny sposób obsługuje 6 podstawowych operacji w VFS:

  1. otwarty
  2. Blisko
  3. Czytać
  4. pisać
  5. Szukać
  6. Powiedzieć

Ponadto pliki urządzeń obsługują kontrolę we / wy, co pozwala na wykonywanie innych operacji nieobjętych pierwszą 6.

W przypadku znaku specjalnego wyszukiwanie i mów nie są realizowane, ponieważ obsługują interfejs przesyłania strumieniowego . Oznacza to, że czytanie lub pisanie bezpośrednio, tak jak w przypadku przekierowania w powłoce:

echo 'foo' > /dev/some/char
sed ... < /dev/some/char

6

Minimalny możliwy do uruchomienia file_operationsprzykład

Gdy zobaczysz minimalny przykład, wszystko stanie się oczywiste.

Kluczowe pomysły to:

  • file_operations zawiera wywołania zwrotne dla każdego wywołania systemowego związanego z plikiem
  • mknod <path> c <major> <minor> tworzy urządzenie postaci, które je wykorzystuje file_operations
  • dla urządzeń znakowych, które dynamicznie przydzielają numery urządzeń (norma, aby uniknąć konfliktów), znajdź numer za pomocą cat /proc/devices

character_device.ko moduł jądra:

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <uapi/linux/stat.h> /* S_IRUSR */

#define NAME "lkmc_character_device"

MODULE_LICENSE("GPL");

static int major;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    size_t ret;
    char kbuf[] = {'a', 'b', 'c', 'd'};

    ret = 0;
    if (*off == 0) {
        if (copy_to_user(buf, kbuf, sizeof(kbuf))) {
            ret = -EFAULT;
        } else {
            ret = sizeof(kbuf);
            *off = 1;
        }
    }
    return ret;
}

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

static void myexit(void)
{
    unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)

Program testowy użytkownika:

insmod /character_device.ko
dev="lkmc_character_device"
major="$(grep "$dev" /proc/devices | cut -d ' ' -f 1)"
mknod "/dev/$dev" c "$major" 0
cat /dev/lkmc_character_device
# => abcd
rm /dev/lkmc_character_device
rmmod character_device

GitHub QEMU + Buildroot w górę z płytą grzewczą, aby go uruchomić:

Bardziej złożone przykłady:


To było bardzo pomocne dzięki! Tylko jedno pytanie, co dokładnie to robi *off = 1;i dlaczego jest ustawione 1?
SilverSlash

1
@SilverSlash ta wartość jest przekazywana przez wiele readwywołań do tego samego open(deskryptora pliku. Kierowca może przy tym robić co chce. Zazwyczaj semantyczny ma zawierać liczbę odczytanych bajtów. W tym przykładzie mamy tylko prostszy semantyczny: 0dla pierwszego czytania, 1po pierwszym czytaniu. Spróbuj go uruchomić i debuguj krok printk lub GDB.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

4

„Postać na raz” jest mylącą nazwą (podobnie jak idea, że ​​urządzenia postaci niekoniecznie obsługują wyszukiwanie i mówienie). W rzeczywistości urządzenia „blokuj na raz” (tj. Urządzenia ściśle zorientowane na zapis, takie jak napęd taśmowy *) muszą być urządzeniami znakowymi. Podobnie jest z ideą, że urządzenie znakowe musi koniecznie być niewidzialne - sterowniki urządzeń znakowych definiują pełną file_operationsstrukturę, która może dowolnie definiować lseek, czy nie, zależnie od tego, czy urządzenie obsługuje tę operację. Urządzenia postaci, które większość ludzi uważa za przykłady, to null, urandom, urządzenia TTY, karta dźwiękowa, mysz itp. i / dev / kmem są również urządzeniami postaci i wszystkie są widoczne.

Jak wspomniałem, sterownik urządzenia znakowego definiuje strukturę operacji file_operation, która ma wskaźniki funkcji dla wszystkich operacji, które ktoś może chcieć wywołać dla pliku - szukaj, czytaj, pisz, ioctl itp. - i każda z nich jest wywoływana raz, gdy odpowiednie wywołanie systemowe jest wykonywany przy otwartym pliku urządzenia. A zatem czytanie i pisanie może w ten sposób robić wszystko, co chce dzięki swoim argumentom - może odmówić przyjęcia zapisu, który jest zbyt duży lub pisać tylko to, co pasuje; może odczytać tylko dane odpowiadające jednemu rekordowi, a nie całej żądanej liczby bajtów.

Czym więc jest urządzenie blokowe? Zasadniczo urządzenia blokowe są dyskami. Żadne inne urządzenie (z wyjątkiem wirtualnych napędów dyskowych, takich jak ramdysk i pętla zwrotna) nie jest urządzeniem blokowym. Są one zintegrowane z systemem żądania we / wy, warstwą systemu plików, systemem bufora / pamięci podręcznej i systemem pamięci wirtualnej w sposób, w jaki nie są używane urządzenia znakowe, nawet gdy uzyskujesz dostęp np. / Dev / sda z procesu użytkownika . Nawet „surowe urządzenia”, o których strona wspomina jako wyjątek, są urządzeniami znakowymi .

* Niektóre systemy UNIX zaimplementowały tak zwany „tryb stałego bloku” - który pozwala grupom jądra i podzielonym żądaniom We / Wy dopasować skonfigurowane granice bloków mniej więcej tak samo, jak w przypadku napędów dyskowych - jako blok urządzenie. Urządzenie znakowe jest potrzebne do „trybu zmiennych bloków”, który zachowuje granice bloków z programu użytkownika, ponieważ pojedyncze wywołanie write (2) zapisuje jeden blok, a pojedyncze wywołanie read (2) zwraca jeden blok. Ponieważ przełączanie trybów jest teraz realizowane jako ioctl, a nie jako osobny plik urządzenia, używane jest urządzenie znakowe. Napędy taśmowe o zmiennych rekordach są w większości „niewidzialne”, ponieważ wyszukiwanie wymaga zliczenia liczby rekordów, a nie liczby bajtów, a natywna operacja wyszukiwania jest zaimplementowana jako ioctl.


1

Urządzenia znakowe mogą być tworzone przez moduły jądra (lub samo jądro). Podczas tworzenia urządzenia twórca udostępnia wskaźniki do funkcji, które implementują obsługę standardowych wywołań, takich jak open, read itp. Jądro Linux następnie kojarzy te funkcje z urządzeniem znakowym, na przykład gdy aplikacja w trybie użytkownika wywołuje funkcję read () funkcja w pliku urządzenia znakowego spowoduje wywołanie systemowe, a następnie jądro przekieruje to wywołanie do funkcji odczytu określonej podczas tworzenia sterownika. Jest to poradnik krok po kroku na stworzenie urządzenia znakowego tutaj można stworzyć przykładowy projekt i przejść przez nią za pomocą debuggera, aby zrozumieć, w jaki sposób tworzony jest obiekt urządzenie i kiedy teleskopowe są wywoływane.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.