/**Copyright(c)1997,1998DougRabson*Allrightsreserved.**Redistributionanduseinsourceandbinaryforms,withorwithout*modification,arepermittedprovidedthatth
efollowingconditions*aremet:*1.Redistributionsofsourcecodemustretaintheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimer.*2.Redistrib
utionsinbinaryformmustreproducetheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimerinthe*documentationand/orothermaterialsprovidedwit
hthedistribution.**THISSOFTWAREISPROVIDEDBYTHEAUTHORANDCONTRIBUTORS``ASIS''AND*ANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE*IMPLIEDWARRA
NTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE*AREDISCLAIMED.INNOEVENTSHALLTHEAUTHORORCONTRIBUTORSBELIABLE*FORANYDIRECT,INDIRECT,INCIDENTAL,SPEC
IAL,EXEMPLARY,ORCONSEQUENTIAL*DAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODS*ORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESSINTERRUPTION
)*HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICT*LIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAY*OUTOFTHEUSEOFTHISSOFT
WARE,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#inc
lude<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,indent*2spacesp
lusa'.'aheadofthatto*preventsyslogfromdeletinginitialspaces*/#defineindentprintf(p)do{intiJ;printf(".");for(iJ=0;iJ<indent;iJ++)printf("");printfp;}whi
le(0)staticvoidprint_method_list(device_method_t*m,intindent);staticvoidprint_device_ops(device_ops_tops,intindent);staticvoidprint_device_short(device
_tdev,intindent);staticvoidprint_device(device_tdev,intindent);voidprint_device_tree_short(device_tdev,intindent);voidprint_device_tree(device_tdev,int
indent);staticvoidprint_driver_short(driver_t*driver,intindent);staticvoidprint_driver(driver_t*driver,intindent);staticvoidprint_driver_list(driver_li
st_tdrivers,intindent);staticvoidprint_devclass_short(devclass_tdc,intindent);staticvoidprint_devclass(devclass_tdc,intindent);voidprint_devclass_list_
short(void);voidprint_devclass_list(void);#else/*Makethecompilerignorethefunctioncalls*/#definePDEBUG(a)/*nop*/#defineDEVICENAME(d)/*nop*/#defineDRIVER
NAME(d)/*nop*/#defineDEVCLANAME(d)/*nop*/#defineprint_method_list(m,i)/*nop*/#defineprint_device_ops(o,i)/*nop*/#defineprint_device_short(d,i)/*nop*/#d
efineprint_device(d,i)/*nop*/#defineprint_device_tree_short(d,i)/*nop*/#defineprint_device_tree(d,i)/*nop*/#defineprint_driver_short(d,i)/*nop*/#define
print_driver(d,i)/*nop*/#defineprint_driver_list(d,i)/*nop*/#defineprint_devclass_short(d,i)/*nop*/#defineprint_devclass(d,i)/*nop*/#defineprint_devcla
ss_list_short()/*nop*/#defineprint_devclass_list()/*nop*/#endif#ifdefDEVICE_SYSCTLSstaticvoiddevice_register_oids(device_tdev);staticvoiddevice_unregis
ter_oids(device_tdev);#endif/**Methodtablehandling*/staticinterror_method(void);staticintnext_method_offset=1;LIST_HEAD(methodlist,method)methods;struc
tmethod{LIST_ENTRY(method)link;/*linkedlistofmethods*/intoffset;/*offsetinmethodtable*/intrefs;/*countofdevice_op_descusers*/devop_tdeflt;/*defaultimpl
ementation*/char*name;/*uniquenameofmethod*/};staticvoidregister_method(structdevice_op_desc*desc){structmethod*m;if(desc->method){desc->method->refs++
;return;}/**Makesurethatdesc->defltisalwaysvalidtosimplifydispatch.*/if(!desc->deflt)desc->deflt=error_method;for(m=LIST_FIRST(&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)panic("register_method:outofmemo
ry");bzero(m,sizeof(structmethod)+strlen(desc->name)+1);m->offset=next_method_offset++;m->refs=1;m->deflt=desc->deflt;m->name=(char*)(m+1);strcpy(m->na
me,desc->name);LIST_INSERT_HEAD(&methods,m,link);desc->offset=m->offset;desc->method=m;}staticvoidunregister_method(structdevice_op_desc*desc){structme
thod*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;}}static
interror_method(void){returnENXIO;}staticstructdevice_opsnull_ops={1,{error_method}};staticvoidcompile_methods(driver_t*driver){device_ops_tops;structd
evice_method*m;structmethod*cm;inti;/**Firstregisteranymethodswhichneedit.*/for(i=0,m=driver->methods;m->desc;i++,m++)register_method(m->desc);/**Thena
llocatethecompiledoptable.*/ops=malloc(sizeof(structdevice_ops)+(next_method_offset-1)*sizeof(devop_t),M_BUS,M_NOWAIT);if(!ops)panic("compile_methods:o
utofmemory");bzero(ops,sizeof(structdevice_ops)+(next_method_offset-1)*sizeof(devop_t));ops->maxoffset=next_method_offset;/*Fillindefaultmethodsandthen
overwritewithdrivermethods*/for(i=0;i<next_method_offset;i++)ops->methods[i]=error_method;for(cm=LIST_FIRST(&methods);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,wast
ing%dbytes",DRIVERNAME(driver),i,(i==1?"":"s"),(next_method_offset-i)*sizeof(devop_t)));driver->ops=ops;}staticvoidfree_methods(driver_t*driver){inti;s
tructdevice_method*m;/**Unregisteranymethodswhicharenolongerused.*/for(i=0,m=driver->methods;m->desc;i++,m++)unregister_method(m->desc);/**Freememoryan
dcleanup.*/free(driver->ops,M_BUS);driver->ops=0;}/**Devclassimplementation*/staticdevclass_list_tdevclasses=TAILQ_HEAD_INITIALIZER(devclasses);staticd
evclass_tdevclass_find_internal(constchar*classname,intcreate){devclass_tdc;PDEBUG(("lookingfor%s",classname));if(!classname)returnNULL;for(dc=TAILQ_FI
RST(&devclasses);dc;dc=TAILQ_NEXT(dc,link))if(!strcmp(dc->name,classname))returndc;PDEBUG(("%snotfound%s",classname,(create?",creating":"")));if(create
){dc=malloc(sizeof(structdevclass)+strlen(classname)+1,M_BUS,M_NOWAIT);if(!dc)returnNULL;bzero(dc,sizeof(structdevclass)+strlen(classname)+1);dc->name=
(char*)(dc+1);strcpy(dc->name,classname);dc->devices=NULL;dc->maxunit=0;TAILQ_INIT(&dc->drivers);TAILQ_INSERT_TAIL(&devclasses,dc,link);}returndc;}devc
lass_tdevclass_create(constchar*classname){returndevclass_find_internal(classname,TRUE);}devclass_tdevclass_find(constchar*classname){returndevclass_fi
nd_internal(classname,FALSE);}intdevclass_add_driver(devclass_tdc,driver_t*driver){driverlink_tdl;inti;PDEBUG(("%s",DRIVERNAME(driver)));dl=malloc(size
of*dl,M_BUS,M_NOWAIT);if(!dl)returnENOMEM;bzero(dl,sizeof*dl);/**Compilethedriver'smethods.*/if(!driver->ops)compile_methods(driver);/**Makesurethedevc
lasswhichthedriverisimplementingexists.*/devclass_find_internal(driver->name,TRUE);dl->driver=driver;TAILQ_INSERT_TAIL(&dc->drivers,dl,link);driver->re
fs++;/**CallBUS_DRIVER_ADDEDforanyexistingbussesinthisclass.*/for(i=0;i<dc->maxunit;i++)if(dc->devices[i])BUS_DRIVER_ADDED(dc->devices[i],driver);retur
n0;}intdevclass_delete_driver(devclass_tbusclass,driver_t*driver){devclass_tdc=devclass_find(driver->name);driverlink_tdl;device_tdev;inti;interror;PDE
BUG(("%sfromdevclass%s",driver->name,DEVCLANAME(busclass)));if(!dc)return0;/**Findthelinkstructureinthebus'listofdrivers.*/for(dl=TAILQ_FIRST(&busclass
->drivers);dl;dl=TAILQ_NEXT(dl,link)){if(dl->driver==driver)break;}if(!dl){PDEBUG(("%snotfoundin%slist",driver->name,busclass->name));returnENOENT;}/**
Disassociatefromanydevices.Weiteratethroughallthe*devicesinthedevclassofthedriveranddetachanywhichare*usingthedriverandwhichhaveaparentinthedevclasswhi
ch*wearedeletingfrom.**Notethatsinceadrivercanbeinmultipledevclasses,we*shouldnotdetachdeviceswhicharenotchildrenofdevicesin*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_det
ach(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,constchar*classname){driverlink_tdl;PDEBUG(("%sindevclass%s",clas
sname,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)retur
ndl->driver;elsereturnNULL;}constchar*devclass_get_name(devclass_tdc){returndc->name;}device_tdevclass_get_device(devclass_tdc,intunit){if(dc==NULL||un
it<0||unit>=dc->maxunit)returnNULL;returndc->devices[unit];}void*devclass_get_softc(devclass_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(device_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;}int
devclass_get_maxunit(devclass_tdc){returndc->maxunit;}staticintdevclass_alloc_unit(devclass_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){i
f(bootverbose)printf("%s-:%s%dexists,usingnextavailableunitnumber\n",dc->name,dc->name,unit);/*findthenextavailableslot*/while(++unit<dc->maxunit&&dc->
devices[unit]!=NULL);}}else{/*Unwireddevice,findthenextavailableslotforit*/unit=0;while(unit<dc->maxunit&&dc->devices[unit]!=NULL)unit++;}/**We'veselec
tedaunitbeyondthelengthofthetable,solet'sextend*thetabletomakeroomforallunitsuptoandincludingthisone.*/if(unit>=dc->maxunit){device_t*newlist;intnewsiz
e;newsize=roundup((unit+1),MINALLOCSIZE/sizeof(device_t));newlist=malloc(sizeof(device_t)*newsize,M_BUS,M_NOWAIT);if(!newlist)returnENOMEM;bcopy(dc->de
vices,newlist,sizeof(device_t)*dc->maxunit);bzero(newlist+dc->maxunit,sizeof(device_t)*(newsize-dc->maxunit));if(dc->devices)free(dc->devices,M_BUS);dc
->devices=newlist;dc->maxunit=newsize;}PDEBUG(("now:unit%dindevclass%s",unit,DEVCLANAME(dc)));*unitp=unit;return0;}staticintdevclass_add_device(devclas
s_tdc,device_tdev){intbuflen,error;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DEVCLANAME(dc)));buflen=strlen(dc->name)+5;dev->nameunit=malloc(buflen,M_BU
S,M_NOWAIT);if(!dev->nameunit)returnENOMEM;bzero(dev->nameunit,buflen);if((error=devclass_alloc_unit(dc,&dev->unit))!=0){free(dev->nameunit,M_BUS);dev-
>nameunit=NULL;returnerror;}dc->devices[dev->unit]=dev;dev->devclass=dc;snprintf(dev->nameunit,buflen,"%s%d",dc->name,dev->unit);#ifdefDEVICE_SYSCTLSde
vice_register_oids(dev);#endifreturn0;}staticintdevclass_delete_device(devclass_tdc,device_tdev){if(!dc||!dev)return0;PDEBUG(("%sindevclass%s",DEVICENA
ME(dev),DEVCLANAME(dc)));if(dev->devclass!=dc||dc->devices[dev->unit]!=dev)panic("devclass_delete_device:inconsistentdeviceclass");dc->devices[dev->uni
t]=NULL;if(dev->flags&DF_WILDCARD)dev->unit=-1;dev->devclass=NULL;free(dev->nameunit,M_BUS);dev->nameunit=NULL;#ifdefDEVICE_SYSCTLSdevice_unregister_oi
ds(dev);#endifreturn0;}staticdevice_tmake_device(device_tparent,constchar*name,intunit){device_tdev;devclass_tdc;PDEBUG(("%sat%sasunit%d",name,DEVICENA
ME(parent),unit));if(name){dc=devclass_find_internal(name,TRUE);if(!dc){printf("make_device:can'tfinddeviceclass%s\n",name);returnNULL;}}elsedc=NULL;de
v=malloc(sizeof(structdevice),M_BUS,M_NOWAIT);if(!dev)return0;bzero(dev,sizeof(structdevice));dev->parent=parent;TAILQ_INIT(&dev->children);dev->ops=&n
ull_ops;dev->driver=NULL;dev->devclass=NULL;dev->unit=unit;dev->nameunit=NULL;dev->desc=NULL;dev->busy=0;dev->devflags=0;dev->flags=DF_ENABLED;dev->ord
er=0;if(unit==-1)dev->flags|=DF_WILDCARD;if(name){dev->flags|=DF_FIXEDCLASS;devclass_add_device(dc,dev);}dev->ivars=NULL;dev->softc=NULL;dev->state=DS_
NOTPRESENT;returndev;}staticintdevice_print_child(device_tdev,device_tchild){intretval=0;if(device_is_alive(child)){retval+=BUS_PRINT_CHILD(dev,child);
}elseretval+=device_printf(child,"notfound\n");return(retval);}device_tdevice_add_child(device_tdev,constchar*name,intunit){returndevice_add_child_orde
red(dev,0,name,unit);}device_tdevice_add_child_ordered(device_tdev,intorder,constchar*name,intunit){device_tchild;device_tplace;PDEBUG(("%sat%swithorde
r%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){/**Thedevice'place'isthefirstdevicewhoseorderis*greaterthanthenewchild.*/TAILQ_INSERT_BEFORE(place
,child,link);}else{/**Thenewchild'sorderisgreaterorequaltotheorderof*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),DEVICENAM
E(dev)));/*removechildrenfirst*/while((grandchild=TAILQ_FIRST(&child->children))){error=device_delete_child(child,grandchild);if(error)returnerror;}if(
(error=device_detach(child))!=0)returnerror;if(child->devclass)devclass_delete_device(child->devclass,child);TAILQ_REMOVE(&dev->children,child,link);de
vice_set_desc(child,NULL);free(child,M_BUS);return0;}/**Findonlydevicesattachedtothisbus.*/device_tdevice_find_child(device_tdev,constchar*classname,in
tunit){devclass_tdc;device_tchild;dc=devclass_find(classname);if(!dc)returnNULL;child=devclass_get_device(dc,unit);if(child&&child->parent==dev)returnc
hild;returnNULL;}staticdriverlink_tfirst_matching_driver(devclass_tdc,device_tdev){if(dev->devclass)returndevclass_find_driver_internal(dc,dev->devclas
s->name);elsereturnTAILQ_FIRST(&dc->drivers);}staticdriverlink_tnext_matching_driver(devclass_tdc,device_tdev,driverlink_tlast){if(dev->devclass){drive
rlink_tdl;for(dl=TAILQ_NEXT(last,link);dl;dl=TAILQ_NEXT(dl,link))if(!strcmp(dev->devclass->name,dl->driver->name))returndl;returnNULL;}elsereturnTAILQ_
NEXT(last,link);}staticintdevice_probe_child(device_tdev,device_tchild){devclass_tdc;driverlink_tbest=0;driverlink_tdl;intresult,pri=0;inthasclass=(chi
ld->devclass!=0);dc=dev->devclass;if(!dc)panic("device_probe_child:parentdevicehasnodevclass");if(child->state==DS_ALIVE)return0;for(dl=first_matching_
driver(dc,child);dl;dl=next_matching_driver(dc,child,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,therecanb
enohighermatch*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,changestateandinitialisethedevclass.*/if(best){if(!child->devclass)device_set_devclass(child,best->driver-
>name);device_set_driver(child,best->driver);if(pri<0){/**Abitbogus.Calltheprobemethodagaintomakesure*thatwehavetherightdescription.*/DEVICE_PROBE(chil
d);}child->state=DS_ALIVE;return0;}returnENXIO;}device_tdevice_get_parent(device_tdev){returndev->parent;}intdevice_get_children(device_tdev,device_t**
devlistp,int*devcountp){intcount;device_tchild;device_t*list;count=0;for(child=TAILQ_FIRST(&dev->children);child;child=TAILQ_NEXT(child,link))count++;l
ist=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->childre
n);child;child=TAILQ_NEXT(child,link)){list[count]=child;count++;}*devlistp=list;*devcountp=count;return0;}driver_t*device_get_driver(device_tdev){retu
rndev->driver;}devclass_tdevice_get_devclass(device_tdev){returndev->devclass;}constchar*device_get_name(device_tdev){if(dev->devclass)returndevclass_g
et_name(dev->devclass);returnNULL;}constchar*device_get_nameunit(device_tdev){returndev->nameunit;}intdevice_get_unit(device_tdev){returndev->unit;}con
stchar*device_get_desc(device_tdev){returndev->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;intretval;retval=device_print_prettyname(dev);va_start(ap,fmt);retval+=vprintf(fmt,ap);va_end(ap);returnretval;}stati
cvoiddevice_set_desc_internal(device_tdev,constchar*desc,intcopy){if(dev->desc&&(dev->flags&DF_DESCMALLOCED)){free(dev->desc,M_BUS);dev->flags&=~DF_DES
CMALLOCED;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_DESCMALLOC
ED;}}else/*Avoida-Wcast-qualwarning*/dev->desc=(char*)(uintptr_t)desc;#ifdefDEVICE_SYSCTLS{structsysctl_oid*oid=&dev->oid[1];oid->oid_arg1=dev->desc?de
v->desc:"";oid->oid_arg2=dev->desc?strlen(dev->desc):0;}#endif}voiddevice_set_desc(device_tdev,constchar*desc){device_set_desc_internal(dev,desc,FALSE)
;}voiddevice_set_desc_copy(device_tdev,constchar*desc){device_set_desc_internal(dev,desc,TRUE);}voiddevice_set_flags(device_tdev,u_int32_tflags){dev->d
evflags=flags;}void*device_get_softc(device_tdev){returndev->softc;}voiddevice_set_softc(device_tdev,void*softc){if(dev->softc&&!(dev->flags&DF_EXTERNA
LSOFTC))free(dev->softc,M_BUS);dev->softc=softc;if(dev->softc)dev->flags|=DF_EXTERNALSOFTC;elsedev->flags&=~DF_EXTERNALSOFTC;}void*device_get_ivars(dev
ice_tdev){returndev->ivars;}voiddevice_set_ivars(device_tdev,void*ivars){if(!dev)return;dev->ivars=ivars;return;}device_state_tdevice_get_state(device_
tdev){returndev->state;}voiddevice_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;}voiddevice_unbusy(device_tdev){if(dev->state!=DS_BUSY)panic("device_unbusy:calledfornon-busydevice");dev->busy--;if(dev->busy==0)
{if(dev->parent)device_unbusy(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)devclass_delete_device(dev->devclass,dev);return0;}if(dev->devclass){printf("device_set_devclass:deviceclassalreadyset\n");returnEINVAL;
}dc=devclass_find_internal(classname,TRUE);if(!dc)returnENOMEM;returndevclass_add_device(dc,dev);}intdevice_set_driver(device_tdev,driver_t*driver){if(
dev->state>=DS_ATTACHED)returnEBUSY;if(dev->driver==driver)return0;if(dev->softc&&!(dev->flags&DF_EXTERNALSOFTC)){free(dev->softc,M_BUS);dev->softc=NUL
L;}dev->ops=&null_ops;dev->driver=driver;if(driver){dev->ops=driver->ops;if(!(dev->flags&DF_EXTERNALSOFTC)){dev->softc=malloc(driver->softc,M_BUS,M_NOW
AIT);if(!dev->softc){dev->ops=&null_ops;dev->driver=NULL;returnENOMEM;}bzero(dev->softc,driver->softc);}}return0;}intdevice_probe_and_attach(device_tde
v){device_tbus=dev->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(!error){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_attach:%s%dattachreturned%d\n",dev->driver->name,dev->unit,error);/*Unsettheclassthatwassetindevice_probe_child*/if(!hasclass)device_set_dev
class(dev,0);device_set_driver(dev,NULL);dev->state=DS_NOTPRESENT;}}else{if(!(dev->flags&DF_DONENOMATCH)){BUS_PROBE_NOMATCH(bus,dev);dev->flags|=DF_DON
ENOMATCH;}}}else{if(bootverbose){device_print_prettyname(dev);printf("notprobed(disabled)\n");}}returnerror;}intdevice_detach(device_tdev){interror;PDE
BUG(("%s",DEVICENAME(dev)));if(dev->state==DS_BUSY)returnEBUSY;if(dev->state!=DS_ATTACHED)return0;if((error=DEVICE_DETACH(dev))!=0)returnerror;device_p
rintf(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)
;}intdevice_set_unit(device_tdev,intunit){devclass_tdc;interr;dc=device_get_devclass(dev);if(unit<dc->maxunit&&dc->devices[unit])returnEBUSY;err=devcla
ss_delete_device(dc,dev);if(err)returnerr;dev->unit=unit;err=devclass_add_device(dc,dev);if(err)returnerr;return0;}#ifdefDEVICE_SYSCTLS/**Sysctlnodesfo
rdevices.*/SYSCTL_NODE(_hw,OID_AUTO,devices,CTLFLAG_RW,0,"Alistofalldevices");staticintsysctl_handle_children(SYSCTL_HANDLER_ARGS){device_tdev=arg1;dev
ice_tchild;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(r
eq,"",1);returnerror;}staticintsysctl_handle_state(SYSCTL_HANDLER_ARGS){device_tdev=arg1;switch(dev->state){caseDS_NOTPRESENT:returnSYSCTL_OUT(req,"not
present",sizeof("notpresent"));caseDS_ALIVE:returnSYSCTL_OUT(req,"alive",sizeof("alive"));caseDS_ATTACHED:returnSYSCTL_OUT(req,"attached",sizeof("attac
hed"));caseDS_BUSY:returnSYSCTL_OUT(req,"busy",sizeof("busy"));}return0;}staticvoiddevice_register_oids(device_tdev){structsysctl_oid*oid;oid=&dev->oid
[0];bzero(oid,sizeof(*oid));oid->oid_parent=&sysctl__hw_devices_children;oid->oid_number=OID_AUTO;oid->oid_kind=CTLTYPE_NODE|CTLFLAG_RW;oid->oid_arg1=&
dev->oidlist[0];oid->oid_arg2=0;oid->oid_name=dev->nameunit;oid->oid_handler=0;oid->oid_fmt="N";SLIST_INIT(&dev->oidlist[0]);sysctl_register_oid(oid);o
id=&dev->oid[1];bzero(oid,sizeof(*oid));oid->oid_parent=&dev->oidlist[0];oid->oid_number=OID_AUTO;oid->oid_kind=CTLTYPE_STRING|CTLFLAG_RD;oid->oid_arg1
=dev->desc?dev->desc:"";oid->oid_arg2=dev->desc?strlen(dev->desc):0;oid->oid_name="desc";oid->oid_handler=sysctl_handle_string;oid->oid_fmt="A";sysctl_
register_oid(oid);oid=&dev->oid[2];bzero(oid,sizeof(*oid));oid->oid_parent=&dev->oidlist[0];oid->oid_number=OID_AUTO;oid->oid_kind=CTLTYPE_INT|CTLFLAG_
RD;oid->oid_arg1=dev;oid->oid_arg2=0;oid->oid_name="children";oid->oid_handler=sysctl_handle_children;oid->oid_fmt="A";sysctl_register_oid(oid);oid=&de
v->oid[3];bzero(oid,sizeof(*oid));oid->oid_parent=&dev->oidlist[0];oid->oid_number=OID_AUTO;oid->oid_kind=CTLTYPE_INT|CTLFLAG_RD;oid->oid_arg1=dev;oid-
>oid_arg2=0;oid->oid_name="state";oid->oid_handler=sysctl_handle_state;oid->oid_fmt="A";sysctl_register_oid(oid);}staticvoiddevice_unregister_oids(devi
ce_tdev){sysctl_unregister_oid(&dev->oid[0]);sysctl_unregister_oid(&dev->oid[1]);sysctl_unregister_oid(&dev->oid[2]);}#endif/*=========================
=============*//**Accessfunctionsfordeviceresources.*//*Suppliedbyconfig(8)inioconf.c*/externstructconfig_deviceconfig_devtab[];externintdevtab_count;/
*Runtimeversion*/structconfig_device*devtab=config_devtab;staticintresource_new_name(constchar*name,intunit){structconfig_device*new;new=malloc((devtab
_count+1)*sizeof(*new),M_TEMP,M_NOWAIT);if(new==NULL)return-1;if(devtab&&devtab_count>0)bcopy(devtab,new,devtab_count*sizeof(*new));bzero(&new[devtab_c

Hosted by uCoz