在相应实例上的 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()。