DMA リソースは次の 2 つのインタフェースで割り当てられます。
ddi_dma_buf_bind_handle(9F) – buf(9S) 構造体とともに使用されます
ddi_dma_addr_bind_handle(9F) – 仮想アドレスとともに使用されます
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) の両方に共通です。
DMA ハンドルと、リソースを割り当てるためのオブジェクトです。
転送方向などの属性を指定するフラグセットです。DDI_DMA_READ はデバイスからメモリーへのデータ転送を指定します。DDI_DMA_WRITE はメモリーからデバイスへのデータ転送を指定します。利用できるフラグの詳細は、ddi_dma_addr_bind_handle(9F) または ddi_dma_buf_bind_handle(9F) のマニュアルページを参照してください。
リソース割り当てエラーに対処するためのコールバック関数のアドレスです。 ddi_dma_alloc_handle(9F) のマニュアルページを参照してください。
コールバック関数に渡される引数です。
このオブジェクトの最初の DMA cookie へのポインタです。
このオブジェクトの DMA cookie の数へのポインタです。
ddi_dma_addr_bind_handle(9F) の場合、オブジェクトは、次のパラメータでアドレス範囲を指定することによって記述します。
アドレス空間構造体へのポインタです。as の値は NULL になります。
オブジェクトのベースカーネルアドレスです。
オブジェクトの長さをバイト単位で指定します。
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. */
Example 9–1 では、コールバック関数として xxstart() を使用します。また、xxstart() の引数としてデバイスごとの状態構造体を使用します。xxstart() 関数は、コマンドを開始しようとします。リソースが利用できないためにコマンドを開始できない場合、xxstart() はあとでリソースが利用可能になったときに呼び出されるようにスケジュールされます。
xxstart() は、DMA コールバックとして使用されるため、DMA コールバックに課せられている次の規則に従う必要があります。()
リソースは利用可能であると想定できない。コールバックでリソースの割り当てを再度試みる必要がある。
コールバックで、割り当てが成功したかどうかをシステムに知らせる必要がある。コールバックがリソースの割り当てに失敗すると、DDI_DMA_CALLBACK_RUNOUT が返されます。その場合は、あとで xxstart() を再度呼び出す必要があります。DDI_DMA_CALLBACK_DONE は成功を示しているため、これ以上コールバックは必要ありません。
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); }