Example 9-2 shows the required driver configuration
entry points _init(9E), _fini(9E),
and _info(9E).
In addition to installing the driver using mod_install(9F), the _init entry point also initializes the per-instance driver structure
using ddi_soft_state_init(9F). _fini(9E) performs the complementary calls to mod_remove(9F)
and ddi_soft_state_fini(9F) to unload the driver and release the resources used
by the soft-state routines.
Example 9-2 Configuration Entry Points
int
_init(void)
{
int e;
if ((e = ddi_soft_state_init(&lp_state,
sizeof (struct lp), 1)) != 0) {
return (e);
}
if ((e = mod_install(&modlinkage)) != 0) {
ddi_soft_state_fini(&lp_state);
}
return (e);
}
int
_fini(void)
{
int e;
if ((e = mod_remove(&modlinkage)) != 0) {
return (e);
}
ddi_soft_state_fini(&lp_state);
return (e);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
|
Example 9-3 shows the lp driver's
implementation of the initialization entry points. In lpidentify, the driver ensures that the name of the device being attached
is "lp".
lpattach first uses ddi_soft_state_zalloc(9F)
to allocate a per-instance structure for the printer being attached. Next
it creates a node in the device tree for the printer using ddi_create_minor_node(9F);
user programs use the node to access the device. lpattach
then registers the driver interrupt handler because the sample is driver pseudo-hardware,
the driver uses soft interrupts. A driver for a real printer would use ddi_add_intr(9F)
instead of ddi_add_softintr(9F). A driver for a real printer
would also need to perform any other required hardware initialization in lpattach. Finally, lpattach initializes the per-instance
mutex.
In lpdetach, the driver undoes everything it did
in lpattach.
lpgetinfo uses the soft-state structures to obtain
the required information.
Example 9-3 Initialization Entry Points
static int
lpidentify(dev_info_t *dip)
{
if (strcmp(ddi_get_name(dip), "lp") == 0) {
return (DDI_IDENTIFIED);
} else
return (DDI_NOT_IDENTIFIED);
}
static int
lpattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int instance;
struct lp *lpp;
switch (cmd) {
case DDI_ATTACH:
instance = ddi_get_instance(dip);
if (ddi_soft_state_zalloc(lp_state, instance) != DDI_SUCCESS) {
cmn_err(CE_CONT, "%s%d: can't allocate state\n",
ddi_get_name(dip), instance);
return (DDI_FAILURE);
} else
lpp = ddi_get_soft_state(lp_state, instance);
if (ddi_create_minor_node(dip, "strlp", S_IFCHR,
instance, NULL, 0) == DDI_FAILURE) {
ddi_remove_minor_node(dip, NULL);
goto attach_failed;
}
lpp->dip = dip;
ddi_set_driver_private(dip, (caddr_t)lpp);
/* add (soft) interrupt */
if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &lpp->siid,
&lpp->iblock_cookie, 0, lpintr, (caddr_t)lpp)
!= DDI_SUCCESS) {
ddi_remove_minor_node(dip, NULL);
goto attach_failed;
}
mutex_init(&lpp->lp_lock, "lp lock", MUTEX_DRIVER,
(void *)lpp->iblock_cookie);
ddi_report_dev(dip);
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
attach_failed:
/*
* Use our own detach routine to toss
* away any stuff we allocated above.
*/
(void) lpdetach(dip, DDI_DETACH);
return (DDI_FAILURE);
}
static int
lpdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
int instance;
struct lp *lpp;
switch (cmd) {
case DDI_DETACH:
/*
* Undo what we did in lpattach, freeing resources
* and removing things we installed. The system
* framework guarantees we are not active with this devinfo
* node in any other entry points at this time.
*/
ddi_prop_remove_all(dip);
instance = ddi_get_instance(dip);
lpp = ddi_get_soft_state(lp_state, instance);
ddi_remove_minor_node(dip, NULL);
ddi_remove_softintr(lpp->siid);
ddi_soft_state_free(lp_state, instance);
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
/*ARGSUSED*/
static int
lpgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result)
{
struct lp *lpp;
int error = DDI_FAILURE;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
if ((lpp = ddi_get_soft_state(lp_state,
getminor((dev_t)arg))) != NULL) {
*result = lpp->dip;
error = DDI_SUCCESS;
} else
*result = NULL;
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)getminor((dev_t)arg);
error = DDI_SUCCESS;
break;
default:
break;
}
return (error);
}
|