在相应实例上的 attach(9E) 成功之前,可能会对次要设备调用 open(9E)。然后 open() 必须返回 ENXIO,这将导致系统尝试连接该设备。如果 attach() 成功,则会自动重试 open()。
/* * 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); } }
attach() 例程不能对不同设备实例上的调用顺序做出任何假设。系统可以并行调用不同设备实例上的 attach()。系统还可以在不同设备实例上同时调用 attach() 和 detach()。