#include #include #include #include #include #include #include #include #include #include "avm_power.h" /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ struct _speedstep { int speedstep_sema; volatile unsigned int speedstep_state; volatile unsigned int act_gov_cpufreqstate; /*--- Kontext des Threads ---*/ void *handle; } speedstep; #define GOVERNOR_CPUFREQ_FILENAME "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" #define GOVERNOR_CPUFREQ_CURFREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void write_to_file(char *filename, char *str, int len) { struct file *fp; mm_segment_t oldfs; fp = filp_open(filename, O_WRONLY, 00); if(IS_ERR(fp) || (fp->f_op == 0)) { /*--- printk(KERN_ERR " failed: open : %s\n", filename); ---*/ return; } /* Schreibzugriff auf File(system) erlaubt? */ if (fp->f_op->write == NULL) { printk(KERN_ERR "[avm_power]speedstep failed: write %s\n", filename); filp_close(fp, NULL); return; } oldfs = get_fs(); set_fs(KERNEL_DS); fp->f_pos = 0; /* Von Anfang an schreiben*/ fp->f_op->write(fp, str, len, &fp->f_pos); set_fs(oldfs); filp_close(fp, NULL); /* Close the file */ } /*--------------------------------------------------------------------------------*\ * beliebiger Kontext * state: 0 kein Takt umschalten (dsl) * 1 Takt umschaltbar (ata) * * verundet mit Telefonie-Profile: * * 0x10 kein Takt umschalten * 0x11 Takt umschalten * * 0x20: Cpufreq-Semaphore -> Auschalten * 0x21: Cpufreq-Semaphore hochzaehlen -> wenn 0: wieder anschalten * 0x40: Abfrage des aktuellen speedstep-Status: 0 an bzw. pending 1: garantiert aus * 0x80: printk-Ausgabe aktueller speedstepstatus * (da nicht im gleichen Kontext) \*--------------------------------------------------------------------------------*/ static int avm_power_speedstep_Callback(int state){ unsigned long flags = avm_power_lock(); DEB_TRACE("%s(%x): speedstep=%x govfreq=%x sema=%d\n", __func__, state, speedstep.speedstep_state, speedstep.act_gov_cpufreqstate, speedstep.speedstep_sema); switch(state) { case 0x00: speedstep.speedstep_state &= ~0x1; break; case 0x10: speedstep.speedstep_state &= ~0x2; break; case 0x01: speedstep.speedstep_state |= 0x1; break; case 0x11: speedstep.speedstep_state |= 0x2; break; case 0x20: speedstep.speedstep_sema--; if(speedstep.speedstep_sema == -1) { speedstep.speedstep_state |= 0x8; /*--- pending: ---*/ speedstep.speedstep_state &= ~0x4; } break; case 0x21: if(speedstep.speedstep_sema < 0) { speedstep.speedstep_sema++; if(speedstep.speedstep_sema == 0) { speedstep.speedstep_state |= 0x8; /*--- pending ---*/ speedstep.speedstep_state |= 0x4; } } break; case 0x40: if(speedstep.speedstep_state == speedstep.act_gov_cpufreqstate) { /*--- also auch nicht pending ---*/ if((speedstep.act_gov_cpufreqstate & 0x1) == 0 || (speedstep.act_gov_cpufreqstate & 0x4) == 0 ) { avm_power_unlock(flags); /*--- es ist garantiert das speedstep aus ---*/ return 1; } } break; case 0x80: { char buf[128]; avm_power_unlock(flags); avm_power_read_from_file(GOVERNOR_CPUFREQ_FILENAME, buf, sizeof(buf) - 1), printk("governor: %smask=%x sema=%d\n", buf, speedstep.act_gov_cpufreqstate, speedstep.speedstep_sema ); return 0; } } pm_ressourceinfo.Changes++; avm_power_unlock(flags); wake_up_interruptible(&pm_ressourceinfo.wait_queue); return 0; } static int avm_power_speedstep_Callback(int state); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int avm_power_speedstep_init(void) { speedstep.speedstep_state = 0x2 | 0x8; /*--- speedstep auch ohne Telefonapplikation ---*/ #if defined(CONFIG_LANTIQ) speedstep.speedstep_state |= 0x1; /*--- speedstep unabhaengig von DSL ---*/ #endif/*--- #if defined(CONFIG_LANTIQ) ---*/ speedstep.speedstep_sema = -1; speedstep.handle = PowerManagmentRegister("speedstep", avm_power_speedstep_Callback); return speedstep.handle ? 0 : -1; } #ifdef CONFIG_AVM_POWER_MODULE /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void avm_power_speedstep_exit(void) { if(speedstep.handle) { PowerManagmentRelease(speedstep.handle); speedstep.handle = NULL; } } #endif/*--- #ifdef CONFIG_AVM_POWER_MODULE ---*/ /*--------------------------------------------------------------------------------*\ * im Kontext des Threads \*--------------------------------------------------------------------------------*/ void avm_power_speedstep_mode(void) { char *p; unsigned int act_gov_cpufreqstate; unsigned long flags = avm_power_lock(); if(speedstep.speedstep_state == speedstep.act_gov_cpufreqstate) { avm_power_unlock(flags); return; } speedstep.speedstep_state &= ~0x8; /*--- pending loeschen ---*/ act_gov_cpufreqstate = speedstep.speedstep_state; avm_power_unlock(flags); /* Disable parameter checking */ p = (act_gov_cpufreqstate == 0x7) ? "ondemand" : "performance"; write_to_file(GOVERNOR_CPUFREQ_FILENAME, p, strlen(p) + 1); flags = avm_power_lock(); speedstep.act_gov_cpufreqstate = act_gov_cpufreqstate; avm_power_unlock(flags); }