编写设备驱动程序

程控 I/O 传输

程控 I/O 设备依赖 CPU 来执行数据传输。程控 I/O 数据传输与设备寄存器的其他读写操作相同。可使用各种数据访问例程,从设备内存读取值或向设备内存中存储值。

可以使用 uiomove(9F) 将数据传输到一些程控 I/O 设备。uiomove(9F)uio(9S) 结构所定义的用户空间与内核之间传输数据。uiomove() 可以处理缺页,因此不必锁定要向其传输数据的内存。uiomove() 还会更新 uio(9S) 结构中的 uio_resid 字段。以下示例说明了编写 ramdisk read(9E) 例程的一种方法。它使用同步 I/O,并依赖 ramdisk 状态结构中下列字段的存在:

caddr_t    ram;        /* base address of ramdisk */
int        ramsize;    /* size of the ramdisk */

示例 15–3 使用 uiomove(9F) 的 ramdisk read(9E) 例程

static int
rd_read(dev_t dev, struct uio *uiop, cred_t *credp)
{
     rd_devstate_t     *rsp;

     rsp = ddi_get_soft_state(rd_statep, getminor(dev));
     if (rsp == NULL)
       return (ENXIO);
     if (uiop->uio_offset >= rsp->ramsize)
       return (EINVAL);
     /*
      * uiomove takes the offset into the kernel buffer,
      * the data transfer count (minimum of the requested and
      * the remaining data), the UIO_READ flag, and a pointer
      * to the uio structure.
      */
     return (uiomove(rsp->ram + uiop->uio_offset,
         min(uiop->uio_resid, rsp->ramsize - uiop->uio_offset),
         UIO_READ, uiop));
}

另一个程控 I/O 示例是每次直接向设备内存中写入一字节数据的驱动程序。每一字节都是使用 uwritec(9F)uio(9S) 结构中检索到的。随后该字节被发送到设备中。read(9E) 可以使用 ureadc(9F) 将字节从设备传输到由 uio(9S) 结构描述的区域中。


示例 15–4 使用 uwritec(9F) 的程控 I/O write(9E) 例程

static int
xxwrite(dev_t dev, struct uio *uiop, cred_t *credp)
{
    int    value;
    struct xxstate     *xsp;

    xsp = ddi_get_soft_state(statep, getminor(dev));
    if (xsp == NULL)
        return (ENXIO);
    /* if the device implements a power manageable component, do this: */
    pm_busy_component(xsp->dip, 0);
    if (xsp->pm_suspended)
        pm_raise_power(xsp->dip, normal power);

    while (uiop->uio_resid > 0) {
        /*
         * do the programmed I/O access
         */
        value = uwritec(uiop);
        if (value == -1)
               return (EFAULT);
        ddi_put8(xsp->data_access_handle, &xsp->regp->data,
            (uint8_t)value);
        ddi_put8(xsp->data_access_handle, &xsp->regp->csr,
            START_TRANSFER);
        /*
         * this device requires a ten microsecond delay
         * between writes
         */
        drv_usecwait(10);
    }
    pm_idle_component(xsp->dip, 0);
    return (0);
}