web-dev-qa-db-ja.com

IOCTL Linuxデバイスドライバー

誰も私を説明できますか、

  1. IOCTLとは何ですか?
  2. それは何に使用されますか?
  3. どうすれば使用できますか?
  4. IOCTLと同じ動作をする新しい関数を定義できないのはなぜですか?
113
flashdisk

__input_output_controlがデバイス固有のシステムコールの一種であることを意味するioctl。 Linuxにはわずかなシステムコール(300〜400)しかありません。これは、デバイスが持つ可能性があるすべての固有の機能を表現するには不十分です。そのため、ドライバーはioctlを定義できます。これにより、ユーザー空間アプリケーションは、オーダーを送信できます。ただし、ioctlはあまり柔軟性がなく、少し雑然とする傾向があり(機能するかどうかに関係なく、多数の「マジックナンバー」)、また、カーネルにバッファを渡すと安全でない可能性があります。簡単に。

代替手段はsysfsインターフェイスです。このインターフェイスでは、/sys/の下にファイルを設定し、それを読み書きしてドライバーとの間で情報を取得します。これを設定する方法の例:

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);

そして、ドライバーのセットアップ中:

device_create_file(dev, &dev_attr_version);

その後、デバイス用のファイルが/sys/にあります(たとえば、ブロックドライバーの場合は/sys/block/myblk/version)。

より重く使用する別の方法はnetlinkで、これはBSDソケットインターフェイスを介してドライバーと通信するIPC(プロセス間通信)メソッドです。これは、たとえばWiFiドライバーによって使用されます。その後、libnlまたはlibnl3ライブラリを使用して、ユーザー空間からそれと通信します。

85
Inductiveload

ioctl関数は、デバイスドライバーを実装してデバイスの構成を設定するのに役立ちます。例えばフォントファミリ、フォントサイズなどを確認および設定するための設定オプションを備えたプリンタ。ioctlを使用して、現在のフォントを取得したり、フォントを新しいフォントに設定したりできます。ユーザーアプリケーションは、ioctlを使用して、現在のフォントを返すか、フォントを新しいフォントに設定するように指示するコードをプリンターに送信します。

int ioctl(int fd, int request, ...)
  1. fdは、openによって返されるファイル記述子です。
  2. requestは要求コードです。例:GETFONTはプリンターから現在のフォントを取得し、SETFONTはプリンターのフォントを設定します。
  3. 3番目の引数はvoid *です。 2番目の引数に応じて、3番目の引数が存在する場合と存在しない場合があります。 2番目の引数がSETFONTの場合、3番目の引数は"Arial"などのフォント名になります。

int requestは単なるマクロではありません。ユーザーアプリケーションは、要求コードとデバイスドライバーモジュールを生成して、デバイス上のどの構成を再生する必要があるかを判断する必要があります。アプリケーションは、ioctlを使用して要求コードを送信し、デバイスドライバーモジュールの要求コードを使用して、実行するアクションを決定します。

要求コードには4つの主要部分があります

    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).  

プリンターにフォントを設定するための要求コードがSETFONTである場合、データ転送の方向はユーザーアプリケーションからデバイスドライバーモジュールになります(ユーザーアプリケーションはフォント名"Arial"をプリンターに送信します)。要求コードがGETFONTの場合、方向はプリンターからユーザーアプリケーションになります。

Linuxは、リクエストコードを生成するために、事前定義された関数のようなマクロをいくつか提供しています。

1 ._IO(MAGIC, SEQ_NO)は両方とも8ビット、0〜255です。プリンターを一時停止したいとします。これにはデータ転送は必要ありません。以下のようにリクエストコードを生成します

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 

そして今ioctl

ret_val = ioctl(fd, PAUSE_PRIN);

ドライバーモジュールの対応するシステムコールは、コードを受け取り、プリンターを一時停止します。

  1. __IOW(MAGIC, SEQ_NO, TYPE)MAGICSEQ_NOは上記と同じであり、TYPEは次の引数のタイプを示します。ioctlの3番目の引数はvoid *であることを思い出してください。 __IOWのWは、データフローがユーザーアプリケーションからドライバーモジュールへのものであることを示します。例として、プリンターフォントを"Arial"に設定したいとします。
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

さらに、

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 

現在、fontはポインターです。これは、unsigned longとして最も適切に表されるアドレスであることを意味します。したがって、_IOWの3番目の部分は、そのような型を示します。また、このフォントのアドレスは、デバイスドライバーモジュールに実装されている対応するシステムコールにunsigned longとして渡され、使用する前に適切なタイプにキャストする必要があります。カーネル空間はユーザー空間にアクセスできるため、これは機能します。他の2つの関数のようなマクロは__IOR(MAGIC, SEQ_NO, TYPE)__IORW(MAGIC, SEQ_NO, TYPE)で、データフローはそれぞれカーネル空間からユーザー空間へ、そしてその両方の方向になります。

これが役立つかどうか教えてください!

140
anukalp