/**ACPIimplementation**Copyright(c)2006FabriceBellard**Thislibraryisfreesoftware;youcanredistributeitand/or*modifyitunderthetermsoftheGNULesserGeneralPublic*Licenseversion2aspublishedbytheFreeSoftwareFoundation.**Thislibraryisdistributedinthehopethatitwillbeuseful,*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.SeetheGNU*LesserGeneralPublicLicenseformoredetails.**YoushouldhavereceivedacopyoftheGNULesserGeneralPublic*Licensealongwiththislibrary;ifnot,writetotheFreeSoftware*Foundation,Inc.,59TemplePlace,Suite330,Boston,MA02111-1307USA*/#include"vl.h"//#defineDEBUG/* i82731AB (PIIX4) compatible power management function */#definePM_FREQ3579545#defineACPI_DBG_IO_ADDR0xb044typedefstructPIIX4PMState{PCIDevicedev;uint16_tpmsts;uint16_tpmen;uint16_tpmcntrl;
/* schedule a timer interruption if needed */if((s->pmen&TMROF_EN)&&!(pmsts&TMROF_EN)){expire_time=muldiv64(s->tmr_overflow_time,ticks_per_sec,PM_FREQ);qemu_mod_timer(s->tmr_timer,expire_time);}else{qemu_del_timer(s->tmr_timer);}}staticvoidpm_tmr_timer(void*opaque){PIIX4PMState*s=opaque;pm_update_sci(s);}staticvoidpm_ioport_writew(void*opaque,uint32_taddr,uint32_tval){PIIX4PMState*s=opaque;addr&=0x3f;switch(addr){case0x00:{int64_td;intpmsts;pmsts=get_pmsts(s);if(pmsts&val&TMROF_EN){/* if TMRSTS is reset, then compute the new overflow time */d=muldiv64(qemu_get_clock(vm_clock),PM_FREQ,ticks_per_sec);s->tmr_overflow_time=(d+0x800000LL)&~0x7fffffLL;}s->pmsts&=~val;pm_update_sci(s);}break;case0x02:s->pmen=val;pm_update_sci(s);break;case0x04:{intsus_typ;s->pmcntrl=val&~(SUS_EN);if(val&SUS_EN){/* change suspend type */sus_typ=(val>>10)&3;switch(sus_typ){case0:/* soft power off */qemu_system_shutdown_request();break;default:break;}}}break;default:break;}#ifdefDEBUGprintf("PM writew port=0x%04x val=0x%04x\n",addr,val);#endif}staticuint32_tpm_ioport_readw(void*opaque,uint32_taddr){PIIX4PMState*s=opaque;uint32_tval;addr&=0x3f;switch(addr){case0x00:val=get_pmsts(s);break;case0x02:val=s->pmen;break;case0x04:val=s->pmcntrl;break;default:val=0;break;}#ifdefDEBUGprintf("PM readw port=0x%04x val=0x%04x\n",addr,val);#endifreturnval;}staticvoidpm_ioport_writel(void*opaque,uint32_taddr,uint32_tval){//PIIX4PMState*s=opaque;addr&=0x3f;#ifdefDEBUGprintf("PM writel port=0x%04x val=0x%08x\n",addr,val);#endif}staticuint32_tpm_ioport_readl(void*opaque,uint32_taddr){PIIX4PMState*s=opaque;uint32_tval;addr&=0x3f;switch(addr){case0x08:val=get_pmtmr(s);break;default:val=0;break;}#ifdefDEBUGprintf("PM readl port=0x%04x val=0x%08x\n",addr,val);#endifreturnval;}
staticvoidpm_io_space_update(PIIX4PMState*s){uint32_tpm_io_base;if(s->dev.config[0x80]&1){pm_io_base=le32_to_cpu(*(uint32_t*)(s->dev.config+0x40));pm_io_base&=0xfffe;/* XXX: need to improve memory and ioport allocation */#ifdefined(DEBUG)printf("PM: mapping to 0x%x\n",pm_io_base);#endifregister_ioport_write(pm_io_base,64,2,pm_ioport_writew,s);register_ioport_read(pm_io_base,64,2,pm_ioport_readw,s);register_ioport_write(pm_io_base,64,4,pm_ioport_writel,s);register_ioport_read(pm_io_base,64,4,pm_ioport_readl,s);}}staticvoidpm_write_config(PCIDevice*d,uint32_taddress,uint32_tval,intlen){pci_default_write_config(d,address,val,len);if(address==0x80)pm_io_space_update((PIIX4PMState*)d);}staticvoidpm_save(QEMUFile*f,void*opaque){PIIX4PMState*s=opaque;pci_device_save(&s->dev,f);qemu_put_be16s(f,&s->pmsts);qemu_put_be16s(f,&s->pmen);qemu_put_be16s(f,&s->pmcntrl);qemu_put_8s(f,&s->apmc);qemu_put_8s(f,&s->apms);qemu_put_timer(f,s->tmr_timer);qemu_put_be64s(f,&s->tmr_overflow_time);}staticintpm_load(QEMUFile*f,void*opaque,intversion_id){PIIX4PMState*s=opaque;intret;if(version_id>1)return-EINVAL;ret=pci_device_load(&s->dev,f);if(ret<0)returnret;qemu_get_be16s(f,&s->pmsts);qemu_get_be16s(f,&s->pmen);qemu_get_be16s(f,&s->pmcntrl);qemu_get_8s(f,&s->apmc);qemu_get_8s(f,&s->apms);qemu_get_timer(f,s->tmr_timer);qemu_get_be64s(f,&s->tmr_overflow_time);pm_io_space_update(s);return0;}