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

印刷ビューの終了

更新: 2014 年 9 月
 
 

DMA リソースの割り当て

DMA リソースは次の 2 つのインタフェースで割り当てられます。

DMA リソースは通常、ドライバの xxstart() ルーチンで割り当てられます (xxstart() ルーチンが存在する場合)。xxstart については、Asynchronous Data Transfers (Block Drivers)()を参照してください。これらの 2 つのインタフェースの構文は次のとおりです。

int ddi_dma_addr_bind_handle(ddi_dma_handle_t handle,
    struct as *as, caddr_t addr,
    size_t len, uint_t flags, int (*callback)(caddr_t),
    caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp);

int ddi_dma_buf_bind_handle(ddi_dma_handle_t handle,
    struct buf *bp, uint_t flags,
    int (*callback)(caddr_t), caddr_t arg,
    ddi_dma_cookie_t *cookiep, uint_t *ccountp);

次の引数は、ddi_dma_addr_bind_handle(9F) ddi_dma_buf_bind_handle(9F) の両方に共通です。

handle

DMA ハンドルと、リソースを割り当てるためのオブジェクトです。

flags

転送方向などの属性を指定するフラグセットです。DDI_DMA_READ はデバイスからメモリーへのデータ転送を指定します。DDI_DMA_WRITE はメモリーからデバイスへのデータ転送を指定します。利用できるフラグの詳細は、ddi_dma_addr_bind_handle(9F) または ddi_dma_buf_bind_handle(9F) のマニュアルページを参照してください。

callback

リソース割り当てエラーに対処するためのコールバック関数のアドレスです。 ddi_dma_alloc_handle(9F) のマニュアルページを参照してください。

arg

コールバック関数に渡される引数です。

cookiep

このオブジェクトの最初の DMA cookie へのポインタです。

ccountp

このオブジェクトの DMA cookie の数へのポインタです。

ddi_dma_addr_bind_handle(9F) の場合、オブジェクトは、次のパラメータでアドレス範囲を指定することによって記述します。

as

アドレス空間構造体へのポインタです。as の値は NULL になります。

addr

オブジェクトのベースカーネルアドレスです。

len

オブジェクトの長さをバイト単位で指定します。

ddi_dma_buf_bind_handle(9F) の場合、オブジェクトは、bp が指す buf(9S) 構造体で記述します。

デバイスレジスタ構造体

DMA 対応デバイスには、前述の例で使用したものよりも多くのレジスタが必要になります。

scatter/gather 機能を使わずに DMA 対応デバイスをサポートするには、デバイスレジスタ構造体で次のフィールドを使用します。

uint32_t      dma_addr;      /* starting address for DMA */
uint32_t      dma_size;      /* amount of data to transfer */

scatter/gather 機能を使って DMA 対応デバイスをサポートするには、デバイスレジスタ構造体で次のフィールドを使用します。

struct sglentry {
    uint32_t    dma_addr;
    uint32_t    dma_size;
} sglist[SGLLEN];

caddr_t       iopb_addr;     /* When written, informs the device of the next */
                             /* command's parameter block address. */
                             /* When read after an interrupt, contains */
                             /* the address of the completed command. */

DMA コールバックの例

Example 9–1 では、コールバック関数として xxstart() を使用します。また、xxstart() の引数としてデバイスごとの状態構造体を使用します。xxstart() 関数は、コマンドを開始しようとします。リソースが利用できないためにコマンドを開始できない場合、xxstart() はあとでリソースが利用可能になったときに呼び出されるようにスケジュールされます。

xxstart() は、DMA コールバックとして使用されるため、DMA コールバックに課せられている次の規則に従う必要があります。()

  • リソースは利用可能であると想定できない。コールバックでリソースの割り当てを再度試みる必要がある。

  • コールバックで、割り当てが成功したかどうかをシステムに知らせる必要がある。コールバックがリソースの割り当てに失敗すると、DDI_DMA_CALLBACK_RUNOUT が返されます。その場合は、あとで xxstart() を再度呼び出す必要があります。DDI_DMA_CALLBACK_DONE は成功を示しているため、これ以上コールバックは必要ありません。

使用例 9-1  DMA コールバックの例
static int
xxstart(caddr_t arg)
{
    struct xxstate *xsp = (struct xxstate *)arg;
    struct device_reg *regp;
    int flags;
    mutex_enter(&xsp->mu);
    if (xsp->busy) {
        /* transfer in progress */
        mutex_exit(&xsp->mu);
        return (DDI_DMA_CALLBACK_RUNOUT);
    }
    xsp->busy = 1;
    regp = xsp->regp;
    if ( /* transfer is a read */ ) {
        flags = DDI_DMA_READ;
    } else {
        flags = DDI_DMA_WRITE;
    }
    mutex_exit(&xsp->mu);
    if (ddi_dma_buf_bind_handle(xsp->handle,xsp->bp,flags, xxstart,
        (caddr_t)xsp, &cookie, &ccount) != DDI_DMA_MAPPED) {
        /* really should check all return values in a switch */
        mutex_enter(&xsp->mu);
        xsp->busy=0;
        mutex_exit(&xsp->mu);
        return (DDI_DMA_CALLBACK_RUNOUT);
    }
    /* Program the DMA engine. */
    return (DDI_DMA_CALLBACK_DONE);
}