编写设备驱动程序

设备访问函数

驱动程序结合使用 ddi_get8(9F)ddi_put8(9F) 系列例程以及 ddi_regs_map_setup(9F) 返回的句柄,以与设备相互传送数据。DDI 框架自动处理为满足主机或设备的字节序格式所需的任何字节交换,并强制实施设备可能具有的任何存储排序约束。

DDI 提供了用于传送 8 位、16 位、32 位和 64 位数据的接口,以及用于重复传送多个值的接口。有关这些接口的完整列表和说明,请参见 ddi_get8(9F)ddi_put8(9F)ddi_rep_get8(9F)ddi_rep_put8(9F) 系列例程的手册页。

以下示例建立在示例 7–1 的基础上,其中,驱动程序映射了设备的 CSR 寄存器和数据寄存器。在本示例中,调用驱动程序的 write(9E) 入口点时,会将数据缓冲区写入(每次一个字节)设备。


示例 7–2 映射设置:缓冲区

static  int
pio_write(dev_t dev, struct uio *uiop, cred_t *credp)
{
    int  retval;
    int  error = OK;
    Pio *pio_p = ddi_get_soft_state(pio_softstate, getminor(dev));
    if (pio_p == NULL)
    return (ENXIO);
    mutex_enter(&pio_p->mutex);
    /*
     * enable interrupts from the device by setting the Interrupt
     * Enable bit in the devices CSR register
     */
    ddi_put8(pio_p->csr_handle, pio_p->csr,
      (ddi_get8(pio_p->csr_handle, pio_p->csr) | PIO_INTR_ENABLE));
    while (uiop->uio_resid > 0) {
    /*
     * This device issues an IDLE interrupt when it is ready
     * to accept a character; the interrupt can be cleared
     * by setting PIO_INTR_CLEAR.  The interrupt is reasserted
     * after the next character is written or the next time
     * PIO_INTR_ENABLE is toggled on.
     *
     * wait for interrupt (see pio_intr)
     */
     cv_wait(&pio_p->cv, &pio_p->mutex);
     /*
      * get a character from the user's write request
      * fail the write request if any errors are encountered
      */
     if ((retval = uwritec(uiop)) == -1) {
         error = retval;
         break;
     }
     /*
      * pass the character to the device by writing it to
      * the device's data register
      */
     ddi_put8(pio_p->data_handle, pio_p->data, (uchar_t)retval);
    }
    /*
     * disable interrupts by clearing the Interrupt Enable bit
     * in the CSR
     */
    ddi_put8(pio_p->csr_handle, pio_p->csr,
      (ddi_get8(pio_p->csr_handle, pio_p->csr) & ~PIO_INTR_ENABLE));
    mutex_exit(&pio_p->mutex);
    return (error);
}

备用设备访问接口

除通过 ddi_get8(9F)ddi_put8(9F) 接口系列实现所有设备访问之外,Solaris OS 还提供特定于特殊总线实现的接口。虽然在某些平台上这些函数会更加有效,但使用这些例程会限制驱动程序在设备的各总线版本间保持可移植的能力。

访问内存空间

对于内存映射访问,设备寄存器会出现在内存地址空间中。驱动程序可以将 ddi_getX 系列例程和 ddi_putX 系列用作标准设备访问接口的备用接口。

访问 I/O 空间

对于 I/O 空间访问,设备寄存器会出现在 I/O 空间中,其中每个可寻址元素都称为 I/O 端口。驱动程序可以将 ddi_io_get8(9F)ddi_io_put8(9F) 例程用作标准设备访问接口的备用接口。

PCI 配置空间访问

要在不使用常规设备访问接口的情况下访问 PCI 配置空间,驱动程序需要通过调用 pci_config_setup(9F)(而非 ddi_regs_map_setup(9F))来映射 PCI 配置空间。然后,驱动程序可以调用 pci_config_get8(9F)pci_config_put8(9F) 接口系列,以访问 PCI 配置空间。