static void e_ddi_devid_hold_installed_driver(ddi_devid_t devid) { impl_devid_t *id = (impl_devid_t *)devid; major_t major, hint_major; char hint[DEVID_HINT_SIZE + 1]; char **drvp; int i; /* Count non-null bytes */ for (i = 0; i < DEVID_HINT_SIZE; i++) if (id->did_driver[i] == '\0') break; /* Make a copy of the driver hint */ bcopy(id->did_driver, hint, i); hint[i] = '\0'; /* search for the devid using the hint driver */ hint_major = ddi_name_to_major(hint); if (hint_major != (major_t)-1) { e_ddi_devid_hold_by_major(hint_major); } drvp = e_ddi_devid_hold_driver_list; for (i = 0; i < N_DRIVERS_TO_HOLD; i++, drvp++) { major = ddi_name_to_major(*drvp); if (major != (major_t)-1 && major != hint_major) { e_ddi_devid_hold_by_major(major); } } }
void load_platform_drivers(void) { dev_info_t *dip; /* dip of the isa driver */ /* * Install power driver which handles the power button. */ if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS) cmn_err(CE_WARN, "Failed to install \"power\" driver."); (void) ddi_hold_driver(ddi_name_to_major("power")); /* * It is OK to return error because 'us' driver is not available * in all clusters (e.g. missing in Core cluster). */ (void) i_ddi_attach_hw_nodes("us"); if (i_ddi_attach_hw_nodes("grbeep") != DDI_SUCCESS) cmn_err(CE_WARN, "Failed to install \"beep\" driver."); /* * mc-us3i must stay loaded for plat_get_mem_unum() */ if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS) cmn_err(CE_WARN, "mc-us3i driver failed to install"); (void) ddi_hold_driver(ddi_name_to_major("mc-us3i")); /* * Install Isa driver. This is required for the southbridge IDE * workaround - to reset the IDE channel during IDE bus reset. * Panic the system in case ISA driver could not be loaded or * any problem in accessing its pci config space. Since the register * to reset the channel for IDE is in ISA config space!. */ dip = e_ddi_hold_devi_by_path(ENCHILADA_ISA_PATHNAME, 0); if (dip == NULL) { cmn_err(CE_PANIC, "Could not install the isa driver\n"); return; } if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) { cmn_err(CE_PANIC, "Could not get the config space of isa\n"); return; } }
/* * For a given instance, load that driver and its parents */ static int load_parent_drivers(dev_info_t *dip, char *path) { int rval = 0; major_t major = (major_t)-1; char *drv; char *p; while (dip) { /* check for path-oriented alias */ if (path) major = ddi_name_to_major(path); else major = (major_t)-1; if (major != (major_t)-1) drv = ddi_major_to_name(major); else drv = ddi_binding_name(dip); if (load_boot_driver(drv) != 0) rval = -1; dip = ddi_get_parent(dip); if (path) { p = strrchr(path, '/'); if (p) *p = 0; } } return (rval); }
static int dr_resolve_devname(dev_info_t *dip, char *buffer, char *alias) { major_t devmajor; char *aka, *name; *buffer = *alias = 0; if (dip == NULL) return (-1); if ((name = ddi_get_name(dip)) == NULL) name = "<null name>"; aka = name; if ((devmajor = ddi_name_to_major(aka)) != -1) aka = ddi_major_to_name(devmajor); strcpy(buffer, name); if (strcmp(name, aka)) strcpy(alias, aka); else *alias = 0; return (0); }
static int lx_ptm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int err; if (cmd != DDI_ATTACH) return (DDI_FAILURE); if (ddi_create_minor_node(dip, LX_PTM_MINOR_NODE, S_IFCHR, ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) return (DDI_FAILURE); err = ldi_ident_from_dip(dip, &lps.lps_li); if (err != 0) { ddi_remove_minor_node(dip, ddi_get_name(dip)); return (DDI_FAILURE); } lps.lps_dip = dip; lps.lps_pts_major = ddi_name_to_major(LP_PTS_DRV_NAME); rw_init(&lps.lps_lh_rwlock, NULL, RW_DRIVER, NULL); lps.lps_lh_count = 0; lps.lps_lh_array = NULL; return (DDI_SUCCESS); }
/* ARGSUSED */ static int dr_check_dip(dev_info_t *dip, void *arg, uint_t ref) { major_t major; char *dname; struct dr_ref *rp = (struct dr_ref *)arg; if (dip == NULL) return (DDI_WALK_CONTINUE); if (!dr_is_real_device(dip)) return (DDI_WALK_CONTINUE); dname = ddi_binding_name(dip); if (dr_bypass_device(dname)) return (DDI_WALK_CONTINUE); if (dname && ((major = ddi_name_to_major(dname)) != (major_t)-1)) { if (ref && rp->refcount) { *rp->refcount += ref; PR_QR("\n %s (major# %d) is referenced(%u)\n", dname, major, ref); } if (dr_is_unsafe_major(major) && i_ddi_devi_attached(dip)) { PR_QR("\n %s (major# %d) not hotpluggable\n", dname, major); if (rp->arr != NULL && rp->idx != NULL) *rp->idx = dr_add_int(rp->arr, *rp->idx, rp->len, (uint64_t)major); } } return (DDI_WALK_CONTINUE); }
/* * Returns true if instance no. is already in use by named driver */ static int in_inuse(int instance, char *name) { major_t major; in_drv_t *dp; struct devnames *dnp; ASSERT(e_ddi_inst_state.ins_busy); /* * For now, if we've never heard of this device we assume it is not * in use, since we can't tell * XXX could do the weaker search through the nomajor list checking * XXX for the same name */ if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE) return (0); dnp = &devnamesp[major]; dp = dnp->dn_inlist; while (dp) { if (dp->ind_instance == instance) return (1); dp = dp->ind_next; } return (0); }
/*ARGSUSED*/ static int zfs_vfsinit(int fstype, char *name) { int error; zfsfstype = fstype; /* * Setup vfsops and vnodeops tables. */ error = vfs_setfsops(fstype, zfs_vfsops_template, &zfs_vfsops); if (error != 0) { cmn_err(CE_WARN, "zfs: bad vfs ops template"); } error = zfs_create_op_tables(); if (error) { zfs_remove_op_tables(); cmn_err(CE_WARN, "zfs: bad vnode ops template"); (void) vfs_freevfsops_by_type(zfsfstype); return (error); } mutex_init(&zfs_dev_mtx, NULL, MUTEX_DEFAULT, NULL); /* * Unique major number for all zfs mounts. * If we run out of 32-bit minors, we'll getudev() another major. */ zfs_major = ddi_name_to_major(ZFS_DRIVER); zfs_minor = ZFS_MIN_MINOR; return (0); }
static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { if (cmd != DDI_ATTACH) return (DDI_FAILURE); /* * We only support only one "instance". Note that * "instances" are different from minor units. * We get one (unique) minor unit per open. */ if (ddi_get_instance(dip) > 0) return (DDI_FAILURE); if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { cmn_err(CE_WARN, "nsmb_attach: create minor"); return (DDI_FAILURE); } /* * We need the major number a couple places, * i.e. in smb_dev2share() */ nsmb_major = ddi_name_to_major(NSMB_NAME); nsmb_dip = dip; ddi_report_dev(dip); return (DDI_SUCCESS); }
/* * This is a nasty, slow hack. But we're stuck with it until we do some * major surgery on the instance assignment subsystem, to allow pseudonode * instance assignment to be tracked there. * * To auto-assign an instance number, we exhaustively search the instance * list for each possible instance number until we find one which is unused. */ static int pseudonex_auto_assign(dev_info_t *child) { dev_info_t *tdip; kmutex_t *dmp; const char *childname = ddi_driver_name(child); major_t childmaj = ddi_name_to_major((char *)childname); int inst = 0; dmp = &devnamesp[childmaj].dn_lock; LOCK_DEV_OPS(dmp); for (inst = 0; inst <= MAXMIN32; inst++) { for (tdip = devnamesp[childmaj].dn_head; tdip != NULL; tdip = ddi_get_next(tdip)) { /* is this the current node? */ if (tdip == child) continue; if (inst == ddi_get_instance(tdip)) { break; } } if (tdip == NULL) { UNLOCK_DEV_OPS(dmp); return (inst); } } UNLOCK_DEV_OPS(dmp); return (-1); }
/* * This opens and closes the appropriate device with minor number - * hopefully, it will cause the driver to attach and register a controller * with us */ static vnode_t * rsmops_device_open(const char *major_name, const minor_t minor_num) { major_t maj; vnode_t *vp; int ret; if (minor_num == (minor_t)-1) { return (NULL); } maj = ddi_name_to_major((char *)major_name); if (maj == (major_t)-1) { return (NULL); } vp = makespecvp(makedevice(maj, minor_num), VCHR); ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL); if (ret == 0) { return (vp); } else { VN_RELE(vp); return (NULL); } }
/* * Load drivers required for a platform * Since all hardware nodes should be available in the device * tree, walk the per-driver list and load the parents of * each node found. If not a hardware node, try to load it. * Pseudo nexus is already loaded. */ static int load_boot_platform_modules(char *drv) { major_t major; dev_info_t *dip; char *drvname; int rval = 0; if ((major = ddi_name_to_major(drv)) == (major_t)-1) { cmn_err(CE_CONT, "%s: no major number\n", drv); return (-1); } /* * resolve aliases */ drvname = ddi_major_to_name(major); if ((major = ddi_name_to_major(drvname)) == (major_t)-1) return (-1); #ifdef DEBUG if (strcmp(drv, drvname) == 0) { BMDPRINTF(("load_boot_platform_modules: %s\n", drv)); } else { BMDPRINTF(("load_boot_platform_modules: %s -> %s\n", drv, drvname)); } #endif /* DEBUG */ dip = devnamesp[major].dn_head; if (dip == NULL) { /* pseudo node, not-enumerated, needs to be loaded */ if (modloadonly("drv", drvname) == -1) { cmn_err(CE_CONT, "%s: cannot load platform driver\n", drvname); rval = -1; } } else { while (dip) { if (load_parent_drivers(dip, NULL) != 0) rval = -1; dip = ddi_get_next(dip); } } return (rval); }
/* * Starting from the root node suspend all devices in the device tree. * Assumes that all devices have already been marked busy. */ static int sbdp_suspend_devices_(dev_info_t *dip, sbdp_sr_handle_t *srh) { major_t major; char *dname; for (; dip != NULL; dip = ddi_get_next_sibling(dip)) { char d_name[40], d_alias[40], *d_info; if (sbdp_suspend_devices_(ddi_get_child(dip), srh)) { return (ENXIO); } if (!sbdp_is_real_device(dip)) continue; major = (major_t)-1; if ((dname = DEVI(dip)->devi_binding_name) != NULL) major = ddi_name_to_major(dname); #ifdef DEBUG if (sbdp_bypass_device(dname)) { SBDP_DBG_QR("bypassed suspend of %s (major# %d)\n", dname, major); continue; } #endif if ((d_info = ddi_get_name_addr(dip)) == NULL) d_info = "<null>"; d_name[0] = 0; if (sbdp_resolve_devname(dip, d_name, d_alias) == 0) { if (d_alias[0] != 0) { SBDP_DBG_QR("\tsuspending %s@%s (aka %s)\n", d_name, d_info, d_alias); } else { SBDP_DBG_QR("\tsuspending %s@%s\n", d_name, d_info); } } else { SBDP_DBG_QR("\tsuspending %s@%s\n", dname, d_info); } if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) { (void) sprintf(sbdp_get_err_buf(&srh->sep), "%d", major); sbdp_set_err(&srh->sep, ESGT_SUSPEND, NULL); ndi_hold_devi(dip); SR_FAILED_DIP(srh) = dip; return (DDI_FAILURE); } } return (DDI_SUCCESS); }
static int zfs_create_unique_device(dev_t *dev) { major_t new_major; do { ASSERT3U(zfs_minor, <=, MAXMIN32); minor_t start = zfs_minor; do { mutex_enter(&zfs_dev_mtx); if (zfs_minor >= MAXMIN32) { /* * If we're still using the real major * keep out of /dev/zfs and /dev/zvol minor * number space. If we're using a getudev()'ed * major number, we can use all of its minors. */ if (zfs_major == ddi_name_to_major(ZFS_DRIVER)) zfs_minor = ZFS_MIN_MINOR; else zfs_minor = 0; } else { zfs_minor++; } *dev = makedevice(zfs_major, zfs_minor); mutex_exit(&zfs_dev_mtx); } while (vfs_devismounted(*dev) && zfs_minor != start); if (zfs_minor == start) { /* * We are using all ~262,000 minor numbers for the * current major number. Create a new major number. */ if ((new_major = getudev()) == (major_t)-1) { cmn_err(CE_WARN, "zfs_mount: Can't get unique major " "device number."); return (-1); } mutex_enter(&zfs_dev_mtx); zfs_major = new_major; zfs_minor = 0; mutex_exit(&zfs_dev_mtx); } else { break; } /* CONSTANTCONDITION */ } while (1); return (0); }
/* * If the bridge is empty, disable it */ int npe_disable_empty_bridges_workaround(dev_info_t *child) { /* * Do not bind drivers to empty bridges. * Fail above, if the bridge is found to be hotplug capable */ if (ddi_driver_major(child) == ddi_name_to_major("pcieb") && ddi_get_child(child) == NULL && ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE) return (1); return (0); }
int _init(void) { int error; (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); /* Can initialize some mutexes also. */ mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); /* * Create a major name and number. */ nsmb_major = ddi_name_to_major(NSMB_NAME); nsmb_minor = 0; /* Connection data structures. */ (void) smb_sm_init(); /* Initialize password Key chain DB. */ smb_pkey_init(); /* Time conversion stuff. */ smb_time_init(); /* Initialize crypto mechanisms. */ smb_crypto_mech_init(); zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, nsmb_zone_destroy); /* * Install the module. Do this after other init, * to prevent entrances before we're ready. */ if ((error = mod_install((&nsmb_modlinkage))) != 0) { /* Same as 2nd half of _fini */ (void) zone_key_delete(nsmb_zone_key); smb_pkey_fini(); smb_sm_done(); mutex_destroy(&dev_lck); ddi_soft_state_fini(&statep); return (error); } return (0); }
/*ARGSUSED*/ static int mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0) { struct modctl *mcp; char *mod_name; if ((mcp = mod_getctl(modlp)) == NULL) { *p0 = -1; return (0); /* driver is not yet installed */ } mod_name = mcp->mod_modname; *p0 = ddi_name_to_major(mod_name); return (0); }
static void in_hashdrv(in_drv_t *dp) { struct devnames *dnp; in_drv_t *mp, *pp; major_t major; /* hash to no major list */ major = ddi_name_to_major(dp->ind_driver_name); if (major == DDI_MAJOR_T_NONE) { dp->ind_next = e_ddi_inst_state.ins_no_major; e_ddi_inst_state.ins_no_major = dp; return; } /* * dnp->dn_inlist is sorted by instance number. * Adding a new instance entry may introduce holes, * set dn_instance to IN_SEARCHME so the next instance * assignment may fill in holes. */ dnp = &devnamesp[major]; pp = mp = dnp->dn_inlist; if (mp == NULL || dp->ind_instance < mp->ind_instance) { /* prepend as the first entry, turn on IN_SEARCHME */ dnp->dn_instance = IN_SEARCHME; dp->ind_next = mp; dnp->dn_inlist = dp; return; } ASSERT(mp->ind_instance != dp->ind_instance); while (mp->ind_instance < dp->ind_instance && mp->ind_next) { pp = mp; mp = mp->ind_next; ASSERT(mp->ind_instance != dp->ind_instance); } if (mp->ind_instance < dp->ind_instance) { /* end of list */ dp->ind_next = NULL; mp->ind_next = dp; } else { ASSERT(dnp->dn_instance == IN_SEARCHME); dp->ind_next = pp->ind_next; pp->ind_next = dp; } }
static void create_devinfo_tree(void) { major_t major; pnode_t nodeid; i_ddi_node_cache_init(); #if defined(__sparc) nodeid = prom_nextnode(0); #else /* x86 */ nodeid = DEVI_SID_NODEID; #endif top_devinfo = i_ddi_alloc_node(NULL, rootname, nodeid, -1, NULL, KM_SLEEP); ndi_hold_devi(top_devinfo); /* never release the root */ i_ddi_add_devimap(top_devinfo); /* * Bind root node. * This code is special because root node has no parent */ major = ddi_name_to_major("rootnex"); ASSERT(major != DDI_MAJOR_T_NONE); DEVI(top_devinfo)->devi_major = major; devnamesp[major].dn_head = top_devinfo; i_ddi_set_binding_name(top_devinfo, rootname); i_ddi_set_node_state(top_devinfo, DS_BOUND); /* * Record that devinfos have been made for "rootnex." * di_dfs() is used to read the prom because it doesn't get the * next sibling until the function returns, unlike ddi_walk_devs(). */ di_dfs(ddi_root_node(), get_neighbors, 0); #if !defined(__sparc) /* * On x86, there is no prom. Create device tree by * probing pci config space */ { extern void impl_setup_ddi(void); impl_setup_ddi(); } #endif /* x86 */ }
static int sbdp_check_dip(dev_info_t *dip, void *arg, uint_t ref) { char *dname; sbdp_ref_t *sbrp = (sbdp_ref_t *)arg; if (dip == NULL) return (DDI_WALK_CONTINUE); ASSERT(sbrp->sep != NULL); ASSERT(sbrp->refcount != NULL); if (!sbdp_is_real_device(dip)) return (DDI_WALK_CONTINUE); dname = ddi_binding_name(dip); if ((strcmp(dname, "pciclass,060940") == 0) || (strcmp(dname, "pciclass,060980") == 0)) { (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); (*sbrp->refcount)++; return (DDI_WALK_TERMINATE); } #ifdef DEBUG if (sbdp_bypass_device(dname)) return (DDI_WALK_CONTINUE); #endif if (ref) { (*sbrp->refcount)++; SBDP_DBG_QR("\n%s (major# %d) is referenced\n", dname, ddi_name_to_major(dname)); (void) ddi_pathname(dip, sbdp_get_err_buf(sbrp->sep)); sbdp_set_err(sbrp->sep, ESBD_BUSY, NULL); return (DDI_WALK_TERMINATE); } return (DDI_WALK_CONTINUE); }
int _init() { int ret; if (ddi_name_to_major(EIB_DRV_NAME) == (major_t)-1) return (ENODEV); if ((ret = ddi_soft_state_init(&eib_state, sizeof (eib_t), 0)) != 0) return (ret); mac_init_ops(&eib_ops, EIB_DRV_NAME); if ((ret = mod_install(&eib_modlinkage)) != 0) { mac_fini_ops(&eib_ops); ddi_soft_state_fini(&eib_state); return (ret); } eib_debug_init(); return (ret); }
static char * plat_devpath(char *name, char *path) { major_t major; dev_info_t *dip, *pdip; if ((major = ddi_name_to_major(name)) == (major_t)-1) return (NULL); if ((dip = devnamesp[major].dn_head) == NULL) return (NULL); pdip = ddi_get_parent(dip); if (i_ddi_attach_node_hierarchy(pdip) != DDI_SUCCESS) return (NULL); if (ddi_initchild(pdip, dip) != DDI_SUCCESS) return (NULL); (void) ddi_pathname(dip, path); return (path); }
static char * plat_ttypath(int inum) { static char *defaultpath[] = { "/isa/asy@1,3f8:a", "/isa/asy@1,2f8:b" }; static char path[MAXPATHLEN]; char *bp; major_t major; dev_info_t *dip; if (pseudo_isa) return (defaultpath[inum]); if ((major = ddi_name_to_major("asy")) == (major_t)-1) return (NULL); if ((dip = devnamesp[major].dn_head) == NULL) return (NULL); for (; dip != NULL; dip = ddi_get_next(dip)) { if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS) return (NULL); if (DEVI(dip)->devi_minor->ddm_name[0] == ('a' + (char)inum)) break; } if (dip == NULL) return (NULL); (void) ddi_pathname(dip, path); bp = path + strlen(path); (void) snprintf(bp, 3, ":%s", DEVI(dip)->devi_minor->ddm_name); return (path); }
static int pseudonex_check_assignment(dev_info_t *child, int test_inst) { dev_info_t *tdip; kmutex_t *dmp; const char *childname = ddi_driver_name(child); major_t childmaj = ddi_name_to_major((char *)childname); dmp = &devnamesp[childmaj].dn_lock; LOCK_DEV_OPS(dmp); for (tdip = devnamesp[childmaj].dn_head; tdip != NULL; tdip = ddi_get_next(tdip)) { /* is this the current node? */ if (tdip == child) continue; /* is this a duplicate instance? */ if (test_inst == ddi_get_instance(tdip)) { UNLOCK_DEV_OPS(dmp); return (DDI_FAILURE); } } UNLOCK_DEV_OPS(dmp); return (DDI_SUCCESS); }
void load_platform_drivers(void) { dev_info_t *dip; /* dip of the isa driver */ /* * Install 'us' driver. */ (void) i_ddi_attach_hw_nodes("us"); /* * mc-us3i must stay loaded for plat_get_mem_unum() */ if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS) cmn_err(CE_WARN, "mc-us3i driver failed to install"); (void) ddi_hold_driver(ddi_name_to_major("mc-us3i")); /* * Install Isa driver. This is required for the southbridge IDE * workaround - to reset the IDE channel during IDE bus reset. * Panic the system in case ISA driver could not be loaded or * any problem in accessing its pci config space. Since the register * to reset the channel for IDE is in ISA config space!. */ dip = e_ddi_hold_devi_by_path(SCHUMACHER_ISA_PATHNAME, 0); if (dip == NULL) { cmn_err(CE_PANIC, "Could not install the isa driver\n"); return; } if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) { cmn_err(CE_PANIC, "Could not get the config space of isa\n"); return; } }
/* * dm2s_attach - Module's attach routine. */ int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance; dm2s_t *dm2sp; char name[20]; instance = ddi_get_instance(dip); /* Only one instance is supported. */ if (instance != 0) { cmn_err(CE_WARN, "only one instance is supported"); return (DDI_FAILURE); } if (cmd != DDI_ATTACH) { return (DDI_FAILURE); } if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { cmn_err(CE_WARN, "softstate allocation failure"); return (DDI_FAILURE); } dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); if (dm2sp == NULL) { ddi_soft_state_free(dm2s_softstate, instance); cmn_err(CE_WARN, "softstate allocation failure."); return (DDI_FAILURE); } dm2sp->ms_dip = dip; dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip)); dm2sp->ms_ppa = instance; /* * Get an interrupt block cookie corresponding to the * interrupt priority of the event handler. * Assert that the event priority is not re-defined to * some higher priority. */ /* LINTED */ ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, &dm2sp->ms_ibcookie) != DDI_SUCCESS) { cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); goto error; } mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, (void *)dm2sp->ms_ibcookie); dm2sp->ms_clean |= DM2S_CLEAN_LOCK; cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); dm2sp->ms_clean |= DM2S_CLEAN_CV; (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); if (ddi_create_minor_node(dip, name, S_IFCHR, instance, DDI_PSEUDO, NULL) == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); cmn_err(CE_WARN, "Device node creation failed."); goto error; } dm2sp->ms_clean |= DM2S_CLEAN_NODE; ddi_set_driver_private(dip, (caddr_t)dm2sp); ddi_report_dev(dip); return (DDI_SUCCESS); error: dm2s_cleanup(dm2sp); return (DDI_FAILURE); }
void load_platform_drivers(void) { extern int watchdog_available; extern int watchdog_enable; dev_info_t *dip; /* dip of the isa driver */ int simba_present = 0; dev_info_t *root_child_node; major_t major; if (ddi_install_driver("power") != DDI_SUCCESS) cmn_err(CE_WARN, "Failed to install \"power\" driver."); /* * Install Isa driver. This is required for the southbridge IDE * workaround - to reset the IDE channel during IDE bus reset. * Panic the system in case ISA driver could not be loaded or * any problem in accessing its pci config space. Since the register * to reset the channel for IDE is in ISA config space!. */ root_child_node = ddi_get_child(ddi_root_node()); while (root_child_node != NULL) { if (strcmp(ddi_node_name(root_child_node), "pci") == 0) { root_child_node = ddi_get_child(root_child_node); if (strcmp(ddi_node_name(root_child_node), "pci") == 0) simba_present = 1; break; } root_child_node = ddi_get_next_sibling(root_child_node); } if (simba_present) dip = e_ddi_hold_devi_by_path(PLATFORM_ISA_PATHNAME_WITH_SIMBA, 0); else dip = e_ddi_hold_devi_by_path(PLATFORM_ISA_PATHNAME, 0); if (dip == NULL) { cmn_err(CE_PANIC, "Could not install the isa driver\n"); return; } if (pci_config_setup(dip, &platform_isa_handle) != DDI_SUCCESS) { cmn_err(CE_PANIC, "Could not get the config space of isa\n"); return; } /* * Load the blade support chip driver. * */ if (((major = ddi_name_to_major(BSC_DRV)) == -1) || (ddi_hold_installed_driver(major) == NULL)) { cmn_err(CE_WARN, "%s: failed to load", BSC_DRV); } else { bsc_drv_func_ptr = (void (*)(struct bscv_idi_info *)) modgetsymvalue(BSC_DRV_FUNC, 0); if (bsc_drv_func_ptr == NULL) { cmn_err(CE_WARN, "load_platform_defaults: %s()" " not found; signatures will not be updated\n", BSC_DRV_FUNC); watchdog_available = 0; if (watchdog_enable) { cmn_err(CE_WARN, "load_platform_defaults: %s()" " not found; BSC OS watchdog service not available\n", BSC_DRV_FUNC); } } } }
/* * Install a new driver */ static int mod_installdrv(struct modldrv *modl, struct modlinkage *modlp) { struct modctl *mcp; struct dev_ops *ops; char *modname; major_t major; struct dev_ops *dp; struct devnames *dnp; struct streamtab *str; cdevsw_impl_t *cdp; uint_t sqtype; uint_t qflag; uint_t flag; int err = 0; /* sanity check module */ if ((mcp = mod_getctl(modlp)) == NULL) { cmn_err(CE_WARN, "mod_install: bad module linkage data"); err = ENXIO; goto done; } modname = mcp->mod_modname; /* Sanity check modname */ if ((major = ddi_name_to_major(modname)) == (major_t)-1) { #ifdef DEBUG cmn_err(CE_WARN, "mod_installdrv: no major number for %s", modname); #endif err = ENXIO; goto done; } /* Verify MP safety flag */ ops = modl->drv_dev_ops; if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL && !(ops->devo_cb_ops->cb_flag & D_MP)) { cmn_err(CE_WARN, "mod_installdrv: MT-unsafe driver '%s' rejected", modname); err = ENXIO; goto done; } /* Is bus_map_fault signature correct (version 8 and higher)? */ if (ops->devo_bus_ops != NULL && ops->devo_bus_ops->bus_map_fault != NULL && ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault && ops->devo_bus_ops->busops_rev < BUSO_REV_8) { cmn_err(CE_WARN, "mod_installdrv: busops' revision of '%s' is too low" " (must be at least 8)", modname); err = ENXIO; goto done; } /* Make sure the driver is uninstalled */ dnp = &devnamesp[major]; LOCK_DEV_OPS(&dnp->dn_lock); dp = devopsp[major]; if (dnp->dn_flags & DN_DRIVER_REMOVED) { #ifdef DEBUG cmn_err(CE_NOTE, "mod_installdrv: driver has been removed %s", modname); #endif err = ENXIO; goto unlock; } if (dp != &nodev_ops && dp != &mod_nodev_ops) { cmn_err(CE_WARN, "mod_installdrv: driver already installed %s", modname); err = EALREADY; goto unlock; } devopsp[major] = ops; /* setup devopsp */ if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ flag = CBFLAG(major); if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0) goto unlock; cdp = &devimpl[major]; ASSERT(cdp->d_str == NULL); cdp->d_str = str; cdp->d_qflag = qflag | QISDRV; cdp->d_sqtype = sqtype; } if (ops->devo_bus_ops == NULL) dnp->dn_flags |= DN_LEAF_DRIVER; unlock: UNLOCK_DEV_OPS(&dnp->dn_lock); done: return (err); }
static int mod_removedrv(struct modldrv *modl, struct modlinkage *modlp) { struct modctl *mcp; struct dev_ops *ops; struct devnames *dnp; struct dev_ops *dp; major_t major; char *modname; extern kthread_id_t mod_aul_thread; struct streamtab *str; cdevsw_impl_t *cdp; int err = 0; /* Don't auto unload modules on if moddebug flag is set */ if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) { err = EBUSY; goto done; } /* Verify modname has a driver major */ mcp = mod_getctl(modlp); ASSERT(mcp != NULL); modname = mcp->mod_modname; if ((major = ddi_name_to_major(modname)) == -1) { cmn_err(CE_WARN, uninstall_err, modname); err = EINVAL; goto done; } ops = modl->drv_dev_ops; dnp = &(devnamesp[major]); LOCK_DEV_OPS(&(dnp->dn_lock)); dp = devopsp[major]; if (dp != ops) { cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s", modname); err = EBUSY; goto unlock; } /* * A driver is not unloadable if its dev_ops are held */ if (!DRV_UNLOADABLE(dp)) { mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>," " refcnt %d\n", modname, dp->devo_refcnt); err = EBUSY; goto unlock; } /* * OK to unload. */ if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ cdp = &devimpl[major]; ASSERT(cdp->d_str == str); cdp->d_str = NULL; /* check for reference to per-dev syncq */ if (cdp->d_dmp != NULL) { rele_dm(cdp->d_dmp); cdp->d_dmp = NULL; } } devopsp[major] = &mod_nodev_ops; dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH); unlock: UNLOCK_DEV_OPS(&(dnp->dn_lock)); done: return (err); }
void load_platform_drivers(void) { /* * It is OK to return error because 'us' driver is not available * in all clusters (e.g. missing in Core cluster). */ (void) i_ddi_attach_hw_nodes("us"); /* * mc-us3i must stay loaded for plat_get_mem_unum() */ if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS) cmn_err(CE_WARN, "mc-us3i driver failed to install"); (void) ddi_hold_driver(ddi_name_to_major("mc-us3i")); /* * load the power button driver */ if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS) cmn_err(CE_WARN, "power button driver failed to install"); (void) ddi_hold_driver(ddi_name_to_major("power")); /* * load the GPIO driver for the ALOM reset and watchdog lines */ if (i_ddi_attach_hw_nodes("pmugpio") != DDI_SUCCESS) cmn_err(CE_WARN, "pmugpio failed to install"); else { extern int watchdog_enable, watchdog_available; extern int disable_watchdog_on_exit; /* * Disable an active h/w watchdog timer upon exit to OBP. */ disable_watchdog_on_exit = 1; watchdog_enable = 1; watchdog_available = 1; } (void) ddi_hold_driver(ddi_name_to_major("pmugpio")); /* * Figure out which mi2cv dip is shared with OBP for the nvram * device, so the lock can be acquired. */ shared_mi2cv_dip = e_ddi_hold_devi_by_path(SHARED_MI2CV_PATH, 0); /* * Load the environmentals driver (rmclomv) * * We need this driver to handle events from the RMC when state * changes occur in the environmental data. */ if (i_ddi_attach_hw_nodes("rmc_comm") != DDI_SUCCESS) { cmn_err(CE_WARN, "rmc_comm failed to install"); } else { (void) ddi_hold_driver(ddi_name_to_major("rmc_comm")); if (e_ddi_hold_devi_by_path(RMCLOMV_PATHNAME, 0) == NULL) { cmn_err(CE_WARN, "Could not install rmclomv driver\n"); } } /* * These two dummy functions are loaded over the original * todm5823 set and clear_power_alarm functions. On Boston, * these functionalities are not supported. * The load_platform_drivers(void) is called from post_startup() * which is after all the initialization of the tod module is * finished, then we replace 2 of the tod_ops function pointers * with our dummy version. */ tod_ops.tod_set_power_alarm = dummy_todm5823_set_power_alarm; tod_ops.tod_clear_power_alarm = dummy_todm5823_clear_power_alarm; /* * create a handle to the rmc_comm_request_nowait() function * inside the rmc_comm module. * * The Seattle/Boston todm5823 driver will use this handle to * use the rmc_comm_request_nowait() function to send time/date * updates to ALOM. */ rmc_req_now = (int (*)(rmc_comm_msg_t *, uint8_t)) modgetsymvalue("rmc_comm_request_nowait", 0); }