subr_autoconf.c

来自「MIPS处理器的bootloader,龙芯就是用的修改过的PMON2」· C语言 代码 · 共 943 行 · 第 1/2 页

C
943
字号
	lname = strlen(cd->cd_name);	xunit = number(&num[sizeof num], dev->dv_unit);	lunit = &num[sizeof num] - xunit;	if (lname + lunit >= sizeof(dev->dv_xname))		panic("config_make_softc: device name too long");	bcopy(cd->cd_name, dev->dv_xname, lname);	bcopy(xunit, dev->dv_xname + lname, lunit);	dev->dv_parent = parent;	/* put this device in the devices array */	if (dev->dv_unit >= cd->cd_ndevs) {		/*		 * Need to expand the array.		 */		int old = cd->cd_ndevs, new;		void **nsp;		if (old == 0)			new = MINALLOCSIZE / sizeof(void *);		else			new = old * 2;		while (new <= dev->dv_unit)			new *= 2;		cd->cd_ndevs = new;		nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);			if (nsp == 0)			panic("config_make_softc: %sing dev array",			    old != 0 ? "expand" : "creat");		bzero(nsp + old, (new - old) * sizeof(void *));		if (old != 0) {			bcopy(cd->cd_devs, nsp, old * sizeof(void *));			free(cd->cd_devs, M_DEVBUF);		}		cd->cd_devs = nsp;	}	if (cd->cd_devs[dev->dv_unit])		panic("config_make_softc: duplicate %s", dev->dv_xname);	dev->dv_ref = 1;	return (dev);}/* * Detach a device.  Optionally forced (e.g. because of hardware * removal) and quiet.  Returns zero if successful, non-zero * (an error code) otherwise. * * Note that this code wants to be run from a process context, so * that the detach can sleep to allow processes which have a device * open to run and unwind their stacks. */intconfig_detach(dev, flags)	struct device *dev;	int flags;{	struct cfdata *cf;	struct cfattach *ca;	struct cfdriver *cd;#ifdef DIAGNOSTIC	struct device *d;#endif	int rv = 0, i;	cf = dev->dv_cfdata;#ifdef DIAGNOSTIC	if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)		panic("config_detach: bad device fstate");#endif	ca = cf->cf_attach;	cd = cf->cf_driver;	/*	 * Ensure the device is deactivated.  If the device doesn't	 * have an activation entry point, we allow DVF_ACTIVE to	 * remain set.  Otherwise, if DVF_ACTIVE is still set, the	 * device is busy, and the detach fails.	 */	if (ca->ca_activate != NULL)		rv = config_deactivate(dev);	/*	 * Try to detach the device.  If that's not possible, then	 * we either panic() (for the forced but failed case), or	 * return an error.	 */	if (rv == 0) {		if (ca->ca_detach != NULL)			rv = (*ca->ca_detach)(dev, flags);		else			rv = EOPNOTSUPP;	}	if (rv != 0) {		if ((flags & DETACH_FORCE) == 0)			return (rv);		else			panic("config_detach: forced detach of %s failed (%d)",			    dev->dv_xname, rv);	}	/*	 * The device has now been successfully detached.	 */#ifdef DIAGNOSTIC	/*	 * Sanity: If you're successfully detached, you should have no	 * children.  (Note that because children must be attached	 * after parents, we only need to search the latter part of	 * the list.)	 */	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;	     d = TAILQ_NEXT(d, dv_list)) {		if (d->dv_parent == dev)			panic("config_detach: detached device has children");	}#endif	/*	 * Mark cfdata to show that the unit can be reused, if possible.	 * Note that we can only re-use a starred unit number if the unit	 * being detached had the last assigned unit number.	 */	for (cf = cfdata; cf->cf_driver; cf++) {		if (cf->cf_driver == cd) {			if (cf->cf_fstate == FSTATE_FOUND &&			    cf->cf_unit == dev->dv_unit)				cf->cf_fstate = FSTATE_NOTFOUND;			if (cf->cf_fstate == FSTATE_STAR &&			    cf->cf_unit == dev->dv_unit + 1)				cf->cf_unit--;		}	}	/*	 * Unlink from device list.	 */	TAILQ_REMOVE(&alldevs, dev, dv_list);	device_unref(dev);	/*	 * Remove from cfdriver's array, tell the world, and free softc.	 */	cd->cd_devs[dev->dv_unit] = NULL;	if ((flags & DETACH_QUIET) == 0)		printf("%s detached\n", dev->dv_xname);	device_unref(dev);	/*	 * If the device now has no units in use, deallocate its softc array.	 */	for (i = 0; i < cd->cd_ndevs; i++)		if (cd->cd_devs[i] != NULL)			break;	if (i == cd->cd_ndevs) {		/* nothing found; deallocate */		free(cd->cd_devs, M_DEVBUF);		cd->cd_devs = NULL;		cd->cd_ndevs = 0;	}	/*	 * Return success.	 */	return (0);}intconfig_activate(dev)	struct device *dev;{	struct cfattach *ca = dev->dv_cfdata->cf_attach;	int rv = 0, oflags = dev->dv_flags;	if (ca->ca_activate == NULL)		return (EOPNOTSUPP);	if ((dev->dv_flags & DVF_ACTIVE) == 0) {		dev->dv_flags |= DVF_ACTIVE;		rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);		if (rv)			dev->dv_flags = oflags;	}	return (rv);}intconfig_deactivate(dev)	struct device *dev;{	struct cfattach *ca = dev->dv_cfdata->cf_attach;	int rv = 0, oflags = dev->dv_flags;	if (ca->ca_activate == NULL)		return (EOPNOTSUPP);	if (dev->dv_flags & DVF_ACTIVE) {		dev->dv_flags &= ~DVF_ACTIVE;		rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);		if (rv)			dev->dv_flags = oflags;	}	return (rv);}/* * Defer the configuration of the specified device until all * of its parent's devices have been attached. */voidconfig_defer(dev, func)	struct device *dev;	void (*func) __P((struct device *));{	struct deferred_config *dc;	if (dev->dv_parent == NULL)		panic("config_defer: can't defer config of a root device");#ifdef DIAGNOSTIC	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;	     dc = TAILQ_NEXT(dc, dc_queue)) {		if (dc->dc_dev == dev)			panic("config_defer: deferred twice");	}#endif	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)		panic("config_defer: can't allocate defer structure");	dc->dc_dev = dev;	dc->dc_func = func;	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);}/* * Process the deferred configuration queue for a device. */voidconfig_process_deferred_children(parent)	struct device *parent;{	struct deferred_config *dc, *ndc;	for (dc = TAILQ_FIRST(&deferred_config_queue);	     dc != NULL; dc = ndc) {		ndc = TAILQ_NEXT(dc, dc_queue);		if (dc->dc_dev->dv_parent == parent) {			TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);			(*dc->dc_func)(dc->dc_dev);			free(dc, M_DEVBUF);		}	}}intconfig_detach_children(parent, flags)	struct device *parent;	int flags;{	struct device *dev, *next_dev;	int  rv = 0;	/* The config_detach routine may sleep, meaning devices	   may be added to the queue. However, all devices will	   be added to the tail of the queue, the queue won't	   be re-organized, and the subtree of parent here should be locked	   for purposes of adding/removing children.	*/	for (dev  = TAILQ_FIRST(&alldevs);	     dev != NULL; dev = next_dev) {		next_dev = TAILQ_NEXT(dev, dv_list);		if (dev->dv_parent == parent &&		    (rv = config_detach(dev, flags)))			return (rv);	}	return  (rv);}intconfig_activate_children(parent, act)	struct device *parent;	enum devact act;{	struct device *dev, *next_dev;	int  rv = 0;	/* The config_deactivate routine may sleep, meaning devices	   may be added to the queue. However, all devices will	   be added to the tail of the queue, the queue won't	   be re-organized, and the subtree of parent here should be locked	   for purposes of adding/removing children.	*/	for (dev = TAILQ_FIRST(&alldevs);	     dev != NULL; dev = next_dev) {		next_dev = TAILQ_NEXT(dev, dv_list);		if (dev->dv_parent == parent) {			switch (act) {			case DVACT_ACTIVATE:				rv = config_activate(dev);				break;			case DVACT_DEACTIVATE:				rv = config_deactivate(dev);				break;			default:#ifdef DIAGNOSTIC				printf ("config_activate_children: shouldn't get here");#endif				rv = EOPNOTSUPP;				break;			}									if (rv)				break;		}	}	return  (rv);}/*  * Lookup a device in the cfdriver device array.  Does not return a * device if it is not active. * * Increments ref count on the device by one, reflecting the * new reference created on the stack. * * Context: process only  */struct device *device_lookup(cd, unit)	struct cfdriver *cd;	int unit;{	struct device *dv = NULL;	if (unit >= 0 && unit < cd->cd_ndevs)		dv = (struct device *)(cd->cd_devs[unit]);		if (!dv)		return (NULL);	if (!(dv->dv_flags & DVF_ACTIVE))		dv = NULL;	if (dv != NULL)		device_ref(dv);	return (dv);}/* * Increments the ref count on the device structure. The device * structure is freed when the ref count hits 0. * * Context: process or interrupt */voiddevice_ref(dv)	struct device *dv;{	dv->dv_ref++;}/* * Decrement the ref count on the device structure. * * free's the structure when the ref count hits zero and calls the zeroref * function. * * Context: process or interrupt */voiddevice_unref(dv)	struct device *dv;{	dv->dv_ref--;	if (dv->dv_ref == 0) {		if (dv->dv_cfdata->cf_attach->ca_zeroref)			(*dv->dv_cfdata->cf_attach->ca_zeroref)(dv);				free(dv, M_DEVBUF);	}}/* * Attach an event.  These must come from initially-zero space (see * commented-out assignments below), but that occurs naturally for * device instance variables. */voidevcnt_attach(dev, name, ev)	struct device *dev;	const char *name;	struct evcnt *ev;{#ifdef DIAGNOSTIC	if (strlen(name) >= sizeof(ev->ev_name))		panic("evcnt_attach");#endif	/* ev->ev_next = NULL; */	ev->ev_dev = dev;	/* ev->ev_count = 0; */	strcpy(ev->ev_name, name);	TAILQ_INSERT_TAIL(&allevents, ev, ev_list);}#if 0intattach_loadable(parentname, parentunit, cftable)	char *parentname;	int parentunit;	struct cftable *cftable;{	int found = 0;	struct device *d;	TAILQ_INSERT_TAIL(&allcftables, cftable, list);	for(d = alldevs.tqh_first; d != NULL; d = d->dv_list.tqe_next) {		struct cfdriver *drv = d->dv_cfdata->cf_driver;		if (strcmp(parentname, drv->cd_name) == NULL &&		    (parentunit == -1 || parentunit == d->dv_unit)) {			int s;			s = splhigh(); /* ??? */			found |= (*d->dv_cfdata->cf_attach->ca_reprobe)(d,			    &(cftable->tab[0]));			splx(s);		}	}	if (!found)		TAILQ_REMOVE(&allcftables, cftable, list);	return(found);}intdevcf_intable __P((struct device *, void *));intdevcf_intable(dev, arg)	struct device *dev;	void *arg;{	struct cftable *tbl = arg;	struct cfdata *cf;	for(cf = tbl->tab; cf->cf_driver; cf++) {		if (dev->dv_cfdata == cf)			return(1);	}	return(0);}intdetach_loadable(cftable)	struct cftable *cftable;{	if (!detach_devices(devcf_intable, cftable, 0, 0))		return(0);	TAILQ_REMOVE(&allcftables, cftable, list);	return(1);}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?