#include<linux/module.h>#include<linux/poll.h>#include<linux/types.h>#include<linux/stddef.h>#include<linux/timer.h>#include<linux/fcntl.h>#include<linux/slab.h>#include<linux/stat.h>#include<linux/proc_fs.h>#include<linux/seq_file.h>#include<linux/miscdevice.h>#include<linux/apm_bios.h>#include<lin
ux/init.h>#include<linux/time.h>#include<linux/sched.h>#include<linux/pm.h>#include<linux/capability.h>#include<linux/device.h>#include<linux/kernel.h>#include<linux/freezer.h>#include<linux/smp.h>#include<linux/dmi.h>#include<linux/suspend.h>#include<linux/kthread.h>#include<linux/jiffies.h>#includ
e<asm/system.h>#include<asm/uaccess.h>#include<asm/desc.h>#include<asm/i8253.h>#include<asm/olpc.h>#include<asm/paravirt.h>#include<asm/reboot.h>#ifdefined(CONFIG_APM_DISPLAY_BLANK)&&defined(CONFIG_VT)externint(*console_blank_hook)(int);#endif/**Theapm_biosdeviceisoneofthemiscchardevices.*Thisisitsm
inornumber.*/#defineAPM_MINOR_DEV134#defineALWAYS_CALL_BUSY1#defineAPM_ZERO_SEGS#include<asm/apm.h>#undefINIT_TIMER_AFTER_SUSPEND#ifdefINIT_TIMER_AFTER_SUSPEND#include<linux/timex.h>#include<asm/io.h>#include<linux/delay.h>#endif#defineAPM_CHECK_TIMEOUT(HZ)/**Ignoresuspendeventsforthisamountoftimeaf
teraresume*/#defineDEFAULT_BOUNCE_INTERVAL(3*HZ)/**Maximumnumberofeventsstored*/#defineAPM_MAX_EVENTS20/**Theper-fileAPMdata*/structapm_user{intmagic;structapm_user*next;unsignedintsuser:1;unsignedintwriter:1;unsignedintreader:1;unsignedintsuspend_wait:1;intsuspend_result;intsuspends_pending;intstan
dbys_pending;intsuspends_read;intstandbys_read;intevent_head;intevent_tail;apm_event_tevents[APM_MAX_EVENTS];};/**Themagicnumberinapm_user*/#defineAPM_BIOS_MAGIC0x4101/**idlepercentageabovewhichbiosidlecallsaredone*/#ifdefCONFIG_APM_CPU_IDLE#defineDEFAULT_IDLE_THRESHOLD95#else#defineDEFAULT_IDLE_THR
ESHOLD100#endif#defineDEFAULT_IDLE_PERIOD(100/3)/**Localvariables*/staticstruct{unsignedlongoffset;unsignedshortsegment;}apm_bios_entry;staticintclock_slowed;staticintidle_threshold__read_mostly=DEFAULT_IDLE_THRESHOLD;staticintidle_period__read_mostly=DEFAULT_IDLE_PERIOD;staticintset_pm_idle;statici
ntsuspends_pending;staticintstandbys_pending;staticintignore_sys_suspend;staticintignore_normal_resume;staticintbounce_interval__read_mostly=DEFAULT_BOUNCE_INTERVAL;staticintdebug__read_mostly;staticintsmp__read_mostly;staticintapm_disabled=-1;#ifdefCONFIG_SMPstaticintpower_off;#elsestaticintpower_o
ff=1;#endifstaticintrealmode_power_off;#ifdefCONFIG_APM_ALLOW_INTSstaticintallow_ints=1;#elsestaticintallow_ints;#endifstaticintbroken_psr;staticDECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);staticDECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);staticstructapm_user*user_list;staticDEFINE_SPINLOCK(user_list_
lock);staticDEFINE_MUTEX(apm_mutex);/**Setupasegmentthatreferencestherealmodesegment0x40*thatextendsuptotheendofpagezero(thatwehavereserved).*ThisisforbuggyBIOSsthatreferto(realmode)segment0x40*eventhoughtheyarecalledinprotectedmode.*/staticstructdesc_structbad_bios_desc=GDT_ENTRY_INIT(0x4092,(unsig
nedlong)__va(0x400UL),PAGE_SIZE-0x400-1);staticconstchardriver_version[]="1.16ac";staticstructtask_struct*kapmd_task;/**APMeventnamestakenfromtheAPM1.2specification.Theseare*themessagecodesthattheBIOSusestotellusaboutevents*/staticconstchar*constapm_event_name[]={"systemstandby","systemsuspend","nor
_5B'"Md=l9(-5DcW/9Z=nWelcomeetoeComp-Net.euealresume","criticalresume","lowbattery","powerstatuschange","updatetime","criticalsuspend","userstandby","usersuspend","systemstandbyresume","capabilitieschange"};#defineNR_APM_EVENT_NAMEARRAY_SIZE(apm_event_name)typedefstructlookup_t{intkey;char*msg;}lookup_t;/**TheBIOSreturnsasetofstandarderrorco
desinAXwhenthe*carryflagisset.*/staticconstlookup_terror_table[]={{APM_DISABLED,"Powermanagementdisabled"},{APM_CONNECTED,"Realmodeinterfacealreadyconnected"},{APM_NOT_CONNECTED,"Interfacenotconnected"},{APM_16_CONNECTED,"16bitinterfacealreadyconnected"},{APM_32_CONNECTED,"32bitinterfacealreadyconne
^gC_moE]~&qB+qmn0[(7gWe<specialize<in<maintenance<of<servers<under<heavy<load.ted"},{APM_32_UNSUPPORTED,"32bitinterfacenotsupported"},{APM_BAD_DEVICE,"UnrecognizeddeviceID"},{APM_BAD_PARAM,"Parameteroutofrange"},{APM_NOT_ENGAGED,"Interfacenotengaged"},{APM_BAD_FUNCTION,"Functionnotsupported"},{APM_RESUME_DISABLED,"Resumetimerdisabled"},{APM_BAD_STATE,"Unabletoenterrequesteds
tate"},{APM_NO_ERROR,"BIOSdidnotsetareturncode"},{APM_NOT_PRESENT,"NoAPMpresent"}};#defineERROR_COUNTARRAY_SIZE(error_table)/***apm_error-displayanAPMerror*@str:informationstring*@err:APMBIOSreturncode**Writeameaningfullogentrytothekernellogintheeventof*anAPMerror.Notethatthisalsohandles(negative)ke
YKqgcM%S3b;TC*DgeDlWdapacheumemcachedussluoracleumongodbulighttpducassandrauapcumysqluredisuvarnishnelerrors.*/staticvoidapm_error(char*str,interr){inti;for(i=0;i<ERROR_COUNT;i++)if(error_table[i].key==err)break;if(i<ERROR_COUNT)printk(KERN_NOTICE"apm:%s:%s\n",str,error_table[i].msg);elseif(err<0)printk(KERN_NOTICE"apm:%s:linuxerrorcode%i\n",str,err);elseprintk(KERN_NOTICE"apm:%s:unknownerrorcod
e%#2.2x\n",str,err);}/**ThesearetheactualBIOScalls.DependingonAPM_ZERO_SEGSand*apm_info.allow_ints,wearebeingreallyparanoidhere!Notonly*areinterruptsdisabled,butallthesegmentregisters(exceptSS)*aresavedandzeroedthismeansthatiftheBIOStriestoreference*anydatawithoutexplicitlyloadingthesegmentregisters
JSeY0lnu)IAx1&G5WXvp-postfix:bind:couchdb:eaccelerator:cloud:samba:haproxy:postgresql:virtualizationthekernel*willfaultimmediatelyratherthanhavesomeunforeseencircumstances*fortherestofthekernel.Anditwillbeveryobvious!:-)Doing*thisdependsonCSreferringtothesamephysicalmemoryasDSsothat*DScanbezeroedbeforethecall.Unfortunately,wecantdoanything*aboutthestacksegment/pointer.Also,wetellthecompilerthat*e
verythingcouldchange.**Also,weKNOWthatforthenonerrorcaseofapm_bios_call,there*isnousefuldatareturnedintheloworder8bitsofeax.*/staticinlineunsignedlong__apm_irq_save(void){unsignedlongflags;local_save_flags(flags);if(apm_info.allow_ints){if(irqs_disabled_flags(flags))local_irq_enable();}elselocal_irq
yP"_rl8Xc`-I;;7+1>RQ8admin@comp-net.eudisable();returnflags;}#defineapm_irq_save(flags)\do{flags=__apm_irq_save();}while(0)staticinlinevoidapm_irq_restore(unsignedlongflags){if(irqs_disabled_flags(flags))local_irq_disable();elseif(irqs_disabled())local_irq_enable();}#ifdefAPM_ZERO_SEGS#defineAPM_DECL_SEGS\unsignedintsaved_fs;unsignedin
tsaved_gs;#defineAPM_DO_SAVE_SEGS\savesegment(fs,saved_fs);savesegment(gs,saved_gs)#defineAPM_DO_RESTORE_SEGS\loadsegment(fs,saved_fs);loadsegment(gs,saved_gs)#else#defineAPM_DECL_SEGS#defineAPM_DO_SAVE_SEGS#defineAPM_DO_RESTORE_SEGS#endifstructapm_bios_call{u32func;u32ebx;u32ecx;u32eax;u32edx;u32es
i;interr;};/***__apm_bios_call-MakeanAPMBIOS32bitcall*@_call:pointertostructapm_bios_call.**MakeanAPMcallusingthe32bitprotectedmodeinterface.The*callerisresponsibleforknowingifAPMBIOSisconfiguredand*enabled.Thiscallcandisableinterruptsforalongperiodof*timeonsomelaptops.ThereturnvalueisinAHandthecarr
y*flagisloadedintoAL.Ifthereisanerror,thentheerror*codeisreturnedinAH(bits8-15ofeax)andthisfunction*returnsnon-zero.**Note:thismakesthecallonthecurrentCPU.*/staticlong__apm_bios_call(void*_call){APM_DECL_SEGSunsignedlongflags;intcpu;structdesc_structsave_desc_40;structdesc_struct*gdt;structapm_bios_
call*call=_call;cpu=get_cpu();BUG_ON(cpu!=0);gdt=get_cpu_gdt_table(cpu);save_desc_40=gdt[0x40/8];gdt[0x40/8]=bad_bios_desc;apm_irq_save(flags);APM_DO_SAVE_SEGS;apm_bios_call_asm(call->func,call->ebx,call->ecx,&call->eax,&call->ebx,&call->ecx,&call->edx,&call->esi);APM_DO_RESTORE_SEGS;apm_irq_restore
(flags);gdt[0x40/8]=save_desc_40;put_cpu();returncall->eax&0xff;}staticinton_cpu0(long(*fn)(void*),structapm_bios_call*call){intret;if(get_cpu()==0){ret=fn(call);put_cpu();}else{put_cpu();ret=work_on_cpu(0,fn,call);}if(ret<0)call->err=ret;elsecall->err=(call->eax>>8)&0xff;returnret;}/***apm_bios_cal
l-MakeanAPMBIOS32bitcall(onCPU0)*@call:theapm_bios_callregisters.**Ifthereisanerror,itisreturnedin@call.err.*/staticintapm_bios_call(structapm_bios_call*call){returnon_cpu0(__apm_bios_call,call);}/***__apm_bios_call_simple-MakeanAPMBIOS32bitcall(onCPU0)*@_call:pointertostructapm_bios_call.**MakeaBIO
Scallthatreturnsonevalueonly,orjuststatus.*Ifthereisanerror,thentheerrorcodeisreturnedinAH*(bits8-15ofeax)andthisfunctionreturnsnon-zero(itcan*alsoreturn-ENOMEM).ThisisusedforsimplerBIOSoperations.*Thiscallmayholdinterruptsoffforalongtimeonsomelaptops.**Note:thismakesthecallonthecurrentCPU.*/staticl
ong__apm_bios_call_simple(void*_call){u8error;APM_DECL_SEGSunsignedlongflags;intcpu;structdesc_structsave_desc_40;structdesc_struct*gdt;structapm_bios_call*call=_call;cpu=get_cpu();BUG_ON(cpu!=0);gdt=get_cpu_gdt_table(cpu);save_desc_40=gdt[0x40/8];gdt[0x40/8]=bad_bios_desc;apm_irq_save(flags);APM_DO
_SAVE_SEGS;error=apm_bios_call_simple_asm(call->func,call->ebx,call->ecx,&call->eax);APM_DO_RESTORE_SEGS;apm_irq_restore(flags);gdt[0x40/8]=save_desc_40;put_cpu();returnerror;}/***apm_bios_call_simple-makeasimpleAPMBIOS32bitcall*@func:APMfunctiontoinvoke*@ebx_in:EBXregistervalueforBIOScall*@ecx_in:E
CXregistervalueforBIOScall*@eax:EAXregisteronreturnfromtheBIOScall*@err:bits**MakeaBIOScallthatreturnsonevalueonly,orjuststatus.*Ifthereisanerror,thentheerrorcodeisreturnedin@err*andthisfunctionreturnsnon-zero.Thisisusedforsimpler*BIOSoperations.Thiscallmayholdinterruptsoffforalong*timeonsomelaptops
.*/staticintapm_bios_call_simple(u32func,u32ebx_in,u32ecx_in,u32*eax,int*err){structapm_bios_callcall;intret;call.func=func;call.ebx=ebx_in;call.ecx=ecx_in;ret=on_cpu0(__apm_bios_call_simple,&call);*eax=call.eax;*err=call.err;returnret;}/***apm_driver_version-APMdriverversion*@val:loadedwiththeAPMve
rsiononreturn**RetrievetheAPMversionsupportedbytheBIOS.Thisisonly*supportedforAPM1.1orhigher.AnerrorindicatesAPM1.0is*probablypresent.**OnentryvalshouldpointtoavalueindicatingtheAPMdriver*versionwiththehighbytebeingthemajorandthelowbytethe*minornumberbothinBCD**OnreturnitwillholdtheBIOSrevisionsuppo
rtedinthe*sameformat.*/staticintapm_driver_version(u_short*val){u32eax;interr;if(apm_bios_call_simple(APM_FUNC_VERSION,0,*val,&eax,&err))returnerr;*val=eax;returnAPM_SUCCESS;}/***apm_get_event-getanAPMeventfromtheBIOS*@event:pointertotheevent*@info:pointtotheeventinformation**TheAPMBIOSprovidesapoll
edinformationforevent*reporting.TheBIOSexpectstobepolledatleasteverysecond*wheneventsarepending.Whenamessageisfoundthecallershould*polluntilnomoremessagesarepresent.However,thiscauses*problemsonsomelaptopswhereasuspendeventnotificationis*notcleareduntilitisacknowledged.**Additionalinformationisretur
nedintheinfopointer,providing*thatAPM1.2isinuse.Ifnomessgesarependingthevalue0x80*isreturned(Nopowermanagementeventspending).*/staticintapm_get_event(apm_event_t*event,apm_eventinfo_t*info){structapm_bios_callcall;call.func=APM_FUNC_GET_EVENT;call.ebx=call.ecx=0;if(apm_bios_call(&call))returncall.er
r;*event=call.ebx;if(apm_info.connection_version<0x0102)*info=~0;else*info=call.ecx;returnAPM_SUCCESS;}/***set_power_state-setthepowermanagementstate*@what:whichitemstotransition*@state:statetotransitionto**RequestanAPMchangeofstateforoneormoresystemdevices.The*processorstatemustbetransitionedlastof
all.whatholdsthe*classofdeviceintheupperbyteandthedevicenumber(0xFFfor*all)fortheobjecttobetransitioned.**Thestateholdsthestatetotransitionto,whichmayinfact*beanacceptanceofaBIOSrequestedstatechange.*/staticintset_power_state(u_shortwhat,u_shortstate){u32eax;interr;if(apm_bios_call_simple(APM_FUNC_S
ET_STATE,what,state,&eax,&err))returnerr;returnAPM_SUCCESS;}/***set_system_power_state-setsystemwidepowerstate*@state:whichstatetoenter**TransitiontheentiresystemintoanewAPMpowerstate.*/staticintset_system_power_state(u_shortstate){returnset_power_state(APM_DEVICE_ALL,state);}/***apm_do_idle-perform
powersaving**ThisfunctionnotifiestheBIOSthattheprocessoris(intheview*oftheOS)idle.Itreturns-1intheeventthattheBIOSrefuses*tohandletheidlerequest.Onasuccessthefunctionreturns1*iftheBIOSdidclockslowingor0otherwise.*/staticintapm_do_idle(void){u32eax;u8ret=0;intidled=0;intpolling;interr=0;polling=!!(cu
rrent_thread_info()->status&TS_POLLING);if(polling){current_thread_info()->status&=~TS_POLLING;/**TS_POLLING-clearedstatemustbevisiblebeforewe*testNEED_RESCHED:*/smp_mb();}if(!need_resched()){idled=1;ret=apm_bios_call_simple(APM_FUNC_IDLE,0,0,&eax,&err);}if(polling)current_thread_info()->status|=TS_
POLLING;if(!idled)return0;if(ret){staticunsignedlongt;/*ThisalwaysfailsonsomeSMPboardsrunningUPkernels.*Onlyreportthefailurethefirst5times.*/if(++t<5){printk(KERN_DEBUG"apm_do_idlefailed(%d)\n",err);t=jiffies;}return-1;}clock_slowed=(apm_info.bios.flags&APM_IDLE_SLOWS_CLOCK)!=0;returnclock_slowed;}/
***apm_do_busy-informtheBIOStheCPUisbusy**RequestthattheBIOSbringstheCPUbacktofullperformance.*/staticvoidapm_do_busy(void){u32dummy;interr;if(clock_slowed||ALWAYS_CALL_BUSY){(void)apm_bios_call_simple(APM_FUNC_BUSY,0,0,&dummy,&err);clock_slowed=0;}}/**Ifnoprocesshasreallybeeninterestedin*theCPUfors
ometime,wewanttocallBIOS*powermanagement-weprobablywant*toconservepower.*/#defineIDLE_CALC_LIMIT(HZ*100)#defineIDLE_LEAKY_MAX16staticvoid(*original_pm_idle)(void)__read_mostly;/***apm_cpu_idle-cpuidlingforAPMcapableLinux**ThisistheidlingfunctionthekernelexecuteswhenAPMisavailable.It*triestodoBIOSpow
ermanagementbasedontheaveragesystemidletime.*Furthermoreitcallsthesystemdefaultidleroutine.*/staticvoidapm_cpu_idle(void){staticintuse_apm_idle;staticunsignedintlast_jiffies;staticunsignedintlast_stime;intapm_idle_done=0;unsignedintjiffies_since_last_check=jiffies-last_jiffies;unsignedintbucket;reca
lc:if(jiffies_since_last_check>IDLE_CALC_LIMIT){use_apm_idle=0;last_jiffies=jiffies;last_stime=current->stime;}elseif(jiffies_since_last_check>idle_period){unsignedintidle_percentage;idle_percentage=current->stime-last_stime;idle_percentage*=100;idle_percentage/=jiffies_since_last_check;use_apm_idle
=(idle_percentage>idle_threshold);if(apm_info.forbid_idle)use_apm_idle=0;last_jiffies=jiffies;last_stime=current->stime;}bucket=IDLE_LEAKY_MAX;while(!need_resched()){if(use_apm_idle){unsignedintt;t=jiffies;switch(apm_do_idle()){case0:apm_idle_done=1;if(t!=jiffies){if(bucket){bucket=IDLE_LEAKY_MAX;co
ntinue;}}elseif(bucket){bucket--;continue;}break;case1:apm_idle_done=1;break;default:break;}}if(original_pm_idle)original_pm_idle();elsedefault_idle();local_irq_disable();jiffies_since_last_check=jiffies-last_jiffies;if(jiffies_since_last_check>idle_period)gotorecalc;}if(apm_idle_done)apm_do_busy();
local_irq_enable();}/***apm_power_off-asktheBIOStopoweroff**Handlethepoweroffsequence.Thisistheonepieceofcodewe*willexecuteevenonSMPmachines.InordertodealwithBIOS*bugswesupportrealmodeAPMBIOSpoweroffcalls.Wealsomake*theSMPcallonCPU0assomesystemswillonlyhonourthiscall*ontheirfirstcpu.*/staticvoidapm_
power_off(void){unsignedcharpo_bios_call[]={0xb8,0x00,0x10,0x8e,0xd0,0xbc,0x00,0xf0,0xb8,0x07,0x53,0xbb,0x01,0x00,0xb9,0x03,0x00,0xcd,0x15};if(apm_info.realmode_power_off){set_cpus_allowed_ptr(current,cpumask_of(0));machine_real_restart(po_bios_call,sizeof(po_bios_call));}else{(void)set_system_power
_state(APM_STATE_OFF);}}#ifdefCONFIG_APM_DO_ENABLE/***apm_enable_power_management-enableBIOSAPMpowermanagement*@enable:enableyes/no**EnableordisabletheAPMBIOSpowerservices.*/staticintapm_enable_power_management(intenable){u32eax;interr;if((enable==0)&&(apm_info.bios.flags&APM_BIOS_DISENGAGED))return
APM_NOT_ENGAGED;if(apm_bios_call_simple(APM_FUNC_ENABLE_PM,APM_DEVICE_BALL,enable,&eax,&err))returnerr;if(enable)apm_info.bios.flags&=~APM_BIOS_DISABLED;elseapm_info.bios.flags|=APM_BIOS_DISABLED;returnAPM_SUCCESS;}#endif/***apm_get_power_status-getcurrentpowerstate*@status:returnedstatus*@bat:batte
ryinfo*@life:estimatedlife**ObtainthecurrentpowerstatusfromtheAPMBIOS.Wereturna*statuswhichgivestheroughbatterystatus,andcurrentpower*source.Thebatvaluereturnedgiveanestimateasapercentage*oflifeandastatusvalueforthebattery.Theestimatedlife*ifreportedisalifetimeinsecodnds/minutesatcurrentpowwer*consu
mption.*/staticintapm_get_power_status(u_short*status,u_short*bat,u_short*life){structapm_bios_callcall;call.func=APM_FUNC_GET_STATUS;call.ebx=APM_DEVICE_ALL;call.ecx=0;if(apm_info.get_power_status_broken)returnAPM_32_UNSUPPORTED;if(apm_bios_call(&call))returncall.err;*status=call.ebx;*bat=call.ecx;
if(apm_info.get_power_status_swabinminutes){*life=swab16((u16)call.edx);*life|=0x8000;}else*life=call.edx;returnAPM_SUCCESS;}#if0staticintapm_get_battery_status(u_shortwhich,u_short*status,u_short*bat,u_short*life,u_short*nbat){u32eax;u32ebx;u32ecx;u32edx;u32esi;if(apm_info.connection_version<0x0102
){if(which!=1)returnAPM_BAD_DEVICE;*nbat=1;returnapm_get_power_status(status,bat,life);}if(apm_bios_call(APM_FUNC_GET_STATUS,(0x8000|(which)),0,&eax,&ebx,&ecx,&edx,&esi))return(eax>>8)&0xff;*status=ebx;*bat=ecx;*life=edx;*nbat=esi;returnAPM_SUCCESS;}#endif/***apm_engage_power_management-enablePMonad
evice*@device:identityofdevice*@enable:on/off**Activateordeactivepowermanagementoneitheraspecificdevice*ortheentiresystem(%APM_DEVICE_ALL).*/staticintapm_engage_power_management(u_shortdevice,intenable){u32eax;interr;if((enable==0)&&(device==APM_DEVICE_ALL)&&(apm_info.bios.flags&APM_BIOS_DISABLED))r
eturnAPM_DISABLED;if(apm_bios_call_simple(APM_FUNC_ENGAGE_PM,device,enable,&eax,&err))returnerr;if(device==APM_DEVICE_ALL){if(enable)apm_info.bios.flags&=~APM_BIOS_DISENGAGED;elseapm_info.bios.flags|=APM_BIOS_DISENGAGED;}returnAPM_SUCCESS;}#ifdefined(CONFIG_APM_DISPLAY_BLANK)&&defined(CONFIG_VT)/***
apm_console_blank-blankthedisplay*@blank:on/off**Attempttoblanktheconsole,firstlybyblankingjustvideodevice*zero,andifthatfails(someBIOSesdontsupportit)thenitblanks*allvideodevices.TypicallytheBIOSwilldolaptopbacklightand*monitorpowerdownforus.*/staticintapm_console_blank(intblank){interror=APM_NOT_E
NGAGED;inti;u_shortstate;staticconstu_shortdev[3]={0x100,0x1FF,0x101};state=blank?APM_STATE_STANDBY:APM_STATE_READY;for(i=0;i<ARRAY_SIZE(dev);i++){error=set_power_state(dev[i],state);if((error==APM_SUCCESS)||(error==APM_NO_ERROR))return1;if(error==APM_NOT_ENGAGED)break;}if(error==APM_NOT_ENGAGED){st
aticinttried;inteng_error;if(tried++==0){eng_error=apm_engage_power_management(APM_DEVICE_ALL,1);if(eng_error){apm_error("setdisplay",error);apm_error("engageinterface",eng_error);return0;}elsereturnapm_console_blank(blank);}}apm_error("setdisplay",error);return0;}#endifstaticintqueue_empty(structap
m_user*as){returnas->event_head==as->event_tail;}staticapm_event_tget_queued_event(structapm_user*as){if(++as->event_tail>=APM_MAX_EVENTS)as->event_tail=0;returnas->events[as->event_tail];}staticvoidqueue_event(apm_event_tevent,structapm_user*sender){structapm_user*as;spin_lock(&user_list_lock);if(u
ser_list==NULL)gotoout;for(as=user_list;as!=NULL;as=as->next){if((as==sender)||(!as->reader))continue;if(++as->event_head>=APM_MAX_EVENTS)as->event_head=0;if(as->event_head==as->event_tail){staticintnotified;if(notified++==0)printk(KERN_ERR"apm:aneventqueueoverflowed\n");if(++as->event_tail>=APM_MAX
_EVENTS)as->event_tail=0;}as->events[as->event_head]=event;if(!as->suser||!as->writer)continue;switch(event){caseAPM_SYS_SUSPEND:caseAPM_USER_SUSPEND:as->suspends_pending++;suspends_pending++;break;caseAPM_SYS_STANDBY:caseAPM_USER_STANDBY:as->standbys_pending++;standbys_pending++;break;}}wake_up_int
erruptible(&apm_waitqueue);out:spin_unlock(&user_list_lock);}staticvoidreinit_timer(void){#ifdefINIT_TIMER_AFTER_SUSPENDunsignedlongflags;raw_spin_lock_irqsave(&i8253_lock,flags);outb_pit(0x34,PIT_MODE);udelay(10);outb_pit(LATCH&0xff,PIT_CH0);udelay(10);outb_pit(LATCH>>8,PIT_CH0);udelay(10);raw_spin
_unlock_irqrestore(&i8253_lock,flags);#endif}staticintsuspend(intvetoable){interr;structapm_user*as;dpm_suspend_start(PMSG_SUSPEND);dpm_suspend_noirq(PMSG_SUSPEND);local_irq_disable();sysdev_suspend(PMSG_SUSPEND);local_irq_enable();save_processor_state();err=set_system_power_state(APM_STATE_SUSPEND)
;ignore_normal_resume=1;restore_processor_state();local_irq_disable();reinit_timer();if(err==APM_NO_ERROR)err=APM_SUCCESS;if(err!=APM_SUCCESS)apm_error("suspend",err);err=(err==APM_SUCCESS)?0:-EIO;sysdev_resume();local_irq_enable();dpm_resume_noirq(PMSG_RESUME);dpm_resume_end(PMSG_RESUME);queue_even
t(APM_NORMAL_RESUME,NULL);spin_lock(&user_list_lock);for(as=user_list;as!=NULL;as=as->next){as->suspend_wait=0;as->suspend_result=err;}spin_unlock(&user_list_lock);wake_up_interruptible(&apm_suspend_waitqueue);returnerr;}staticvoidstandby(void){interr;dpm_suspend_noirq(PMSG_SUSPEND);local_irq_disabl
e();sysdev_suspend(PMSG_SUSPEND);local_irq_enable();err=set_system_power_state(APM_STATE_STANDBY);if((err!=APM_SUCCESS)&&(err!=APM_NO_ERROR))apm_error("standby",err);local_irq_disable();sysdev_resume();local_irq_enable();dpm_resume_noirq(PMSG_RESUME);}staticapm_event_tget_event(void){interror;apm_ev
ent_tevent=APM_NO_EVENTS;apm_eventinfo_tinfo;staticintnotified;error=apm_get_event(&event,&info);if(error==APM_SUCCESS)returnevent;if((error!=APM_NO_EVENTS)&&(notified++==0))apm_error("get_event",error);return0;}staticvoidcheck_events(void){apm_event_tevent;staticunsignedlonglast_resume;staticintign
ore_bounce;while((event=get_event())!=0){if(debug){if(event<=NR_APM_EVENT_NAME)printk(KERN_DEBUG"apm:received%snotify\n",apm_event_name[event-1]);elseprintk(KERN_DEBUG"apm:receivedunknown""event0x%02x\n",event);}if(ignore_bounce&&(time_after(jiffies,last_resume+bounce_interval)))ignore_bounce=0;swit
ch(event){caseAPM_SYS_STANDBY:caseAPM_USER_STANDBY:queue_event(event,NULL);if(standbys_pending<=0)standby();break;caseAPM_USER_SUSPEND:#ifdefCONFIG_APM_IGNORE_USER_SUSPENDif(apm_info.connection_version>0x100)set_system_power_state(APM_STATE_REJECT);break;#endifcaseAPM_SYS_SUSPEND:if(ignore_bounce){i
f(apm_info.connection_version>0x100)set_system_power_state(APM_STATE_REJECT);break;}/**IfwearealreadyprocessingaSUSPEND,*thenfurtherSUSPENDeventsfromtheBIOS*willbeignored.Wealsoreturnhereto*copewiththefactthattheThinkpadskeep*sendingaSUSPENDeventuntilsomethingelse*happens!*/if(ignore_sys_suspend)ret
urn;ignore_sys_suspend=1;queue_event(event,NULL);if(suspends_pending<=0)(void)suspend(1);break;caseAPM_NORMAL_RESUME:caseAPM_CRITICAL_RESUME:caseAPM_STANDBY_RESUME:ignore_sys_suspend=0;last_resume=jiffies;ignore_bounce=1;if((event!=APM_NORMAL_RESUME)||(ignore_normal_resume==0)){dpm_resume_end(PMSG_R
ESUME);queue_event(event,NULL);}ignore_normal_resume=0;break;caseAPM_CAPABILITY_CHANGE:caseAPM_LOW_BATTERY:caseAPM_POWER_STATUS_CHANGE:queue_event(event,NULL);break;caseAPM_UPDATE_TIME:break;caseAPM_CRITICAL_SUSPEND:/**Wearenotallowedtorejectacriticalsuspend.*/(void)suspend(0);break;}}}staticvoidapm
_event_handler(void){staticintpending_count=4;interr;if((standbys_pending>0)||(suspends_pending>0)){if((apm_info.connection_version>0x100)&&(pending_count--<=0)){pending_count=4;if(debug)printk(KERN_DEBUG"apm:settingstatebusy\n");err=set_system_power_state(APM_STATE_BUSY);if(err)apm_error("busy",err
);}}elsepending_count=4;check_events();}/**ThisistheAPMthreadmainloop.*/staticvoidapm_mainloop(void){DECLARE_WAITQUEUE(wait,current);add_wait_queue(&apm_waitqueue,&wait);set_current_state(TASK_INTERRUPTIBLE);for(;;){schedule_timeout(APM_CHECK_TIMEOUT);if(kthread_should_stop())break;/**Ok,checkalleve
nts,checkforidle(andmarkussleeping*soasnottocounttowardstheloadaverage)..*/set_current_state(TASK_INTERRUPTIBLE);apm_event_handler();}remove_wait_queue(&apm_waitqueue,&wait);}staticintcheck_apm_user(structapm_user*as,constchar*func){if(as==NULL||as->magic!=APM_BIOS_MAGIC){printk(KERN_ERR"apm:%spasse
dbadfilp\n",func);return1;}return0;}staticssize_tdo_read(structfile*fp,char__user*buf,size_tcount,loff_t*ppos){structapm_user*as;inti;apm_event_tevent;as=fp->private_data;if(check_apm_user(as,"read"))return-EIO;if((int)count<sizeof(apm_event_t))return-EINVAL;if((queue_empty(as))&&(fp->f_flags&O_NONB
LOCK))return-EAGAIN;wait_event_interruptible(apm_waitqueue,!queue_empty(as));i=count;while((i>=sizeof(event))&&!queue_empty(as)){event=get_queued_event(as);if(copy_to_user(buf,&event,sizeof(event))){if(i<count)break;return-EFAULT;}switch(event){caseAPM_SYS_SUSPEND:caseAPM_USER_SUSPEND:as->suspends_r
ead++;break;caseAPM_SYS_STANDBY:caseAPM_USER_STANDBY:as->standbys_read++;break;}buf+=sizeof(event);i-=sizeof(event);}if(i<count)returncount-i;if(signal_pending(current))return-ERESTARTSYS;return0;}staticunsignedintdo_poll(structfile*fp,poll_table*wait){structapm_user*as;as=fp->private_data;if(check_
apm_user(as,"poll"))return0;poll_wait(fp,&apm_waitqueue,wait);if(!queue_empty(as))returnPOLLIN|POLLRDNORM;return0;}staticlongdo_ioctl(structfile*filp,u_intcmd,u_longarg){structapm_user*as;intret;as=filp->private_data;if(check_apm_user(as,"ioctl"))return-EIO;if(!as->suser||!as->writer)return-EPERM;sw
itch(cmd){caseAPM_IOC_STANDBY:mutex_lock(&apm_mutex);if(as->standbys_read>0){as->standbys_read--;as->standbys_pending--;standbys_pending--;}elsequeue_event(APM_USER_STANDBY,as);if(standbys_pending<=0)standby();mutex_unlock(&apm_mutex);break;caseAPM_IOC_SUSPEND:mutex_lock(&apm_mutex);if(as->suspends_
read>0){as->suspends_read--;as->suspends_pending--;suspends_pending--;}elsequeue_event(APM_USER_SUSPEND,as);if(suspends_pending<=0){ret=suspend(1);mutex_unlock(&apm_mutex);}else{as->suspend_wait=1;mutex_unlock(&apm_mutex);wait_event_interruptible(apm_suspend_waitqueue,as->suspend_wait==0);ret=as->su
spend_result;}returnret;default:return-ENOTTY;}return0;}staticintdo_release(structinode*inode,structfile*filp){structapm_user*as;as=filp->private_data;if(check_apm_user(as,"release"))return0;filp->private_data=NULL;if(as->standbys_pending>0){standbys_pending-=as->standbys_pending;if(standbys_pending
<=0)standby();}if(as->suspends_pending>0){suspends_pending-=as->suspends_pending;if(suspends_pending<=0)(void)suspend(1);}spin_lock(&user_list_lock);if(user_list==as)user_list=as->next;else{structapm_user*as1;for(as1=user_list;(as1!=NULL)&&(as1->next!=as);as1=as1->next);if(as1==NULL)printk(KERN_ERR"
apm:filpnotinuserlist\n");elseas1->next=as->next;}spin_unlock(&user_list_lock);kfree(as);return0;}staticintdo_open(structinode*inode,structfile*filp){structapm_user*as;as=kmalloc(sizeof(*as),GFP_KERNEL);if(as==NULL){printk(KERN_ERR"apm:cannotallocatestructofsize%dbytes\n",sizeof(*as));return-ENOMEM;
}as->magic=APM_BIOS_MAGIC;as->event_tail=as->event_head=0;as->suspends_pending=as->standbys_pending=0;as->suspends_read=as->standbys_read=0;/**XXX-thisisatinybitbroken,whenweconsiderBSD*processaccounting.Ifthedeviceisopenedbyroot,we*instantlyflagthatweusedsuperuserprivs.Whoknows,*wemightclosethedevi
ceimmediatelywithoutdoinga*privilegedoperation--cevans*/as->suser=capable(CAP_SYS_ADMIN);as->writer=(filp->f_mode&FMODE_WRITE)==FMODE_WRITE;as->reader=(filp->f_mode&FMODE_READ)==FMODE_READ;spin_lock(&user_list_lock);as->next=user_list;user_list=as;spin_unlock(&user_list_lock);filp->private_data=as;r
eturn0;}staticintproc_apm_show(structseq_file*m,void*v){unsignedshortbx;unsignedshortcx;unsignedshortdx;interror;unsignedshortac_line_status=0xff;unsignedshortbattery_status=0xff;unsignedshortbattery_flag=0xff;intpercentage=-1;inttime_units=-1;char*units="?";if((num_online_cpus()==1)&&!(error=apm_ge
t_power_status(&bx,&cx,&dx))){ac_line_status=(bx>>8)&0xff;battery_status=bx&0xff;if((cx&0xff)!=0xff)percentage=cx&0xff;if(apm_info.connection_version>0x100){battery_flag=(cx>>8)&0xff;if(dx!=0xffff){units=(dx&0x8000)?"min":"sec";time_units=dx&0x7fff;}}}/*Arguments,withsymbolsfromlinux/apm_bios.h.Info
rmationisfromtheGetPowerStatus(0x0a)callunlessotherwisenoted.0)Linuxdriverversion(thiswillchangeifformatchanges)1)APMBIOSVersion.Usually1.0,1.1or1.2.2)APMflagsfromAPMInstallationCheck(0x00):bit0:APM_16_BIT_SUPPORTbit1:APM_32_BIT_SUPPORTbit2:APM_IDLE_SLOWS_CLOCKbit3:APM_BIOS_DISABLEDbit4:APM_BIOS_DIS
ENGAGED3)AClinestatus0x00:Off-line0x01:On-line0x02:Onbackuppower(BIOS>=1.1only)0xff:Unknown4)Batterystatus0x00:High0x01:Low0x02:Critical0x03:Charging0x04:Selectedbatterynotpresent(BIOS>=1.2only)0xff:Unknown5)Batteryflagbit0:Highbit1:Lowbit2:Criticalbit3:Chargingbit7:Nosystembattery0xff:Unknown6)Rema
iningbatterylife(percentageofcharge):0-100:valid-1:Unknown7)Remainingbatterylife(timeunits):Numberofremainingminutesorseconds-1:Unknown8)min=minutes;sec=seconds*/seq_printf(m,"%s%d.%d0x%02x0x%02x0x%02x0x%02x%d%%%d%s\n",driver_version,(apm_info.bios.version>>8)&0xff,apm_info.bios.version&0xff,apm_inf
o.bios.flags,ac_line_status,battery_status,battery_flag,percentage,time_units,units);return0;}staticintproc_apm_open(structinode*inode,structfile*file){returnsingle_open(file,proc_apm_show,NULL);}staticconststructfile_operationsapm_file_ops={.owner=THIS_MODULE,.open=proc_apm_open,.read=seq_read,.lls
eek=seq_lseek,.release=single_release,};staticintapm(void*unused){unsignedshortbx;unsignedshortcx;unsignedshortdx;interror;char*power_stat;char*bat_stat;/*2002/08/01-WT*Thisistoavoidrandomcrashesatboottimeduringinitialization*onSMPsystemsincaseof"apm=power-off"mode.SeenonASUSA7M266D.*Somebiosesdontl
ikebeingcalledfromCPU!=0.*MethodsuggestedbyIngoMolnar.*/set_cpus_allowed_ptr(current,cpumask_of(0));BUG_ON(smp_processor_id()!=0);if(apm_info.connection_version==0){apm_info.connection_version=apm_info.bios.version;if(apm_info.connection_version>0x100){/**WeonlysupportBIOSsuptoversion1.2*/if(apm_inf
o.connection_version>0x0102)apm_info.connection_version=0x0102;error=apm_driver_version(&apm_info.connection_version);if(error!=APM_SUCCESS){apm_error("driverversion",error);apm_info.connection_version=0x100;}}}if(debug)printk(KERN_INFO"apm:Connectionversion%d.%d\n",(apm_info.connection_version>>8)&
0xff,apm_info.connection_version&0xff);#ifdefCONFIG_APM_DO_ENABLEif(apm_info.bios.flags&APM_BIOS_DISABLED){/**ThiscallcausesmyNECUltraLiteVersa33/Ctohangifit*isbootedwithPMdisabledbutnotinthedockingstation.*Unfortunate...*/error=apm_enable_power_management(1);if(error){apm_error("enablepowermanageme
nt",error);return-1;}}#endifif((apm_info.bios.flags&APM_BIOS_DISENGAGED)&&(apm_info.connection_version>0x0100)){error=apm_engage_power_management(APM_DEVICE_ALL,1);if(error){apm_error("engagepowermanagement",error);return-1;}}if(debug&&(num_online_cpus()==1||smp)){error=apm_get_power_status(&bx,&cx,
&dx);if(error)printk(KERN_INFO"apm:powerstatusnotavailable\n");else{switch((bx>>8)&0xff){case0:power_stat="offline";break;case1:power_stat="online";break;case2:power_stat="onbackuppower";break;default:power_stat="unknown";break;}switch(bx&0xff){case0:bat_stat="high";break;case1:bat_stat="low";break;
case2:bat_stat="critical";break;case3:bat_stat="charging";break;default:bat_stat="unknown";break;}printk(KERN_INFO"apm:AC%s,batterystatus%s,batterylife",power_stat,bat_stat);if((cx&0xff)==0xff)printk("unknown\n");elseprintk("%d%%\n",cx&0xff);if(apm_info.connection_version>0x100){printk(KERN_INFO"apm
:batteryflag0x%02x,batterylife",(cx>>8)&0xff);if(dx==0xffff)printk("unknown\n");elseprintk("%d%s\n",dx&0x7fff,(dx&0x8000)?"minutes":"seconds");}}}if(power_off)pm_power_off=apm_power_off;if(num_online_cpus()==1||smp){#ifdefined(CONFIG_APM_DISPLAY_BLANK)&&defined(CONFIG_VT)console_blank_hook=apm_conso
le_blank;#endifapm_mainloop();#ifdefined(CONFIG_APM_DISPLAY_BLANK)&&defined(CONFIG_VT)console_blank_hook=NULL;#endif}return0;}#ifndefMODULEstaticint__initapm_setup(char*str){intinvert;while((str!=NULL)&&(*str!=\0)){if(strncmp(str,"off",3)==0)apm_disabled=1;if(strncmp(str,"on",2)==0)apm_disabled=0;if
((strncmp(str,"bounce-interval=",16)==0)||(strncmp(str,"bounce_interval=",16)==0))bounce_interval=simple_strtol(str+16,NULL,0);if((strncmp(str,"idle-threshold=",15)==0)||(strncmp(str,"idle_threshold=",15)==0))idle_threshold=simple_strtol(str+15,NULL,0);if((strncmp(str,"idle-period=",12)==0)||(strncm
p(str,"idle_period=",12)==0))idle_period=simple_strtol(str+12,NULL,0);invert=(strncmp(str,"no-",3)==0)||(strncmp(str,"no_",3)==0);if(invert)str+=3;if(strncmp(str,"debug",5)==0)debug=!invert;if((strncmp(str,"power-off",9)==0)||(strncmp(str,"power_off",9)==0))power_off=!invert;if(strncmp(str,"smp",3)=
=0){smp=!invert;idle_threshold=100;}if((strncmp(str,"allow-ints",10)==0)||(strncmp(str,"allow_ints",10)==0))apm_info.allow_ints=!invert;if((strncmp(str,"broken-psr",10)==0)||(strncmp(str,"broken_psr",10)==0))apm_info.get_power_status_broken=!invert;if((strncmp(str,"realmode-power-off",18)==0)||(strn
cmp(str,"realmode_power_off",18)==0))apm_info.realmode_power_off=!invert;str=strchr(str,,);if(str!=NULL)str+=strspn(str,",\t");}return1;}__setup("apm=",apm_setup);#endifstaticconststructfile_operationsapm_bios_fops={.owner=THIS_MODULE,.read=do_read,.poll=do_poll,.unlocked_ioctl=do_ioctl,.open=do_ope
n,.release=do_release,.llseek=noop_llseek,};staticstructmiscdeviceapm_device={APM_MINOR_DEV,"apm_bios",&apm_bios_fops};staticint__initprint_if_true(conststructdmi_system_id*d){printk("%s\n",d->ident);return0;}/**SomeBiosesenablethePS/2mouse(touchpad)atresume,evenifitwas*disabledbeforethesuspend.Linu
xusedtogetterriblyconfusedbythat.*/staticint__initbroken_ps2_resume(conststructdmi_system_id*d){printk(KERN_INFO"%smachinedetected.MousepadResumeBug""workaroundhopefullynotneeded.\n",d->ident);return0;}staticint__initset_realmode_power_off(conststructdmi_system_id*d){if(apm_info.realmode_power_off==
0){apm_info.realmode_power_off=1;printk(KERN_INFO"%sbiosdetected.""Usingrealmodepoweroffonly.\n",d->ident);}return0;}staticint__initset_apm_ints(conststructdmi_system_id*d){if(apm_info.allow_ints==0){apm_info.allow_ints=1;printk(KERN_INFO"%smachinedetected.""EnablinginterruptsduringAPMcalls.\n",d->i
dent);}return0;}staticint__initapm_is_horked(conststructdmi_system_id*d){if(apm_info.disabled==0){apm_info.disabled=1;printk(KERN_INFO"%smachinedetected.""DisablingAPM.\n",d->ident);}return0;}staticint__initapm_is_horked_d850md(conststructdmi_system_id*d){if(apm_info.disabled==0){apm_info.disabled=1
;printk(KERN_INFO"%smachinedetected.""DisablingAPM.\n",d->ident);printk(KERN_INFO"ThisbugisfixedinbiosP15whichisavailablefor\n");printk(KERN_INFO"downloadfromsupport.intel.com\n");}return0;}staticint__initapm_likes_to_melt(conststructdmi_system_id*d){if(apm_info.forbid_idle==0){apm_info.forbid_idle=
1;printk(KERN_INFO"%smachinedetected.""DisablingAPMidlecalls.\n",d->ident);}return0;}/**CheckforcluefreeBIOSimplementationswhouse*thefollowingQAtechnique**[WriteBIOSCode]<------*|^*<DoesitCompile>----N--*|Y^*<DoesitBootWin98>-N--*|Y*[ShipIt]**PhoenixA0408/24/2000isknownbad(DellInspiron5000e)*Phoenix
A0709/29/2000isknowngood(DellInspiron5000)*/staticint__initbroken_apm_power(conststructdmi_system_id*d){apm_info.get_power_status_broken=1;printk(KERN_WARNING"BIOSstringssuggestAPMbugs,""disablingpowerstatusreporting.\n");return0;}/**ThisbiosswapstheAPMminutereportingbytesover(Manysonylaptops*haveth
isproblem).*/staticint__initswab_apm_power_in_minutes(conststructdmi_system_id*d){apm_info.get_power_status_swabinminutes=1;printk(KERN_WARNING"BIOSstringssuggestAPMreportsbatterylife""inminutesandwrongbyteorder.\n");return0;}staticstructdmi_system_id__initdataapm_dmi_table[]={{print_if_true,KERN_WA
RNING"IBMT23-BIOS1.03b+andcontrollerfirmware1.02+maybeneededforLinuxAPM.",{DMI_MATCH(DMI_SYS_VENDOR,"IBM"),DMI_MATCH(DMI_BIOS_VERSION,"1AET38WW(1.01b)"),},},{broken_ps2_resume,"DellLatitudeC600",{DMI_MATCH(DMI_SYS_VENDOR,"Dell"),DMI_MATCH(DMI_PRODUCT_NAME,"LatitudeC600"),},},{set_apm_ints,"DellLatit
ude",{DMI_MATCH(DMI_SYS_VENDOR,"DellComputerCorporation"),DMI_MATCH(DMI_PRODUCT_NAME,"LatitudeC510"),}},{apm_is_horked,"DellInspiron2500",{DMI_MATCH(DMI_SYS_VENDOR,"DellComputerCorporation"),DMI_MATCH(DMI_PRODUCT_NAME,"Inspiron2500"),DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_
BIOS_VERSION,"A11"),},},{set_apm_ints,"DellInspiron",{DMI_MATCH(DMI_SYS_VENDOR,"DellComputerCorporation"),DMI_MATCH(DMI_PRODUCT_NAME,"Inspiron4000"),},},{broken_apm_power,"DellInspiron5000e",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"A04"),DMI_MATCH(DMI_BIOS_DAT
E,"08/24/2000"),},},{broken_apm_power,"DellInspiron2500",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"A12"),DMI_MATCH(DMI_BIOS_DATE,"02/04/2002"),},},{apm_is_horked,"DellDimension4100",{DMI_MATCH(DMI_SYS_VENDOR,"DellComputerCorporation"),DMI_MATCH(DMI_PRODUCT_NAME
,"XPS-Z"),DMI_MATCH(DMI_BIOS_VENDOR,"IntelCorp."),DMI_MATCH(DMI_BIOS_VERSION,"A11"),},},{set_apm_ints,"Compaq12XL125",{DMI_MATCH(DMI_SYS_VENDOR,"Compaq"),DMI_MATCH(DMI_PRODUCT_NAME,"CompaqPC"),DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"4.06"),},},{set_apm_ints,"A
SUSTeK",{DMI_MATCH(DMI_SYS_VENDOR,"ASUSTeKComputerInc."),DMI_MATCH(DMI_PRODUCT_NAME,"L8400KseriesNotebookPC"),},},{apm_is_horked,"ABITKX7-333[R]",{DMI_MATCH(DMI_BOARD_VENDOR,"ABIT"),DMI_MATCH(DMI_BOARD_NAME,"VT8367-8233A(KX7-333[R])"),},},{apm_is_horked,"TrigemDelhi3",{DMI_MATCH(DMI_SYS_VENDOR,"TriG
emComputer,Inc"),DMI_MATCH(DMI_PRODUCT_NAME,"Delhi3"),},},{apm_is_horked,"Fujitsu-Siemens",{DMI_MATCH(DMI_BIOS_VENDOR,"hoenix/FUJITSUSIEMENS"),DMI_MATCH(DMI_BIOS_VERSION,"Version1.01"),},},{apm_is_horked_d850md,"IntelD850MD",{DMI_MATCH(DMI_BIOS_VENDOR,"IntelCorp."),DMI_MATCH(DMI_BIOS_VERSION,"MV8501
0A.86A.0016.P07.0201251536"),},},{apm_is_horked,"IntelD810EMO",{DMI_MATCH(DMI_BIOS_VENDOR,"IntelCorp."),DMI_MATCH(DMI_BIOS_VERSION,"MO81010A.86A.0008.P04.0004170800"),},},{apm_is_horked,"DellXPS-Z",{DMI_MATCH(DMI_BIOS_VENDOR,"IntelCorp."),DMI_MATCH(DMI_BIOS_VERSION,"A11"),DMI_MATCH(DMI_PRODUCT_NAME,
"XPS-Z"),},},{apm_is_horked,"SharpPC-PJ/AX",{DMI_MATCH(DMI_SYS_VENDOR,"SHARP"),DMI_MATCH(DMI_PRODUCT_NAME,"PC-PJ/AX"),DMI_MATCH(DMI_BIOS_VENDOR,"SystemSoft"),DMI_MATCH(DMI_BIOS_VERSION,"VersionR2.08"),},},{apm_is_horked,"DellInspiron2500",{DMI_MATCH(DMI_SYS_VENDOR,"DellComputerCorporation"),DMI_MATC
H(DMI_PRODUCT_NAME,"Inspiron2500"),DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"A11"),},},{apm_likes_to_melt,"JabilAMD",{DMI_MATCH(DMI_BIOS_VENDOR,"AmericanMegatrendsInc."),DMI_MATCH(DMI_BIOS_VERSION,"0AASNP06"),},},{apm_likes_to_melt,"AMIBios",{DMI_MATCH(DMI_BIOS_
VENDOR,"AmericanMegatrendsInc."),DMI_MATCH(DMI_BIOS_VERSION,"0AASNP05"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0206H"),DMI_MATCH(DMI_BIOS_DATE,"08/23/99"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIO
S_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"W2K06H0"),DMI_MATCH(DMI_BIOS_DATE,"02/03/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0117A0"),DMI_MATCH(DMI_BIOS_DATE,"04/25/00"),},},{swab_apm_power_in
_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0121Z1"),DMI_MATCH(DMI_BIOS_DATE,"05/11/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"WME01Z1"),DMI_MATCH(DMI_BIOS_D
ATE,"08/11/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0206Z3"),DMI_MATCH(DMI_BIOS_DATE,"12/25/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_V
ERSION,"R0203D0"),DMI_MATCH(DMI_BIOS_DATE,"05/12/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0203Z3"),DMI_MATCH(DMI_BIOS_DATE,"08/25/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix
TechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0209Z3"),DMI_MATCH(DMI_BIOS_DATE,"05/12/01"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0204K2"),DMI_MATCH(DMI_BIOS_DATE,"08/28/00"),},},{swab_apm_power_in_minutes,"SonyVAI
O",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0208P1"),DMI_MATCH(DMI_BIOS_DATE,"11/09/00"),},},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"R0204P1"),DMI_MATCH(DMI_BIOS_DATE,"09/12/00"),}
,},{swab_apm_power_in_minutes,"SonyVAIO",{DMI_MATCH(DMI_BIOS_VENDOR,"PhoenixTechnologiesLTD"),DMI_MATCH(DMI_BIOS_VERSION,"WXPO1Z3"),DMI_MATCH(DMI_BIOS_DATE,"10/26/01"),},},{set_realmode_power_off,"AwardSoftwarev4.60PGMA",{DMI_MATCH(DMI_BIOS_VENDOR,"AwardSoftwareInternational,Inc."),DMI_MATCH(DMI_BIO
S_VERSION,"4.60PGMA"),DMI_MATCH(DMI_BIOS_DATE,"134526184"),},},{set_apm_ints,"IBM",{DMI_MATCH(DMI_SYS_VENDOR,"IBM"),},},{}};/**JuststarttheAPMthread.WedoNOTwanttodoAPMBIOS*callsfromanythingbuttheAPMthread,iffornootherreason*thanthefactthatwedonttrusttheAPMBIOS.Thisway,*mostcommonAPMBIOSproblemsthatl
eadtoprotectionerrors*etcwillhaveatleastsomelevelofbeingcontained...**Inshort,ifsomethingbadhappens,atleastwehaveachoice*ofjustkillingtheapmthread..*/staticint__initapm_init(void){structdesc_struct*gdt;interr;dmi_check_system(apm_dmi_table);if(apm_info.bios.version==0||paravirt_enabled()||machine_is
_olpc()){printk(KERN_INFO"apm:BIOSnotfound.\n");return-ENODEV;}printk(KERN_INFO"apm:BIOSversion%d.%dFlags0x%02x(Driverversion%s)\n",((apm_info.bios.version>>8)&0xff),(apm_info.bios.version&0xff),apm_info.bios.flags,driver_version);if((apm_info.bios.flags&APM_32_BIT_SUPPORT)==0){printk(KERN_INFO"apm:
no32bitBIOSsupport\n");return-ENODEV;}if(allow_ints)apm_info.allow_ints=1;if(broken_psr)apm_info.get_power_status_broken=1;if(realmode_power_off)apm_info.realmode_power_off=1;if(apm_disabled!=-1)apm_info.disabled=apm_disabled;/**FixfortheCompaqContura3/25cwhichreportsBIOSversion0.1*butisreportedlya1
.0BIOS.*/if(apm_info.bios.version==0x001)apm_info.bios.version=0x100;if(apm_info.bios.version<0x102)apm_info.bios.cseg_16_len=0;if(debug){printk(KERN_INFO"apm:entry%x:%xcseg16%xdseg%x",apm_info.bios.cseg,apm_info.bios.offset,apm_info.bios.cseg_16,apm_info.bios.dseg);if(apm_info.bios.version>0x100)pr
intk("cseglen%x,dseglen%x",apm_info.bios.cseg_len,apm_info.bios.dseg_len);if(apm_info.bios.version>0x101)printk("cseg16len%x",apm_info.bios.cseg_16_len);printk("\n");}if(apm_info.disabled){printk(KERN_NOTICE"apm:disabledonuserrequest.\n");return-ENODEV;}if((num_online_cpus()>1)&&!power_off&&!smp){pr
intk(KERN_NOTICE"apm:disabled-APMisnotSMPsafe.\n");apm_info.disabled=1;return-ENODEV;}if(pm_flags&PM_ACPI){printk(KERN_NOTICE"apm:overriddenbyACPI.\n");apm_info.disabled=1;return-ENODEV;}pm_flags|=PM_APM;/**SetupthelongjumpentrypointtotheAPMBIOS,whichiscalled*frominlineassembly.*/apm_bios_entry.offs
et=apm_info.bios.offset;apm_bios_entry.segment=APM_CS;/**TheAPM1.1BIOSissupposedtoprovidelimitinformationthatit*recognizes.Manymachinesdothiscorrectly,butmanyothersdo*notrestrictthemselvestotheirclaimedlimit.Whenthishappens,*theywillcauseasegmentationviolationinthekernelatboottime.*MostBIOSs,however
,willrespecta64klimit,soweusethat.**NoteweonlysetAPMsegmentsonCPUzero,sincewepintheAPM*codetothatCPU.*/gdt=get_cpu_gdt_table(0);set_desc_base(&gdt[APM_CS>>3],(unsignedlong)__va((unsignedlong)apm_info.bios.cseg<<4));set_desc_base(&gdt[APM_CS_16>>3],(unsignedlong)__va((unsignedlong)apm_info.bios.cseg_
16<<4));set_desc_base(&gdt[APM_DS>>3],(unsignedlong)__va((unsignedlong)apm_info.bios.dseg<<4));proc_create("apm",0,NULL,&apm_file_ops);kapmd_task=kthread_create(apm,NULL,"kapmd");if(IS_ERR(kapmd_task)){printk(KERN_ERR"apm:disabled-Unabletostartkernel""thread.\n");err=PTR_ERR(kapmd_task);kapmd_task=N
ULL;remove_proc_entry("apm",NULL);returnerr;}wake_up_process(kapmd_task);if(num_online_cpus()>1&&!smp){printk(KERN_NOTICE"apm:disabled-APMisnotSMPsafe(poweroffactive).\n");return0;}/**Notewedontactuallycareifthemisc_devicecannotberegistered.*thisdrivercandoitsjobwithoutit,evenifuserspacecant*control
it.justlogtheerror*/if(misc_register(&apm_device))printk(KERN_WARNING"apm:Couldnotregistermiscdevice.\n");if(HZ!=100)idle_period=(idle_period*HZ)/100;if(idle_threshold<100){original_pm_idle=pm_idle;pm_idle=apm_cpu_idle;set_pm_idle=1;}return0;}staticvoid__exitapm_exit(void){interror;if(set_pm_idle){p
m_idle=original_pm_idle;/**Weareabouttounloadthecurrentidlethreadpmcallback*(pm_idle),Waitforallprocessorstoupdatecached/local*copiesofpm_idlebeforeproceeding.*/cpu_idle_wait();}if(((apm_info.bios.flags&APM_BIOS_DISENGAGED)==0)&&(apm_info.connection_version>0x0100)){error=apm_engage_power_management
(APM_DEVICE_ALL,0);if(error)apm_error("disengagepowermanagement",error);}misc_deregister(&apm_device);remove_proc_entry("apm",NULL);if(power_off)pm_power_off=NULL;if(kapmd_task){kthread_stop(kapmd_task);kapmd_task=NULL;}pm_flags&=~PM_APM;}module_init(apm_init);module_exit(apm_exit);MODULE_AUTHOR("St
ephenRothwell");MODULE_DESCRIPTION("AdvancedPowerManagement");MODULE_LICENSE("GPL");module_param(debug,bool,0644);MODULE_PARM_DESC(debug,"Enabledebugmode");module_param(power_off,bool,0444);MODULE_PARM_DESC(power_off,"Enablepoweroff");module_param(bounce_interval,int,0444);MODULE_PARM_DESC(bounce_in
terval,"Setthenumberoftickstoignoresuspendbounces");module_param(allow_ints,bool,0444);MODULE_PARM_DESC(allow_ints,"AllowinterruptsduringBIOScalls");module_param(broken_psr,bool,0444);MODULE_PARM_DESC(broken_psr,"BIOShasabrokenGetPowerStatuscall");module_param(realmode_power_off,bool,0444);MODULE_PA
RM_DESC(realmode_power_off,"Switchtorealmodebeforepoweringoff");module_param(idle_threshold,int,0444);MODULE_PARM_DESC(idle_threshold,"SystemidlepercentageabovewhichtomakeAPMBIOSidlecalls");module_param(idle_period,int,0444);MODULE_PARM_DESC(idle_period,"Period(insec/100)overwhichtocaculatetheidlepe
rcentage");module_param(smp,bool,0444);MODULE_PARM_DESC(smp,"SetthistoenableAPMuseonanSMPplatform.Usewithcautiononoldersystems");MODULE_ALIAS_MISCDEV(APM_MINOR_DEV);</100){original_pm_idle=pm_idle;pm_idle=apm_cpu_idle;set_pm_idle=1;}return0;}staticvoid__exitapm_exit(void){interror;if(set_pm_idle){pm
_idle=original_pm_idle;/**Weareabouttounloadthecurrentidlethreadpmcallback*(pm_idle),Waitforallprocessorstoupdatecached/local*copiesofpm_idlebeforeproceeding.*/cpu_idle_wait();}if(((apm_info.bios.flags&APM_BIOS_DISENGAGED)==0)&&(apm_info.connection_version>pre>