Writing Device Drivers

Deferred Attach

open(9E) might be called on a minor device before attach(9E) has succeeded on the corresponding instance. open(9E) must then return ENXIO, which will cause the system to attempt to attach the device. If the attach succeeds, the open is retried automatically.


Example 5-4 Example attach(9E) Entry Point

/*
 * Attach an instance of the driver.  We take all the knowledge we
 * have about our board and check it against what has been filled in for
 * us from our FCode or from our driver.conf(4) file.
 */
static int
xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    int instance;
    Pio *pio_p;
    ddi_device_acc_attr_t   da_attr;
    static int pio_validate_device(dev_info_t *);

    switch (cmd) {
    case DDI_ATTACH:

        /*
         * first validate the device conforms to a configuration this driver
         * supports
         */
        if (pio_validate_device(dip) == 0)
            return (DDI_FAILURE);

        /*
         * Allocate a soft state structure for this device instance
         * Store a pointer to the device node in our soft state structure
         * and a reference to the soft state structure in the device
         * node.
         */
        instance = ddi_get_instance(dip);
        if (ddi_soft_state_zalloc(pio_softstate, instance) != 0)
            return (DDI_FAILURE);
        pio_p = ddi_get_soft_state(pio_softstate, instance);
        ddi_set_driver_private(dip, (caddr_t)pio_p);
        pio_p->dip = dip;

        /*
         * Before adding the interrupt, get the interrupt block
         * cookie associated with the interrupt specification to
         * initialize the mutex used by the interrupt handler.
         */
        if (ddi_get_iblock_cookie(dip, 0, &pio_p->iblock_cookie) !=
          DDI_SUCCESS) {
            ddi_soft_state_free(pio_softstate, instance);
            return (DDI_FAILURE);
        }

        mutex_init(&pio_p->mutex, NULL, MUTEX_DRIVER, pio_p->iblock_cookie);

        /*
         * Now that the mutex is initialized, add the interrupt itself.
         */
        if (ddi_add_intr(dip, 0, NULL, NULL, pio_intr, (caddr_t)instance) !=
          DDI_SUCCESS) {
            mutex_destroy(&pio_p>mutex);
            ddi_soft_state_free(pio_softstate, instance);
            return (DDI_FAILURE);
        }


        /*
         * Initialize the device access attributes for the register
         * mapping
         */
        dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
        dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
        dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;

        /*
         * Map in the csr register (register 0)
         */
        if (ddi_regs_map_setup(dip, 0, (caddr_t *)&(pio_p->csr), 0,
            sizeof (Pio_csr), &dev_acc_attr, &pio_p->csr_handle) !=
            DDI_SUCCESS) {
            ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie);
            mutex_destroy(&pio_p->mutex);
            ddi_soft_state_free(pio_softstate, instance);
            return (DDI_FAILURE);
        }

        /*
         * Map in the data register (register 1)
         */
        if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(pio_p->data), 0,
            sizeof (uchar_t), &dev_acc_attr, &pio_p->data_handle) !=
            DDI_SUCCESS) {
            ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie);
            ddi_regs_map_free(&pio_p->csr_handle);
            mutex_destroy(&pio_p->mutex);
            ddi_soft_state_free(pio_softstate, instance);
            return (DDI_FAILURE);
        }

        /*
         * Create an entry in /devices for user processes to open(2)
         * This driver will create a minor node entry in /devices
         * of the form:  /devices/..../pio@X,Y:pio
         */
        if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
            instance, DDI_PSEUDO, 0) == DDI_FAILURE) {
            ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie);
            ddi_regs_map_free(&pio_p->csr_handle);
            ddi_regs_map_free(&pio_p->data_handle);
            mutex_destroy(&pio_p->mutex);
            ddi_soft_state_free(pio_softstate, instance);
            return (DDI_FAILURE);
        }

        /*
         * reset device (including disabling interrupts)
         */
        ddi_put8(pio_p->csr_handle, pio_p->csr, PIO_RESET);

        /*
         * report the name of the device instance which has attached
         */
        ddi_report_dev(dip);
        return (DDI_SUCCESS);

    case DDI_RESUME:
        return (DDI_SUCCESS);

    default:
        return (DDI_FAILURE);
    }

}