/**Copyright(c)1997,1998DougRabson*Allrightsreserved.**Redistributionanduseinsourceandbinaryforms,withorwithout*modification,arepermittedprovidedthatthefollowingconditions*areme
t:*1.Redistributionsofsourcecodemustretaintheabovecopyright*notice,thislistofconditionsandthefollowingdisclaimer.*2.Redistributionsinbinaryformmustreproducetheabovecopyright*not
ice,thislistofconditionsandthefollowingdisclaimerinthe*documentationand/orothermaterialsprovidedwiththedistribution.**THISSOFTWAREISPROVIDEDBYTHEAUTHORANDCONTRIBUTORS``ASIS''AND
*ANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THE*IMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSE*AREDISCLAIMED.INNOEVENTSHALLTHEAUTHORORCONTRIBUTOR
SBELIABLE*FORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIAL*DAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODS*ORSERVICES;LOSSOFUSE,DATA,ORPROFITS;O
RBUSINESSINTERRUPTION)*HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICT*LIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAY*OUTOFTHEUSEOFTHISSOFTWARE,
EVENIFADVISEDOFTHEPOSSIBILITYOF*SUCHDAMAGE.**$FreeBSD:src/sys/kern/subrbus.c,v1.54.2.82001/01/1800:19:50nhibmaExp$*/#include"optbus.h"#include<sys/param.h>#include<sys/queue.h>#
include<sys/malloc.h>#include<sys/kernel.h>#include<sys/module.h>#ifdefDEVICESYSCTLS#include<sys/sysctl.h>#endif#include<sys/busprivate.h>#include<sys/systm.h>#include<machine/b
us.h>#include<sys/rman.h>#include<machine/stdarg.h>/*fordeviceprintf()*/MALLOCDEFINE(MBUS,"bus","Busdatastructures");#ifdefBUSDEBUG#definePDEBUG(a)(printf(FUNCTION":%d:",LINE),p
rintfa,printf("\n"))#defineDEVICENAME(d)((d)?devicegetname(d):"nodevice")#defineDRIVERNAME(d)((d)?d->name:"nodriver")#defineDEVCLANAME(d)((d)?d->name:"nodevclass")/*Producethein
denting,indent*2spacesplusa'.'aheadofthatto*preventsyslogfromdeletinginitialspaces*/#defineindentprintf(p)do{intiJ;printf(".");for(iJ=0;iJ<indent;iJ++)printf("");printfp;}while(
0)staticvoidprintmethodlist(devicemethodt*m,intindent);staticvoidprintdeviceops(deviceopstops,intindent);staticvoidprintdeviceshort(devicetdev,intindent);staticvoidprintdevice(d
evicetdev,intindent);voidprintdevicetreeshort(devicetdev,intindent);voidprintdevicetree(devicetdev,intindent);staticvoidprintdrivershort(drivert*driver,intindent);staticvoidprin
tdriver(drivert*driver,intindent);staticvoidprintdriverlist(driverlisttdrivers,intindent);staticvoidprintdevclassshort(devclasstdc,intindent);staticvoidprintdevclass(devclasstdc
,intindent);voidprintdevclasslistshort(void);voidprintdevclasslist(void);#else/*Makethecompilerignorethefunctioncalls*/#definePDEBUG(a)/*nop*/#defineDEVICENAME(d)/*nop*/#defineD
RIVERNAME(d)/*nop*/#defineDEVCLANAME(d)/*nop*/#defineprintmethodlist(m,i)/*nop*/#defineprintdeviceops(o,i)/*nop*/#defineprintdeviceshort(d,i)/*nop*/#defineprintdevice(d,i)/*nop*
/#defineprintdevicetreeshort(d,i)/*nop*/#defineprintdevicetree(d,i)/*nop*/#defineprintdrivershort(d,i)/*nop*/#defineprintdriver(d,i)/*nop*/#defineprintdriverlist(d,i)/*nop*/#def
ineprintdevclassshort(d,i)/*nop*/#defineprintdevclass(d,i)/*nop*/#defineprintdevclasslistshort()/*nop*/#defineprintdevclasslist()/*nop*/#endif#ifdefDEVICESYSCTLSstaticvoiddevice
registeroids(devicetdev);staticvoiddeviceunregisteroids(devicetdev);#endif/**Methodtablehandling*/staticinterrormethod(void);staticintnextmethodoffset=1;LISTHEAD(methodlist,meth
od)methods;structmethod{LISTENTRY(method)link;/*linkedlistofmethods*/intoffset;/*offsetinmethodtable*/intrefs;/*countofdeviceopdescusers*/devoptdeflt;/*defaultimplementation*/ch
ar*name;/*uniquenameofmethod*/};staticvoidregistermethod(structdeviceopdesc*desc){structmethod*m;if(desc->method){desc->method->refs++;return;}/**Makesurethatdesc->defltisalways
validtosimplifydispatch.*/if(!desc->deflt)desc->deflt=errormethod;for(m=LISTFIRST(&methods);m;m=LISTNEXT(m,link)){if(!strcmp(m->name,desc->name)){desc->offset=m->offset;desc->me
thod=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,MNOWAIT);if(!m)panic("registermethod:outofmemory");bzero(m,sizeof(structmethod)+strlen(desc->name)+1);m->offset=nextmethodoffset++;m->refs=1;m->deflt=desc->deflt;m->name=(ch
ar*)(m+1);strcpy(m->name,desc->name);LISTINSERTHEAD(&methods,m,link);desc->offset=m->offset;desc->method=m;}staticvoidunregistermethod(structdeviceopdesc*desc){structmethod*m=de
sc->method;m->refs--;if(m->refs==0){PDEBUG(("method%s,reachedrefcount0",desc->name));LISTREMOVE(m,link);free(m,MBUS);desc->method=0;}}staticinterrormethod(void){returnENXIO;}sta
ticstructdeviceopsnullops={1,{errormethod}};staticvoidcompilemethods(drivert*driver){deviceopstops;structdevicemethod*m;structmethod*cm;inti;/**Firstregisteranymethodswhichneedi
t.*/for(i=0,m=driver->methods;m->desc;i++,m++)registermethod(m->desc);/**Thenallocatethecompiledoptable.*/ops=malloc(sizeof(structdeviceops)+(nextmethodoffset-1)*sizeof(devopt),
MBUS,MNOWAIT);if(!ops)panic("compilemethods:outofmemory");bzero(ops,sizeof(structdeviceops)+(nextmethodoffset-1)*sizeof(devopt));ops->maxoffset=nextmethodoffset;/*Fillindefaultm
ethodsandthenoverwritewithdrivermethods*/for(i=0;i<nextmethodoffset;i++)ops->methods[i]=errormethod;for(cm=LISTFIRST(&methods);cm;cm=LISTNEXT(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
"),(nextmethodoffset-i)*sizeof(devopt)));driver->ops=ops;}staticvoidfreemethods(drivert*driver){inti;structdevicemethod*m;/**Unregisteranymethodswhicharenolongerused.*/for(i=0,m
=driver->methods;m->desc;i++,m++)unregistermethod(m->desc);/**Freememoryandcleanup.*/free(driver->ops,MBUS);driver->ops=0;}/**Devclassimplementation*/staticdevclasslisttdevclass
es=TAILQHEADINITIALIZER(devclasses);staticdevclasstdevclassfindinternal(constchar*classname,intcreate){devclasstdc;PDEBUG(("lookingfor%s",classname));if(!classname)returnNULL;fo
r(dc=TAILQFIRST(&devclasses);dc;dc=TAILQNEXT(dc,link))if(!strcmp(dc->name,classname))returndc;PDEBUG(("%snotfound%s",classname,(create?",creating":"")));if(create){dc=malloc(siz
eof(structdevclass)+strlen(classname)+1,MBUS,MNOWAIT);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;TAILQINIT(&dc->drivers);TAILQINSERTTAIL(&devclasses,dc,link);}returndc;}devclasstdevclasscreate(constchar*classname){returndevclassfindinternal(clas
sname,TRUE);}devclasstdevclassfind(constchar*classname){returndevclassfindinternal(classname,FALSE);}intdevclassadddriver(devclasstdc,drivert*driver){driverlinktdl;inti;PDEBUG((
"%s",DRIVERNAME(driver)));dl=malloc(sizeof*dl,MBUS,MNOWAIT);if(!dl)returnENOMEM;bzero(dl,sizeof*dl);/**Compilethedriver'smethods.*/if(!driver->ops)compilemethods(driver);/**Make
surethedevclasswhichthedriverisimplementingexists.*/devclassfindinternal(driver->name,TRUE);dl->driver=driver;TAILQINSERTTAIL(&dc->drivers,dl,link);driver->refs++;/**CallBUSDRIV
ERADDEDforanyexistingbussesinthisclass.*/for(i=0;i<dc->maxunit;i++)if(dc->devices[i])BUSDRIVERADDED(dc->devices[i],driver);return0;}intdevclassdeletedriver(devclasstbusclass,dri
vert*driver){devclasstdc=devclassfind(driver->name);driverlinktdl;devicetdev;inti;interror;PDEBUG(("%sfromdevclass%s",driver->name,DEVCLANAME(busclass)));if(!dc)return0;/**Findt
helinkstructureinthebus'listofdrivers.*/for(dl=TAILQFIRST(&busclass->drivers);dl;dl=TAILQNEXT(dl,link)){if(dl->driver==driver)break;}if(!dl){PDEBUG(("%snotfoundin%slist",driver-
>name,busclass->name));returnENOENT;}/**Disassociatefromanydevices.Weiteratethroughallthe*devicesinthedevclassofthedriveranddetachanywhichare*usingthedriverandwhichhaveaparentin
thedevclasswhich*wearedeletingfrom.**Notethatsinceadrivercanbeinmultipledevclasses,we*shouldnotdetachdeviceswhicharenotchildrenofdevicesin*theaffecteddevclass.*/for(i=0;i<dc->ma
xunit;i++){if(dc->devices[i]){dev=dc->devices[i];if(dev->driver==driver&&dev->parent&&dev->parent->devclass==busclass){if((error=devicedetach(dev))!=0)returnerror;devicesetdrive
r(dev,NULL);}}}TAILQREMOVE(&busclass->drivers,dl,link);free(dl,MBUS);driver->refs--;if(driver->refs==0)freemethods(driver);return0;}staticdriverlinktdevclassfinddriverinternal(d
evclasstdc,constchar*classname){driverlinktdl;PDEBUG(("%sindevclass%s",classname,DEVCLANAME(dc)));for(dl=TAILQFIRST(&dc->drivers);dl;dl=TAILQNEXT(dl,link)){if(!strcmp(dl->driver
->name,classname))returndl;}PDEBUG(("notfound"));returnNULL;}drivert*devclassfinddriver(devclasstdc,constchar*classname){driverlinktdl;dl=devclassfinddriverinternal(dc,classname
);if(dl)returndl->driver;elsereturnNULL;}constchar*devclassgetname(devclasstdc){returndc->name;}devicetdevclassgetdevice(devclasstdc,intunit){if(dc==NULL||unit<0||unit>=dc->maxu
nit)returnNULL;returndc->devices[unit];}void*devclassgetsoftc(devclasstdc,intunit){devicetdev;dev=devclassgetdevice(dc,unit);if(!dev)return(NULL);return(devicegetsoftc(dev));}in
tdevclassgetdevices(devclasstdc,devicet**devlistp,int*devcountp){inti;intcount;devicet*list;count=0;for(i=0;i<dc->maxunit;i++)if(dc->devices[i])count++;list=malloc(count*sizeof(
devicet),MTEMP,MNOWAIT);if(!list)returnENOMEM;bzero(list,count*sizeof(devicet));count=0;for(i=0;i<dc->maxunit;i++)if(dc->devices[i]){list[count]=dc->devices[i];count++;}*devlist
p=list;*devcountp=count;return0;}intdevclassgetmaxunit(devclasstdc){returndc->maxunit;}staticintdevclassallocunit(devclasstdc,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->name,unit);/*findthenextavailableslot*/while(++unit<dc->maxunit&&dc->devices[unit]!=NULL);}}else{/*Unwireddevice,find
thenextavailableslotforit*/unit=0;while(unit<dc->maxunit&&dc->devices[unit]!=NULL)unit++;}/**We'veselectedaunitbeyondthelengthofthetable,solet'sextend*thetabletomakeroomforallun
itsuptoandincludingthisone.*/if(unit>=dc->maxunit){devicet*newlist;intnewsize;newsize=roundup((unit+1),MINALLOCSIZE/sizeof(devicet));newlist=malloc(sizeof(devicet)*newsize,MBUS,
MNOWAIT);if(!newlist)returnENOMEM;bcopy(dc->devices,newlist,sizeof(devicet)*dc->maxunit);bzero(newlist+dc->maxunit,sizeof(devicet)*(newsize-dc->maxunit));if(dc->devices)free(dc-
>devices,MBUS);dc->devices=newlist;dc->maxunit=newsize;}PDEBUG(("now:unit%dindevclass%s",unit,DEVCLANAME(dc)));*unitp=unit;return0;}staticintdevclassadddevice(devclasstdc,device
tdev){intbuflen,error;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DEVCLANAME(dc)));buflen=strlen(dc->name)+5;dev->nameunit=malloc(buflen,MBUS,MNOWAIT);if(!dev->nameunit)returnENOME
M;bzero(dev->nameunit,buflen);if((error=devclassallocunit(dc,&dev->unit))!=0){free(dev->nameunit,MBUS);dev->nameunit=NULL;returnerror;}dc->devices[dev->unit]=dev;dev->devclass=d
c;snprintf(dev->nameunit,buflen,"%s%d",dc->name,dev->unit);#ifdefDEVICESYSCTLSdeviceregisteroids(dev);#endifreturn0;}staticintdevclassdeletedevice(devclasstdc,devicetdev){if(!dc
||!dev)return0;PDEBUG(("%sindevclass%s",DEVICENAME(dev),DEVCLANAME(dc)));if(dev->devclass!=dc||dc->devices[dev->unit]!=dev)panic("devclassdeletedevice:inconsistentdeviceclass");
dc->devices[dev->unit]=NULL;if(dev->flags&DFWILDCARD)dev->unit=-1;dev->devclass=NULL;free(dev->nameunit,MBUS);dev->nameunit=NULL;#ifdefDEVICESYSCTLSdeviceunregisteroids(dev);#en
difreturn0;}staticdevicetmakedevice(devicetparent,constchar*name,intunit){devicetdev;devclasstdc;PDEBUG(("%sat%sasunit%d",name,DEVICENAME(parent),unit));if(name){dc=devclassfind
internal(name,TRUE);if(!dc){printf("makedevice:can'tfinddeviceclass%s\n",name);returnNULL;}}elsedc=NULL;dev=malloc(sizeof(structdevice),MBUS,MNOWAIT);if(!dev)return0;bzero(dev,s
izeof(structdevice));dev->parent=parent;TAILQINIT(&dev->children);dev->ops=&nullops;dev->driver=NULL;dev->devclass=NULL;dev->unit=unit;dev->nameunit=NULL;dev->desc=NULL;dev->bus
y=0;dev->devflags=0;dev->flags=DFENABLED;dev->order=0;if(unit==-1)dev->flags|=DFWILDCARD;if(name){dev->flags|=DFFIXEDCLASS;devclassadddevice(dc,dev);}dev->ivars=NULL;dev->softc=
NULL;dev->state=DSNOTPRESENT;returndev;}staticintdeviceprintchild(devicetdev,devicetchild){intretval=0;if(deviceisalive(child)){retval+=BUSPRINTCHILD(dev,child);}elseretval+=dev
iceprintf(child,"notfound\n");return(retval);}devicetdeviceaddchild(devicetdev,constchar*name,intunit){returndeviceaddchildordered(dev,0,name,unit);}devicetdeviceaddchildordered
(devicetdev,intorder,constchar*name,intunit){devicetchild;devicetplace;PDEBUG(("%sat%swithorder%dasunit%d",name,DEVICENAME(dev),order,unit));child=makedevice(dev,name,unit);if(c
hild==NULL)returnchild;child->order=order;TAILQFOREACH(place,&dev->children,link)if(place->order>order)break;if(place){/**Thedevice'place'isthefirstdevicewhoseorderis*greatertha
nthenewchild.*/TAILQINSERTBEFORE(place,child,link);}else{/**Thenewchild'sorderisgreaterorequaltotheorderof*anyexistingdevice.Addthechildtothetailofthelist.*/TAILQINSERTTAIL(&dev
->children,child,link);}returnchild;}intdevicedeletechild(devicetdev,devicetchild){interror;devicetgrandchild;PDEBUG(("%sfrom%s",DEVICENAME(child),DEVICENAME(dev)));/*removechil
drenfirst*/while((grandchild=TAILQFIRST(&child->children))){error=devicedeletechild(child,grandchild);if(error)returnerror;}if((error=devicedetach(child))!=0)returnerror;if(chil
d->devclass)devclassdeletedevice(child->devclass,child);TAILQREMOVE(&dev->children,child,link);devicesetdesc(child,NULL);free(child,MBUS);return0;}/**Findonlydevicesattachedtoth
isbus.*/devicetdevicefindchild(devicetdev,constchar*classname,intunit){devclasstdc;devicetchild;dc=devclassfind(classname);if(!dc)returnNULL;child=devclassgetdevice(dc,unit);if(
child&&child->parent==dev)returnchild;returnNULL;}staticdriverlinktfirstmatchingdriver(devclasstdc,devicetdev){if(dev->devclass)returndevclassfinddriverinternal(dc,dev->devclass
->name);elsereturnTAILQFIRST(&dc->drivers);}staticdriverlinktnextmatchingdriver(devclasstdc,devicetdev,driverlinktlast){if(dev->devclass){driverlinktdl;for(dl=TAILQNEXT(last,lin
k);dl;dl=TAILQNEXT(dl,link))if(!strcmp(dev->devclass->name,dl->driver->name))returndl;returnNULL;}elsereturnTAILQNEXT(last,link);}staticintdeviceprobechild(devicetdev,devicetchi
ld){devclasstdc;driverlinktbest=0;driverlinktdl;intresult,pri=0;inthasclass=(child->devclass!=0);dc=dev->devclass;if(!dc)panic("deviceprobechild:parentdevicehasnodevclass");if(c
hild->state==DSALIVE)return0;for(dl=firstmatchingdriver(dc,child);dl;dl=nextmatchingdriver(dc,child,dl)){PDEBUG(("Trying%s",DRIVERNAME(dl->driver)));devicesetdriver(child,dl->dr
iver);if(!hasclass)devicesetdevclass(child,dl->driver->name);result=DEVICEPROBE(child);if(!hasclass)devicesetdevclass(child,0);/**IfthedriverreturnsSUCCESS,therecanbenohighermat
ch*forthisdevice.*/if(result==0){best=dl;pri=0;break;}/**Thedriverreturnedanerrorsoitcertainlydoesn'tmatch.*/if(result>0){devicesetdriver(child,0);continue;}/**Aprioritylowertha
nSUCCESS,rememberthebestmatching*driver.Initialisethevalueofpriforthefirstmatch.*/if(best==0||result>pri){best=dl;pri=result;continue;}}/**Ifwefoundadriver,changestateandinitial
isethedevclass.*/if(best){if(!child->devclass)devicesetdevclass(child,best->driver->name);devicesetdriver(child,best->driver);if(pri<0){/**Abitbogus.Calltheprobemethodagaintomak
esure*thatwehavetherightdescription.*/DEVICEPROBE(child);}child->state=DSALIVE;return0;}returnENXIO;}devicetdevicegetparent(devicetdev){returndev->parent;}intdevicegetchildren(d
evicetdev,devicet**devlistp,int*devcountp){intcount;devicetchild;devicet*list;count=0;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link))count++;list=malloc(
count*sizeof(devicet),MTEMP,MNOWAIT);if(!list)returnENOMEM;bzero(list,count*sizeof(devicet));count=0;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link)){list
[count]=child;count++;}*devlistp=list;*devcountp=count;return0;}drivert*devicegetdriver(devicetdev){returndev->driver;}devclasstdevicegetdevclass(devicetdev){returndev->devclass
;}constchar*devicegetname(devicetdev){if(dev->devclass)returndevclassgetname(dev->devclass);returnNULL;}constchar*devicegetnameunit(devicetdev){returndev->nameunit;}intdeviceget
unit(devicetdev){returndev->unit;}constchar*devicegetdesc(devicetdev){returndev->desc;}uint32tdevicegetflags(devicetdev){returndev->devflags;}intdeviceprintprettyname(devicetdev
){constchar*name=devicegetname(dev);if(name==0)returnprintf("unknown:");elsereturnprintf("%s%d:",name,devicegetunit(dev));}intdeviceprintf(devicetdev,constchar*fmt,...){valistap
;intretval;retval=deviceprintprettyname(dev);vastart(ap,fmt);retval+=vprintf(fmt,ap);vaend(ap);returnretval;}staticvoiddevicesetdescinternal(devicetdev,constchar*desc,intcopy){i
f(dev->desc&&(dev->flags&DFDESCMALLOCED)){free(dev->desc,MBUS);dev->flags&=~DFDESCMALLOCED;dev->desc=NULL;}if(copy&&desc){dev->desc=malloc(strlen(desc)+1,MBUS,MNOWAIT);if(dev->d
esc){strcpy(dev->desc,desc);dev->flags|=DFDESCMALLOCED;}}else/*Avoida-Wcast-qualwarning*/dev->desc=(char*)(uintptrt)desc;#ifdefDEVICESYSCTLS{structsysctloid*oid=&dev->oid[1];oid
->oidarg1=dev->desc?dev->desc:"";oid->oidarg2=dev->desc?strlen(dev->desc):0;}#endif}voiddevicesetdesc(devicetdev,constchar*desc){devicesetdescinternal(dev,desc,FALSE);}voiddevic
esetdesccopy(devicetdev,constchar*desc){devicesetdescinternal(dev,desc,TRUE);}voiddevicesetflags(devicetdev,uint32tflags){dev->devflags=flags;}void*devicegetsoftc(devicetdev){re
turndev->softc;}voiddevicesetsoftc(devicetdev,void*softc){if(dev->softc&&!(dev->flags&DFEXTERNALSOFTC))free(dev->softc,MBUS);dev->softc=softc;if(dev->softc)dev->flags|=DFEXTERNA
LSOFTC;elsedev->flags&=~DFEXTERNALSOFTC;}void*devicegetivars(devicetdev){returndev->ivars;}voiddevicesetivars(devicetdev,void*ivars){if(!dev)return;dev->ivars=ivars;return;}devi
cestatetdevicegetstate(devicetdev){returndev->state;}voiddeviceenable(devicetdev){dev->flags|=DFENABLED;}voiddevicedisable(devicetdev){dev->flags&=~DFENABLED;}voiddevicebusy(dev
icetdev){if(dev->state<DSATTACHED)panic("devicebusy:calledforunattacheddevice");if(dev->busy==0&&dev->parent)devicebusy(dev->parent);dev->busy++;dev->state=DSBUSY;}voiddeviceunb
usy(devicetdev){if(dev->state!=DSBUSY)panic("deviceunbusy:calledfornon-busydevice");dev->busy--;if(dev->busy==0){if(dev->parent)deviceunbusy(dev->parent);dev->state=DSATTACHED;}
}voiddevicequiet(devicetdev){dev->flags|=DFQUIET;}voiddeviceverbose(devicetdev){dev->flags&=~DFQUIET;}intdeviceisquiet(devicetdev){return(dev->flags&DFQUIET)!=0;}intdeviceisenab
led(devicetdev){return(dev->flags&DFENABLED)!=0;}intdeviceisalive(devicetdev){returndev->state>=DSALIVE;}intdevicesetdevclass(devicetdev,constchar*classname){devclasstdc;if(!cla
ssname){if(dev->devclass)devclassdeletedevice(dev->devclass,dev);return0;}if(dev->devclass){printf("devicesetdevclass:deviceclassalreadyset\n");returnEINVAL;}dc=devclassfindinte
rnal(classname,TRUE);if(!dc)returnENOMEM;returndevclassadddevice(dc,dev);}intdevicesetdriver(devicetdev,drivert*driver){if(dev->state>=DSATTACHED)returnEBUSY;if(dev->driver==dri
ver)return0;if(dev->softc&&!(dev->flags&DFEXTERNALSOFTC)){free(dev->softc,MBUS);dev->softc=NULL;}dev->ops=&nullops;dev->driver=driver;if(driver){dev->ops=driver->ops;if(!(dev->f
lags&DFEXTERNALSOFTC)){dev->softc=malloc(driver->softc,MBUS,MNOWAIT);if(!dev->softc){dev->ops=&nullops;dev->driver=NULL;returnENOMEM;}bzero(dev->softc,driver->softc);}}return0;}
intdeviceprobeandattach(devicetdev){devicetbus=dev->parent;interror=0;inthasclass=(dev->devclass!=0);if(dev->state>=DSALIVE)return0;if(dev->flags&DFENABLED){error=deviceprobechi
ld(bus,dev);if(!error){if(!deviceisquiet(dev))deviceprintchild(bus,dev);error=DEVICEATTACH(dev);if(!error)dev->state=DSATTACHED;else{printf("deviceprobeandattach:%s%dattachretur
ned%d\n",dev->driver->name,dev->unit,error);/*Unsettheclassthatwassetindeviceprobechild*/if(!hasclass)devicesetdevclass(dev,0);devicesetdriver(dev,NULL);dev->state=DSNOTPRESENT;
}}else{if(!(dev->flags&DFDONENOMATCH)){BUSPROBENOMATCH(bus,dev);dev->flags|=DFDONENOMATCH;}}}else{if(bootverbose){deviceprintprettyname(dev);printf("notprobed(disabled)\n");}}re
turnerror;}intdevicedetach(devicetdev){interror;PDEBUG(("%s",DEVICENAME(dev)));if(dev->state==DSBUSY)returnEBUSY;if(dev->state!=DSATTACHED)return0;if((error=DEVICEDETACH(dev))!=
0)returnerror;deviceprintf(dev,"detached\n");if(dev->parent)BUSCHILDDETACHED(dev->parent,dev);if(!(dev->flags&DFFIXEDCLASS))devclassdeletedevice(dev->devclass,dev);dev->state=DS
NOTPRESENT;devicesetdriver(dev,NULL);return0;}intdeviceshutdown(devicetdev){if(dev->state<DSATTACHED)return0;returnDEVICESHUTDOWN(dev);}intdevicesetunit(devicetdev,intunit){devc
lasstdc;interr;dc=devicegetdevclass(dev);if(unit<dc->maxunit&&dc->devices[unit])returnEBUSY;err=devclassdeletedevice(dc,dev);if(err)returnerr;dev->unit=unit;err=devclassadddevic
e(dc,dev);if(err)returnerr;return0;}#ifdefDEVICESYSCTLS/**Sysctlnodesfordevices.*/SYSCTLNODE(hw,OIDAUTO,devices,CTLFLAGRW,0,"Alistofalldevices");staticintsysctlhandlechildren(SY
SCTLHANDLERARGS){devicetdev=arg1;devicetchild;intfirst=1,error=0;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link)){if(child->nameunit){if(!first){error=SYS
CTLOUT(req,",",1);if(error)returnerror;}else{first=0;}error=SYSCTLOUT(req,child->nameunit,strlen(child->nameunit));if(error)returnerror;}}error=SYSCTLOUT(req,"",1);returnerror;}
staticintsysctlhandlestate(SYSCTLHANDLERARGS){devicetdev=arg1;switch(dev->state){caseDSNOTPRESENT:returnSYSCTLOUT(req,"notpresent",sizeof("notpresent"));caseDSALIVE:returnSYSCTL
OUT(req,"alive",sizeof("alive"));caseDSATTACHED:returnSYSCTLOUT(req,"attached",sizeof("attached"));caseDSBUSY:returnSYSCTLOUT(req,"busy",sizeof("busy"));}return0;}staticvoiddevi
ceregisteroids(devicetdev){structsysctloid*oid;oid=&dev->oid[0];bzero(oid,sizeof(*oid));oid->oidparent=&sysctlhwdeviceschildren;oid->oidnumber=OIDAUTO;oid->oidkind=CTLTYPENODE|C
TLFLAGRW;oid->oidarg1=&dev->oidlist[0];oid->oidarg2=0;oid->oidname=dev->nameunit;oid->oidhandler=0;oid->oidfmt="N";SLISTINIT(&dev->oidlist[0]);sysctlregisteroid(oid);oid=&dev->o
id[1];bzero(oid,sizeof(*oid));oid->oidparent=&dev->oidlist[0];oid->oidnumber=OIDAUTO;oid->oidkind=CTLTYPESTRING|CTLFLAGRD;oid->oidarg1=dev->desc?dev->desc:"";oid->oidarg2=dev->d
esc?strlen(dev->desc):0;oid->oidname="desc";oid->oidhandler=sysctlhandlestring;oid->oidfmt="A";sysctlregisteroid(oid);oid=&dev->oid[2];bzero(oid,sizeof(*oid));oid->oidparent=&de
v->oidlist[0];oid->oidnumber=OIDAUTO;oid->oidkind=CTLTYPEINT|CTLFLAGRD;oid->oidarg1=dev;oid->oidarg2=0;oid->oidname="children";oid->oidhandler=sysctlhandlechildren;oid->oidfmt="
A";sysctlregisteroid(oid);oid=&dev->oid[3];bzero(oid,sizeof(*oid));oid->oidparent=&dev->oidlist[0];oid->oidnumber=OIDAUTO;oid->oidkind=CTLTYPEINT|CTLFLAGRD;oid->oidarg1=dev;oid-
>oidarg2=0;oid->oidname="state";oid->oidhandler=sysctlhandlestate;oid->oidfmt="A";sysctlregisteroid(oid);}staticvoiddeviceunregisteroids(devicetdev){sysctlunregisteroid(&dev->oi
d[0]);sysctlunregisteroid(&dev->oid[1]);sysctlunregisteroid(&dev->oid[2]);}#endif/*======================================*//**Accessfunctionsfordeviceresources.*//*Suppliedbycon
fig(8)inioconf.c*/externstructconfigdeviceconfigdevtab[];externintdevtabcount;/*Runtimeversion*/structconfigdevice*devtab=configdevtab;staticintresourcenewname(constchar*name,in
tunit){structconfigdevice*new;new=malloc((devtabcount+1)*sizeof(*new),MTEMP,MNOWAIT);if(new==NULL)return-1;if(devtab&&devtabcount>0)bcopy(devtab,new,devtabcount*sizeof(*new));bz
ero(&new[devtabcount],sizeof(*new));new[devtabcount].name=malloc(strlen(name)+1,MTEMP,MNOWAIT);if(new[devtabcount].name==NULL){free(new,MTEMP);return-1;}strcpy(new[devtabcount].
name,name);new[devtabcount].unit=unit;new[devtabcount].resourcecount=0;new[devtabcount].resources=NULL;devtab=new;returndevtabcount++;}staticintresourcenewresname(intj,constchar
*resname,resourcetypetype){structconfigresource*new;inti;i=devtab[j].resourcecount;new=malloc((i+1)*sizeof(*new),MTEMP,MNOWAIT);if(new==NULL)return-1;if(devtab[j].resources&&i>0
)bcopy(devtab[j].resources,new,i*sizeof(*new));bzero(&new[i],sizeof(*new));new[i].name=malloc(strlen(resname)+1,MTEMP,MNOWAIT);if(new[i].name==NULL){free(new,MTEMP);return-1;}st
rcpy(new[i].name,resname);new[i].type=type;if(devtab[j].resources)free(devtab[j].resources,MTEMP);devtab[j].resources=new;devtab[j].resourcecount=i+1;returni;}staticintresourcem
atchstring(inti,constchar*resname,constchar*value){intj;structconfigresource*res;for(j=0,res=devtab[i].resources;j<devtab[i].resourcecount;j++,res++)if(!strcmp(res->name,resname
)&&res->type==RESSTRING&&!strcmp(res->u.stringval,value))returnj;return-1;}staticintresourcefind(constchar*name,intunit,constchar*resname,structconfigresource**result){inti,j;st
ructconfigresource*res;/**Firstcheckspecificinstances,thengeneric.*/for(i=0;i<devtabcount;i++){if(devtab[i].unit<0)continue;if(!strcmp(devtab[i].name,name)&&devtab[i].unit==unit
){res=devtab[i].resources;for(j=0;j<devtab[i].resourcecount;j++,res++)if(!strcmp(res->name,resname)){*result=res;return0;}}}for(i=0;i<devtabcount;i++){if(devtab[i].unit>=0)conti
nue;/*XXXshouldthis`&&devtab[i].unit==unit'behere?*//*XXXifso,thenthegenericmatchdoesnothing*/if(!strcmp(devtab[i].name,name)&&devtab[i].unit==unit){res=devtab[i].resources;for(
j=0;j<devtab[i].resourcecount;j++,res++)if(!strcmp(res->name,resname)){*result=res;return0;}}}returnENOENT;}intresourceintvalue(constchar*name,intunit,constchar*resname,int*resu
lt){interror;structconfigresource*res;if((error=resourcefind(name,unit,resname,&res))!=0)returnerror;if(res->type!=RESINT)returnEFTYPE;*result=res->u.intval;return0;}intresource
longvalue(constchar*name,intunit,constchar*resname,long*result){interror;structconfigresource*res;if((error=resourcefind(name,unit,resname,&res))!=0)returnerror;if(res->type!=RE
SLONG)returnEFTYPE;*result=res->u.longval;return0;}intresourcestringvalue(constchar*name,intunit,constchar*resname,char**result){interror;structconfigresource*res;if((error=reso
urcefind(name,unit,resname,&res))!=0)returnerror;if(res->type!=RESSTRING)returnEFTYPE;*result=res->u.stringval;return0;}intresourcequerystring(inti,constchar*resname,constchar*v
alue){if(i<0)i=0;elsei=i+1;for(;i<devtabcount;i++)if(resourcematchstring(i,resname,value)>=0)returni;return-1;}intresourcelocate(inti,constchar*resname){if(i<0)i=0;elsei=i+1;for
(;i<devtabcount;i++)if(!strcmp(devtab[i].name,resname))returni;return-1;}intresourcecount(void){returndevtabcount;}char*resourcequeryname(inti){returndevtab[i].name;}intresource
queryunit(inti){returndevtab[i].unit;}staticintresourcecreate(constchar*name,intunit,constchar*resname,resourcetypetype,structconfigresource**result){inti,j;structconfigresource
*res=NULL;for(i=0;i<devtabcount;i++){if(!strcmp(devtab[i].name,name)&&devtab[i].unit==unit){res=devtab[i].resources;break;}}if(res==NULL){i=resourcenewname(name,unit);if(i<0)ret
urnENOMEM;res=devtab[i].resources;}for(j=0;j<devtab[i].resourcecount;j++,res++){if(!strcmp(res->name,resname)){*result=res;return0;}}j=resourcenewresname(i,resname,type);if(j<0)
returnENOMEM;res=&devtab[i].resources[j];*result=res;return0;}intresourcesetint(constchar*name,intunit,constchar*resname,intvalue){interror;structconfigresource*res;error=resour
cecreate(name,unit,resname,RESINT,&res);if(error)returnerror;if(res->type!=RESINT)returnEFTYPE;res->u.intval=value;return0;}intresourcesetlong(constchar*name,intunit,constchar*r
esname,longvalue){interror;structconfigresource*res;error=resourcecreate(name,unit,resname,RESLONG,&res);if(error)returnerror;if(res->type!=RESLONG)returnEFTYPE;res->u.longval=v
alue;return0;}intresourcesetstring(constchar*name,intunit,constchar*resname,constchar*value){interror;structconfigresource*res;error=resourcecreate(name,unit,resname,RESSTRING,&
res);if(error)returnerror;if(res->type!=RESSTRING)returnEFTYPE;if(res->u.stringval)free(res->u.stringval,MTEMP);res->u.stringval=malloc(strlen(value)+1,MTEMP,MNOWAIT);if(res->u.
stringval==NULL)returnENOMEM;strcpy(res->u.stringval,value);return0;}staticvoidresourcecfgload(void*dummyunused){structconfigresource*res,*cfgres;inti,j;interror;char*name,*resn
ame;intunit;resourcetypetype;char*stringval;intconfigdevtabcount;configdevtabcount=devtabcount;devtab=NULL;devtabcount=0;for(i=0;i<configdevtabcount;i++){name=configdevtab[i].na
me;unit=configdevtab[i].unit;for(j=0;j<configdevtab[i].resourcecount;j++){cfgres=configdevtab[i].resources;resname=cfgres[j].name;type=cfgres[j].type;error=resourcecreate(name,u
nit,resname,type,&res);if(error){printf("createresource%s%d:error%d\n",name,unit,error);continue;}if(res->type!=type){printf("typemismatch%s%d:%d!=%d\n",name,unit,res->type,type
);continue;}switch(type){caseRESINT:res->u.intval=cfgres[j].u.intval;break;caseRESLONG:res->u.longval=cfgres[j].u.longval;break;caseRESSTRING:if(res->u.stringval)free(res->u.str
ingval,MTEMP);stringval=cfgres[j].u.stringval;res->u.stringval=malloc(strlen(stringval)+1,MTEMP,MNOWAIT);if(res->u.stringval==NULL)break;strcpy(res->u.stringval,stringval);break
;default:panic("unknownresourcetype%d\n",type);}}}}SYSINIT(cfgload,SISUBKMEM,SIORDERANY+50,resourcecfgload,0)/*======================================*//**Someusefulmethodimpleme
ntationstomakelifeeasierforbusdrivers.*/voidresourcelistinit(structresourcelist*rl){SLISTINIT(rl);}voidresourcelistfree(structresourcelist*rl){structresourcelistentry*rle;while(
(rle=SLISTFIRST(rl))!=NULL){if(rle->res)panic("resourcelistfree:resourceentryisbusy");SLISTREMOVEHEAD(rl,link);free(rle,MBUS);}}voidresourcelistadd(structresourcelist*rl,inttype
,intrid,ulongstart,ulongend,ulongcount){structresourcelistentry*rle;rle=resourcelistfind(rl,type,rid);if(!rle){rle=malloc(sizeof(structresourcelistentry),MBUS,MNOWAIT);if(!rle)p
anic("resourcelistadd:can'trecordentry");SLISTINSERTHEAD(rl,rle,link);rle->type=type;rle->rid=rid;rle->res=NULL;}if(rle->res)panic("resourcelistadd:resourceentryisbusy");rle->st
art=start;rle->end=end;rle->count=count;}structresourcelistentry*resourcelistfind(structresourcelist*rl,inttype,intrid){structresourcelistentry*rle;SLISTFOREACH(rle,rl,link)if(r
le->type==type&&rle->rid==rid)returnrle;returnNULL;}voidresourcelistdelete(structresourcelist*rl,inttype,intrid){structresourcelistentry*rle=resourcelistfind(rl,type,rid);if(rle
){SLISTREMOVE(rl,rle,resourcelistentry,link);free(rle,MBUS);}}structresource*resourcelistalloc(structresourcelist*rl,devicetbus,devicetchild,inttype,int*rid,ulongstart,ulongend,
ulongcount,uintflags){structresourcelistentry*rle=0;intpassthrough=(devicegetparent(child)!=bus);intisdefault=(start==0UL&&end==~0UL);if(passthrough){returnBUSALLOCRESOURCE(devi
cegetparent(bus),child,type,rid,start,end,count,flags);}rle=resourcelistfind(rl,type,*rid);if(!rle)return0;/*noresourceofthattype/rid*/if(rle->res)panic("resourcelistalloc:resou
rceentryisbusy");if(isdefault){start=rle->start;count=max(count,rle->count);end=max(rle->end,start+count-1);}rle->res=BUSALLOCRESOURCE(devicegetparent(bus),child,type,rid,start,
end,count,flags);/**Recordthenewrange.*/if(rle->res){rle->start=rmangetstart(rle->res);rle->end=rmangetend(rle->res);rle->count=count;}returnrle->res;}intresourcelistrelease(str
uctresourcelist*rl,devicetbus,devicetchild,inttype,intrid,structresource*res){structresourcelistentry*rle=0;intpassthrough=(devicegetparent(child)!=bus);interror;if(passthrough)
{returnBUSRELEASERESOURCE(devicegetparent(bus),child,type,rid,res);}rle=resourcelistfind(rl,type,rid);if(!rle)panic("resourcelistrelease:can'tfindresource");if(!rle->res)panic("
resourcelistrelease:resourceentryisnotbusy");error=BUSRELEASERESOURCE(devicegetparent(bus),child,type,rid,res);if(error)returnerror;rle->res=NULL;return0;}/**CallDEVICEIDENTIFYf
oreachdriver.*/intbusgenericprobe(devicetdev){devclasstdc=dev->devclass;driverlinktdl;for(dl=TAILQFIRST(&dc->drivers);dl;dl=TAILQNEXT(dl,link))DEVICEIDENTIFY(dl->driver,dev);ret
urn0;}intbusgenericattach(devicetdev){devicetchild;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link))deviceprobeandattach(child);return0;}intbusgenericdetac
h(devicetdev){devicetchild;interror;if(dev->state!=DSATTACHED)returnEBUSY;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link))if((error=devicedetach(child))!=
0)returnerror;return0;}intbusgenericshutdown(devicetdev){devicetchild;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link))deviceshutdown(child);return0;}intbu
sgenericsuspend(devicetdev){interror;devicetchild,child2;for(child=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link)){error=DEVICESUSPEND(child);if(error){for(child2=
TAILQFIRST(&dev->children);child2&&child2!=child;child2=TAILQNEXT(child2,link))DEVICERESUME(child2);return(error);}}return0;}intbusgenericresume(devicetdev){devicetchild;for(chi
ld=TAILQFIRST(&dev->children);child;child=TAILQNEXT(child,link)){DEVICERESUME(child);/*ifresumefails,there'snothingwecanusefullydo...*/}return0;}intbusprintchildheader(devicetde
v,devicetchild){intretval=0;if(devicegetdesc(child)){retval+=deviceprintf(child,"<%s>",devicegetdesc(child));}else{retval+=printf("%s",devicegetnameunit(child));}return(retval);
}intbusprintchildfooter(devicetdev,devicetchild){return(printf("on%s\n",devicegetnameunit(dev)));}intbusgenericprintchild(devicetdev,devicetchild){intretval=0;retval+=busprintch
ildheader(dev,child);retval+=busprintchildfooter(dev,child);return(retval);}intbusgenericreadivar(devicetdev,devicetchild,intindex,uintptrt*result){returnENOENT;}intbusgenericwr
iteivar(devicetdev,devicetchild,intindex,uintptrtvalue){returnENOENT;}voidbusgenericdriveradded(devicetdev,drivert*driver){devicetchild;DEVICEIDENTIFY(driver,dev);for(child=TAIL
QFIRST(&dev->children);child;child=TAILQNEXT(child,link))if(child->state==DSNOTPRESENT)deviceprobeandattach(child);}intbusgenericsetupintr(devicetdev,devicetchild,structresource

Hosted by uCoz