/**Copyright(c)1997,1998DougRabson*Allrightsreserved.**Redistributionanduseinsourceandbinaryforms,withorwithout*modification,arepermittedprovidedth
atthefollowingconditions*aremet:*1.Redistributionsofsourcecodemustretaintheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimer.*2.R
edistributionsinbinaryformmustreproducetheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimerinthe*documentationand/orothermaterial
sprovidedwiththedistribution.**THISSOFTWAREISPROVIDEDBYTHEAUTHORANDCONTRIBUTORS``ASIS''AND*ANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,
THE*IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE*AREDISCLAIMED.INNOEVENTSHALLTHEAUTHORORCONTRIBUTORSBELIABLE*FORANYDIRECT,INDI
RECT,INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIAL*DAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODS*ORSERVICES;LOSSOFUSE,DATA,ORPROFIT
S;ORBUSINESSINTERRUPTION)*HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICT*LIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGIN
ANYWAY*OUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOF*SUCHDAMAGE.**$FreeBSD:src/sys/kern/subr_bus.c,v1.54.2.82001/01/1800:19:50n_hibmaEx
p$*/#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_SYS
CTLS#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:"n
odevclass")/*Producetheindenting,indent*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_device_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_driver_list(driver_list_tdrivers,intindent);staticvoidprint_devclass_short(devclass_tdc,intindent);stati
cvoidprint_devclass(devclass_tdc,intindent);voidprint_devclass_list_short(void);voidprint_devclass_list(void);#else/*Makethecompilerignorethefuncti
oncalls*/#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_short(d,i)/*nop*/#defineprint_driver(d,i)/*nop*/#defineprint_driver_list(d,i)/*nop*/#define
print_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);staticvoiddevice_unregister_oids(device_tdev);#endif/**Methodtablehandling*/statici
nterror_method(void);staticintnext_method_offset=1;LIST_HEAD(methodlist,method)methods;structmethod{LIST_ENTRY(method)link;/*linkedlistofmethods*/i
ntoffset;/*offsetinmethodtable*/intrefs;/*countofdevice_op_descusers*/devop_tdeflt;/*defaultimplementation*/char*name;/*uniquenameofmethod*/};stati
cvoidregister_method(structdevice_op_desc*desc){structmethod*m;if(desc->method){desc->method->refs++;return;}/**Makesurethatdesc->defltisalwaysvali
dtosimplifydispatch.*/if(!desc->deflt)desc->deflt=error_method;for(m=LIST_FIRST(&methods);m;m=LIST_NEXT(m,link)){if(!strcmp(m->name,desc->name)){de
sc->offset=m->offset;desc->method=m;m->refs++;PDEBUG(("method%phasthesamename,%s,withoffset%d",(void*)m,desc->name,desc->offset));return;}}m=(struc
tmethod*)malloc(sizeof(structmethod)+strlen(desc->name)+1,M_BUS,M_NOWAIT);if(!m)panic("register_method:outofmemory");bzero(m,sizeof(structmethod)+s
trlen(desc->name)+1);m->offset=next_method_offset++;m->refs=1;m->deflt=desc->deflt;m->name=(char*)(m+1);strcpy(m->name,desc->name);LIST_INSERT_HEAD
(&methods,m,link);desc->offset=m->offset;desc->method=m;}staticvoidunregister_method(structdevice_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){r
eturnENXIO;}staticstructdevice_opsnull_ops={1,{error_method}};staticvoidcompile_methods(driver_t*driver){device_ops_tops;structdevice_method*m;stru
ctmethod*cm;inti;/**Firstregisteranymethodswhichneedit.*/for(i=0,m=driver->methods;m->desc;i++,m++)register_method(m->desc);/**Thenallocatethecompi
ledoptable.*/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_offset;/*Fillindefaultmethodsandthenoverwri
tewithdrivermethods*/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->def
lt)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,was
ting%dbytes",DRIVERNAME(driver),i,(i==1?"":"s"),(next_method_offset-i)*sizeof(devop_t)));driver->ops=ops;}staticvoidfree_methods(driver_t*driver){i
nti;structdevice_method*m;/**Unregisteranymethodswhicharenolongerused.*/for(i=0,m=driver->methods;m->desc;i++,m++)unregister_method(m->desc);/**Fre
ememoryandcleanup.*/free(driver->ops,M_BUS);driver->ops=0;}/**Devclassimplementation*/staticdevclass_list_tdevclasses=TAILQ_HEAD_INITIALIZER(devcla
sses);staticdevclass_tdevclass_find_internal(constchar*classname,intcreate){devclass_tdc;PDEBUG(("lookingfor%s",classname));if(!classname)returnNUL
L;for(dc=TAILQ_FIRST(&devclasses);dc;dc=TAILQ_NEXT(dc,link))if(!strcmp(dc->name,classname))returndc;PDEBUG(("%snotfound%s",classname,(create?",crea
ting":"")));if(create){dc=malloc(sizeof(structdevclass)+strlen(classname)+1,M_BUS,M_NOWAIT);if(!dc)returnNULL;bzero(dc,sizeof(structdevclass)+strle
n(classname)+1);dc->name=(char*)(dc+1);strcpy(dc->name,classname);dc->devices=NULL;dc->maxunit=0;TAILQ_INIT(&dc->drivers);TAILQ_INSERT_TAIL(&devcla
sses,dc,link);}returndc;}devclass_tdevclass_create(constchar*classname){returndevclass_find_internal(classname,TRUE);}devclass_tdevclass_find(const
char*classname){returndevclass_find_internal(classname,FALSE);}intdevclass_add_driver(devclass_tdc,driver_t*driver){driverlink_tdl;inti;PDEBUG(("%s
",DRIVERNAME(driver)));dl=malloc(sizeof*dl,M_BUS,M_NOWAIT);if(!dl)returnENOMEM;bzero(dl,sizeof*dl);/**Compilethedriver'smethods.*/if(!driver->ops)c
ompile_methods(driver);/**Makesurethedevclasswhichthedriverisimplementingexists.*/devclass_find_internal(driver->name,TRUE);dl->driver=driver;TAILQ
_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(drive
r->name);driverlink_tdl;device_tdev;inti;interror;PDEBUG(("%sfromdevclass%s",driver->name,DEVCLANAME(busclass)));if(!dc)return0;/**Findthelinkstruc
tureinthebus'listofdrivers.*/for(dl=TAILQ_FIRST(&busclass->drivers);dl;dl=TAILQ_NEXT(dl,link)){if(dl->driver==driver)break;}if(!dl){PDEBUG(("%snotf
oundin%slist",driver->name,busclass->name));returnENOENT;}/**Disassociatefromanydevices.Weiteratethroughallthe*devicesinthedevclassofthedriverandde
tachanywhichare*usingthedriverandwhichhaveaparentinthedevclasswhich*wearedeletingfrom.**Notethatsinceadrivercanbeinmultipledevclasses,we*shouldnotd
etachdeviceswhicharenotchildrenofdevicesin*theaffecteddevclass.*/for(i=0;i<dc->maxunit;i++){if(dc->devices[i]){dev=dc->devices[i];if(dev->driver==d
river&&dev->parent&&dev->parent->devclass==busclass){if((error=device_detach(dev))!=0)returnerror;device_set_driver(dev,NULL);}}}TAILQ_REMOVE(&busc
lass->drivers,dl,link);free(dl,M_BUS);driver->refs--;if(driver->refs==0)free_methods(driver);return0;}staticdriverlink_tdevclass_find_driver_intern
al(devclass_tdc,constchar*classname){driverlink_tdl;PDEBUG(("%sindevclass%s",classname,DEVCLANAME(dc)));for(dl=TAILQ_FIRST(&dc->drivers);dl;dl=TAIL
Q_NEXT(dl,link)){if(!strcmp(dl->driver->name,classname))returndl;}PDEBUG(("notfound"));returnNULL;}driver_t*devclass_find_driver(devclass_tdc,const
char*classname){driverlink_tdl;dl=devclass_find_driver_internal(dc,classname);if(dl)returndl->driver;elsereturnNULL;}constchar*devclass_get_name(de
vclass_tdc){returndc->name;}device_tdevclass_get_device(devclass_tdc,intunit){if(dc==NULL||unit<0||unit>=dc->maxunit)returnNULL;returndc->devices[u
nit];}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->devic
es[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->ma
xunit;i++)if(dc->devices[i]){list[count]=dc->devices[i];count++;}*devlistp=list;*devcountp=count;return0;}intdevclass_get_maxunit(devclass_tdc){ret
urndc->maxunit;}staticintdevclass_alloc_unit(devclass_tdc,int*unitp){intunit=*unitp;PDEBUG(("unit%dindevclass%s",unit,DEVCLANAME(dc)));/*Ifwehavebe
engivenawiredunitnumber,checkforexistingdevice*/if(unit!=-1){if(unit>=0&&unit<dc->maxunit&&dc->devices[unit]!=NULL){if(bootverbose)printf("%s-:%s%d
exists,usingnextavailableunitnumber\n",dc->name,dc->name,unit);/*findthenextavailableslot*/while(++unit<dc->maxunit&&dc->devices[unit]!=NULL);}}els
e{/*Unwireddevice,findthenextavailableslotforit*/unit=0;while(unit<dc->maxunit&&dc->devices[unit]!=NULL)unit++;}/**We'veselectedaunitbeyondthelengt
hofthetable,solet'sextend*thetabletomakeroomforallunitsuptoandincludingthisone.*/if(unit>=dc->maxunit){device_t*newlist;intnewsize;newsize=roundup(
(unit+1),MINALLOCSIZE/sizeof(device_t));newlist=malloc(sizeof(device_t)*newsize,M_BUS,M_NOWAIT);if(!newlist)returnENOMEM;bcopy(dc->devices,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(devclass_tdc,
device_tdev){intbuflen,error;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DEVCLANAME(dc)));buflen=strlen(dc->name)+5;dev->nameunit=malloc(buflen,M_BUS,
M_NOWAIT);if(!dev->nameunit)returnENOMEM;bzero(dev->nameunit,buflen);if((error=devclass_alloc_unit(dc,&dev->unit))!=0){free(dev->nameunit,M_BUS);de
v->nameunit=NULL;returnerror;}dc->devices[dev->unit]=dev;dev->devclass=dc;snprintf(dev->nameunit,buflen,"%s%d",dc->name,dev->unit);#ifdefDEVICE_SYS
CTLSdevice_register_oids(dev);#endifreturn0;}staticintdevclass_delete_device(devclass_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->de
vices[dev->unit]=NULL;if(dev->flags&DF_WILDCARD)dev->unit=-1;dev->devclass=NULL;free(dev->nameunit,M_BUS);dev->nameunit=NULL;#ifdefDEVICE_SYSCTLSde
vice_unregister_oids(dev);#endifreturn0;}staticdevice_tmake_device(device_tparent,constchar*name,intunit){device_tdev;devclass_tdc;PDEBUG(("%sat%sa
sunit%d",name,DEVICENAME(parent),unit));if(name){dc=devclass_find_internal(name,TRUE);if(!dc){printf("make_device:can'tfinddeviceclass%s\n",name);r
eturnNULL;}}elsedc=NULL;dev=malloc(sizeof(structdevice),M_BUS,M_NOWAIT);if(!dev)return0;bzero(dev,sizeof(structdevice));dev->parent=parent;TAILQ_IN
IT(&dev->children);dev->ops=&null_ops;dev->driver=NULL;dev->devclass=NULL;dev->unit=unit;dev->nameunit=NULL;dev->desc=NULL;dev->busy=0;dev->devflag
s=0;dev->flags=DF_ENABLED;dev->order=0;if(unit==-1)dev->flags|=DF_WILDCARD;if(name){dev->flags|=DF_FIXEDCLASS;devclass_add_device(dc,dev);}dev->iva
rs=NULL;dev->softc=NULL;dev->state=DS_NOTPRESENT;returndev;}staticintdevice_print_child(device_tdev,device_tchild){intretval=0;if(device_is_alive(c
hild)){retval+=BUS_PRINT_CHILD(dev,child);}elseretval+=device_printf(child,"notfound\n");return(retval);}device_tdevice_add_child(device_tdev,const
char*name,intunit){returndevice_add_child_ordered(dev,0,name,unit);}device_tdevice_add_child_ordered(device_tdev,intorder,constchar*name,intunit){d
evice_tchild;device_tplace;PDEBUG(("%sat%swithorder%dasunit%d",name,DEVICENAME(dev),order,unit));child=make_device(dev,name,unit);if(child==NULL)re
turnchild;child->order=order;TAILQ_FOREACH(place,&dev->children,link)if(place->order>order)break;if(place){/**Thedevice'place'isthefirstdevicewhose
orderis*greaterthanthenewchild.*/TAILQ_INSERT_BEFORE(place,child,link);}else{/**Thenewchild'sorderisgreaterorequaltotheorderof*anyexistingdevice.Ad
dthechildtothetailofthelist.*/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_FIRST(&child->children)))
{error=device_delete_child(child,grandchild);if(error)returnerror;}if((error=device_detach(child))!=0)returnerror;if(child->devclass)devclass_delet
e_device(child->devclass,child);TAILQ_REMOVE(&dev->children,child,link);device_set_desc(child,NULL);free(child,M_BUS);return0;}/**Findonlydevicesat
tachedtothisbus.*/device_tdevice_find_child(device_tdev,constchar*classname,intunit){devclass_tdc;device_tchild;dc=devclass_find(classname);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);}staticdriverlin
k_tnext_matching_driver(devclass_tdc,device_tdev,driverlink_tlast){if(dev->devclass){driverlink_tdl;for(dl=TAILQ_NEXT(last,link);dl;dl=TAILQ_NEXT(d
l,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("d
evice_probe_child:parentdevicehasnodevclass");if(child->state==DS_ALIVE)return0;for(dl=first_matching_driver(dc,child);dl;dl=next_matching_driver(d
c,child,dl)){PDEBUG(("Trying%s",DRIVERNAME(dl->driver)));device_set_driver(child,dl->driver);if(!hasclass)device_set_devclass(child,dl->driver->nam
e);result=DEVICE_PROBE(child);if(!hasclass)device_set_devclass(child,0);/**IfthedriverreturnsSUCCESS,therecanbenohighermatch*forthisdevice.*/if(res
ult==0){best=dl;pri=0;break;}/**Thedriverreturnedanerrorsoitcertainlydoesn'tmatch.*/if(result>0){device_set_driver(child,0);continue;}/**Apriorityl
owerthanSUCCESS,rememberthebestmatching*driver.Initialisethevalueofpriforthefirstmatch.*/if(best==0||result>pri){best=dl;pri=result;continue;}}/**I
fwefoundadriver,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(child);}child->state=DS_A
LIVE;return0;}returnENXIO;}device_tdevice_get_parent(device_tdev){returndev->parent;}intdevice_get_children(device_tdev,device_t**devlistp,int*devc
ountp){intcount;device_tchild;device_t*list;count=0;for(child=TAILQ_FIRST(&dev->children);child;child=TAILQ_NEXT(child,link))count++;list=malloc(co
unt*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)){list[count]=child;count++;}*devlistp=list;*devcountp=count;return0;}driver_t*device_get_driver(device_tdev){returndev
->driver;}devclass_tdevice_get_devclass(device_tdev){returndev->devclass;}constchar*device_get_name(device_tdev){if(dev->devclass)returndevclass_ge
t_name(dev->devclass);returnNULL;}constchar*device_get_nameunit(device_tdev){returndev->nameunit;}intdevice_get_unit(device_tdev){returndev->unit;}
constchar*device_get_desc(device_tdev){returndev->desc;}u_int32_tdevice_get_flags(device_tdev){returndev->devflags;}intdevice_print_prettyname(devi
ce_tdev){constchar*name=device_get_name(dev);if(name==0)returnprintf("unknown:");elsereturnprintf("%s%d:",name,device_get_unit(dev));}intdevice_pri
ntf(device_tdev,constchar*fmt,...){va_listap;intretval;retval=device_print_prettyname(dev);va_start(ap,fmt);retval+=vprintf(fmt,ap);va_end(ap);retu
rnretval;}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);de
v->flags|=DF_DESCMALLOCED;}}else/*Avoida-Wcast-qualwarning*/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->desc?strlen(dev->desc):0;}#endif}voiddevice_set_desc(device_tdev,constchar*desc){device_se
t_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->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;}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(de
vice_tdev){dev->flags&=~DF_ENABLED;}voiddevice_busy(device_tdev){if(dev->state<DS_ATTACHED)panic("device_busy:calledforunattacheddevice");if(dev->b
usy==0&&dev->parent)device_busy(dev->parent);dev->busy++;dev->state=DS_BUSY;}voiddevice_unbusy(device_tdev){if(dev->state!=DS_BUSY)panic("device_un
busy:calledfornon-busydevice");dev->busy--;if(dev->busy==0){if(dev->parent)device_unbusy(dev->parent);dev->state=DS_ATTACHED;}}voiddevice_quiet(dev
ice_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_d
evclass(device_tdev,constchar*classname){devclass_tdc;if(!classname){if(dev->devclass)devclass_delete_device(dev->devclass,dev);return0;}if(dev->de
vclass){printf("device_set_devclass:deviceclassalreadyset\n");returnEINVAL;}dc=devclass_find_internal(classname,TRUE);if(!dc)returnENOMEM;returndev
class_add_device(dc,dev);}intdevice_set_driver(device_tdev,driver_t*driver){if(dev->state>=DS_ATTACHED)returnEBUSY;if(dev->driver==driver)return0;i
f(dev->softc&&!(dev->flags&DF_EXTERNALSOFTC)){free(dev->softc,M_BUS);dev->softc=NULL;}dev->ops=&null_ops;dev->driver=driver;if(driver){dev->ops=dri
ver->ops;if(!(dev->flags&DF_EXTERNALSOFTC)){dev->softc=malloc(driver->softc,M_BUS,M_NOWAIT);if(!dev->softc){dev->ops=&null_ops;dev->driver=NULL;ret
urnENOMEM;}bzero(dev->softc,driver->softc);}}return0;}intdevice_probe_and_attach(device_tdev){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->d
river->name,dev->unit,error);/*Unsettheclassthatwassetindevice_probe_child*/if(!hasclass)device_set_devclass(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_DONENOMATCH;}}}else{if(bootverbose){device_
print_prettyname(dev);printf("notprobed(disabled)\n");}}returnerror;}intdevice_detach(device_tdev){interror;PDEBUG(("%s",DEVICENAME(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);}intdevice_set_unit(dev
ice_tdev,intunit){devclass_tdc;interr;dc=device_get_devclass(dev);if(unit<dc->maxunit&&dc->devices[unit])returnEBUSY;err=devclass_delete_device(dc,
dev);if(err)returnerr;dev->unit=unit;err=devclass_add_device(dc,dev);if(err)returnerr;return0;}#ifdefDEVICE_SYSCTLS/**Sysctlnodesfordevices.*/SYSCT
L_NODE(_hw,OID_AUTO,devices,CTLFLAG_RW,0,"Alistofalldevices");staticintsysctl_handle_children(SYSCTL_HANDLER_ARGS){device_tdev=arg1;device_tchild;i
ntfirst=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,"not
present",sizeof("notpresent"));caseDS_ALIVE:returnSYSCTL_OUT(req,"alive",sizeof("alive"));caseDS_ATTACHED:returnSYSCTL_OUT(req,"attached",sizeof("a
ttached"));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_reg

Hosted by uCoz