编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

分配 DMA 资源

以下两个接口用于分配 DMA 资源:

如果存在驱动程序的 xxstart() 例程,则 DMA 资源通常在 xxstart() 例程中分配。有关 xxstart() 的讨论,请参见Asynchronous Data Transfers (Block Drivers)。这两个接口的语法如下所示:

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 功能的设备,要使用的寄存器比前面示例中所用寄存器多。

设备寄存器结构中使用以下字段来支持具有 DMA 功能但不支持分散/集中的设备:

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

设备寄存器结构中使用以下字段来支持具有 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 回调,因此 xxstart() 必须遵守以下规则,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);
}