segmap(9E) エントリポイントは、mmap(2) システムコールからリクエストされたメモリーマッピングを設定する役割を担います。多くのメモリーマップドデバイスに対応するドライバは、独自の segmap(9E) ルーチンを定義する代わりに、ddi_devmap_segmap(9F) をエントリポイントとして使用します。ドライバは、segmap() エントリポイントを提供することにより、マッピング作成の前後で一般的なタスクを処理できます。たとえば、ドライバ内でマッピング許可を確認し、非公開のマッピングリソースを割り当てることができます。また、ドライバ内でマッピングを調整し、ページ境界割り当てされていないデバイスバッファーに対応させることもできます。segmap() エントリポイントは、復帰する前に ddi_devmap_segmap(9F) 関数を呼び出す必要があります。ddi_devmap_segmap() 関数は、ドライバの devmap(9E) エントリポイントを呼び出すことで実際のマッピングを実行します。
segmap() 関数の構文は次のとおりです。
int segmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp);
ここでは:
マップするメモリーを含むデバイス。
マッピングの開始位置となる、デバイスメモリー内のオフセット。
デバイスメモリーのマッピング先となるアドレス空間へのポインタ。
この引数には、Example 10–1 に示した struct as *、Example 10–2 に示した ddi_as_handle_t のどちらを指定してもかまいません。これは、ddidevmap.h に次の宣言が含まれているからです。
typedef struct as *ddi_as_handle_t
デバイスメモリーのマッピング先となる、アドレス空間内のアドレスへのポインタ。
マップするメモリーの長さ (バイト)。
保護を指定するビットフィールド。指定可能な設定は、PROT_READ、PROT_WRITE、PROT_EXEC、PROT_USER、および PROT_ALL です。詳細はマニュアルページを参照してください。
試みられたマッピングで使用可能な最大の保護フラグ。ユーザーが特殊ファイルを読み取り専用で開いた場合には、PROT_WRITE ビットをマスキングして除外できます。
マッピングのタイプを示すフラグ。指定可能な値は MAP_SHARED と MAP_PRIVATE です。
ユーザー資格構造体へのポインタ。
次の例のドライバは、書き込み専用マッピングを許可するフレームバッファーを制御しています。このドライバは、アプリケーションが読み取りアクセス権の取得を試みた場合に EINVAL を返し、続いて ddi_devmap_segmap(9F) を呼び出してユーザーマッピングを設定しています。
使用例 10-1 segmap(9E) ルーチンstatic int xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp) { if (prot & PROT_READ) return (EINVAL); return (ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, cred)); }
次の例は、レジスタ空間内でページ境界割り当てされていないバッファーを持つデバイスの処理方法を示したものです。この例では、バッファーの先頭に対応するアドレスが mmap(2) から返されるように、オフセット 0x800 から始まるバッファーをマップしています。 devmap_devmem_setup(9F) 関数は、ページの全体をマップし、マッピングがページ境界割り当てされるように要求したあと、ページの先頭のアドレスを返します。このアドレスが segmap(9E) をパススルーしたり、segmap() エントリポイントが未定義の場合には、バッファーの先頭に対応するアドレスではなくページの先頭に対応するアドレスが mmap() から返されます。この例では、結果として返されるアドレスが目的とするバッファーの先頭位置になるように、devmap_devmem_setup からの戻り値であるページ境界割り当てされたアドレスに、バッファーのオフセットが加算されています。
使用例 10-2 mmap() 呼び出しから返されるアドレスを segmap() 関数を使用して変更する#define BUFFER_OFFSET 0x800 int xx_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp, off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp) { int rval; unsigned long pagemask = ptob(1L) - 1L; if ((rval = ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, credp)) == DDI_SUCCESS) { /* * The address returned by ddi_devmap_segmap is the start of the page * that contains the buffer. Add the offset of the buffer to get the * final address. */ *addrp += BUFFER_OFFSET & pagemask); } return (rval); }