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

印刷ビューの終了

更新: 2014 年 9 月
 
 

最初の転送の開始

キューへの登録を実装しているデバイスドライバは通常、start() ルーチンを備えています。start() は次の要求をキューから取り出し、デバイスとの間のデータ転送を開始します。この例では、start() はデバイスの状態 (ビジー状態か空いているか) には関係なく、すべての要求を処理します。


注 - start() は、任意のコンテキストから呼び出されるように記述する必要があります。start() は、カーネルコンテキスト内の strategy ルーチンと、割り込みコンテキスト内の割り込みルーチンの両方から呼び出すことができます。

start() は、アイドルのデバイスを起動できるように strategy() が要求をキューに入れるたびに strategy(9E) によって呼び出されます。デバイスがビジー状態の場合、start() はただちに復帰します。

start() はまた、取り込まれた割り込みから割り込みハンドラが復帰する前に、その割り込みハンドラからも呼び出されるため、空でないキューを処理できます。キューが空の場合、start() はただちに復帰します。

start() は非公開のドライバルーチンであるため、start() は任意の引数を取り、任意の型を返すことができます。次のコーディング例は、DMA コールバックとして使用するために記述されています (ただし、その部分は示されていません)。したがって、この例では caddr_t を引数として取り、int を返す必要があります。DMA コールバックルーチンの詳細については、Handling Resource Allocation Failuresを参照してください。

使用例 16-6  ブロックドライバに対する最初のデータ要求の開始
static int
xxstart(caddr_t arg)
{
    struct xxstate *xsp = (struct xxstate *)arg;
    struct buf *bp;

    mutex_enter(&xsp->mu);
    /*
     * If there is nothing more to do, or the device is
     * busy, return.
     */
    if (xsp->list_head == NULL || xsp->busy) {
       mutex_exit(&xsp->mu);
       return (0);
    }
    xsp->busy = 1;
    /* Get the first buffer off the transfer list */
    bp = xsp->list_head;
    /* Update the head and tail pointer */
    xsp->list_head = xsp->list_head->av_forw;
    if (xsp->list_head == NULL)
       xsp->list_tail = NULL;
    bp->av_forw = NULL;
    mutex_exit(&xsp->mu);
    /* 
     * If the device has power manageable components, 
     * mark the device busy with pm_busy_components(9F),
     * and then ensure that the device 
     * is powered up by calling pm_raise_power(9F).
     *
     * Set up DMA resources with ddi_dma_alloc_handle(9F) and
     * ddi_dma_buf_bind_handle(9F).
     */
    xsp->bp = bp;
    ddi_put32(xsp->data_access_handle, &xsp->regp->dma_addr,
        cookie.dmac_address);
    ddi_put32(xsp->data_access_handle, &xsp->regp->dma_size,
        (uint32_t)cookie.dmac_size);
    ddi_put8(xsp->data_access_handle, &xsp->regp->csr,
        ENABLE_INTERRUPTS | START_TRANSFER);
    return (0);
}