/**Copyright(c)1997,1998DougRabson*Allrightsreserved.**Redistributionanduseinsourceandbinaryforms,withorwithout*modification,arepermittedprovidedthatt
hefollowingconditions*aremet:*1.Redistributionsofsourcecodemustretaintheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimer.*2.Redistr
ibutionsinbinaryformmustreproducetheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimerinthe*documentationand/orothermaterialsprovided
withthedistribution.**THISSOFTWAREISPROVIDEDBYTHEAUTHORANDCONTRIBUTORS``ASIS''AND*ANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE*IMPLIEDW
ARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE*AREDISCLAIMED.INNOEVENTSHALLTHEAUTHORORCONTRIBUTORSBELIABLE*FORANYDIRECT,INDIRECT,INCIDENTAL
,SPECIAL,EXEMPLARY,ORCONSEQUENTIAL*DAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODS*ORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESSINTERR
UPTION)*HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICT*LIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAY*OUTOFTHEUSEOFT
HISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOF*SUCHDAMAGE.**$FreeBSD:src/sys/kern/subr_bus.c,v1.54.2.82001/01/1800:19:50n_hibmaExp$*/#include"opt_bus.h"#
include<sys/param.h>#include<sys/queue.h>#include<sys/malloc.h>#include<sys/kernel.h>#include<sys/module.h>#ifdefDEVICE_SYSCTLS#include<sys/sysctl.h>#
endif#include<sys/bus_private.h>#include<sys/systm.h>#include<machine/bus.h>#include<sys/rman.h>#include<machine/stdarg.h>/*fordevice_printf()*/MALLOC
_DEFINE(M_BUS,"bus","Busdatastructures");#ifdefBUS_DEBUG#definePDEBUG(a)(printf(__FUNCTION__":%d:",__LINE__),printfa,printf("\n"))#defineDEVICENAME(d)
((d)?device_get_name(d):"nodevice")#defineDRIVERNAME(d)((d)?d->name:"nodriver")#defineDEVCLANAME(d)((d)?d->name:"nodevclass")/*Producetheindenting,ind
ent*2spacesplusa'.'aheadofthatto*preventsyslogfromdeletinginitialspaces*/#defineindentprintf(p)do{intiJ;printf(".");for(iJ=0;iJ<indent;iJ++)printf("")
;printfp;}while(0)staticvoidprint_method_list(device_method_t*m,intindent);staticvoidprint_device_ops(device_ops_tops,intindent);staticvoidprint_devic
e_short(device_tdev,intindent);staticvoidprint_device(device_tdev,intindent);voidprint_device_tree_short(device_tdev,intindent);voidprint_device_tree(
device_tdev,intindent);staticvoidprint_driver_short(driver_t*driver,intindent);staticvoidprint_driver(driver_t*driver,intindent);staticvoidprint_drive
r_list(driver_list_tdrivers,intindent);staticvoidprint_devclass_short(devclass_tdc,intindent);staticvoidprint_devclass(devclass_tdc,intindent);voidpri
nt_devclass_list_short(void);voidprint_devclass_list(void);#else/*Makethecompilerignorethefunctioncalls*/#definePDEBUG(a)/*nop*/#defineDEVICENAME(d)/*
nop*/#defineDRIVERNAME(d)/*nop*/#defineDEVCLANAME(d)/*nop*/#defineprint_method_list(m,i)/*nop*/#defineprint_device_ops(o,i)/*nop*/#defineprint_device_
short(d,i)/*nop*/#defineprint_device(d,i)/*nop*/#defineprint_device_tree_short(d,i)/*nop*/#defineprint_device_tree(d,i)/*nop*/#defineprint_driver_shor
t(d,i)/*nop*/#defineprint_driver(d,i)/*nop*/#defineprint_driver_list(d,i)/*nop*/#defineprint_devclass_short(d,i)/*nop*/#defineprint_devclass(d,i)/*nop
*/#defineprint_devclass_list_short()/*nop*/#defineprint_devclass_list()/*nop*/#endif#ifdefDEVICE_SYSCTLSstaticvoiddevice_register_oids(device_tdev);st
aticvoiddevice_unregister_oids(device_tdev);#endif/**Methodtablehandling*/staticinterror_method(void);staticintnext_method_offset=1;LIST_HEAD(methodli
st,method)methods;structmethod{LIST_ENTRY(method)link;/*linkedlistofmethods*/intoffset;/*offsetinmethodtable*/intrefs;/*countofdevice_op_descusers*/de
vop_tdeflt;/*defaultimplementation*/char*name;/*uniquenameofmethod*/};staticvoidregister_method(structdevice_op_desc*desc){structmethod*m;if(desc->met
hod){desc->method->refs++;return;}/**Makesurethatdesc->defltisalwaysvalidtosimplifydispatch.*/if(!desc->deflt)desc->deflt=error_method;for(m=LIST_FIRS
T(&methods);m;m=LIST_NEXT(m,link)){if(!strcmp(m->name,desc->name)){desc->offset=m->offset;desc->method=m;m->refs++;PDEBUG(("method%phasthesamename,%s,
withoffset%d",(void*)m,desc->name,desc->offset));return;}}m=(structmethod*)malloc(sizeof(structmethod)+strlen(desc->name)+1,M_BUS,M_NOWAIT);if(!m)pani
c("register_method:outofmemory");bzero(m,sizeof(structmethod)+strlen(desc->name)+1);m->offset=next_method_offset++;m->refs=1;m->deflt=desc->deflt;m->n
ame=(char*)(m+1);strcpy(m->name,desc->name);LIST_INSERT_HEAD(&methods,m,link);desc->offset=m->offset;desc->method=m;}staticvoidunregister_method(struc
tdevice_op_desc*desc){structmethod*m=desc->method;m->refs--;if(m->refs==0){PDEBUG(("method%s,reachedrefcount0",desc->name));LIST_REMOVE(m,link);free(m
,M_BUS);desc->method=0;}}staticinterror_method(void){returnENXIO;}staticstructdevice_opsnull_ops={1,{error_method}};staticvoidcompile_methods(driver_t
*driver){device_ops_tops;structdevice_method*m;structmethod*cm;inti;/**Firstregisteranymethodswhichneedit.*/for(i=0,m=driver->methods;m->desc;i++,m++)
register_method(m->desc);/**Thenallocatethecompiledoptable.*/ops=malloc(sizeof(structdevice_ops)+(next_method_offset-1)*sizeof(devop_t),M_BUS,M_NOWAIT
);if(!ops)panic("compile_methods:outofmemory");bzero(ops,sizeof(structdevice_ops)+(next_method_offset-1)*sizeof(devop_t));ops->maxoffset=next_method_o
ffset;/*Fillindefaultmethodsandthenoverwritewithdrivermethods*/for(i=0;i<next_method_offset;i++)ops->methods[i]=error_method;for(cm=LIST_FIRST(&method
s);cm;cm=LIST_NEXT(cm,link)){if(cm->deflt)ops->methods[cm->offset]=cm->deflt;}for(i=0,m=driver->methods;m->desc;i++,m++)ops->methods[m->desc->offset]=
m->func;PDEBUG(("%shas%dmethod%s,wasting%dbytes",DRIVERNAME(driver),i,(i==1?"":"s"),(next_method_offset-i)*sizeof(devop_t)));driver->ops=ops;}staticvo
idfree_methods(driver_t*driver){inti;structdevice_method*m;/**Unregisteranymethodswhicharenolongerused.*/for(i=0,m=driver->methods;m->desc;i++,m++)unr
egister_method(m->desc);/**Freememoryandcleanup.*/free(driver->ops,M_BUS);driver->ops=0;}/**Devclassimplementation*/staticdevclass_list_tdevclasses=TA
ILQ_HEAD_INITIALIZER(devclasses);staticdevclass_tdevclass_find_internal(constchar*classname,intcreate){devclass_tdc;PDEBUG(("lookingfor%s",classname))
;if(!classname)returnNULL;for(dc=TAILQ_FIRST(&devclasses);dc;dc=TAILQ_NEXT(dc,link))if(!strcmp(dc->name,classname))returndc;PDEBUG(("%snotfound%s",cla
ssname,(create?",creating":"")));if(create){dc=malloc(sizeof(structdevclass)+strlen(classname)+1,M_BUS,M_NOWAIT);if(!dc)returnNULL;bzero(dc,sizeof(str
uctdevclass)+strlen(classname)+1);dc->name=(char*)(dc+1);strcpy(dc->name,classname);dc->devices=NULL;dc->maxunit=0;TAILQ_INIT(&dc->drivers);TAILQ_INSE
RT_TAIL(&devclasses,dc,link);}returndc;}devclass_tdevclass_create(constchar*classname){returndevclass_find_internal(classname,TRUE);}devclass_tdevclas
s_find(constchar*classname){returndevclass_find_internal(classname,FALSE);}intdevclass_add_driver(devclass_tdc,driver_t*driver){driverlink_tdl;inti;PD
EBUG(("%s",DRIVERNAME(driver)));dl=malloc(sizeof*dl,M_BUS,M_NOWAIT);if(!dl)returnENOMEM;bzero(dl,sizeof*dl);/**Compilethedriver'smethods.*/if(!driver-
>ops)compile_methods(driver);/**Makesurethedevclasswhichthedriverisimplementingexists.*/devclass_find_internal(driver->name,TRUE);dl->driver=driver;TA
ILQ_INSERT_TAIL(&dc->drivers,dl,link);driver->refs++;/**CallBUS_DRIVER_ADDEDforanyexistingbussesinthisclass.*/for(i=0;i<dc->maxunit;i++)if(dc->devices
[i])BUS_DRIVER_ADDED(dc->devices[i],driver);return0;}intdevclass_delete_driver(devclass_tbusclass,driver_t*driver){devclass_tdc=devclass_find(driver->
name);driverlink_tdl;device_tdev;inti;interror;PDEBUG(("%sfromdevclass%s",driver->name,DEVCLANAME(busclass)));if(!dc)return0;/**Findthelinkstructurein
thebus'listofdrivers.*/for(dl=TAILQ_FIRST(&busclass->drivers);dl;dl=TAILQ_NEXT(dl,link)){if(dl->driver==driver)break;}if(!dl){PDEBUG(("%snotfoundin%sl
ist",driver->name,busclass->name));returnENOENT;}/**Disassociatefromanydevices.Weiteratethroughallthe*devicesinthedevclassofthedriveranddetachanywhich
are*usingthedriverandwhichhaveaparentinthedevclasswhich*wearedeletingfrom.**Notethatsinceadrivercanbeinmultipledevclasses,we*shouldnotdetachdeviceswhi
charenotchildrenofdevicesin*theaffecteddevclass.*/for(i=0;i<dc->maxunit;i++){if(dc->devices[i]){dev=dc->devices[i];if(dev->driver==driver&&dev->parent
&&dev->parent->devclass==busclass){if((error=device_detach(dev))!=0)returnerror;device_set_driver(dev,NULL);}}}TAILQ_REMOVE(&busclass->drivers,dl,link
);free(dl,M_BUS);driver->refs--;if(driver->refs==0)free_methods(driver);return0;}staticdriverlink_tdevclass_find_driver_internal(devclass_tdc,constcha
r*classname){driverlink_tdl;PDEBUG(("%sindevclass%s",classname,DEVCLANAME(dc)));for(dl=TAILQ_FIRST(&dc->drivers);dl;dl=TAILQ_NEXT(dl,link)){if(!strcmp
(dl->driver->name,classname))returndl;}PDEBUG(("notfound"));returnNULL;}driver_t*devclass_find_driver(devclass_tdc,constchar*classname){driverlink_tdl
;dl=devclass_find_driver_internal(dc,classname);if(dl)returndl->driver;elsereturnNULL;}constchar*devclass_get_name(devclass_tdc){returndc->name;}devic
e_tdevclass_get_device(devclass_tdc,intunit){if(dc==NULL||unit<0||unit>=dc->maxunit)returnNULL;returndc->devices[unit];}void*devclass_get_softc(devcla
ss_tdc,intunit){device_tdev;dev=devclass_get_device(dc,unit);if(!dev)return(NULL);return(device_get_softc(dev));}intdevclass_get_devices(devclass_tdc,
device_t**devlistp,int*devcountp){inti;intcount;device_t*list;count=0;for(i=0;i<dc->maxunit;i++)if(dc->devices[i])count++;list=malloc(count*sizeof(dev
ice_t),M_TEMP,M_NOWAIT);if(!list)returnENOMEM;bzero(list,count*sizeof(device_t));count=0;for(i=0;i<dc->maxunit;i++)if(dc->devices[i]){list[count]=dc->
devices[i];count++;}*devlistp=list;*devcountp=count;return0;}intdevclass_get_maxunit(devclass_tdc){returndc->maxunit;}staticintdevclass_alloc_unit(dev
class_tdc,int*unitp){intunit=*unitp;PDEBUG(("unit%dindevclass%s",unit,DEVCLANAME(dc)));/*Ifwehavebeengivenawiredunitnumber,checkforexistingdevice*/if(
unit!=-1){if(unit>=0&&unit<dc->maxunit&&dc->devices[unit]!=NULL){if(bootverbose)printf("%s-:%s%dexists,usingnextavailableunitnumber\n",dc->name,dc->na
me,unit);/*findthenextavailableslot*/while(++unit<dc->maxunit&&dc->devices[unit]!=NULL);}}else{/*Unwireddevice,findthenextavailableslotforit*/unit=0;w
hile(unit<dc->maxunit&&dc->devices[unit]!=NULL)unit++;}/**We'veselectedaunitbeyondthelengthofthetable,solet'sextend*thetabletomakeroomforallunitsuptoa
ndincludingthisone.*/if(unit>=dc->maxunit){device_t*newlist;intnewsize;newsize=roundup((unit+1),MINALLOCSIZE/sizeof(device_t));newlist=malloc(sizeof(d
evice_t)*newsize,M_BUS,M_NOWAIT);if(!newlist)returnENOMEM;bcopy(dc->devices,newlist,sizeof(device_t)*dc->maxunit);bzero(newlist+dc->maxunit,sizeof(dev
ice_t)*(newsize-dc->maxunit));if(dc->devices)free(dc->devices,M_BUS);dc->devices=newlist;dc->maxunit=newsize;}PDEBUG(("now:unit%dindevclass%s",unit,DE
VCLANAME(dc)));*unitp=unit;return0;}staticintdevclass_add_device(devclass_tdc,device_tdev){intbuflen,error;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DE
VCLANAME(dc)));buflen=strlen(dc->name)+5;dev->nameunit=malloc(buflen,M_BUS,M_NOWAIT);if(!dev->nameunit)returnENOMEM;bzero(dev->nameunit,buflen);if((er
ror=devclass_alloc_unit(dc,&dev->unit))!=0){free(dev->nameunit,M_BUS);dev->nameunit=NULL;returnerror;}dc->devices[dev->unit]=dev;dev->devclass=dc;snpr
intf(dev->nameunit,buflen,"%s%d",dc->name,dev->unit);#ifdefDEVICE_SYSCTLSdevice_register_oids(dev);#endifreturn0;}staticintdevclass_delete_device(devc
lass_tdc,device_tdev){if(!dc||!dev)return0;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DEVCLANAME(dc)));if(dev->devclass!=dc||dc->devices[dev->unit]!=dev
)panic("devclass_delete_device:inconsistentdeviceclass");dc->devices[dev->unit]=NULL;if(dev->flags&DF_WILDCARD)dev->unit=-1;dev->devclass=NULL;free(de
v->nameunit,M_BUS);dev->nameunit=NULL;#ifdefDEVICE_SYSCTLSdevice_unregister_oids(dev);#endifreturn0;}staticdevice_tmake_device(device_tparent,constcha
r*name,intunit){device_tdev;devclass_tdc;PDEBUG(("%sat%sasunit%d",name,DEVICENAME(parent),unit));if(name){dc=devclass_find_internal(name,TRUE);if(!dc)
{printf("make_device:can'tfinddeviceclass%s\n",name);returnNULL;}}elsedc=NULL;dev=malloc(sizeof(structdevice),M_BUS,M_NOWAIT);if(!dev)return0;bzero(de
v,sizeof(structdevice));dev->parent=parent;TAILQ_INIT(&dev->children);dev->ops=&null_ops;dev->driver=NULL;dev->devclass=NULL;dev->unit=unit;dev->nameu
nit=NULL;dev->desc=NULL;dev->busy=0;dev->devflags=0;dev->flags=DF_ENABLED;dev->order=0;if(unit==-1)dev->flags|=DF_WILDCARD;if(name){dev->flags|=DF_FIX
EDCLASS;devclass_add_device(dc,dev);}dev->ivars=NULL;dev->softc=NULL;dev->state=DS_NOTPRESENT;returndev;}staticintdevice_print_child(device_tdev,devic
e_tchild){intretval=0;if(device_is_alive(child)){retval+=BUS_PRINT_CHILD(dev,child);}elseretval+=device_printf(child,"notfound\n");return(retval);}dev
ice_tdevice_add_child(device_tdev,constchar*name,intunit){returndevice_add_child_ordered(dev,0,name,unit);}device_tdevice_add_child_ordered(device_tde
v,intorder,constchar*name,intunit){device_tchild;device_tplace;PDEBUG(("%sat%swithorder%dasunit%d",name,DEVICENAME(dev),order,unit));child=make_device
(dev,name,unit);if(child==NULL)returnchild;child->order=order;TAILQ_FOREACH(place,&dev->children,link)if(place->order>order)break;if(place){/**Thedevi
ce'place'isthefirstdevicewhoseorderis*greaterthanthenewchild.*/TAILQ_INSERT_BEFORE(place,child,link);}else{/**Thenewchild'sorderisgreaterorequaltotheo
rderof*anyexistingdevice.Addthechildtothetailofthelist.*/TAILQ_INSERT_TAIL(&dev->children,child,link);}returnchild;}intdevice_delete_child(device_tdev
,device_tchild){interror;device_tgrandchild;PDEBUG(("%sfrom%s",DEVICENAME(child),DEVICENAME(dev)));/*removechildrenfirst*/while((grandchild=TAILQ_FIRS
T(&child->children))){error=device_delete_child(child,grandchild);if(error)returnerror;}if((error=device_detach(child))!=0)returnerror;if(child->devcl
ass)devclass_delete_device(child->devclass,child);TAILQ_REMOVE(&dev->children,child,link);device_set_desc(child,NULL);free(child,M_BUS);return0;}/**Fi
ndonlydevicesattachedtothisbus.*/device_tdevice_find_child(device_tdev,constchar*classname,intunit){devclass_tdc;device_tchild;dc=devclass_find(classn
ame);if(!dc)returnNULL;child=devclass_get_device(dc,unit);if(child&&child->parent==dev)returnchild;returnNULL;}staticdriverlink_tfirst_matching_driver
(devclass_tdc,device_tdev){if(dev->devclass)returndevclass_find_driver_internal(dc,dev->devclass->name);elsereturnTAILQ_FIRST(&dc->drivers);}staticdri
verlink_tnext_matching_driver(devclass_tdc,device_tdev,driverlink_tlast){if(dev->devclass){driverlink_tdl;for(dl=TAILQ_NEXT(last,link);dl;dl=TAILQ_NEX
T(dl,link))if(!strcmp(dev->devclass->name,dl->driver->name))returndl;returnNULL;}elsereturnTAILQ_NEXT(last,link);}staticintdevice_probe_child(device_t
dev,device_tchild){devclass_tdc;driverlink_tbest=0;driverlink_tdl;intresult,pri=0;inthasclass=(child->devclass!=0);dc=dev->devclass;if(!dc)panic("devi
ce_probe_child:parentdevicehasnodevclass");if(child->state==DS_ALIVE)return0;for(dl=first_matching_driver(dc,child);dl;dl=next_matching_driver(dc,chil
d,dl)){PDEBUG(("Trying%s",DRIVERNAME(dl->driver)));device_set_driver(child,dl->driver);if(!hasclass)device_set_devclass(child,dl->driver->name);result
=DEVICE_PROBE(child);if(!hasclass)device_set_devclass(child,0);/**IfthedriverreturnsSUCCESS,therecanbenohighermatch*forthisdevice.*/if(result==0){best
=dl;pri=0;break;}/**Thedriverreturnedanerrorsoitcertainlydoesn'tmatch.*/if(result>0){device_set_driver(child,0);continue;}/**AprioritylowerthanSUCCESS
,rememberthebestmatching*driver.Initialisethevalueofpriforthefirstmatch.*/if(best==0||result>pri){best=dl;pri=result;continue;}}/**Ifwefoundadriver,ch
angestateandinitialisethedevclass.*/if(best){if(!child->devclass)device_set_devclass(child,best->driver->name);device_set_driver(child,best->driver);i
f(pri<0){/**Abitbogus.Calltheprobemethodagaintomakesure*thatwehavetherightdescription.*/DEVICE_PROBE(child);}child->state=DS_ALIVE;return0;}returnENXI
O;}device_tdevice_get_parent(device_tdev){returndev->parent;}intdevice_get_children(device_tdev,device_t**devlistp,int*devcountp){intcount;device_tchi
ld;device_t*list;count=0;for(child=TAILQ_FIRST(&dev->children);child;child=TAILQ_NEXT(child,link))count++;list=malloc(count*sizeof(device_t),M_TEMP,M_
NOWAIT);if(!list)returnENOMEM;bzero(list,count*sizeof(device_t));count=0;for(child=TAILQ_FIRST(&dev->children);child;child=TAILQ_NEXT(child,link)){lis
t[count]=child;count++;}*devlistp=list;*devcountp=count;return0;}driver_t*device_get_driver(device_tdev){returndev->driver;}devclass_tdevice_get_devcl
ass(device_tdev){returndev->devclass;}constchar*device_get_name(device_tdev){if(dev->devclass)returndevclass_get_name(dev->devclass);returnNULL;}const
char*device_get_nameunit(device_tdev){returndev->nameunit;}intdevice_get_unit(device_tdev){returndev->unit;}constchar*device_get_desc(device_tdev){ret
urndev->desc;}u_int32_tdevice_get_flags(device_tdev){returndev->devflags;}intdevice_print_prettyname(device_tdev){constchar*name=device_get_name(dev);
if(name==0)returnprintf("unknown:");elsereturnprintf("%s%d:",name,device_get_unit(dev));}intdevice_printf(device_tdev,constchar*fmt,...){va_listap;int
retval;retval=device_print_prettyname(dev);va_start(ap,fmt);retval+=vprintf(fmt,ap);va_end(ap);returnretval;}staticvoiddevice_set_desc_internal(device
_tdev,constchar*desc,intcopy){if(dev->desc&&(dev->flags&DF_DESCMALLOCED)){free(dev->desc,M_BUS);dev->flags&=~DF_DESCMALLOCED;dev->desc=NULL;}if(copy&&
desc){dev->desc=malloc(strlen(desc)+1,M_BUS,M_NOWAIT);if(dev->desc){strcpy(dev->desc,desc);dev->flags|=DF_DESCMALLOCED;}}else/*Avoida-Wcast-qualwarnin
g*/dev->desc=(char*)(uintptr_t)desc;#ifdefDEVICE_SYSCTLS{structsysctl_oid*oid=&dev->oid[1];oid->oid_arg1=dev->desc?dev->desc:"";oid->oid_arg2=dev->des
c?strlen(dev->desc):0;}#endif}voiddevice_set_desc(device_tdev,constchar*desc){device_set_desc_internal(dev,desc,FALSE);}voiddevice_set_desc_copy(devic
e_tdev,constchar*desc){device_set_desc_internal(dev,desc,TRUE);}voiddevice_set_flags(device_tdev,u_int32_tflags){dev->devflags=flags;}void*device_get_
softc(device_tdev){returndev->softc;}voiddevice_set_softc(device_tdev,void*softc){if(dev->softc&&!(dev->flags&DF_EXTERNALSOFTC))free(dev->softc,M_BUS)
;dev->softc=softc;if(dev->softc)dev->flags|=DF_EXTERNALSOFTC;elsedev->flags&=~DF_EXTERNALSOFTC;}void*device_get_ivars(device_tdev){returndev->ivars;}v
oiddevice_set_ivars(device_tdev,void*ivars){if(!dev)return;dev->ivars=ivars;return;}device_state_tdevice_get_state(device_tdev){returndev->state;}void
device_enable(device_tdev){dev->flags|=DF_ENABLED;}voiddevice_disable(device_tdev){dev->flags&=~DF_ENABLED;}voiddevice_busy(device_tdev){if(dev->state
<DS_ATTACHED)panic("device_busy:calledforunattacheddevice");if(dev->busy==0&&dev->parent)device_busy(dev->parent);dev->busy++;dev->state=DS_BUSY;}void
device_unbusy(device_tdev){if(dev->state!=DS_BUSY)panic("device_unbusy:calledfornon-busydevice");dev->busy--;if(dev->busy==0){if(dev->parent)device_un
busy(dev->parent);dev->state=DS_ATTACHED;}}voiddevice_quiet(device_tdev){dev->flags|=DF_QUIET;}voiddevice_verbose(device_tdev){dev->flags&=~DF_QUIET;}
intdevice_is_quiet(device_tdev){return(dev->flags&DF_QUIET)!=0;}intdevice_is_enabled(device_tdev){return(dev->flags&DF_ENABLED)!=0;}intdevice_is_alive
(device_tdev){returndev->state>=DS_ALIVE;}intdevice_set_devclass(device_tdev,constchar*classname){devclass_tdc;if(!classname){if(dev->devclass)devclas
s_delete_device(dev->devclass,dev);return0;}if(dev->devclass){printf("device_set_devclass:deviceclassalreadyset\n");returnEINVAL;}dc=devclass_find_int
ernal(classname,TRUE);if(!dc)returnENOMEM;returndevclass_add_device(dc,dev);}intdevice_set_driver(device_tdev,driver_t*driver){if(dev->state>=DS_ATTAC
HED)returnEBUSY;if(dev->driver==driver)return0;if(dev->softc&&!(dev->flags&DF_EXTERNALSOFTC)){free(dev->softc,M_BUS);dev->softc=NULL;}dev->ops=&null_o
ps;dev->driver=driver;if(driver){dev->ops=driver->ops;if(!(dev->flags&DF_EXTERNALSOFTC)){dev->softc=malloc(driver->softc,M_BUS,M_NOWAIT);if(!dev->soft
c){dev->ops=&null_ops;dev->driver=NULL;returnENOMEM;}bzero(dev->softc,driver->softc);}}return0;}intdevice_probe_and_attach(device_tdev){device_tbus=de
v->parent;interror=0;inthasclass=(dev->devclass!=0);if(dev->state>=DS_ALIVE)return0;if(dev->flags&DF_ENABLED){error=device_probe_child(bus,dev);if(!er
ror){if(!device_is_quiet(dev))device_print_child(bus,dev);error=DEVICE_ATTACH(dev);if(!error)dev->state=DS_ATTACHED;else{printf("device_probe_and_atta
ch:%s%dattachreturned%d\n",dev->driver->name,dev->unit,error);/*Unsettheclassthatwassetindevice_probe_child*/if(!hasclass)device_set_devclass(dev,0);d
evice_set_driver(dev,NULL);dev->state=DS_NOTPRESENT;}}else{if(!(dev->flags&DF_DONENOMATCH)){BUS_PROBE_NOMATCH(bus,dev);dev->flags|=DF_DONENOMATCH;}}}e
lse{if(bootverbose){device_print_prettyname(dev);printf("notprobed(disabled)\n");}}returnerror;}intdevice_detach(device_tdev){interror;PDEBUG(("%s",DE
VICENAME(dev)));if(dev->state==DS_BUSY)returnEBUSY;if(dev->state!=DS_ATTACHED)return0;if((error=DEVICE_DETACH(dev))!=0)returnerror;device_printf(dev,"
detached\n");if(dev->parent)BUS_CHILD_DETACHED(dev->parent,dev);if(!(dev->flags&DF_FIXEDCLASS))devclass_delete_device(dev->devclass,dev);dev->state=DS
_NOTPRESENT;device_set_driver(dev,NULL);return0;}intdevice_shutdown(device_tdev){if(dev->state<DS_ATTACHED)return0;returnDEVICE_SHUTDOWN(dev);}intdevi
ce_set_unit(device_tdev,intunit){devclass_tdc;interr;dc=device_get_devclass(dev);if(unit<dc->maxunit&&dc->devices[unit])returnEBUSY;err=devclass_delet
e_device(dc,dev);if(err)returnerr;dev->unit=unit;err=devclass_add_device(dc,dev);if(err)returnerr;return0;}#ifdefDEVICE_SYSCTLS/**Sysctlnodesfordevice
s.*/SYSCTL_NODE(_hw,OID_AUTO,devices,CTLFLAG_RW,0,"Alistofalldevices");staticintsysctl_handle_children(SYSCTL_HANDLER_ARGS){device_tdev=arg1;device_tc
hild;intfirst=1,error=0;for(child=TAILQ_FIRST(&dev->children);child;child=TAILQ_NEXT(child,link)){if(child->nameunit){if(!first){error=SYSCTL_OUT(req,
",",1);if(error)returnerror;}else{first=0;}error=SYSCTL_OUT(req,child->nameunit,strlen(child->nameunit));if(error)returnerror;}}error=SYSCTL_OUT(req,"
",1);returnerror;}staticintsysctl_handle_state(SYSCTL_HANDLER_ARGS){device_tdev=arg1;switch(dev->state){caseDS_NOTPRESENT:returnSYSCTL_OUT(req,"notpre
sent",sizeof("notpresent"));caseDS_ALIVE:returnSYSCTL_OUT(req,"alive",sizeof("alive"));caseDS_ATTACHED:returnSYSCTL_OUT(req,"attached",sizeof("attache
d"));caseDS_BUSY:returnSYSCTL_OUT(req,"busy",sizeof("busy"));}return0;}staticvoiddevice_register_oids(device_tdev){structsysctl_oid*oid;oid=&dev->oid[

Hosted by uCoz