Oracle® Solaris 11.2 デバイスドライバの記述

印刷ビューの終了

更新: 2014 年 9 月
 
 

ioctl() エントリポイント (文字ドライバ)

int xxioctl(dev_t dev, int cmd, intptr_t arg, int mode,
     cred_t *credp, int *rvalp);

cmd パラメータは、ioctl (9E) がどのコマンドを実行するべきかを示します。慣例により、入出力制御コマンドが関連付けられているドライバは、そのコマンドのビット 8 から 15 で示されます。通常は、文字の ASCII コードがドライバを表します。ドライバ固有のコマンドはビット 0 から 7 にあります。次の例には、いくつかの入出力コマンドの作成が示されています。

#define XXIOC            ('x' << 8)   /* 'x' is a character that represents device xx */
#define XX_GET_STATUS    (XXIOC | 1)  /* get status register */
#define XX_SET_CMD       (XXIOC | 2)  /* send command */

arg の解釈は、コマンドによって異なります。入出力制御コマンドは、ドライバのドキュメントまたはマニュアルページで説明されています。コマンドはまた、アプリケーションがコマンドの名前、コマンドが何を実行するか、およびコマンドが arg として何を受け入れるか、または返すかを判定できるように、公開ヘッダーファイルでも定義されます。ドライバとの間の arg のデータ転送はすべて、ドライバによって実行される必要があります。

フレームバッファーやディスクなどの特定のクラスのデバイスは、標準的な一連の入出力制御要求をサポートする必要があります。これらの標準の入出力制御インタフェースは、Solaris 8 のリファレンスドキュメントコレクションで説明されています。たとえば、 fbio(7I) ではフレームバッファーがサポートする必要のある入出力制御について、また dkio(7I) では標準のディスク入出力制御について説明しています。入出力制御の詳細については、Miscellaneous I/O Controlを参照してください。

ドライバは、arg のデータをユーザーレベルのアプリケーションからカーネルレベルに転送するために ddi_copyin(9F) を使用する必要があります。ドライバは、カーネルレベルからユーザーレベルにデータを転送するために ddi_copyout(9F) を使用する必要があります。ddi_copyin(9F) または ddi_copyout(9F) を使用しないと、2 つの条件でパニックが発生することがあります。アーキテクチャーによってカーネルとユーザーのアドレス空間が分離されている場合、またはユーザーアドレスがスワップアウトされている場合はパニックが発生します。

ioctl(9E) は通常、サポートされている各 ioctl (9E) 要求に対応するケースを含む switch 文です。

使用例 15-12  ioctl (9E) ルーチン
static int
xxioctl(dev_t dev, int cmd, intptr_t arg, int mode,
    cred_t *credp, int *rvalp)
{
    uint8_t        csr;
    struct xxstate     *xsp;

    xsp = ddi_get_soft_state(statep, getminor(dev));
    if (xsp == NULL) {
        return (ENXIO);
    }
    switch (cmd) {
    case XX_GET_STATUS:
        csr = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
        if (ddi_copyout(&csr, (void *)arg, sizeof (uint8_t), mode) != 0) {
            return (EFAULT);
        }
        break;
    case XX_SET_CMD:
        if (ddi_copyin((void *)arg, &csr, sizeof (uint8_t), mode) != 0) {
            return (EFAULT);
        }
        ddi_put8(xsp->data_access_handle, &xsp->regp->csr, csr);
        break;
    default:
        /* generic "ioctl unknown" error */
        return (ENOTTY);
    }
    return (0);
}

cmd 変数は、特定のデバイス制御操作を識別します。arg にユーザー仮想アドレスが含まれていると、問題が発生することがあります。 ioctl(9E) は、arg によって示されたアプリケーションプログラム内のデータ構造体とドライバの間でデータを転送するために ddi_copyin(9F) または ddi_copyout(9F) を呼び出す必要があります。Example 15–12 では、XX_GET_STATUS 要求のケースに対して、xsp->regp->csr の内容が arg 内のアドレスにコピーされます。ioctl(9E) は、成功した要求を行なった ioctl(2) システムコールへの戻り値として任意の整数値を *rvalp に格納できます。負の戻り値 (-1 など) は避けるべきです。多くのアプリケーションプログラムは、負の値が失敗を示すことを前提にしています。

次の例は、前の段落で説明した入出力制御を使用するアプリケーションを示しています。

使用例 15-13  ioctl (9E) の使用
#include <sys/types.h>
#include "xxio.h"     /* contains device's ioctl cmds and args */
int
main(void)
{
     uint8_t    status;
     /* ... */
     /*
      * read the device status
      */
     if (ioctl(fd, XX_GET_STATUS, &status) == -1) {
         /* error handling */
     }
     printf("device status %x\n", status);
     exit(0);
}