ioctl
Funkce je užitečná pro implementaci ovladače zařízení pro nastavení konfigurace na zařízení. např. tiskárna, která má možnosti konfigurace pro kontrolu a nastavení rodiny písem, velikosti písma atd. ioctl
lze použít k získání aktuálního písma a také k nastavení písma na nové. Uživatelská aplikace používá ioctl
k odeslání kódu do tiskárny, který jí řekne, že má vrátit aktuální písmo nebo nastavit písmo na nové.
int ioctl(int fd, int request, ...)
fd
je deskriptor souboru, který vracíopen
;request
je kód požadavku. např.GETFONT
získá aktuální písmo z tiskárny,SETFONT
nastaví písmo na tiskárně;- třetí argument je
void *
. V závislosti na druhém argumentu může nebo nemusí být přítomen třetí, např. pokud je druhý argumentSETFONT
, třetím argumentem může být název písma, například"Arial"
;
int request
není jen makro. Uživatelská aplikace je vyžadována ke generování kódu požadavku a modulu ovladače zařízení k určení, se kterou konfigurací na zařízení je třeba hrát. Aplikace odešle kód požadavku pomocí ioctl
a poté použije kód požadavku v modulu ovladače zařízení k určení, kterou akci provést.
Kód požadavku má 4 hlavní části
1. A Magic number - 8 bits
2. A sequence number - 8 bits
3. Argument type (typically 14 bits), if any.
4. Direction of data transfer (2 bits).
Pokud je kód požadavku SETFONT
pro nastavení písma na tiskárně bude směr přenosu dat z uživatelské aplikace do modulu ovladače zařízení (Uživatelská aplikace odešle název písma "Arial"
do tiskárny). Pokud je kód požadavku GETFONT
, směr je od tiskárny k uživatelské aplikaci.
Aby bylo možné vygenerovat kód požadavku, Linux poskytuje některá předdefinovaná makra podobná funkcím.
1._IO(MAGIC, SEQ_NO)
oba jsou 8 bitů, 0 až 255, např. řekněme, že chceme tiskárnu pozastavit. To nevyžaduje přenos dat. Vygenerovali bychom tedy kód požadavku, jak je uvedeno níže
#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM)
a nyní použijte ioctl
jako
ret_val = ioctl(fd, PAUSE_PRIN);
Odpovídající systémové volání v modulu ovladače obdrží kód a pozastaví tiskárnu.
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
aSEQ_NO
jsou stejné jako výše aTYPE
udává typ dalšího argumentu, připomene třetí argument zioctl
jevoid *
. W v__IOW
označuje, že datový tok je z uživatelské aplikace do modulu ovladače. Předpokládejme například, že chceme nastavit písmo tiskárny na"Arial"
.
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)
dále,
char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font);
Nyní font
je ukazatel, což znamená, že jde o adresu nejlépe reprezentovanou jako unsigned long
, tedy třetí část _IOW
zmiňuje typ jako takový. Tato adresa písma je také předána odpovídajícímu systémovému volání implementovanému v modulu ovladače zařízení jako unsigned long
a před použitím jej musíme přetypovat na správný typ. Prostor jádra může přistupovat k uživatelskému prostoru, a proto to funguje. další dvě makra podobná funkci jsou __IOR(MAGIC, SEQ_NO, TYPE)
a __IORW(MAGIC, SEQ_NO, TYPE)
kde tok dat bude probíhat z prostoru jádra do uživatelského prostoru a oběma způsoby.
Prosím, dejte mi vědět, jestli to pomůže!
ioctl
, což znamená, že „řízení vstupu a výstupu“ je druh systémového volání specifického pro zařízení. V Linuxu existuje jen několik systémových volání (300-400), která nestačí k vyjádření všech jedinečných funkcí, které zařízení mohou mít. Ovladač tedy může definovat ioctl, který umožňuje aplikaci v uživatelském prostoru odesílat příkazy. Ioctl však nejsou příliš flexibilní a mají tendenci být trochu nepřehledné (desítky „magických čísel“, která prostě fungují... nebo ne) a mohou být také nejisté, protože do jádra předáváte vyrovnávací paměť – špatná manipulace se může zlomit věci snadno.
Alternativou je sysfs
rozhraní, kde nastavíte soubor pod /sys/
a číst/zapisovat to, abyste získali informace z a do ovladače. Příklad, jak to nastavit:
static ssize_t mydrvr_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", DRIVER_RELEASE);
}
static DEVICE_ATTR(version, S_IRUGO, mydrvr_version_show, NULL);
A během nastavování ovladače:
device_create_file(dev, &dev_attr_version);
Pak byste měli soubor pro své zařízení ve formátu /sys/
, například /sys/block/myblk/version
pro blokový ovladač.
Další metodou pro náročnější použití je netlink, což je metoda IPC (inter-process communication) pro komunikaci s vaším ovladačem přes rozhraní soketu BSD. Toho využívají například ovladače WiFi. Poté s ním komunikujete z uživatelského prostoru pomocí libnl
nebo libnl3
knihovny.