/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2006 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*--- #include ---*/ #include /*--- #include ---*/ /*--- #include ---*/ /*--- #include ---*/ #include #include "avm_power.h" #include "wyatt_earp.h" #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) /*--- #if defined(CONFIG_MIPS_UR8) ---*/ #define MIN_SYSTEMCLK 62500000 #define STD_SYSTEMCLK 125000000 #define MAX_SYSTEMCLK 150000000 #define STD_DSPCLK 212000000 #define MAX_DSPCLK 250000000 #define STD_MIPSCLK 212000000 #define MAX_MIPSCLK 212000000 #else #if defined(CONFIG_MIPS_UR8) #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) #include #endif #if defined(CONFIG_AVM_SIMPLE_PROFILING) #include #endif/*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ /*--- fiktive Werte: ---*/ #define MIN_SYSTEMCLK 120000000 #define STD_SYSTEMCLK 120000000 #define MAX_SYSTEMCLK 120000000 #define STD_DSPCLK 360000000 #define MAX_DSPCLK 360000000 #define STD_MIPSCLK 360000000 #define MAX_MIPSCLK 360000000 #endif/*--- #else ---*//*--- #if defined(CONFIG_MIPS_UR8) ---*/ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #define AVM_POWER_UDEV #endif/*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) #include #include #define LOCAL_MAJOR AVM_POWER_MAJOR #else #include #include #define LOCAL_MAJOR 0 static devfs_handle_t avm_power_devfs_handle; #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define MODULE_NAME "avm_power" MODULE_DESCRIPTION("AVM powermanagment module"); MODULE_LICENSE("GPL"); /*--- #define DEBUG_TRACE_POWERTAB ---*/ #if defined(DEBUG_TRACE_POWERTAB) #define DEB_TRC_PT DEB_ERR #else/*--- #if defined(DEBUG_TRACE_POWERTAB) ---*/ #define DEB_TRC_PT(args...) #endif/*--- #else ---*//*--- #if defined(DEBUG_TRACE_POWERTAB) ---*/ /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ #define SKIP_SPACES(p) while((p) && *(p) && ((*(p) == ' ') || (*(p) == '\t'))) (p)++; #define CMD_MODE "MODE" #define WE_CMD_MODE "WE_MODE" #define PMINFO_MODE "PMINFO_MODE" #define PMINFO_SET "PMINFO_SET" #define ETH_MODE "ETH_MODE" #define IDLE_MODE "IDLE_MODE" #define SEMTECH_MODE "SEMTECH_MODE" #define DYNPLL_MODE "DYNPLL_MODE" static volatile struct _power_managment_clients *PwClientAnker; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) static spinlock_t avm_power_lock = SPIN_LOCK_UNLOCKED; #endif/*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_FUSIV) static unsigned int WyattEarpMode = 0x1FFF; #endif /*--- #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_FUSIV) ---*/ #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_dspboost; #if defined(CONFIG_AVM_SEMTECHFIX) static int avm_power_activate_semtechfix = 1; #else/*--- #if defined(CONFIG_AVM_SEMTECHFIX) ---*/ static int avm_power_activate_semtechfix = 0; #endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_SEMTECHFIX) ---*/ #if defined(CONFIG_MIPS_OHIO) static void avm_power_semtechfix(void); #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ static int avm_power_disp_loadrate = 0; #define ETH_THROTTLE_DEMAND (0x1 << 2) #define ETH_THROTTLE_ACTIVE (0x1 << 3) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _telefonieprofile { void *handle; unsigned int on; } telefonevent; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _powermanagment_status_event { void *handle; int dsl_status; } powermanagment_status_event; #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) static void avmevent_telefonprofile_notify(void *context, enum _avm_event_id id); static void avm_event_powermanagment_status_notify(void *context, enum _avm_event_id id); #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ #if defined(DECTSYNC_PATCH) static int idle_dectsynchandler(void); static int timer_dectsynchandler(int cycles_per_jiffy); /*--- #define DEBUG_DECTSYNC ---*/ #if defined(DEBUG_DECTSYNC) #define DBG_DS_TRC(args...) printk(KERN_ERR args) /*--- #define DBG_DS_TRC(args...) ---*/ #else #define DBG_DS_TRC(args...) #endif #define DBG_DS_ERR(args...) printk(KERN_ERR args) #define TIME_DIFF(act, old) ((unsigned long)(act) - (unsigned long)(old)) #if 0 #define CLK_TO_USEC(a) ((a) / (gdectsync.clk) ) #define CLK_TO_MSEC(a) ((a) / (gdectsync.clk) / 1000) #define USEC_TO_CLK(a) ((a) * gdectsync.clk ) #else #define UR8_MHZ 180L /*--- #define CLK_TO_NSEC(a) ((a) * (1000L / UR8_MHZ)) ---*//*--- ggT(1000, 180) = 20 ---*/ #define CLK_TO_NSEC(a) (((long)(a) * (1000L / 20)) / (UR8_MHZ / 20)) /*--- ggT(1000, 180) = 20 ---*/ #define CLK_TO_USEC(a) ((a) / UR8_MHZ ) #define CLK_TO_MSEC(a) ((a) / UR8_MHZ / 1000) #define USEC_TO_CLK(a) ((a) * UR8_MHZ) #endif struct _dectsynchandler { enum { resetmode, inactive, invalid_clk, init_dectsync, calibration_mode, calibration_mode2, calibrate_timerirq_delay, calibrate_timerirq, timerset_ok, corrupt_mode, wlantraffic_mode} state; unsigned long clk; unsigned int wastepercent; unsigned long waste_idle; int cycles_per_jiffy; int dt_offset; int run; int failcntdown; int lastwasgood; unsigned long synccnt; unsigned long synclost; unsigned long periodjiffies; unsigned long periodcycle; int goodcnt, periodcnt; unsigned long settriggerusec; unsigned long lowedgejiffies; unsigned long lowedgecycles; unsigned long lowcycles; signed long nohigh; signed long drift; unsigned long violation; unsigned long timeout; unsigned long latency; unsigned long goodpercent; unsigned long avg_cycle_perjiffies; unsigned long last_wlan_traffic; unsigned long maxrun; unsigned long start_maxrun; } gdectsync; #define DECT_SYNCGPIO CONFIG_AVM_DECT_SYNC #define DECTFAILCNTDOWN (120 * HZ) static void get_wlantraffic(unsigned long *rx_bytes, unsigned long *tx_bytes); #endif/*--- #if defined(DECTSYNC_PATCH) ---*/ #if defined(POWERMANAGEMENT_THROTTLE_ETH) int limit_set_eth(struct _power_managment_ressource_info *pm_info, unsigned int eth_idx, unsigned int force); #endif/*--- #if defined(POWERMANAGEMENT_THROTTLE_ETH) ---*/ /*-------------------------------------------------------------------------------------*\ * Liste von registrierten Treibern, die den PowermanagmentCallback-Befehl bekommen \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry dslmode_entries[] = { { "speedup", AVM_PM_CB_IGNORE, 0 }, /*--- idleabhängiges Speedup-Control FastSpeed wird durch ATA-Abfrage verhindert ---*/ { "adsl_event", AVM_PM_CB_UNINSTALLED_OR_FAILED, 10 }, /*--- DSL an: erzeuge Event ---*/ { "adsl", AVM_PM_CB_UNINSTALLED_OR_FAILED, 10 }, /*--- DSL an ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry atamode_entries[] = { { "speedup", AVM_PM_CB_IGNORE, 0 }, /*--- idleabhängiges Speedup-Control an ---*/ { "adsl_event", AVM_PM_CB_UNINSTALLED_OR_FAILED, 1 }, /*--- DSL komplett aus: erzeuge Event ---*/ { "adsl", AVM_PM_CB_UNINSTALLED_OR_FAILED, 1 }, /*--- DSL komplett aus ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry vdslmode_entries[] = { { "speedup", AVM_PM_CB_IGNORE, 0x80 }, /*--- kein idleabhängiges Speedup-Control ??? ---*/ { "adsl_event", AVM_PM_CB_UNINSTALLED_OR_FAILED, 10 }, /*--- VDSL oder DSL (FUSIV) an: erzeuge Event ---*/ { "adsl", AVM_PM_CB_UNINSTALLED_OR_FAILED, 3 }, /*--- (VDSL) OHIO/UR8-DSL aus aber Spannung an ---*/ { NULL, 0, 0 } }; #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry dspboost_entries[] = { { "dspboost", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- DSP auf 250 MHz (inklusive Spannung auf 1.65 V) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Experimentell: unterstuetze bei OHIO 300 MHz DSP (150 MHz Systemclock) \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry dspmaxboost_entries[] = { { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x81 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "dspboost", AVM_PM_CB_IGNORE, 0x2 }, /*--- DSP auf 300 MHz (inklusive Spannung auf 1.65 V) ---*/ { "speedup", AVM_PM_CB_IGNORE, 0x81 }, /*--- kein idleabhängiges Speedup-Control (Systemclock auf Maximum) ---*/ { "piglet", AVM_PM_CB_FAILED, 0x1 }, /*--- Piglet-Clock aendern, wenn nicht registriert: ignore ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry dspnormal_entries[] = { { "dspboost", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0 }, /*--- DSP auf 200 MHz (inklusive Spannung auf 1.5 V) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry dspnormalreset_entries[] = { { "dspboost", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x80 }, /*--- DSP auf 200 MHz (inklusive Spannung auf 1.5 V) + Reset des Subsystems! ---*/ { NULL, 0, 0 } }; #endif/*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) ---*/ #if defined(CONFIG_MIPS_UR8) /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerup_wlan_entries[] = { { "wlanboost", AVM_PM_CB_IGNORE, 0x01 }, /*--- DSP Spannung auf 1.2 V) 7212 ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerdown_wlan_entries[] = { { "wlanboost", AVM_PM_CB_IGNORE, 0x00 }, /*--- DSP Spannung auf 1.2 V) 7212 ---*/ { NULL, 0, 0 } }; #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry updatemode_entries[] = { { "speedup", AVM_PM_CB_IGNORE, 0x80 }, /*--- kein idleabhängiges Speedup-Control ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Umschalten der Takte und Piglet-Umsetzung hat Atomar zu erfolgen! * erste Piglet-Aufruf fragt Möglichkeit ab, und stoppt bei Erfolg die Codecs! \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry fast_speed_entries[] = { { "adsl", AVM_PM_CB_UNINSTALLED_OR_FAILED, 20 }, /*--- nur Request: DSL im ATA-Mode ? ---*/ { "speedup", AVM_PM_CB_FAILED, 0x401 }, /*--- Abfrage, ob momentan fastspeed freigeschaltet ---*/ { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x81 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 1 }, /*--- Clocks aendern ---*/ { "piglet", AVM_PM_CB_FAILED, 1 }, /*--- Piglet-Clock aendern, wenn nicht registriert: ignore ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Umschalten der Takte und Piglet-Umsetzung hat Atomar zu erfolgen! * erste Piglet-Aufruf fragt Möglichkeit ab, und stoppt bei Erfolg die Codecs! \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry normal_speed_entries[] = { { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x80 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0 }, /*--- Clocks auf normal ---*/ { "piglet", AVM_PM_CB_FAILED, 0 }, /*--- Piglet-Clock aendern ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Umschalten der Takte und Piglet-Umsetzung hat Atomar zu erfolgen! * erste Piglet-Aufruf fragt Möglichkeit ab, und stoppt bei Erfolg die Codecs! \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry slow_speed_entries[] = { { "speedup", AVM_PM_CB_FAILED, 0x402 }, /*--- Abfrage, ob momentan slowspeed freigeschaltet ---*/ { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x82 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 2 }, /*--- Clocks aendern ---*/ { "piglet", AVM_PM_CB_FAILED, 2 }, /*--- Piglet-Clock aendern, wenn nicht registriert: ignore ---*/ { NULL, 0, 0 } }; #if !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) /*-------------------------------------------------------------------------------------*\ * Hiermit wird die Idle-abhängige Speedaänderung überhaupt erst aktiviert (nur slow) \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pd_speed_slow[] = { { "speedup", AVM_PM_CB_FAILED, 0x102 }, /*--- Speed-Aenderung unterstuetzten (nur slow!!!) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Hiermit wird die Idle-abhängige Speedaänderung überhaupt erst aktiviert \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pd_speed_slowandfast[] = { { "speedup", AVM_PM_CB_FAILED, 0x103 }, /*--- Speed-Aenderung unterstuetzten (fast + slow) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * Hiermit wird die manuelle Speedänderung aktiviert \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pd_speed_man[] = { { "speedup", AVM_PM_CB_FAILED, 0x183 }, /*--- Speed-Aenderung unterstuetzten manuelles Switching ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pd_speed_off[] = { { "speedup", AVM_PM_CB_FAILED, 0x100 }, /*--- keine Speed-Aenderung unterstuetzten ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * alles wie gehabt \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry usb_profile_off[] = { { "speedup", AVM_PM_CB_FAILED, 0x800 }, /*--- usb-profil-Mode aus ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * auf Normal schalten, maximal Hochtakten erlauben (da aber auch kein runtertakten mehr) * Nicht notwendig wenn Piglet-Clock unabhaengig von Systemtakt \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry usb_profile_on[] = { { "piglet", AVM_PM_CB_FAILED, 0x10 }, /*--- Piglet-Clock abfragen: unabhaengig von Systemclock: ja: profil ignorieren ---*/ { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x80 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0 }, /*--- Clocks auf normal ---*/ { "piglet", AVM_PM_CB_FAILED, 0 }, /*--- Piglet-Clock aendern ---*/ { "speedup", AVM_PM_CB_FAILED, 0x801 }, /*--- keine speed-Aenderung unterstuetzen (USB-Treiber) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * alles wie gehabt \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry atm_profile_off[] = { { "speedup", AVM_PM_CB_FAILED, 0x1000 }, /*--- dsp-profil-Mode aus ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * auf Normal schalten, maximal Hochtakten erlauben (da aber auch kein runtertakten mehr) \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry atm_profile_on[] = { { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x80 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0 }, /*--- Clocks auf normal ---*/ { "piglet", AVM_PM_CB_FAILED, 0 }, /*--- Piglet-Clock aendern ---*/ { "speedup", AVM_PM_CB_FAILED, 0x1001 }, /*--- kein speed-down (nur noch speed-up) unterstuetzen ---*/ { NULL, 0, 0 } }; #endif/*--- #if !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) ---*/ #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_UR8) /*-------------------------------------------------------------------------------------*\ * alles wie gehabt \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry telefon_profile_off[] = { { "avm_event", AVM_PM_CB_FAILED, 0x0 }, /*--- Eventmanager bekommt telefon-profil aus mit ---*/ #if defined(CONFIG_MIPS_OHIO) { "speedup", AVM_PM_CB_FAILED, 0x200 }, /*--- telefon-profil-Mode aus ---*/ #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ { NULL, 0, 0 } }; /*-------------------------------------------------------------------------------------*\ * auf Normal schalten, maximal Hochtakten erlauben (da aber auch kein runtertakten mehr) * Nicht notwendig wenn Piglet-Clock unabhaengig von Systemtakt \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry telefon_profile_on[] = { { "avm_event", AVM_PM_CB_FAILED, 0x1 }, /*--- Eventmanager bekommt telefon-profil an mit ---*/ #if defined(CONFIG_MIPS_OHIO) { "piglet", AVM_PM_CB_FAILED, 0x10 }, /*--- Piglet-Clock abfragen: unabhaengig von Systemclock: ja: profil ignorieren ---*/ { "piglet", AVM_PM_CB_FAILED | AVM_PM_LOCK, 0x80 }, /*--- Piglet-Clock abfragen + Codec-Stop, wenn nicht registriert: ignore ---*/ { "speedup", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0 }, /*--- Clocks auf normal ---*/ { "piglet", AVM_PM_CB_FAILED, 0 }, /*--- Piglet-Clock aendern ---*/ { "speedup", AVM_PM_CB_FAILED, 0x201 }, /*--- kein speed-down (nur noch speed-up) unterstuetzen ---*/ #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ { NULL, 0, 0 } }; #endif/*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_UR8) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry usbcurrentreq_entries[] = { { "usbpower", AVM_PM_CB_FAILED, 0x2 }, /*--- Abfrage aktueller Stromverbrauch aller USB-Hosts ----*/ { NULL, 0, 0 } }; #if defined(CONFIG_MIPS_UR8) /*-------------------------------------------------------------------------------------*\ * schaltet 5V-Versorgung USB an \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry usbpoweron_entries[] = { { "usbpower_req", AVM_PM_CB_FAILED, 0x1 }, /*--- Abfragem ob Power on erlaubt ----*/ { "usbpower", AVM_PM_CB_FAILED, 0x1 }, { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry usbpoweroff_entries[] = { { "usbpower_req", AVM_PM_CB_FAILED, 0x0 }, /*--- Abfrage ob Power off erlaubt ----*/ { "usbpower", AVM_PM_CB_FAILED, 0x0 }, { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerdown_isdnab_entries[] = { { "piglet", AVM_PM_CB_FAILED, 0x100 }, /*--- 40 V ausschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerup_isdnab_entries[] = { { "piglet", AVM_PM_CB_FAILED, 0x101 }, /*--- 40 V anschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerdown_slic1_entries[] = { { "isdn", AVM_PM_CB_FAILED, 0x10 }, /*--- ueber PCM-Register ausschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerup_slic1_entries[] = { { "isdn", AVM_PM_CB_FAILED, 0x11 }, /*--- ueber PCM-Register anschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerdown_slic2_entries[] = { { "isdn", AVM_PM_CB_FAILED, 0x20 }, /*--- ueber PCM-Register ausschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry powerup_slic2_entries[] = { { "isdn", AVM_PM_CB_FAILED, 0x21 }, /*--- ueber PCM-Register anschalten ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pcmlinkbus_stop_entries[] = { { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x0 }, /*--- PCM-Bus deaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pcmlinkbus_start_entries[] = { { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- PCM-Bus reaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pots_load_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x200 }, /*--- checke ob 2 Bitfiles ueberhaupt existent ---*/ { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x203 }, /*--- nur wenn TE aktuell Wechsel notwendig ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x0 }, /*--- PCM-Bus deaktivieren ---*/ { "piglet", AVM_PM_CB_IGNORE, 0x210 }, /*--- lade POTS-File ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- PCMBus reaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry te_load_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x200 }, /*--- checke ob 2 Bitfiles ueberhaupt existent ---*/ { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x202 }, /*--- nur wenn POTS aktuell Wechsel notwendig ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x0 }, /*--- PCM-Bus deaktivieren ---*/ { "piglet", AVM_PM_CB_IGNORE, 0x211 }, /*--- lade TE-File ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- PCMBus reaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry te_reload_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x200 }, /*--- checke ob 2 Bitfiles ueberhaupt existent ---*/ { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x203 }, /*--- nur wenn TE aktuell reload notwendig ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x0 }, /*--- PCM-Bus deaktivieren ---*/ { "piglet", AVM_PM_CB_IGNORE, 0x213 }, /*--- lade TE-File (force) ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- PCMBus reaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry pots_reload_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x200 }, /*--- checke ob 2 Bitfiles ueberhaupt existent ---*/ { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x202 }, /*--- nur wenn POTS aktuell reload notwendig ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x0 }, /*--- PCM-Bus deaktivieren ---*/ { "piglet", AVM_PM_CB_IGNORE, 0x212 }, /*--- lade POTS-File (force) ---*/ { "pcmlink", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x1 }, /*--- PCMBus reaktivieren ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry tepots_switchauto_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x204 }, /*--- AutoMode an ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry tepots_switchmanu_entries[] = { { "piglet", AVM_PM_CB_UNINSTALLED_OR_FAILED, 0x205 }, /*----AutoMode aus ---*/ { NULL, 0, 0 } }; /*--------------------------------------------------------------------------------*\ * wird vom pcmlink-Treiber ausgewertet: \*--------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry teactive_entries[] = { { "piglet", AVM_PM_CB_FAILED, 0x201 }, { NULL, 0, 0 } }; #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ /*-------------------------------------------------------------------------------------*\ * powermode mit nachfolgender Powermanagment-Treiber-Liste \*-------------------------------------------------------------------------------------*/ static struct _power_managment power[] = { { "dsl", dslmode_entries, PM_ACESS_ALL}, { "ata", atamode_entries, PM_ACESS_ALL}, { "vdsl", vdslmode_entries, PM_ACESS_ALL}, /*--- im VDSL-Mode DSL auf ATA stellen ---*/ { "update", updatemode_entries, PM_ACESS_ALL}, #if !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) /*--- beim Sangam unterstuetzen wir kein Runtertakten (geht zwar aber nicht ausreichend untersucht!) ---*/ { "fastspeed", fast_speed_entries, PM_ACESS_ALL}, { "normalspeed", normal_speed_entries, PM_ACESS_ALL}, { "slowspeed", slow_speed_entries, PM_ACESS_ALL}, { "usb_profile_on", usb_profile_on, PM_ACESS_DRIVER}, /*--- schalte auf normalspeed - niemals takten ---*/ { "usb_profile_off", usb_profile_off, PM_ACESS_DRIVER}, /*--- vorhergehendes Profil ---*/ { "pd_speed_on", pd_speed_slow, PM_ACESS_ALL}, { "pd_speed_onfast", pd_speed_slowandfast, PM_ACESS_ALL}, { "pd_speed_off", pd_speed_off, PM_ACESS_ALL}, { "pd_speed_man", pd_speed_man, PM_ACESS_DRIVER}, /*--- nur intern, um manulles Switchen anzuschalten ---*/ { "atm_profile_on", atm_profile_on, PM_ACESS_DRIVER}, /*--- schalte auf normalspeed - niemals takten ---*/ { "atm_profile_off", atm_profile_off, PM_ACESS_DRIVER}, /*--- vorhergehendes Profil ---*/ #endif/*--- #if !defined(CONFIG_MIPS_AR7) ---*/ #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_UR8) { "telefon_profile_on", telefon_profile_on, PM_ACESS_ALL}, /*--- schalte auf normalspeed - niemals runter (maximal hoch) ---*/ { "telefon_profile_off", telefon_profile_off, PM_ACESS_ALL}, /*--- vorhergehendes Profil ---*/ #endif/*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_UR8) ---*/ #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) { "dsp_normalreset", dspnormalreset_entries, PM_ACESS_DRIVER}, /*--- nur vom ATM-Treiber aufrufen ---*/ { "dsp_normal", dspnormal_entries, PM_ACESS_DRIVER}, /*--- nur vom ATM-Treiber aufrufen ---*/ { "dsp_boost", dspboost_entries, PM_ACESS_ALL}, #endif/*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) ---*/ #if defined(CONFIG_MIPS_OHIO) { "dsp_maxboost", dspmaxboost_entries, PM_ACESS_ALL}, #endif/*--- #if !defined(CONFIG_MIPS_OHIO) ---*/ #if defined(CONFIG_MIPS_UR8) { "pcmlink_bus_off", pcmlinkbus_stop_entries, PM_ACESS_DRIVER}, { "pcmlink_bus_on", pcmlinkbus_start_entries, PM_ACESS_DRIVER}, { "usb_poweron", usbpoweron_entries, PM_ACESS_ALL}, { "usb_poweroff", usbpoweroff_entries, PM_ACESS_ALL}, { "powerdown_isdnab", powerdown_isdnab_entries, PM_ACESS_ALL}, { "powerup_isdnab", powerup_isdnab_entries, PM_ACESS_ALL}, { "powerdown_slic1", powerdown_slic1_entries, PM_ACESS_ALL}, { "powerup_slic1", powerup_slic1_entries, PM_ACESS_ALL}, { "powerdown_slic2", powerdown_slic2_entries, PM_ACESS_ALL}, { "powerup_slic2", powerup_slic2_entries, PM_ACESS_ALL}, { "wlan_booston", powerup_wlan_entries, PM_ACESS_ALL}, /*--- anheben der Spannung 7212 auf 1.2V ---*/ { "wlan_boostoff", powerdown_wlan_entries, PM_ACESS_ALL}, { "pots_load", pots_load_entries, PM_ACESS_ALL}, { "te_load", te_load_entries, PM_ACESS_ALL}, { "tepots_switchauto", tepots_switchauto_entries, PM_ACESS_ALL}, { "tepots_switchmanu", tepots_switchmanu_entries, PM_ACESS_ALL}, { "te_active", teactive_entries, PM_ACESS_ALL}, /*--- die letzten werden die ersten sein (wird alle 8 msec aufgerufen) ---*/ { "te_reload", te_reload_entries, PM_ACESS_ALL}, { "pots_reload", pots_reload_entries, PM_ACESS_ALL}, #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ { "usb_current_req", usbcurrentreq_entries, PM_ACESS_ALL}, { NULL, NULL, 0} }; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_power_open(struct inode *, struct file *); static int avm_power_close(struct inode *, struct file *); #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_dspboost_Callback(int state); #endif/*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ static int avm_power_event_Callback(int state); static int avm_power_adsl_event_Callback(int state); #if defined(CONFIG_MIPS_UR8) static int avm_power_wlan_Callback(int state); #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ static int avm_power_usb_Callback(int state); static ssize_t avm_power_write(struct file *filp, const char *write_buffer, size_t write_length, loff_t *write_pos); static struct _power_managment_dest_entry *find_powermode(char *powermode, unsigned int access); static void avm_power_writeformaterror(char *text); static struct _power_managment_clients *find_pwclient_by_name(char *client_name); static int powermode_action(struct _power_managment_dest_entry *powermodetab); #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_boost_allowed(void); #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ static int powermode_action_nolist(char *client_name, int State); #ifdef CONFIG_AVM_POWERMETER static void pm_ressourceinfo_init(void); static void pm_ressourceinfo_parse(char *line); static void pm_ressourceinfo_scriptparse(char *line); static struct _power_managment_ressource_info pm_ressourceinfo; #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _avm_power avm_power; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct file_operations avm_power_fops = { owner: THIS_MODULE, open: avm_power_open, release: avm_power_close, /*--- read: avm_power_read, ---*/ write: avm_power_write, /*--- ioctl: avm_power_ioctl, ---*/ /*--- fasync: avm_power_fasync, ---*/ /*--- poll: avm_power_poll, ---*/ }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ __inline static unsigned long LOCK(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) unsigned long flags; spin_lock_irqsave(&avm_power_lock, flags); #else/*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ int flags; save_flags(flags); cli(); #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ return flags; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ __inline static void UNLOCK(unsigned long flags) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) spin_unlock_irqrestore(&avm_power_lock, flags); #else/*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ restore_flags(flags); #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ } /*------------------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------_--------------------*/ __inline static int avm_power_write_check_special_char(char **p, char check_char) { SKIP_SPACES(*p); /* ggf. spaces */ if(**p != check_char) return 1; (*p)++; return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static __inline int avm_power_write_find_special_char(char **p, char check_char) { while(**p && **p != check_char) { (*p)++; } if(**p != check_char) return 1; (*p)++; return 0; } #if defined(CONFIG_MIPS_UR8) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct resource avmpower_gpioressource[] = { { .name = "usb_power", .flags = IORESOURCE_IO, .start = GPIO_BIT_DRVVBUS, .end = GPIO_BIT_DRVVBUS, #if defined(DECTSYNC_PATCH) .name = "dectsync", .flags = IORESOURCE_IO, .start = DECT_SYNCGPIO, .end = DECT_SYNCGPIO, #endif/*--- #if defined(DECTSYNC_PATCH) ---*/ } }; static unsigned int gRequestAvmPower_ok; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int avmpower_requestinit(void) { int i; if(gRequestAvmPower_ok == 0) { for(i = 0; i < sizeof(avmpower_gpioressource) / sizeof(struct resource); i++) { if(request_resource(&gpio_resource, &avmpower_gpioressource[i])) { printk(KERN_ERR"[avmpower_init]ERROR: avmpower-resource %d gpio %u-%u not available\n", i, (unsigned int)avmpower_gpioressource[i].start, (unsigned int)avmpower_gpioressource[i].end); return 1; } } gRequestAvmPower_ok = 1; } return 0; } #ifdef CONFIG_AVM_POWER_MODULE /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avmpower_requestrelease(void) { unsigned int i; if(gRequestAvmPower_ok == 1) { for(i = 0; i < sizeof(avmpower_gpioressource) / sizeof(struct resource); i++) { release_resource(&avmpower_gpioressource[i]); } gRequestAvmPower_ok = 0; } } #endif/*--- #ifdef CONFIG_AVM_POWER_MODULE ---*/ #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int __init avm_power_init(void) { # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) int reason; # endif /*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ #if defined(CONFIG_MIPS_UR8) if(avmpower_requestinit()) { panic("[avmpower]bye bye - can't initialize avmpower-interface!\n"); return -ERESTARTSYS; } #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) spin_lock_init(&avm_power_lock); #if defined(AVM_POWER_UDEV) reason = alloc_chrdev_region(&avm_power.device, 0, 1, MODULE_NAME); #else /*--- #if defined(AVM_POWER_UDEV) ---*/ DEB_INFO("[avm_power] register_chrdev_region()\n"); avm_power.device = MKDEV(LOCAL_MAJOR, 0); reason = register_chrdev_region(avm_power.device, 1, MODULE_NAME); #endif if(reason) { DEB_ERR("[avm_power] register_chrdev_region failed: reason %d!\n", reason); return -ERESTARTSYS; } avm_power.cdev = cdev_alloc(); if (!avm_power.cdev) { unregister_chrdev_region(avm_power.device, 1); DEB_ERR("[avm_power] cdev_alloc failed!\n"); return -ERESTARTSYS; } avm_power.cdev->owner = avm_power_fops.owner; avm_power.cdev->ops = &avm_power_fops; kobject_set_name(&(avm_power.cdev->kobj), MODULE_NAME); #else avm_power.device = register_chrdev( LOCAL_MAJOR/*--- dynamic major ---*/, MODULE_NAME, &avm_power_fops); if(avm_power.device < 1) { DEB_ERR("[%s]: register_chrdrv failed: reason %d\n", MODULE_NAME, avm_power.device); MOD_DEC_USE_COUNT; return -ERESTARTSYS; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) if(cdev_add(avm_power.cdev, avm_power.device, 1)) { kobject_put(&avm_power.cdev->kobj); unregister_chrdev_region(avm_power.device, 1); DEB_ERR("[avm_power] cdev_add failed!\n"); return -ERESTARTSYS; } #if defined(AVM_POWER_UDEV) /*--- Geraetedatei anlegen: ---*/ avm_power.osclass = class_create(THIS_MODULE, MODULE_NAME); device_create(avm_power.osclass, NULL, 1, NULL, "%s%d", "power", 0); #endif/*--- #if defined(AVM_POWER_UDEV) ---*/ #else avm_power_devfs_handle = devfs_register(NULL, MODULE_NAME, DEVFS_FL_DEFAULT, avm_power.device, 0, S_IFCHR | S_IRUGO | S_IWUSR, &avm_power_fops, NULL); if(avm_power_devfs_handle == NULL) { DEB_ERR("%s: avm_power_file: devfs_register(%s, %u ...) failed \n", MODULE_NAME, MODULE_NAME, 0); MOD_DEC_USE_COUNT; return -ENOMEM; } #endif #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) avm_power_dspboost = avm_power_boost_allowed(); PowerManagmentRegister("dspboost", avm_power_dspboost_Callback); #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ #if defined(CONFIG_MIPS_UR8) PowerManagmentRegister("wlanboost", avm_power_wlan_Callback); /*--- für die 7212 ---*/ avm_gpio_ctrl(GPIO_BIT_DRVVBUS, GPIO_PIN, GPIO_OUTPUT_PIN); #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ PowerManagmentRegister("usbpower", avm_power_usb_Callback); #ifdef CONFIG_AVM_POWERMETER pm_ressourceinfo_init(); #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ #if defined(CONFIG_MIPS_FUSIV) { extern void Wyatt_Earp_Init_GPIO(void); Wyatt_Earp_Init_GPIO(); } #endif /*--- #if defined(CONFIG_MIPS_FUSIV) ---*/ PowerManagmentRegister("avm_event", avm_power_event_Callback); #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) telefonevent.handle = avm_event_source_register( "telefonprofile", ( (((unsigned long long) 1) << avm_event_id_telefonprofile)), avmevent_telefonprofile_notify, &telefonevent ); powermanagment_status_event.handle = avm_event_source_register( "powermanagment_status", ( (((unsigned long long) 1) << avm_event_id_powermanagment_status)), avm_event_powermanagment_status_notify, &powermanagment_status_event ); #endif PowerManagmentRegister("adsl_event", avm_power_adsl_event_Callback); /*--- nun wird zusaetzlich ein Event erzeugt ---*/ DEB_INFO("[avm_power]: major %d (success)\n", MAJOR(avm_power.device)); return 0; } module_init(avm_power_init); /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #ifdef CONFIG_AVM_POWER_MODULE static void pm_ressourceinfo_exit(void); void __exit avm_power_cleanup(void) { DEB_INFO("[avm_power]: unregister_chrdev(%u)\n", MAJOR(avm_power.device)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) #if defined(AVM_POWER_UDEV) device_destroy(avm_power.osclass, 1); class_destroy(avm_power.osclass); #endif/*--- #if defined(AVM_POWER_UDEV) ---*/ cdev_del(avm_power.cdev); /* Delete char device */ unregister_chrdev_region(avm_power.device, 1); #else devfs_unregister(avm_power_devfs_handle); devfs_unregister_chrdev(avm_power.device, "avm_power"); #endif pm_ressourceinfo_exit(); #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) if(telefonevent.handle) { avm_event_source_release(telefonevent.handle); telefonevent.handle = NULL; } if(powermanagment_status_event.handle) { avm_event_source_release(powermanagment_status_event.handle); powermanagment_status_event.handle = NULL; } #endif #if defined(CONFIG_MIPS_UR8) avmpower_requestrelease(); #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ return; } module_exit(avm_power_cleanup); #endif /*--- #ifdef CONFIG_AVM_POWER_MODULE ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_power_open(struct inode *inode __attribute__((unused)), struct file *filp) { struct _avm_power_open_data *open_data; DEB_INFO("[%s]: avm_power_open:\n", MODULE_NAME); /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ open_data = (struct _avm_power_open_data *)kmalloc(sizeof(struct _avm_power_open_data), GFP_KERNEL); if(!open_data) { DEB_ERR("%s: avm_power_open: open malloc failed\n", MODULE_NAME); return -EFAULT; } memset(open_data, 0, sizeof(*open_data)); filp->private_data = (void *)open_data; DEB_INFO("[%s]: avm_power_open: open success flags=0x%x\n", MODULE_NAME, filp->f_flags); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_power_close(struct inode *inode __attribute__((unused)), struct file *filp) { DEB_INFO("[%s]: avm_power_close:\n", MODULE_NAME); /*--- achtung auf ind wartende "gefreien" und warten bis alle fertig ---*/ if(filp->private_data) { kfree(filp->private_data); filp->private_data = NULL; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static ssize_t avm_power_write(struct file *filp, const char *write_buffer, size_t write_length, loff_t *write_pos) { char Buffer[256], *p; unsigned int org_write_length; struct _power_managment_dest_entry *powermodetab = NULL; #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_FUSIV) int Mask; #endif/*--- #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_FUSIV) ---*/ if(write_pos != NULL) { DEB_INFO("[%s]: write_length = %u *write_pos = 0x%LX\n", "avm_power_write", write_length, *write_pos); } org_write_length = write_length; if(write_length >= sizeof(Buffer)) { write_length = sizeof(Buffer) - 1; DEB_NOTE("[avm_power] long line reduce to %u bytes\n", write_length); } if(filp == NULL) { memcpy(Buffer, write_buffer, write_length); } else { if(copy_from_user(Buffer, write_buffer, write_length)) { DEB_ERR("[%s]: avm_power_write: copy_from_user failed\n", "avm_power_write"); return -EFAULT; } } /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ Buffer[write_length] = '\0'; DEB_NOTE("[avm_power] avm_power_write org_len=%u len %u = '%s'\n", org_write_length, write_length, Buffer); p = strchr(Buffer, 0x0A); if(p) { *p = '\0'; write_length = strlen(Buffer) + 1; DEB_NOTE("[avm_power] multi line reduce to %u bytes\n", write_length); } p = Buffer; /*--------------------------------------------------------------------------------------*\ * cmd extrahieren \*--------------------------------------------------------------------------------------*/ SKIP_SPACES(p); DEB_NOTE("[avm_power]: process input \"%s\"\n", p); /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ if(!strncmp(CMD_MODE, p, sizeof(CMD_MODE) - 1)) { p += sizeof(CMD_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { avm_power_writeformaterror("[avm_power] format error: \""CMD_MODE" = \""); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); powermodetab = find_powermode(p, PM_ACESS_APPL); if( (powermodetab == slow_speed_entries ) || (powermodetab == normal_speed_entries) || (powermodetab == fast_speed_entries )) { /*--- Umschalten auf manuelle Switching - Achtung Idleabheangiges Switchen bis zum pd_speed_on deaktiviert! ---*/ PowerManagmentActivatePowerMode("pd_speed_man"); } #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_FUSIV) } else if(!strncmp(WE_CMD_MODE, p, sizeof(WE_CMD_MODE) - 1)) { p += sizeof(WE_CMD_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: \""WE_CMD_MODE" = : 0x0: help 0x10000: set only we-mask 0x800: simulate dying gasp\n"); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%x", &Mask); if(Mask & 0x10000) { DEB_ERR("[avm_power] set we-mask: %x\n", Mask); WyattEarpMode = Mask; } else { Wyatt_Earp(Mask); } return write_length; #endif /*--- #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ #ifdef CONFIG_AVM_POWERMETER } else if(!strncmp(PMINFO_MODE, p, sizeof(PMINFO_MODE) - 1)) { p += sizeof(PMINFO_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: '%s'\n", p); DEB_ERR("[avm_power] use: \""PMINFO_MODE" = device, norm_rate, multiplier, divider, offset\"\n"); /*--- return -EPERM; ---*/ return write_length; } pm_ressourceinfo_scriptparse(p); return write_length; } else if(!strncmp(PMINFO_SET, p, sizeof(PMINFO_SET) - 1)) { p += sizeof(PMINFO_SET) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: '%s'\n", p); DEB_ERR("[avm_power] use: \""PMINFO_SET" = device, power_rate\n"); return write_length; } pm_ressourceinfo_parse(p); return write_length; #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ } else if(!strncmp(ETH_MODE, p, sizeof(ETH_MODE) - 1)) { union _powermanagment_ethernet_state eth; unsigned int tmp, throttle = 0; eth.Register = 0; p += sizeof(ETH_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: '%s'\n", p); DEB_ERR("[avm_power] use: \""ETH_MODE" = port, state\"\n"); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%u", &tmp); if(tmp > 255) { DEB_ERR("[avm_power] : unknown port %u:\n", tmp); return write_length; } eth.Bits.port = tmp; tmp = 4; if(avm_power_write_find_special_char(&p, ',') == 0){ SKIP_SPACES(p); sscanf(p, "%u", &tmp); } switch(tmp) { default: DEB_ERR("[avm_power] : unknown status - set status to powered(2)\n"); tmp = 2; /*--- kein break ---*/ case 0: case 2: eth.Bits.status = tmp; break; case 1: throttle = ETH_THROTTLE_DEMAND; eth.Bits.status = tmp; break; case 3: eth.Bits.status = 1; /*--- powersave ohne throttle ---*/ break; } #if defined(POWERMANAGEMENT_THROTTLE_ETH) if(eth.Bits.port < AVMPOWER_MAX_ETHERNETPORTS) { pm_ressourceinfo.eth_status[eth.Bits.port] = eth.Bits.status | throttle; tmp = limit_set_eth(&pm_ressourceinfo, eth.Bits.port, 1); } else { tmp = 1; } #else tmp = powermode_action_nolist("ethernet", eth.Register); #endif if(tmp == 2) { DEB_ERR("[avm_power] : ethernet not registered\n"); } else if(tmp) { DEB_ERR("[avm_power] : ethernet switch failed\n"); #if !defined(POWERMANAGEMENT_THROTTLE_ETH) } else { /*--- Zustand merken, fuer Statistik ---*/ if(eth.Bits.port < AVMPOWER_MAX_ETHERNETPORTS) { DEB_ERR("[avm_power]: ethernet port %d status %d throttle %d\n", eth.Bits.port, eth.Bits.status, throttle); pm_ressourceinfo.eth_status[eth.Bits.port] = eth.Bits.status | throttle; } #endif } return write_length; #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) } else if(!strncmp(SEMTECH_MODE, p, sizeof(SEMTECH_MODE) - 1)) { p += sizeof(SEMTECH_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: '%s'\n", p); DEB_ERR("[avm_power] use: \""SEMTECH_MODE" = mode\"\n"); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%u", &avm_power_activate_semtechfix); return write_length; #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ } else if(!strncmp(IDLE_MODE, p, sizeof(IDLE_MODE) - 1)) { p += sizeof(IDLE_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[avm_power] format error: '%s'\n", p); DEB_ERR("[avm_power] use: \""IDLE_MODE" = mode\"\n"); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%u", &avm_power_disp_loadrate); return write_length; } else { avm_power_writeformaterror("[avm_power] format error: \""CMD_MODE" = \""); /*--- return -EPERM; ---*/ return write_length; } if(powermode_action(powermodetab)) { /*--- printk("[avm_power] error on activate powermode"); ---*/ /*--- return -EPERM; ---*/ return write_length; } return write_length; } /*-------------------------------------------------------------------------------------*\ * hier werden die Tabelleneintraege (struct _power_managment_dest_entry ...[]) * "ausgeführt" \*-------------------------------------------------------------------------------------*/ static int powermode_action(struct _power_managment_dest_entry *powermodetab) { struct _power_managment_clients *registered_client; int ret = 0, i = 0, flags = 0, locked = 0; if(powermodetab == NULL) { return 1; } while(powermodetab[i].client_name) { registered_client = find_pwclient_by_name(powermodetab[i].client_name); if(registered_client == NULL) { if(powermodetab[i].mandatory & AVM_PM_CB_UNINSTALLED_OR_FAILED) { DEB_TRC_PT("[avm_power] '%s' not registered can't execute powermanagment ->stop\n", powermodetab[i].client_name); ret = 1; } else { DEB_TRC_PT("[avm_power] '%s' not registered can't execute powermanagment ->ignore\n", powermodetab[i].client_name); } } else { if((powermodetab[i].mandatory & AVM_PM_LOCK) && (locked == 0)) { locked = 1; flags = LOCK(); } if((ret = registered_client->CallBackPowerManagmentControl(powermodetab[i].state))) { if(powermodetab[i].mandatory & (AVM_PM_CB_UNINSTALLED_OR_FAILED | AVM_PM_CB_FAILED)) { DEB_TRC_PT("[avm_power] '%s'=0x%x powermanagment failed->stop ret=%x\n", powermodetab[i].client_name, powermodetab[i].state, ret); } else { DEB_TRC_PT("[avm_power] '%s'=0x%x powermanagment failed->ignore ret=%x\n", powermodetab[i].client_name, powermodetab[i].state, ret); ret = 0; } } else { /*--- DEB_TRC_PT("[avm_power] '%s'=0x%x powermanagment ok\n", powermodetab[i].client_name, powermodetab[i].state); ---*/ } } if(ret) { break; } i++; } if(locked) { UNLOCK(flags); } return ret; } /*--------------------------------------------------------------------------------*\ * Powermanagegment nicht ueber Tabelle * ret 0: alles ok, 1: Callback-Fehler, 2: Client nicht registriert * \*--------------------------------------------------------------------------------*/ static int powermode_action_nolist(char *client_name, int State) { struct _power_managment_clients *registered_client; registered_client = find_pwclient_by_name(client_name); if(registered_client == NULL) { return 2; } if(registered_client->CallBackPowerManagmentControl(State)) { return 1; } return 0; } /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static void avm_power_writeformaterror(char *text) { char TextBuf[256], *p; int writesize = sizeof(TextBuf); struct _power_managment *powertab = power; p = TextBuf; snprintf(p, writesize, "%s\navailable powermode:", text); writesize -= strlen(p); p += strlen(p); while(powertab->powermode) { if(powertab->Access & PM_ACESS_APPL) { snprintf(p, writesize, "%s%s", powertab->powermode, (powertab+1)->powermode ? "," : ""); writesize -= strlen(p); p += strlen(p); } powertab++; } snprintf(p, writesize, "\n"); DEB_ERR("%s", TextBuf); } /*-------------------------------------------------------------------------------------*\ * access: Zugriff vom Treiber/Applikation PM_ACESS_DRIVER oder PM_ACESS_APPL \*-------------------------------------------------------------------------------------*/ static struct _power_managment_dest_entry *find_powermode(char *powermode_name, unsigned int access) { struct _power_managment *powertab = power; while(powertab->powermode) { if((strcmp(powermode_name, powertab->powermode) == 0) && (powertab->Access & access)) { /*--- DEB_ERR("[avm_power] exec powermanagment '%s'\n", powertab->powermode); ---*/ return powertab->dests; } powertab++; } return NULL; } /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_clients *find_pwclient_by_name(char *client_name) { struct _power_managment_clients *client = (struct _power_managment_clients *)PwClientAnker; while(client) { if(strcmp(client_name, client->client_name) == 0) { return client; } client = client->next; } return NULL; } /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static struct _power_managment_clients *add_pwclient(char *client_name, int (*CallBackPowerManagmentControl)(int state)) { struct _power_managment_clients *new; int flags; new = kmalloc(sizeof(struct _power_managment_clients) + strlen(client_name) + 1, GFP_KERNEL); if(new == NULL) { return NULL; } new->client_name = (char *)new + sizeof(struct _power_managment_clients); strcpy(new->client_name, client_name); new->CallBackPowerManagmentControl = CallBackPowerManagmentControl; new->next = NULL; flags = LOCK(); new->next = (struct _power_managment_clients *)PwClientAnker; PwClientAnker = new; UNLOCK(flags); return new; } /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ static void del_pwclient(struct _power_managment_clients *delclient) { struct _power_managment_clients *prevclient = NULL; int flags = LOCK(); struct _power_managment_clients *client = (struct _power_managment_clients *)PwClientAnker; while(client) { if(client == delclient) { if(prevclient == NULL) { /*--- erste Element ---*/ PwClientAnker = client->next; } else { prevclient->next = client->next; } UNLOCK(flags); kfree(client); return; } prevclient = client; client = client->next; } UNLOCK(flags); } /*-------------------------------------------------------------------------------------*\ * Powermanagment des Treibers anmelden * beide Parameter NULL : dying gasp * state: kontextbezogen - siehe (linux_)avm_power.h \*-------------------------------------------------------------------------------------*/ void *PowerManagmentRegister(char *client_name, int (*CallBackPowerManagmentControl)(int state)){ struct _power_managment_clients *client; DEB_INFO("[avm_power] PowerManagmentRegister(\"%s\", 0x%p)\n", client_name, CallBackPowerManagmentControl); #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) if(client_name == NULL && CallBackPowerManagmentControl == NULL) { /*--- Dying gasp ---*/ Wyatt_Earp(WyattEarpMode); /*--- hier kommt er nie mehr hin ---*/ return NULL; } #endif /*--- #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ if(client_name == NULL || CallBackPowerManagmentControl == NULL) { DEB_ERR("[avm_power]PowerManagmentRegister: invalid param %p %p\n", client_name, CallBackPowerManagmentControl); return NULL; } client = find_pwclient_by_name(client_name); if(client) { return client; } return add_pwclient(client_name, CallBackPowerManagmentControl); } EXPORT_SYMBOL(PowerManagmentRegister); /*-------------------------------------------------------------------------------------*\ * Powermanagment des Treibers abmelden \*-------------------------------------------------------------------------------------*/ void PowerManagmentRelease(void *Handle){ struct _power_managment_clients *delclient = (struct _power_managment_clients *)Handle; if(Handle == NULL) { DEB_ERR("[avm_power]PowerManagmentRelease: invalid Handle\n"); return; } del_pwclient(delclient); } EXPORT_SYMBOL(PowerManagmentRelease); /*-------------------------------------------------------------------------------------*\ * vom Kernel den Powermode ändern * Returnwert: 0 ok sonst Abbruch mit Fehler \*-------------------------------------------------------------------------------------*/ int PowerManagmentActivatePowerMode(char *powermode_name){ struct _power_managment_dest_entry *powermodetab = find_powermode(powermode_name, PM_ACESS_DRIVER); DEB_TRC_PT("[avm_power]PowerManagmentActivatePowerMode: '%s'\n", powermode_name); return powermode_action(powermodetab); } EXPORT_SYMBOL(PowerManagmentActivatePowerMode); /*--------------------------------------------------------------------------------*\ * Maps ax5 daugter card dsp memory address to mips memory space * Input: unsigned int addr, dsp memory address. * oldvalue: beim Sangam alten Wert merken \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static unsigned int avm_power_hostDspAddressTranslate(unsigned int addr, unsigned int *oldvalue) { unsigned int addrMap; addrMap = addr & DSP_ADDRMASK; #if defined(CONFIG_MIPS_OHIO) switch(addrMap) { case DSP_RMEM_MASK: return (OHIO_ADSLSS_BASE0 | (~DSP_ADDRMASK & addr)); case DSP_PMEM_MASK: return(OHIO_ADSLSS_BASE1 | (~DSP_ADDRMASK & addr)); case DSP_DMEM_MASK: return(OHIO_ADSLSS_BASE2 | (~DSP_ADDRMASK & addr)); default: printk(KERN_ERR"[avm_power]translate: unresolved addrmap %x\n", addrMap); } #elif defined(CONFIG_MIPS_AR7) /*--- printk("[avm_power]translate: ADSLSSADR: %x val=%x set to %x\n", AR7_ADSLSSADR, DSL_REG32(AR7_ADSLSSADR), addrMap); ---*/ *oldvalue = DSL_REG32(AR7_ADSLSSADR); if(addrMap != (*oldvalue & DSP_ADDRMASK)) { /*Sascha: neue Addresse im AddrTransRegister */ DSL_REG32(AR7_ADSLSSADR) = addrMap; } return ((AR7_ADSLSS_BASE0 | (~DSP_ADDRMASK & addr))); #endif return 0; } #endif /*--- #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ /*--------------------------------------------------------------------------------*\ * beim Sangam alten Wert restaurieren \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) __inline static void avm_power_hostDspAddressTranslate_End(unsigned int oldvalue) { #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_UR8) #elif defined(CONFIG_MIPS_AR7) unsigned int addrMap = DSL_REG32(AR7_ADSLSSADR); if(oldvalue != (addrMap & DSP_ADDRMASK)) { /* Addresse im AddrTransRegister restaurieren */ DSL_REG32(AR7_ADSLSSADR) = oldvalue; } #else #error unknown CONFIG_MIPS_... #endif } #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_boost_dspvoltage(int boost) { unsigned int rc, oldvalue; #if defined(CONFIG_MIPS_OHIO) /* * The following code is used to boost CODEC voltage for Sangam250 by setting * Buck Trim Bits in CTRL2. For Ohio250, the setting of Buck Trim Bits need * to be set in datapump code because each reset of CODEC will clean these * Buck Trim Bits. */ /*--- Hole Basisaddresse der CodeRegister auf dem DSP ---*/ rc = avm_power_hostDspAddressTranslate(DSP_DEV_CODEC_BASE, &oldvalue); /*--- Setze Password (CodecRegister+103), um Buck digital Trim setzten zu können. ---*/ DSL_REG8(rc + DSP_DEV_CODEC_BUCK_TRIM_PASSWORD_OFFSET)= 6; udelay(2); /*Sascha: Änderung der Spannung*/ if(boost){ /* set Buck switcher to 1,65V => * Wird bei retrain wieder auf 0 gesetzt, daher Buck Digital Trim auf Null. * Dadurch wird der default (1,65V) aus trim block in PM benutzt. PDF S.24*/ DSL_REG8(rc + DSP_DEV_CODEC_CTRL2_OFFSET) &= ~(1<<4); printk(KERN_INFO"[avm_power]#### boostVoltage: DSP Core voltage set to 1,65 V ####\n"); }else { DSL_REG8(rc + DSP_DEV_CODEC_CTRL2_OFFSET) &= (0xF); /* clear Buck switcher Bits to Zero */ DSL_REG8(rc + DSP_DEV_CODEC_CTRL2_OFFSET) |= (1<<4); /* set Buck switcher to 1,5V (000) */ printk(KERN_INFO"[avm_power]#### boostVoltage: DSP Core voltage set to 1,5 V ####\n"); } udelay(2); /*--- printk(KERN_INFO"[avm_power]%x BuckSwitcherRegister=0x%02X\n", KERNEL_ADDR(rc+DSP_DEV_CODEC_CTRL2_OFFSET), DSL_REG8(rc+DSP_DEV_CODEC_CTRL2_OFFSET)); ---*/ /*--- Loesche Password: Zugriff ist nicht mehr erlaubt. ---*/ DSL_REG8(rc + DSP_DEV_CODEC_BUCK_TRIM_PASSWORD_OFFSET)= 0; #elif defined(CONFIG_MIPS_AR7) /* * The following code is used to boost CODEC voltage for Sangam250 by setting * Buck Trim Bits in CTRL2. For Ohio250, the setting of Buck Trim Bits need * to be set in datapump code because each reset of CODEC will clean these * Buck Trim Bits. */ rc = avm_power_hostDspAddressTranslate(DSP_DEV_CODEC_CTRL1_ADDR, &oldvalue); /*--- printk("[avm_power]boost: translated-address: %x val=%x\n", rc, DSL_REG32(rc)); ---*/ if (boost){ DSL_REG32(rc) |= 0x0000F000; /* set Buck Trim Bits in CTRL2 */ printk(KERN_INFO"[avm_power]#### DSP Core voltage set to 1,65 V ####\n"); } else { DSL_REG32(rc) &= 0xFFFF0FFF; printk(KERN_INFO"[avm_power]#### DSP Core voltage set to 1,5 V ####\n"); } #elif defined(CONFIG_MIPS_UR8) rc = 0; rc = rc; #else #error unknown CONFIG_MIPS_... #endif udelay(2); avm_power_hostDspAddressTranslate_End(oldvalue); return 0; } #endif /*--- defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ #if defined(CONFIG_MIPS_OHIO) /*--------------------------------------------------------------------------------*\ * nur Speedport 701 fixing * da die DSP-Firmware auch selber schreibend zugreift, wird im thread geschaut ob der * Wert nicht gefixt werden muss \*--------------------------------------------------------------------------------*/ static void avm_power_semtechfix(void) { unsigned int rc, oldvalue; static unsigned int countdown; volatile unsigned char uc2; volatile unsigned char uc1 = 6; /*--- buckfreq = 2208 ---*/ if(countdown++ < 100) { countdown++; return; } countdown = 0; /*--- rc = avm_power_hostDspAddressTranslate((unsigned int)0x02040000, &oldvalue); ---*/ rc = avm_power_hostDspAddressTranslate(DSP_DEV_CODEC_BASE, &oldvalue); DSL_REG8(rc + 0x57/*DEV_CODEC_PASSWORD_ADDR_OFFSET*/) = 0xf; /*--- Diese 0xf ist sticky im Register ---*/ uc2 = DSL_REG8(rc + 0x5F/*DEV_CODEC_PM_MODE4_ADDR_OFFSET*/); if((uc2 & 0x7) != uc1) { printk(KERN_INFO"[avm_power]SEMTECH-Fix active\n"); uc2 = (uc2&(~7))|uc1; DSL_REG8(rc + 0x5F/*DEV_CODEC_PM_MODE4_ADDR_OFFSET*/)= uc2; udelay(2); uc2 = DSL_REG8(rc + 19); uc2 |= 0xe2; DSL_REG8(rc + 19)= uc2; } DSL_REG8(rc + 0x57/*DEV_CODEC_PASSWORD_ADDR_OFFSET*/)= 0; avm_power_hostDspAddressTranslate_End(oldvalue); } #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ /*--------------------------------------------------------------------------------*\ * checkt ob ueberhaupt hochgetaktet werden darf! * beim OHIO wird dabei auch des DSP-Subsystem resetet! \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_boost_allowed(void) { union _chip_version ChipVersion; int boostdsp = 0; #if defined(CONFIG_MIPS_AR7) unsigned int DIDR1; unsigned int DIDR2; unsigned int timecode; ChipVersion.Reg = AR7_CVR; DIDR1 = AR7_DIDR1; DIDR2 = AR7_DIDR2; #elif defined(CONFIG_MIPS_OHIO) /*--- #if defined(CONFIG_MIPS_AR7) ---*/ unsigned int DIDR1; unsigned int DIDR2; unsigned int TrimRegVal; struct _hw_reset *reset = (struct _hw_reset *)OHIO_RESET_BASE; ChipVersion.Reg = OHIO_CVR; DIDR1 = OHIO_DIDR1; DIDR2 = OHIO_DIDR2; #elif defined(CONFIG_MIPS_UR8) /*--- #if defined(CONFIG_MIPS_AR7) ---*/ ChipVersion.Reg = UR8_CVR; #else #error unknown CONFIG_MIPS_... #endif /*--- #elif defined(CONFIG_MIPS_UR8) ---*//*--- #if defined(CONFIG_MIPS_AR7) ---*/ switch (ChipVersion.Bits.Id) { #if defined(CONFIG_MIPS_AR7) case AR7_CHIP_ID: /*--- 7300, 7300A or 7300C ---*/ printk(KERN_INFO"[avm_power]Sangam %s detected rev=%x\n", (DIDR2 & (1 << 23)) ? "7300C (no overclock)" : "7300 or 7300A (> 2.3 but not 5.7 possible overclock)", ChipVersion.Bits.revision); if ((DIDR2 & (1 << 23))) { /*--- 7300C can't overclock ---*/ break; } /*--- 7300 or 7300A ---*/ if ((ChipVersion.Bits.revision != 0x57) && (ChipVersion.Bits.revision >= 0x23)) { boostdsp = 1; /*--- Rev 2.3 or larger but not 5.7, can boost ---*/ break; } /*--- timecode gereatre than 4208000 can boost ---*/ timecode = ((DIDR2 & 0x1FFF)<<10)|((DIDR1 & 0xFFC00000)>>22); if (timecode > 4208000) { boostdsp = 1; printk(KERN_INFO"[avm_power] timecode over 4208000(%u): overclocking possible\n", timecode); } break; #endif/*--- #if defined(CONFIG_MIPS_AR7) ---*/ #if defined(CONFIG_MIPS_OHIO) case OHIO_CHIP_ID_212: /* Ohio212: don't boost*/ printk(KERN_INFO"[avm_power]Ohio212 detected -> no overclocking\n"); break; case OHIO_CHIP_ID: /* Ohio250 or Ohio212(new)*/ /*--- Check Buck Trim bit see if it's Ohio250 or Ohio 212new ---*/ reset->non_reset.Reg &= ~(1 << ADSLSS_DSP_RESET_BIT); /*--- put DSP in reset ---*/ reset->non_reset.Reg |= (1 << DMA_RESET_BIT) | (1 << ADSLSS_RESET_BIT); /*--- reset ADSLSS ---*/ DSL_REG32(OHIO_ADSLSS_PRCR) |= OHIO_ADSLSS_PRCR_DSL_SPA; /*--- reset ADSLSS DSL_SPA ---*/ mdelay(10); /* Sanjay : Delay the read from the register as sometimes this causes incorrect value to be read from the register */ TrimRegVal = (DSL_REG32(OHIO_ADSLSS_BUCKTRIM_READ) >> 8) & 0x07; if (TrimRegVal == 0x07) { printk(KERN_INFO"[avm_power]Ohio250 detected -> overclocking possible\n"); boostdsp = 1; } else { printk(KERN_INFO"[avm_power]Ohio212new detected -> overclocking not possible)\n"); } break; #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ } return boostdsp; } #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ #if defined(CONFIG_MIPS_UR8) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int avm_power_wlan_Callback(int state){ unsigned int value; #define DEV_SARAS_NM_PWDREG_ADDR (0xA1018000 | 0x38) #define DEV_SARAS_PM_NM_REG1_ADDR (0xA1018000 | 0x0c) #define DEV_SARAS_NM_PWD (0xAB) /*--- printk("avm_power_wlan_Callback: %d\n", state); ---*/ *(volatile unsigned int *)DEV_SARAS_NM_PWDREG_ADDR = DEV_SARAS_NM_PWD; switch (state) { case 1: /*--- on ---*/ value = *(volatile unsigned int *)DEV_SARAS_PM_NM_REG1_ADDR; /*--- printk("[wlan_booston] 0x%x 0x%x\n", DEV_SARAS_PM_NM_REG1_ADDR, value); ---*/ *(volatile unsigned int *)DEV_SARAS_PM_NM_REG1_ADDR = value | (1<<6); /*--- set 1.2V ---*/ break; case 0: /*--- off ---*/ value = *(volatile unsigned int *)DEV_SARAS_PM_NM_REG1_ADDR; /*--- printk("[wlan_boostoff] 0x%x 0x%x\n", DEV_SARAS_PM_NM_REG1_ADDR, value); ---*/ *(volatile unsigned int *)DEV_SARAS_PM_NM_REG1_ADDR = value & ~(1<<6); /*--- set 1.1V ---*/ break; default: break; } *(volatile unsigned int *)DEV_SARAS_NM_PWDREG_ADDR = 0; return 0; } #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int avm_power_usb_Callback(int state){ /*--- printk("avm_power_usb_Callback: %d\n", state); ---*/ if(state < 2) { #if defined(CONFIG_MIPS_UR8) avm_gpio_out_bit(GPIO_BIT_DRVVBUS, state ? 1 : 0); #endif/*--- #if defined(CONFIG_MIPS_UR8) ---*/ } else { /*--- liefere SUM(mA) zurueck ---*/ return pm_ressourceinfo.deviceinfo[powerdevice_usb_host].power_rate + pm_ressourceinfo.deviceinfo[powerdevice_usb_host2].power_rate + pm_ressourceinfo.deviceinfo[powerdevice_usb_host3].power_rate; } return 0; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int avm_power_event_Callback(int state){ /*--- printk("avm_power_event_Callback: %d\n", state); ---*/ if(telefonevent.on != (unsigned)state) { telefonevent.on = state; #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) avmevent_telefonprofile_notify(&telefonevent, avm_event_id_telefonprofile); #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ } return 0; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int avm_power_adsl_event_Callback(int state){ if(powermanagment_status_event.dsl_status == state) { /*--- keine gleichen Werte triggern ---*/ return 1; } powermanagment_status_event.dsl_status = state; /*--- printk("avm_power_adsl_event_Callback: %d\n", state); ---*/ #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) avm_event_powermanagment_status_notify(&powermanagment_status_event, avm_event_id_powermanagment_status); #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ #if defined(POWERMANAGEMENT_THROTTLE_ETH) if(pm_ressourceinfo.thread_id) { /*--- triggere thread ---*/ pm_ressourceinfo.Changes++; wake_up_interruptible(&pm_ressourceinfo.wait_queue); } #endif/*--- #if defined(POWERMANAGEMENT_THROTTLE_ETH) ---*/ return 0; } /*--------------------------------------------------------------------------------*\ * state: 0 normal * 1 boost * 2 maxboost * 0x4x danach den Stand so locken * 0x8x resete SubSystem * Achtung dies darf nur vom DSP-Treiber (mit Abgleich) erfolgen \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) static int avm_power_dspboost_Callback(int state) { static int lock_boost = 0; int flags = LOCK(); if(lock_boost) { UNLOCK(flags); return 0; } if(state & 0x40) { lock_boost = 1; state &= ~0x40; } if(state & 0x80) { /*--- DSP-System beim OHIO reseten ---*/ avm_power_dspboost = avm_power_boost_allowed(); state &= ~0x80; } if((state) && (avm_power_dspboost == 0)) { UNLOCK(flags); return 1; } #if defined(CONFIG_MIPS_OHIO) if(state) { /*--- Erhoehe die Spannung auf 1,65V vor der Takt Erhoehung. ---*/ avm_power_boost_dspvoltage(1); if(state == 1) { avm_set_clock(avm_clock_id_dsp, 250000000); } else { avm_set_clock(avm_clock_id_dsp, 300000000); } } else { avm_set_clock(avm_clock_id_dsp, 211968000); avm_power_boost_dspvoltage(0); } #elif defined(CONFIG_MIPS_AR7)/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ if(state) { /*--- Erhoehe den Takt vor Spannung (??) ---*/ avm_set_clock(avm_clock_id_dsp, 250000000); udelay(2); avm_power_boost_dspvoltage(1); } else { avm_power_boost_dspvoltage(0); avm_set_clock(avm_clock_id_dsp, 200000000); } #elif defined(CONFIG_MIPS_UR8) #else/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ #error unknown CONFIG_MIPS_... #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ UNLOCK(flags); return 0; } #endif /*--- #if defined(CONFIG_MIPS_UR8) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_OHIO) ---*/ #ifdef CONFIG_AVM_POWERMETER /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) static void pm_ressourceinfo_notify(void *context, enum _avm_event_id id) { struct _power_managment_ressource_info *pm_info = (struct _power_managment_ressource_info *)context; struct _avm_event_pm_info_stat *event; int handled; if(id != avm_event_id_pm_ressourceinfo_status){ printk(KERN_WARNING "[avm_power]unknown event: %d\n", id); return; } event = (struct _avm_event_pm_info_stat *)kmalloc(sizeof(struct _avm_event_pm_info_stat), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "[avm_power]can't alloc event: %d\n", id); return; } memcpy(event, &pm_info->stat, sizeof(struct _avm_event_pm_info_stat)); event->header.id = id; handled = avm_event_source_trigger(pm_info->event_handle, id, sizeof(struct _avm_event_pm_info_stat), event); if(handled == 0) { printk(KERN_WARNING "[avm_power]event: %d not handled\n", id); } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avmevent_telefonprofile_notify(void *context, enum _avm_event_id id) { struct _telefonieprofile *ptp = (struct _telefonieprofile *)context; struct _avm_event_telefonprofile *event; int handled; if(id != avm_event_id_telefonprofile){ printk(KERN_WARNING "[avm_power]unknown event: %d\n", id); return; } event = (struct _avm_event_telefonprofile *)kmalloc(sizeof(struct _avm_event_telefonprofile), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "[avm_power]can't alloc event: %d\n", id); return; } event->event_header.id = id; event->on = ptp->on; handled = avm_event_source_trigger(ptp->handle, id, sizeof(struct _avm_event_telefonprofile), event); if(handled == 0) { printk(KERN_WARNING "[avm_power]event: %d not handled\n", id); } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avm_event_powermanagment_status_notify(void *context, enum _avm_event_id id){ struct _powermanagment_status_event *ppm = (struct _powermanagment_status_event *)context; struct _avm_event_powermanagment_status *event; int handled; if(id != avm_event_id_powermanagment_status){ printk(KERN_WARNING "[avm_power]unknown event: %d\n", id); return; } event = (struct _avm_event_powermanagment_status *)kmalloc(sizeof(struct _avm_event_powermanagment_status), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "[avm_power]can't alloc event: %d\n", id); return; } event->event_header.id = id; event->substatus = dsl_status; event->param.dsl_status = ppm->dsl_status; handled = avm_event_source_trigger(ppm->handle, id, sizeof(struct _avm_event_powermanagment_status), event); if(handled == 0) { /*--- printk(KERN_WARNING "[avm_power]event: %d not handled\n", id); ---*/ } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avmevent_temperature_notify(void *context, enum _avm_event_id id) { struct _power_managment_ressource_info *pm_info = (struct _power_managment_ressource_info *)context; struct _avm_event_temperature *event; int handled; if(id != avm_event_id_temperature){ printk(KERN_WARNING "[avm_power]unknown event: %d\n", id); return; } event = (struct _avm_event_temperature *)kmalloc(sizeof(struct _avm_event_temperature), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "[avm_power]can't alloc event: %d\n", id); return; } event->event_header.id = id; event->temperature = pm_info->deviceinfo[powerdevice_temperature].power_rate; if(avm_power_disp_loadrate & 8) { printk(KERN_ERR "[avm_power]temperature event: %d\n", event->temperature); } handled = avm_event_source_trigger(pm_info->temperature_eventhandle, id, sizeof(struct _avm_event_temperature), event); if(handled == 0) { printk(KERN_WARNING "[avm_power]event: %d not handled\n", id); } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avmevent_cpu_idle_notify(void *context, enum _avm_event_id id) { struct _power_managment_ressource_info *pm_info = (struct _power_managment_ressource_info *)context; struct _avm_event_cpu_idle *event; struct sysinfo meminfo; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) struct page_state ps; #endif/*--- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) ---*/ unsigned long inactive; unsigned long active; unsigned long free; unsigned long hard_mem; int handled; if(id != avm_event_id_cpu_idle){ printk(KERN_WARNING "[avm_power]unknown event: %d\n", id); return; } event = (struct _avm_event_cpu_idle *)kmalloc(sizeof(struct _avm_event_cpu_idle), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "[avm_power]can't alloc event: %d\n", id); return; } event->event_header.id = id; event->cpu_idle = pm_info->deviceinfo[powerdevice_loadrate].power_rate > 100 ? 0 : 100 - pm_info->deviceinfo[powerdevice_loadrate].power_rate; event->dsl_dsp_idle = pm_info->deviceinfo[powerdevice_dsp_loadrate].power_rate > 100 ? 0 : 100 - pm_info->deviceinfo[powerdevice_dsp_loadrate].power_rate; event->voice_dsp_idle = pm_info->deviceinfo[powerdevice_vdsp_loadrate].power_rate > 100 ? 0 : 100 - pm_info->deviceinfo[powerdevice_vdsp_loadrate].power_rate; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) get_page_state(&ps); active = ps.pgactivate; free = ps.pgfree; #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 19) get_zone_counts(&active, &inactive, &free); #else free = global_page_state(NR_FREE_PAGES); inactive = global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); active = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE); #endif si_meminfo(&meminfo); si_swapinfo(&meminfo); event->mem_physfree = (unsigned char)((meminfo.freeram * 100) / (meminfo.totalram |1)); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) hard_mem = ps.nr_dirty + ps.nr_writeback + ps.nr_mapped + ps.nr_slab; #else/*--- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) ---*/ hard_mem = global_page_state(NR_FILE_DIRTY) + global_page_state(NR_WRITEBACK) + global_page_state(NR_FILE_MAPPED) + global_page_state(NR_SLAB_UNRECLAIMABLE) + global_page_state(NR_ANON_PAGES); #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) ---*/ if(active > hard_mem) hard_mem = active; event->mem_strictlyused = (unsigned char)((hard_mem * 100) / (meminfo.totalram |1)); event->mem_cacheused = (unsigned char)(100 - event->mem_strictlyused - event->mem_physfree); if(avm_power_disp_loadrate & 4) { printk(KERN_ERR"[avm_power_disp_loadrate] cpu-idle-event: MEM: %d %d %d %%, active=%ld free=%ld/%ld\n", event->mem_strictlyused, event->mem_cacheused, event->mem_physfree, active, free, meminfo.freeram); } handled = avm_event_source_trigger(pm_info->cpu_idle_eventhandle, id, sizeof(struct _avm_event_cpu_idle), event); if(handled == 0) { printk(KERN_WARNING "[avm_power]event: %d not handled\n", id); } } #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ __inline static unsigned int PM_GET_MWATT(struct _power_managment_device_info *df) { unsigned int ret = 0; if(df->divider != 0) { ret = (((PM_GET_RATE(df->power_rate))* df->multiplier) / df->divider) + df->offset; } return ret; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ __inline static unsigned int PM_GET_NORM_MWATT(struct _power_managment_device_info *df) { unsigned int ret = 0; if(df->divider != 0) { ret = (((PM_GET_RATE(df->norm_power_rate))* df->multiplier) / df->divider) + df->offset; } return ret; } #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) #define PM_CALC_SUM(old, new, messure) ((old) + ((new) * (messure))) #define PM_TIME_DIFF(low1, low2) (((low1) - (low2)) < 0 ? -((low1) - (low2)) : ((low1) - (low2))) /*--------------------------------------------------------------------------------*\ * kumulierte Werte berechnen \*--------------------------------------------------------------------------------*/ static void pm_process_cum(struct _power_managment_ressource_info *pm_info) { int i, intervall = 0; struct _power_managment_cum_info *pcum; long MessureSamples, MessureSampleperPeriod; long tail_messure; int rate_dspcum = 0; int rate_systemcum = 0; int rate_sumcum = 0; int rate_wlancum = 0; int rate_ethcum = 0; int rate_abcum = 0; int rate_dectcum = 0; int rate_battcum = 0; int rate_usbhostcum = 0; int rate_temp = 0; signed char min_temp, max_temp; MessureSamples = PM_TIME_DIFF((long)jiffies, (long)pm_info->LastMessureTimeStamp) / HZ; if(MessureSamples == 0) { /*--- ein Messpunkt pro Sekunde: wenn rate_.. max. 100: 40 * 10e6 Samples (kein Overflow zu berücksichtigen!) ---*/ return; } pm_info->LastMessureTimeStamp = jiffies; /*--- Gesamt-Zeitfenster: PM_TIME_INTERVALL mit PM_TIME_ENTRIES Teilzeitfenstern ---*/ MessureSampleperPeriod = PM_TIME_INTERVALL / PM_TIME_ENTRIES; /*--- die Anzahl der Sample pro Teilzeitfenster ---*/ do { pcum = &pm_info->cum[pm_info->ActTimeEntry]; tail_messure = min(MessureSampleperPeriod - pcum->messure_count, MessureSamples); /*--- printk("[%ld j:%ld]Samples: %ld tail_messure: %d act_entry %ld cnt %d\n", pm_info->LastMessureTimeStamp, jiffies, MessureSamples, tail_messure, pm_info->ActTimeEntry, pcum->messure_count); ---*/ if(tail_messure) { /*--- die Werte über Restmesspunkte dieses Teilzeitfensters integrieren ---*/ pcum->rate_sum = PM_CALC_SUM(pcum->rate_sum, pm_info->stat.rate_sumact, tail_messure); pcum->rate_system = PM_CALC_SUM(pcum->rate_system, pm_info->stat.rate_systemact, tail_messure); pcum->rate_dsp = PM_CALC_SUM(pcum->rate_dsp, pm_info->stat.rate_dspact, tail_messure); pcum->rate_wlan = PM_CALC_SUM(pcum->rate_wlan, pm_info->stat.rate_wlanact, tail_messure); pcum->rate_eth = PM_CALC_SUM(pcum->rate_eth, pm_info->stat.rate_ethact, tail_messure); pcum->rate_ab = PM_CALC_SUM(pcum->rate_ab, pm_info->stat.rate_abact, tail_messure); pcum->rate_dect = PM_CALC_SUM(pcum->rate_dect, pm_info->stat.rate_dectact, tail_messure); pcum->rate_battcharge = PM_CALC_SUM(pcum->rate_battcharge, pm_info->stat.rate_battchargeact, tail_messure); pcum->rate_usbhost = PM_CALC_SUM(pcum->rate_usbhost, pm_info->stat.rate_usbhostact, tail_messure); pcum->rate_temp = PM_CALC_SUM(pcum->rate_temp, pm_info->stat.act_temperature, tail_messure); if(pcum->min_temp > pm_info->stat.act_temperature){ pcum->min_temp = pm_info->stat.act_temperature; } if(pcum->max_temp < pm_info->stat.act_temperature){ pcum->max_temp = pm_info->stat.act_temperature; } } MessureSamples -= tail_messure; pcum->messure_count += tail_messure; if(MessureSamples) { /*--- Überlauf in neues Teilzeitfenster ---*/ pm_info->ActTimeEntry++; if(pm_info->ActTimeEntry >= PM_TIME_ENTRIES) { pm_info->ActTimeEntry = 0; } pcum = &pm_info->cum[pm_info->ActTimeEntry]; memset(pcum, 0 , sizeof(pm_info->cum[0])); pcum->min_temp = pcum->max_temp = pm_info->stat.act_temperature; } } while(MessureSamples); min_temp = max_temp = pm_info->stat.act_temperature; for(i = 0; i < PM_TIME_ENTRIES; i++) { /*--- Mittelwert ueber komplettes TIMER_INTERVALL ---*/ pcum = &pm_info->cum[i]; if(pcum->messure_count) { /*--- Addition der einzelnen Teilzeitfenster ---*/ rate_sumcum += pcum->rate_sum; rate_systemcum += pcum->rate_system; rate_dspcum += pcum->rate_dsp; rate_wlancum += pcum->rate_wlan; rate_ethcum += pcum->rate_eth; rate_abcum += pcum->rate_ab; rate_dectcum += pcum->rate_dect; rate_battcum += pcum->rate_battcharge; rate_usbhostcum += pcum->rate_usbhost; rate_temp += pcum->rate_temp; if(min_temp > pcum->min_temp){ min_temp = pcum->min_temp; } if(max_temp < pcum->max_temp) { max_temp = pcum->max_temp; } intervall += pcum->messure_count; } } /*--- printk("intervall: %d\n", intervall); ---*/ if(intervall) { pm_info->stat.rate_sumcum = (unsigned char)min(100, rate_sumcum / intervall); /*--- kumulierter Energieverbrauch in Prozent ---*/ pm_info->stat.rate_systemcum = (unsigned char)min(100, rate_systemcum / intervall); /*--- (gewichtete) kumulierte Aktivität MIPS, System und idle in Prozent ---*/ pm_info->stat.rate_dspcum = (unsigned char)min(100, rate_dspcum / intervall); /*--- kumulierte Aktivität DSP in Prozent ---*/ pm_info->stat.rate_wlancum = (unsigned char)min(100, rate_wlancum / intervall); /*--- kumulierter Verbrauch WLAN in Prozent ---*/ pm_info->stat.rate_ethcum = (unsigned char)min(100, rate_ethcum / intervall); /*--- kumulierter Ethernet-Verbrauch ---*/ pm_info->stat.rate_abcum = (unsigned char)min(100, rate_abcum / intervall); /*--- kumulierter Nebenstellen-Verbrauch in Prozent ---*/ pm_info->stat.rate_dectcum = (unsigned char)min(100, rate_dectcum / intervall); /*--- kumulierter Verbrauch DECT in Prozent ---*/ pm_info->stat.rate_battchargecum = (unsigned char)min(100, rate_battcum / intervall); /*--- kumulierter Verbrauch Battery-Charge in Prozent ---*/ pm_info->stat.rate_usbhostcum = (unsigned char)min(100, rate_usbhostcum / intervall); /*--- kumulierter Verbrauch USB-Host in Prozent ---*/ pm_info->stat.avg_temperature = rate_temp / intervall; pm_info->stat.min_temperature = min_temp; pm_info->stat.max_temperature = max_temp; } } #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ /*--------------------------------------------------------------------------------*\ * die Infos werden erst hier zusammengesammelt, Status wird mit Set/Reset-Flag * signalisiert, Power wird hier gesetzt \*--------------------------------------------------------------------------------*/ static void convert_isdnpowerstate(unsigned int *SaveValue, unsigned int Value) { int i; /*--- Ebene1/3 State uebernehmen ---*/ if(Value & (1 << 31)){ /* Set State */ *SaveValue |= Value; } else { /* Reset State */ *SaveValue &= ~Value; } *SaveValue &= ~0xFFFF; /*--- Powerratebereich loeschen ---*/ for(i = 1; i < 5; i++) { /*--- max. 4 Controller E1 aktiv -> power++ ! ---*/ if(*SaveValue & PM_E1STATUS(i)) { *SaveValue += 100; } } /*--- DBG_ERR(("convert_isdnpowerstate: %x\n", *SaveValue)); ---*/ } #if defined(POWERMANAGEMENT_THROTTLE_ETH) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int check_throttle_eth_condition(struct _power_managment_ressource_info *pm_info __attribute__((unused))) { #if 0 unsigned int usbmA; if((powermanagment_status_event.dsl_status != 10)) { return 0; } usbmA = pm_info->deviceinfo[powerdevice_usb_host].power_rate + pm_info->deviceinfo[powerdevice_usb_host2].power_rate + pm_info->deviceinfo[powerdevice_usb_host3].power_rate; if(usbmA < 250) { return 0; } #endif return 1; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int limit_set_eth(struct _power_managment_ressource_info *pm_info, unsigned int eth_idx, unsigned int force) { union _powermanagment_ethernet_state eth; unsigned int throttle = 0; if(pm_info->eth_status[eth_idx] & ETH_THROTTLE_DEMAND) { throttle = check_throttle_eth_condition(pm_info); if(throttle) { if((pm_info->eth_status[eth_idx] & ETH_THROTTLE_ACTIVE) == 0) { /*--- wir muessen throttlen sind aber momentan nicht im Zustand ---*/ pm_info->eth_status[eth_idx] |= ETH_THROTTLE_ACTIVE; force = 1; } } else { if(((pm_info->eth_status[eth_idx] & ETH_THROTTLE_ACTIVE) == ETH_THROTTLE_ACTIVE)) { /*--- throttlen aufheben sind aber momentan nicht im Zustand ---*/ pm_info->eth_status[eth_idx] &= ~ETH_THROTTLE_ACTIVE; force = 1; } } } if(force == 0) { return 0; } eth.Register = 0; eth.Bits.port = eth_idx; eth.Bits.status = pm_info->eth_status[eth_idx] & 0x3; eth.Bits.throttle_eth = throttle; printk("eth: port %d status %d throttle %d\n", eth.Bits.port, eth.Bits.status, eth.Bits.throttle_eth); if(avm_power_disp_loadrate & 0x10) { printk("[avm_power]eth: port %x status %x throttle %x\n", eth.Bits.port, eth.Bits.status, eth.Bits.throttle_eth); } return powermode_action_nolist("ethernet", eth.Register); } #endif/*--- #if defined(POWERMANAGEMENT_THROTTLE_ETH) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int pm_ressourceinfo_thread( void *data ) { struct _power_managment_ressource_info *pm_info = (struct _power_managment_ressource_info *)data; unsigned long flags; #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) int device, mWatt, norm_p, rate, normmwatt, usbmwatt; int init = 1, activ_ethports, i; #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ /*--- DEB_ERR("[avm_power]pm_ressourceinfo_thread: start\n"); ---*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) daemonize("pm_info"); allow_signal(SIGTERM ); #else/*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ daemonize(); sprintf(current->comm, "pm_info"); #endif/*--- #else ---*//*--- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ---*/ for(;;) { if(wait_event_interruptible( pm_info->wait_queue, pm_info->Changes)){ break; } flags = LOCK(); pm_info->Changes--; UNLOCK(flags); #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) if(init) { /*--- Startphase ignorieren ---*/ init = 0; pm_info->LastMessureTimeStamp = jiffies; pm_info->ActTimeEntry = 0; } pm_info->stat.act_temperature = (signed char)pm_info->deviceinfo[powerdevice_temperature].power_rate; /*--- auf Grundlage der letzten Werte kummulierte Werte ermitteln ---*/ pm_process_cum(pm_info); mWatt = 0; for(device = 0; device < powerdevice_maxdevices; device++) { mWatt += PM_GET_MWATT(&pm_info->deviceinfo[device]); } pm_info->stat.rate_sumact = (mWatt * 100 ) / (pm_info->NormP | 1); /*--- aktueller Energieverbrauch in Prozent ---*/ norm_p= ((pm_info->deviceinfo[powerdevice_cpuclock].norm_power_rate) + (pm_info->deviceinfo[powerdevice_systemclock].norm_power_rate) + (pm_info->deviceinfo[powerdevice_loadrate].norm_power_rate)); rate = ((pm_info->deviceinfo[powerdevice_cpuclock].power_rate) + (pm_info->deviceinfo[powerdevice_systemclock].power_rate) + (pm_info->deviceinfo[powerdevice_loadrate].power_rate)); /*--- printk("rate: %d norm_p %d\n", rate, norm_p); ---*/ pm_info->stat.rate_systemact = (rate * 100) / (norm_p | 1); /*--- 0: Takt 125 MHz 1: 150 MHz 2: 62.5 MHz 3: Takt 120 MHz---*/ #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) pm_info->stat.system_status = (PM_GET_RATE(pm_info->deviceinfo[powerdevice_systemclock].power_rate) == FREQUENZ_TO_PERCENT(MIN_SYSTEMCLK, MAX_SYSTEMCLK)) ? 2: (PM_GET_RATE(pm_info->deviceinfo[powerdevice_systemclock].power_rate) == FREQUENZ_TO_PERCENT(MAX_SYSTEMCLK, MAX_SYSTEMCLK)) ? 1: 0; #else /*--- unbekannt ---*/ pm_info->stat.system_status = 0xFF; #endif #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) pm_info->stat.rate_dspact = PM_GET_RATE(pm_info->deviceinfo[powerdevice_dspclock].power_rate); /*--- aktueller Aktivität DSP in Prozent ---*/ #else /*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) ---*/ pm_info->stat.rate_dspact = PM_GET_RATE(pm_info->deviceinfo[powerdevice_dsl].power_rate); /*--- aktueller Aktivität DSL in Prozent ---*/ #endif/*--- #else ---*//*--- #if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) ---*/ pm_info->stat.rate_wlanact = PM_GET_RATE(pm_info->deviceinfo[powerdevice_wlan].power_rate); /*--- aktueller Verbrauch WLAN in Prozent ---*/ pm_info->stat.wlan_devices = PM_WLAN_GET_DEVICES(pm_info->deviceinfo[powerdevice_wlan].power_rate); /*--- angemeldete WLAN-Devices ---*/ pm_info->stat.wlan_status = PM_WLAN_GET_ECO(pm_info->deviceinfo[powerdevice_wlan].power_rate); /*--- WLAN-Status (1= ECO) ---*/ pm_info->stat.rate_ethact = (PM_GET_RATE(pm_info->deviceinfo[powerdevice_ethernet].norm_power_rate) == 0) ? 0 : (PM_GET_RATE(pm_info->deviceinfo[powerdevice_ethernet].power_rate * 100) / PM_GET_RATE(pm_info->deviceinfo[powerdevice_ethernet].norm_power_rate)); /*--- aktueller Ethernet-Verbrauch in Prozent ---*/ activ_ethports = PM_ETHERNET_GET_DEVICEMASK(pm_info->deviceinfo[powerdevice_ethernet].power_rate); /*--- Maske je Bit ein LAN-Port Bit0: Lan1 ... ---*/ pm_info->stat.eth_status = 0; for(i = 0; i < AVMPOWER_MAX_ETHERNETPORTS; i++) { #if defined(POWERMANAGEMENT_THROTTLE_ETH) limit_set_eth(pm_info, i, 0); #endif/*--- #if defined(POWERMANAGEMENT_THROTTLE_ETH) ---*/ pm_info->stat.eth_status |= ((activ_ethports & (1 << i)) ? (3 << (i * 2)) : (pm_info->eth_status[i] & 0x3) << (i * 2)); } pm_info->stat.isdn_status = 0; for(i = 1; i < 5; i++) { /*--- maximal 4 Controller ---*/ pm_info->stat.isdn_status |= (PM_E1STATUS(i) & pm_info->deviceinfo[powerdevice_isdnnt].power_rate) ? (2 << ((i-1) * 4)) : 0; /*--- NT-E1 ---*/ pm_info->stat.isdn_status |= (PM_E3STATUS(i) & pm_info->deviceinfo[powerdevice_isdnnt].power_rate) ? (4 << ((i-1) * 4)) : 0; /*--- NT E3 ---*/ pm_info->stat.isdn_status |= (PM_E1STATUS(i) & pm_info->deviceinfo[powerdevice_isdnte].power_rate) ? (1 << ((i-1) * 4)) : 0; /*--- TE-Bit ---*/ } pm_info->stat.rate_abact = (PM_GET_RATE(pm_info->deviceinfo[powerdevice_analog].norm_power_rate) == 0) ? 0 : (PM_GET_RATE(pm_info->deviceinfo[powerdevice_analog].power_rate) * 100) / (PM_GET_RATE(pm_info->deviceinfo[powerdevice_analog].norm_power_rate)); /*--- aktueller Nebenstellen-Verbrauch in Prozent ---*/ pm_info->stat.rate_dectact = PM_GET_RATE(pm_info->deviceinfo[powerdevice_dect].power_rate); /*--- aktueller Verbrauch DECT in Prozent ---*/ pm_info->stat.dect_status = PM_DECT_GET_ECO(pm_info->deviceinfo[powerdevice_dect].power_rate) ? 1 : 0; /*--- DECT-ECO Status ---*/ pm_info->stat.rate_battchargeact = (PM_GET_RATE(pm_info->deviceinfo[powerdevice_charge].norm_power_rate) == 0) ? 0 : (PM_GET_RATE(pm_info->deviceinfo[powerdevice_charge].power_rate) * 100) / (PM_GET_RATE(pm_info->deviceinfo[powerdevice_charge].norm_power_rate)); /*--- Batterieladeverbrauch (DECT) ---*/ usbmwatt = PM_GET_MWATT(&pm_info->deviceinfo[powerdevice_usb_host]) + PM_GET_MWATT(&pm_info->deviceinfo[powerdevice_usb_host2]) + PM_GET_MWATT(&pm_info->deviceinfo[powerdevice_usb_host3]) + 0; normmwatt = PM_GET_NORM_MWATT(&pm_info->deviceinfo[powerdevice_usb_host]) + PM_GET_NORM_MWATT(&pm_info->deviceinfo[powerdevice_usb_host2]) + PM_GET_NORM_MWATT(&pm_info->deviceinfo[powerdevice_usb_host3]) + 0; if(normmwatt) { usbmwatt = (usbmwatt * 100) / normmwatt; if(usbmwatt > 100) { usbmwatt = 100; } } pm_info->stat.rate_usbhostact = (unsigned char) usbmwatt; pm_info->stat.usb_status = PM_GET_RATE(pm_info->deviceinfo[powerdevice_usb_client].power_rate) ? 1 : 0; /*--- USB-Client connected ---*/ #if 0 printk(KERN_DEBUG"SUM:%d(%d) SYST:%d(%d)-%x DSP:%d(%d) WLAN:%d(%d)-%d-%x ETH:%d(%d)-%x ISDN:%x AB:%d(%d) DECT:%d(%d) USB:%d(%d)-%x TEMP(%d, %d min %d max %d) want:%d\n", pm_info->stat.rate_sumact, pm_info->stat.rate_sumcum, pm_info->stat.rate_systemact, pm_info->stat.rate_systemcum, pm_info->stat.system_status, pm_info->stat.rate_dspact, pm_info->stat.rate_dspcum, pm_info->stat.rate_wlanact, pm_info->stat.rate_wlancum, pm_info->stat.wlan_devices, pm_info->stat.wlan_status, pm_info->stat.rate_ethact, pm_info->stat.rate_ethcum, pm_info->stat.eth_status, pm_info->stat.isdn_status, pm_info->stat.rate_abact, pm_info->stat.rate_abcum, pm_info->stat.rate_dectact, pm_info->stat.rate_dectcum, pm_info->stat.rate_usbhostact, pm_info->stat.rate_usbhostcum, pm_info->stat.usb_status, pm_info->stat.act_temperature, pm_info->stat.avg_temperature, pm_info->stat.min_temperature, pm_info->stat.max_temperature, avm_event_source_check_id(pm_info->event_handle, avm_event_id_pm_ressourceinfo_status) ); #endif #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ } pm_info->thread_id = 0; DEB_ERR("[avm_power]pm_ressourceinfo_thread: exit\n"); complete_and_exit(&pm_info->on_exit, 0 ); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void pm_ressourceinfo_init(void) { #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) int i; #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ if(pm_ressourceinfo.deviceinfo[powerdevice_dspclock].power_rate == 0) { pm_ressourceinfo.deviceinfo[powerdevice_dspclock].power_rate = FREQUENZ_TO_PERCENT(STD_DSPCLK, MAX_DSPCLK); } if(pm_ressourceinfo.deviceinfo[powerdevice_cpuclock].power_rate == 0) { pm_ressourceinfo.deviceinfo[powerdevice_cpuclock].power_rate = FREQUENZ_TO_PERCENT(STD_MIPSCLK, MAX_MIPSCLK); } if(pm_ressourceinfo.deviceinfo[powerdevice_systemclock].power_rate == 0) { pm_ressourceinfo.deviceinfo[powerdevice_systemclock].power_rate = FREQUENZ_TO_PERCENT(STD_SYSTEMCLK, MAX_SYSTEMCLK); } init_waitqueue_head(&pm_ressourceinfo.wait_queue); init_completion(&pm_ressourceinfo.on_exit ); pm_ressourceinfo.thread_id = kernel_thread(pm_ressourceinfo_thread, (void *) &pm_ressourceinfo, CLONE_SIGHAND); #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) for(i = 0; i < AVMPOWER_MAX_ETHERNETPORTS; i++) { pm_ressourceinfo.eth_status[i] = 2; /*--- auf normal vorinitialisieren ---*/ } pm_ressourceinfo.event_handle = avm_event_source_register( "pm_info_stat", ( (((unsigned long long) 1) << avm_event_id_pm_ressourceinfo_status)), pm_ressourceinfo_notify, &pm_ressourceinfo ); if(pm_ressourceinfo.event_handle == NULL) { printk("[avm_power] avm event register failed !\n"); } pm_ressourceinfo.temperature_eventhandle = avm_event_source_register( "temperature", ( (((unsigned long long) 1) << avm_event_id_temperature)), avmevent_temperature_notify, &pm_ressourceinfo ); if(pm_ressourceinfo.temperature_eventhandle == NULL) { printk("[avm_power] avm event register failed !\n"); } pm_ressourceinfo.cpu_idle_eventhandle = avm_event_source_register( "cpu_idle", ( (((unsigned long long) 1) << avm_event_id_cpu_idle)), avmevent_cpu_idle_notify, &pm_ressourceinfo ); if(pm_ressourceinfo.cpu_idle_eventhandle == NULL) { printk("[avm_power] avm event register failed !\n"); } #endif } #ifdef CONFIG_AVM_POWER_MODULE /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void pm_ressourceinfo_exit(void) { if(pm_ressourceinfo.thread_id) { kill_proc(pm_ressourceinfo.thread_id, SIGTERM, 1 ); wait_for_completion( &pm_ressourceinfo.on_exit ); } #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) if(pm_ressourceinfo.event_handle) { avm_event_source_release(pm_ressourceinfo.event_handle); pm_ressourceinfo.event_handle = NULL; } if(pm_ressourceinfo.temperature_eventhandle) { avm_event_source_release(pm_ressourceinfo.temperature_eventhandle); pm_ressourceinfo.temperature_eventhandle = NULL; } if(pm_ressourceinfo.cpu_idle_eventhandle) { avm_event_source_release(pm_ressourceinfo.cpu_idle_eventhandle); pm_ressourceinfo.cpu_idle_eventhandle = NULL; } #endif } #endif/*--- #ifdef CONFIG_AVM_POWER_MODULE ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static const char *pm_name_device(enum _powermanagment_device device) { switch(device) { case powerdevice_none: return "powerdevice_none"; case powerdevice_cpuclock: return "powerdevice_cpuclock"; case powerdevice_dspclock: return "powerdevice_dspclock"; case powerdevice_systemclock: return "powerdevice_systemclock"; case powerdevice_wlan: return "powerdevice_wlan"; case powerdevice_isdnnt: return "powerdevice_isdnnt"; case powerdevice_isdnte: return "powerdevice_isdnte"; case powerdevice_analog: return "powerdevice_analog"; case powerdevice_dect: return "powerdevice_dect"; case powerdevice_ethernet: return "powerdevice_ethernet"; case powerdevice_dsl: return "powerdevice_dsl"; case powerdevice_usb_host: return "powerdevice_usb_host"; case powerdevice_usb_client: return "powerdevice_usb_client"; case powerdevice_charge: return "powerdevice_charge"; case powerdevice_loadrate: return "powerdevice_loadrate"; case powerdevice_temperature: return "powerdevice_temperature"; case powerdevice_dectsync: return "powerdevice_dectsync"; case powerdevice_usb_host2: return "powerdevice_usb_host2"; case powerdevice_usb_host3: return "powerdevice_usb_host3"; case powerdevice_dsp_loadrate: return "powerdevice_dsp_loadrate"; case powerdevice_vdsp_loadrate: return "powerdevice_vdsp_loadrate"; case powerdevice_maxdevices: return "powerdevice_maxdevices"; } return "powerdevice_unknown"; } /*--------------------------------------------------------------------------------*\ * Zeilenaufbau: alle Werte dezimal (line steht hinter '=') * PMINFO= device, act_power_rate \*--------------------------------------------------------------------------------*/ static void pm_ressourceinfo_parse(char *line) { char *p = line; int device, power_rate; SKIP_SPACES(p); sscanf(p, "%d", &device); if(device <= powerdevice_none || device >= powerdevice_maxdevices) { DEB_ERR("[avm_power] p%s: unknown_device %d: '%s'\n", __func__, device, line); return; } if(avm_power_write_find_special_char(&p, ',')){ DEB_ERR("[avm_power] %s: invalid format '%s'\n", __func__, p); return; } SKIP_SPACES(p); sscanf(p, "%d", &power_rate); PowerManagmentRessourceInfo(device, power_rate); } /*--------------------------------------------------------------------------------*\ * Zeilenaufbau: alle Werte dezimal (line steht hinter '=') * PMINFO_MODE = device, norm_power_rate, multiplier, divider, offset \*--------------------------------------------------------------------------------*/ static void pm_ressourceinfo_scriptparse(char *line) { struct _power_managment_device_info *df; char *p = line; int mWatt, device, i, flags; SKIP_SPACES(p); sscanf(p, "%d", &device); if(device <= powerdevice_none || device >= powerdevice_maxdevices) { DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: unknown_device %d: '%s'\n", device, line); return; } df = &pm_ressourceinfo.deviceinfo[device]; if(avm_power_write_find_special_char(&p, ',')){ DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: invalid format '%s'\n", p); return; } SKIP_SPACES(p); sscanf(p, "%d", &df->norm_power_rate); if(avm_power_write_find_special_char(&p, ',')){ DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: invalid format '%s'\n", p); return; } SKIP_SPACES(p); sscanf(p, "%d", &df->multiplier); if(avm_power_write_find_special_char(&p, ',')){ DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: invalid format '%s'\n", p); return; } SKIP_SPACES(p); sscanf(p, "%d", &df->divider); if(avm_power_write_find_special_char(&p, ',')){ DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: invalid format '%s'\n", p); return; } SKIP_SPACES(p); sscanf(p, "%d", &df->offset); if(df->divider != 0) { int SumNorm_mWatt = 0; for(i = 0; i < powerdevice_maxdevices; i++) { struct _power_managment_device_info *df1 = &pm_ressourceinfo.deviceinfo[i]; SumNorm_mWatt += PM_GET_NORM_MWATT(df1); } mWatt = PM_GET_NORM_MWATT(df); printk(KERN_DEBUG"[avm_power] pm_ressourceinfo_scriptparse: %s: norm_power_rate=%d act_rate=%d mul=%d div=%d offset=%d NormP=%d mW -> SumNormP=%d mW\n", pm_name_device(device), df->norm_power_rate, df->power_rate, df->multiplier, df->divider, df->offset, mWatt, SumNorm_mWatt); pm_ressourceinfo.NormP = SumNorm_mWatt; } else { DEB_ERR("[avm_power] pm_ressourceinfo_scriptparse: warning divider is zero '%s'\n", line); } flags = LOCK(); pm_ressourceinfo.Changes++; UNLOCK(flags); wake_up_interruptible(&pm_ressourceinfo.wait_queue); } /*--------------------------------------------------------------------------------*\ * Funktion wird von Treibern aufgerufen um Infos ueber den aktuellen Power-Status zu liefern \*--------------------------------------------------------------------------------*/ int PowerManagmentRessourceInfo(enum _powermanagment_device device, int power_rate){ int flags = 0, changes = 0, ready; if((unsigned)device >= powerdevice_maxdevices) { DEB_ERR("[avm_power]PowerManagmentRessourceInfo: unknown device: %d\n", device); return 0; } ready = pm_ressourceinfo.thread_id; #if defined(DECTSYNC_PATCH) if(device == powerdevice_dectsync) { if(ready == 0) { return 0; } if(power_rate < 0) { if(power_rate == -1) { /*--- Piglet sagt wir haben DECT ---*/ gdectsync.state = init_dectsync; } else if(power_rate == -2) { gdectsync.state = resetmode; } else { printk(KERN_ERR"dectsync: cnt %ld %s lost %ld wp=%d %% good=%lu.%02lu %% - v/l/t=%lu/%lu/%lu low=%lu usec\n", gdectsync.synccnt, gdectsync.state == timerset_ok ? "activ" : "is off - last value:", gdectsync.synclost, gdectsync.wastepercent, gdectsync.goodpercent / 100, gdectsync.goodpercent % 100, gdectsync.violation, gdectsync.latency, gdectsync.timeout, CLK_TO_USEC(gdectsync.lowcycles)); } power_rate = 0; } if(power_rate == 0) { /*--- Indikator das jetzt im Idle-Kontext ---*/ return idle_dectsynchandler(); } /*--- Indikator das jetzt im Timer-Kontext ---*/ return timer_dectsynchandler(power_rate); } if(device == powerdevice_loadrate) { gdectsync.run = power_rate; if(gdectsync.run == 100) { gdectsync.maxrun++; } if(gdectsync.maxrun && TIME_DIFF(jiffies, gdectsync.start_maxrun) > (10 * HZ)) { gdectsync.start_maxrun = jiffies; printk(KERN_ERR"[%lu]maxrun: %ld\n", jiffies, gdectsync.maxrun); gdectsync.maxrun = 0; } if(gdectsync.wastepercent < power_rate) { /*--- Korrektur der power-rate ---*/ power_rate -= gdectsync.wastepercent; } } #endif/*--- #if defined(DECTSYNC_PATCH) ---*/ if(ready) flags = LOCK(); /*--- falls vor Initialisierung dieses Moduls aufgerufen: kein lock ---*/ if(pm_ressourceinfo.deviceinfo[device].power_rate != power_rate) { if((device == powerdevice_isdnte) || (device == powerdevice_isdnnt)) { convert_isdnpowerstate(&pm_ressourceinfo.deviceinfo[device].power_rate, power_rate); } else { pm_ressourceinfo.deviceinfo[device].power_rate = power_rate; } if((avm_power_disp_loadrate & 1) && (device == powerdevice_loadrate)) { #if defined(DECTSYNC_PATCH) if(gdectsync.state == timerset_ok) printk(KERN_ERR"[%lu]idle: %d %%(%d %%) dectsync: %lu lost %ld wp=%d %% good=%lu.%02lu %% dt=%lu us - v/l/t=%lu/%lu/%lu low=%lu us drift=%ld ns\n", jiffies, 100 - power_rate, power_rate, gdectsync.synccnt, gdectsync.synclost, gdectsync.wastepercent, gdectsync.goodpercent / 100, gdectsync.goodpercent % 100, gdectsync.settriggerusec, gdectsync.violation, gdectsync.latency, gdectsync.timeout, CLK_TO_USEC(gdectsync.lowcycles), CLK_TO_NSEC(gdectsync.drift) ); else #endif/*--- #if defined(DECTSYNC_PATCH) ---*/ printk(KERN_ERR"[%lu]idle: %d %%(%d %%)\n", jiffies, 100 - power_rate, power_rate); } changes = (ready && pm_ressourceinfo.NormP) ? 1 : 0; /*--- nur wenn Thread existiert und script geladen ----*/ pm_ressourceinfo.Changes += changes; if((avm_power_disp_loadrate & 2) && (device != powerdevice_loadrate)) printk(KERN_ERR"[avm_power]PowerManagmentRessourceInfo: device: %s value=(0x%x)%d changes=%d\n", pm_name_device(device), power_rate, power_rate, pm_ressourceinfo.Changes); } if(ready) UNLOCK(flags); if(changes) { wake_up_interruptible(&pm_ressourceinfo.wait_queue); } #if defined(CONFIG_MIPS_OHIO) if(avm_power_activate_semtechfix) { avm_power_semtechfix(); } #endif/*--- #if defined(CONFIG_MIPS_OHIO) ---*/ return 0; } EXPORT_SYMBOL(PowerManagmentRessourceInfo); #endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ #if defined(DECTSYNC_PATCH) #define DECT_SYNC_CHECK() (hw_gpio->InputData.Register & (1 << DECT_SYNCGPIO)) #define KBIT_TO_BYTES(kbit, sec) ((kbit) * (sec) * 1000 / 8) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline unsigned int check_irq_set(unsigned int irq) { struct _irq_hw *IRQ = (struct _irq_hw *)UR8_IRQ_CTRL_BASE; unsigned int _irq = irq - (MIPS_EXCEPTION_OFFSET); return(IRQ->status_set_reg[_irq / 32] & (1 << (_irq % 32))); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static inline int check_dectsyncgpio(unsigned long clktimeout, unsigned int set, unsigned statereset){ volatile struct _hw_gpio *hw_gpio = (struct _hw_gpio *)UR8_GPIO_BASE; register unsigned long start_time, end_time; start_time = get_cycles(); if(set) set = (1 << DECT_SYNCGPIO); while(DECT_SYNC_CHECK() == set) { end_time = get_cycles(); if((clktimeout > USEC_TO_CLK(11000)) || (TIME_DIFF(end_time, start_time) > clktimeout)) { if(statereset) { gdectsync.periodjiffies = jiffies; gdectsync.periodcnt = 0; gdectsync.state = corrupt_mode; } return 0; } } end_time = get_cycles(); return TIME_DIFF(end_time, start_time); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static unsigned int lclock_notify(enum _avm_clock_id clock_id, unsigned int new_clk) { if(gdectsync.state == inactive) { return 0; } if(clock_id == avm_clock_id_cpu) { gdectsync.clk = new_clk / 2 / 1000000; } if(gdectsync.clk != UR8_MHZ) { printk("[dectsync]invalid cycle-cnt %lu\n", gdectsync.clk); gdectsync.state = invalid_clk; } else { gdectsync.state = init_dectsync; } return 0; } /*--------------------------------------------------------------------------------*\ * im Idle-Kontext \*--------------------------------------------------------------------------------*/ static int idle_dectsynchandler(void) { volatile struct _hw_gpio *hw_gpio = (struct _hw_gpio *)UR8_GPIO_BASE; int flags = 0; register unsigned long start_time, low, high, periodcnt, wlan_diff; unsigned long rx_wlan_bytes, tx_wlan_bytes; switch(gdectsync.state) { case resetmode: DBG_DS_ERR("[dectsync] inactive\n"); avm_gpio_ctrl(DECT_SYNCGPIO, GPIO_PIN, GPIO_OUTPUT_PIN); avm_gpio_out_bit(DECT_SYNCGPIO, 0); gdectsync.violation = gdectsync.latency = gdectsync.periodcnt = gdectsync.timeout = 0; gdectsync.state = inactive; break; case invalid_clk: case inactive: break; case init_dectsync: DBG_DS_TRC("[%lu][dectsync] calibration\n", jiffies); avm_gpio_ctrl(DECT_SYNCGPIO, GPIO_PIN, GPIO_INPUT_PIN); gdectsync.clk = (avm_get_clock_notify(avm_clock_id_cpu, lclock_notify) / 2 / 1000000); if(gdectsync.clk != UR8_MHZ) { printk("[dectsync]invalid cycle-cnt %lu -> inactive\n", gdectsync.clk); gdectsync.state = invalid_clk; break; } gdectsync.state = calibration_mode; gdectsync.periodjiffies = jiffies; gdectsync.wastepercent = 0; break; case calibration_mode: if(gdectsync.run > 80) { break; } flags = LOCK(); start_time = get_cycles(); high = avm_gpio_in_bit(DECT_SYNCGPIO); if(high == 0) { UNLOCK(flags); break; } /*--- wir erkennen einen Pegel nur die kuerzerer Highphase ausmessen: ---*/ gdectsync.failcntdown = DECTFAILCNTDOWN; gdectsync.state = calibration_mode2; UNLOCK(flags); break; case calibration_mode2: /*--- lieber nur die kuerzere High-Phase ausmessen: ---*/ if(gdectsync.run > 80) { break; } flags = LOCK(); start_time = get_cycles(); high = avm_gpio_in_bit(DECT_SYNCGPIO); if(high == 1) { gdectsync.failcntdown = DECTFAILCNTDOWN; UNLOCK(flags); break; } if(gdectsync.failcntdown) { gdectsync.failcntdown--; if(gdectsync.failcntdown == 0) { gdectsync.state = calibration_mode; UNLOCK(flags); break; } } /*--- warte auf Flankenwechsel low -> high ---*/ if((low = check_dectsyncgpio(USEC_TO_CLK(4500), 1, 1)) == 0) { UNLOCK(flags); break; } if(check_irq_set(UR8INT_C55_DSP0)) { DBG_DS_TRC("[%lu][dectsync]stop while UR8INT_C55_DSP0\n", jiffies); UNLOCK(flags); break; } /*--- warte auf Flankenwechsel high -> low ---*/ if((high = check_dectsyncgpio(USEC_TO_CLK(6050), 0, 1)) == 0) { DBG_DS_TRC("[%lu][dectsync]can't get tx-dect-mode\n", jiffies); UNLOCK(flags); break; } low = (USEC_TO_CLK(10000) - high); gdectsync.periodjiffies = jiffies; gdectsync.state = calibrate_timerirq_delay; DBG_DS_ERR("[%lu][dectsync]low/high %ld/%ld usec blocked %ld usec\n", jiffies, CLK_TO_USEC(low), CLK_TO_USEC(high), CLK_TO_USEC(TIME_DIFF(get_cycles(), start_time))); UNLOCK(flags); break; case calibrate_timerirq_delay: if(TIME_DIFF(jiffies, gdectsync.periodjiffies) > (HZ * 2)) { gdectsync.periodjiffies = jiffies; gdectsync.state = calibrate_timerirq; } break; case timerset_ok: flags = LOCK(); /*--- hier mal schauen, ob wir hier wieder einen Highpegel messen koennen ---*/ if((gdectsync.lowedgejiffies == jiffies) && DECT_SYNC_CHECK()) { unsigned long lowcycles; gdectsync.lowedgejiffies = 0; /*--- wir haben High-Pegel detektiert ---*/ lowcycles = TIME_DIFF(get_cycles(), gdectsync.lowedgecycles); #if defined(DEBUG_DECTSYNC) & 0 if(((CLK_TO_USEC(lowcycles) + 127) & ~0xFF) != ((CLK_TO_USEC(gdectsync.lowcycles) + 127) & ~0xFF)) { DBG_DS_TRC("[%lu][dectsync]idle: %ld -> %ld\n", jiffies, CLK_TO_USEC(gdectsync.lowcycles), CLK_TO_USEC(lowcycles)); } #endif/*--- #if defined(DEBUG_DECTSYNC) ---*/ gdectsync.lowcycles = lowcycles; } periodcnt = gdectsync.periodcnt; if((TIME_DIFF(jiffies, gdectsync.periodjiffies) >= 10 * HZ) && periodcnt) { gdectsync.goodpercent = ((gdectsync.goodcnt * 10 * 1000) + 1) / periodcnt; gdectsync.wastepercent = CLK_TO_USEC(gdectsync.waste_idle) / 100 / periodcnt; gdectsync.settriggerusec = CLK_TO_USEC((gdectsync.avg_cycle_perjiffies / periodcnt) << 10); DBG_DS_TRC("[%lu][%lu][dectsync]waste %ld %%(syncnt=%ld good=%lu.%02lu %% dt=%lu usec) low=%ld usec v/l/t=%lu/%lu/%lu cpj=%d\n", CLK_TO_MSEC(TIME_DIFF(get_cycles(), gdectsync.periodcycle)), jiffies, gdectsync.wastepercent, gdectsync.synccnt, gdectsync.goodpercent / 100, gdectsync.goodpercent % 100, gdectsync.settriggerusec, CLK_TO_USEC(gdectsync.lowcycles), gdectsync.violation, gdectsync.latency, gdectsync.timeout, gdectsync.cycles_per_jiffy); gdectsync.periodjiffies = jiffies; gdectsync.periodcycle = get_cycles(); gdectsync.goodcnt = 0; gdectsync.periodcnt = 0; gdectsync.waste_idle = 0; gdectsync.avg_cycle_perjiffies = 0; UNLOCK(flags); get_wlantraffic(&rx_wlan_bytes, &tx_wlan_bytes); if(gdectsync.last_wlan_traffic) { wlan_diff = (rx_wlan_bytes + tx_wlan_bytes) - gdectsync.last_wlan_traffic; if(avm_power_disp_loadrate & 1) { printk(KERN_ERR"wlan-traffic(rx+tx): %lu kbit/s\n", wlan_diff * 8 / 10 / 1000); } if(wlan_diff > KBIT_TO_BYTES(25000 * 2, 10)) { gdectsync.periodjiffies = jiffies; gdectsync.periodcnt = 0; gdectsync.state = wlantraffic_mode; gdectsync.last_wlan_traffic = rx_wlan_bytes + tx_wlan_bytes; } } gdectsync.last_wlan_traffic = rx_wlan_bytes + tx_wlan_bytes; } else { UNLOCK(flags); } break; case corrupt_mode: gdectsync.goodcnt = 0; if(gdectsync.run > 80) { break; } gdectsync.last_wlan_traffic = 0; gdectsync.violation = 0; gdectsync.latency = 0; gdectsync.timeout = 0; if(TIME_DIFF(jiffies, gdectsync.periodjiffies ) > HZ) { gdectsync.state = calibration_mode; } break; case wlantraffic_mode: gdectsync.goodcnt = 0; if(TIME_DIFF(jiffies, gdectsync.periodjiffies ) < (10 * HZ)) { break; } gdectsync.periodjiffies = jiffies; if(gdectsync.run > 80) { break; } get_wlantraffic(&rx_wlan_bytes, &tx_wlan_bytes); if(gdectsync.last_wlan_traffic) { wlan_diff = (rx_wlan_bytes + tx_wlan_bytes) - gdectsync.last_wlan_traffic; if(avm_power_disp_loadrate & 1) { printk(KERN_ERR"wlan-traffic(rx+tx): %lu kbit/s\n", wlan_diff * 8 / 10 / 1000); } if(wlan_diff > KBIT_TO_BYTES(25000 * 2, 10)) { gdectsync.last_wlan_traffic = rx_wlan_bytes + tx_wlan_bytes; break; } } gdectsync.state = calibration_mode; break; default: break; } return 0; } /*--------------------------------------------------------------------------------*\ * Im TimerIrq-Kontext * ret: 0 nicht verwenden, sonst direkt expirlo * * Achtung! der Code ist mit LA optimiert, um zu gewährleisten, das keine Speicher- * zugriffe/Instructioncache-prefetches mitten im DECT-Empfang passieren \*--------------------------------------------------------------------------------*/ static int timer_dectsynchandler(int cycles_per_jiffy){ volatile struct _hw_gpio *hw_gpio = (struct _hw_gpio *)UR8_GPIO_BASE; unsigned long flags; int free_slotcycles, cycles_per_jiffies_per_freeslots, cycles_per_jiffies_per_run; long drift = 0; unsigned long start_time, endtime, dt, dt_offset = 0; unsigned int ret = 0; int idx, pegel, cnt, lastlow = 0; enum { wait_for_highpegel = 0, high_pegel_detect, low_edge_found } p_state = wait_for_highpegel; flags = LOCK(); start_time = get_cycles(); #if defined(CONFIG_AVM_SIMPLE_PROFILING) avm_simple_profiling_log(avm_profile_data_type_func_begin, (unsigned int)timer_dectsynchandler, 0); #endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ switch(gdectsync.state) { case calibrate_timerirq: /*--------------------------------------------------------------------------------*\ willkuerlich lowedgetrigger setzen: er sucht dann im timerset_ok sein Optimum, Da wir 500 usec Delay eingebaut haben, wenn wir keinen Trigger finden, ist gegeben, das er durchwandert, und spaetestens nach ca. 20 Sekunden einrastet \*--------------------------------------------------------------------------------*/ gdectsync.periodjiffies = jiffies; gdectsync.state = timerset_ok; gdectsync.lowedgecycles = get_cycles(); cycles_per_jiffy -= USEC_TO_CLK(833); gdectsync.cycles_per_jiffy = cycles_per_jiffy; gdectsync.failcntdown = DECTFAILCNTDOWN; gdectsync.synccnt = 0; gdectsync.periodjiffies = jiffies; gdectsync.periodcycle = get_cycles(); gdectsync.goodcnt = 0; gdectsync.periodcnt = 0; gdectsync.waste_idle = 0; ret = (gdectsync.lowedgecycles + cycles_per_jiffy) | 1; break; case timerset_ok: pegel = DECT_SYNC_CHECK(); /*--- gleich mal Pegel merken ---*/ dt = TIME_DIFF(start_time, gdectsync.lowedgecycles); /*--- die Zeitdifferenz zur letzten Lowflanke ---*/ for(;;) { int cnt = 0; if(dt < cycles_per_jiffy + gdectsync.dt_offset) { break; } /*--- der letzte Timer ist laenger als 10 msec her: neu justieren ---*/ cnt++; DBG_DS_TRC("<[%lu %lu]l %d le=%lu dt=%lu>", jiffies, get_cycles(), cnt, gdectsync.lowedgecycles, dt); gdectsync.lowedgecycles += cycles_per_jiffy; dt = TIME_DIFF(start_time, gdectsync.lowedgecycles); gdectsync.latency++; } /*--- evtl. Latencies sind ausgeglichen, nun schaue ob Retrigger/zu kurzer Abstand ---*/ dt = TIME_DIFF(get_cycles(), gdectsync.lowedgecycles); if(dt < gdectsync.cycles_per_jiffy && (dt < USEC_TO_CLK(4500))) { /*--- wir sind zu frueh getriggert worden ---*/ DBG_DS_TRC("<[%lu %lu]k lcpj=%d dt=%lu>", jiffies, get_cycles(), gdectsync.cycles_per_jiffy, dt); gdectsync.cycles_per_jiffy -= dt; ret = (gdectsync.lowedgecycles + gdectsync.cycles_per_jiffy) | 1; break; } /*--------------------------------------------------------------------------------*\ nun sind wir im Messfenster also wo DECT-Rx laeuft da durch Verkuerzung der Flanke falsche lowedges gemessen werden koennen, halten wir uns strikt an das Zeitfenster \*--------------------------------------------------------------------------------*/ endtime = gdectsync.lowedgecycles + cycles_per_jiffy + USEC_TO_CLK(500); for(;;) { dt = TIME_DIFF(endtime, get_cycles()); if(dt >= cycles_per_jiffy) { /*--- wir haben das Zeitfenster ueberschritten ---*/ break; } if(check_irq_set(UR8INT_C55_DSP0)) { if(dt > (cycles_per_jiffy / 2) - USEC_TO_CLK(1000)) { /*--- es liegt der c55-irq an und es ist noch ca. 4 msec bis zum edge-detect: vorzeitiger Abbruch ---*/ dt_offset = cycles_per_jiffy - dt - USEC_TO_CLK(600); /*--- retrigger dann aber auch spaeter ---*/ break; } } if(p_state == low_edge_found) { /*--- wir haben eine Lowflanke gefunden ---*/ break; } switch(p_state) { case wait_for_highpegel: if(pegel == 0) { lastlow = get_cycles() | 1; } if(pegel) { p_state = high_pegel_detect; cnt = 0; } break; case high_pegel_detect: if((pegel == 0) && (dt < USEC_TO_CLK(833))) { /*--- nur die hinteren 833 usec untersuchen ---*/ p_state = low_edge_found; if(lastlow) { gdectsync.lowcycles = TIME_DIFF(lastlow, gdectsync.lowedgecycles); drift = (long) TIME_DIFF(get_cycles(), gdectsync.lowedgecycles) - (long)cycles_per_jiffy; } gdectsync.lowedgecycles = get_cycles(); /*--- neu kalibriert ---*/ /*--- DBG_DS_TRC("<[%lu]p=%lu>", jiffies, gdectsync.lowedgecycles); ---*/ } break; case low_edge_found: break; } pegel = DECT_SYNC_CHECK(); /*--- Pegel checken ---*/ } if(p_state != low_edge_found) { /*--- mmmh - Lowflanke nicht gefunden ---*/ gdectsync.lastwasgood = 0; gdectsync.timeout++; if(gdectsync.failcntdown) { gdectsync.failcntdown--; } if(gdectsync.failcntdown == 0) { gdectsync.synclost++; gdectsync.periodjiffies = jiffies; gdectsync.periodcnt = 0; gdectsync.state = corrupt_mode; DBG_DS_ERR("[%lu][%u - %lu][dectsync]can't get dectsync synccnt=%lu state=%d pegel=%d lowcylces=%lu\n", jiffies, get_cycles(), gdectsync.lowedgecycles, gdectsync.synccnt, p_state, pegel, CLK_TO_USEC(gdectsync.lowcycles)); break; } if(p_state == wait_for_highpegel) { /*--------------------------------------------------------------------------------*\ haben nicht mal einen Highpegel: schnellere Suche per zusaetzlichen Offset \*--------------------------------------------------------------------------------*/ if(gdectsync.nohigh < USEC_TO_CLK(1000)){ gdectsync.nohigh += USEC_TO_CLK(10); } if(gdectsync.drift < 0) { /*--- MIPS langsamer: suche vorwaerts ---*/ gdectsync.lowedgecycles += cycles_per_jiffy + gdectsync.nohigh; } else { /*--- MIPS schneller: suche rueckwarts ---*/ gdectsync.lowedgecycles += cycles_per_jiffy - gdectsync.nohigh; } } else { gdectsync.lowedgecycles += cycles_per_jiffy - gdectsync.drift; /*--- aproximierter Wert ---*/ gdectsync.nohigh = 0; } gdectsync.lowedgecycles += gdectsync.drift; } else { /*--- alles korrekt erkannt --*/ if(gdectsync.lastwasgood && (drift > -USEC_TO_CLK(100)) && (drift < USEC_TO_CLK(100))) { /*--- letzte war auch ok: drift scheint konsistent: negativ MIPS-Clock langsamer als DECT-Clock ---*/ gdectsync.drift = drift; } gdectsync.nohigh = 0; gdectsync.lowedgejiffies = jiffies + 1; gdectsync.failcntdown = DECTFAILCNTDOWN; gdectsync.goodcnt++; gdectsync.lastwasgood = 1; } cycles_per_jiffy /= 2; gdectsync.synccnt++; /*--- in fruehestens 5 msec sehen wir uns wieder um maximal 5 msec zu sperren ... ---*/ cycles_per_jiffies_per_freeslots = cycles_per_jiffy; free_slotcycles = gdectsync.lowcycles - USEC_TO_CLK(833 + 5000 + 100); if(free_slotcycles > 0) { cycles_per_jiffies_per_freeslots += free_slotcycles; } idx = (gdectsync.run - 55) / 5; cycles_per_jiffies_per_run = cycles_per_jiffy; if(idx > 0) { /*--- ... naja oder spaeter da Box die Rechenleistung braucht ---*/ cycles_per_jiffies_per_run += (cycles_per_jiffy * idx) / 8; } if(cycles_per_jiffies_per_run > cycles_per_jiffies_per_freeslots) { gdectsync.violation++; } cycles_per_jiffy = max(cycles_per_jiffies_per_run, cycles_per_jiffies_per_freeslots); if((cycles_per_jiffy < 0) || (cycles_per_jiffy > USEC_TO_CLK(10000 - 400))) { DBG_DS_TRC("error on cycles per jiffies: %d\n", cycles_per_jiffy); cycles_per_jiffy = USEC_TO_CLK(10000 - 400); } gdectsync.cycles_per_jiffy = cycles_per_jiffy; gdectsync.dt_offset = dt_offset; ret = (gdectsync.lowedgecycles + gdectsync.cycles_per_jiffy + dt_offset) | 1; break; default: break; } gdectsync.periodcnt++; gdectsync.waste_idle += TIME_DIFF(get_cycles(), start_time); gdectsync.avg_cycle_perjiffies += cycles_per_jiffy >> 10; #if defined(CONFIG_AVM_SIMPLE_PROFILING) avm_simple_profiling_log(avm_profile_data_type_func_end, (unsigned int)timer_dectsynchandler, 0); #endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ UNLOCK(flags); return ret; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void get_wlantraffic(unsigned long *rx_bytes, unsigned long *tx_bytes) { struct net_device_stats *pnetdevicestat; struct net_device *pnetdevice = dev_get_by_name( #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) &init_net, #endif "ath0"); *rx_bytes = 0; *tx_bytes = 0; if(pnetdevice == NULL) { return; } #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28) if(pnetdevice->get_stats == NULL) { dev_put(pnetdevice); return; } pnetdevicestat = pnetdevice->get_stats(pnetdevice); #else /*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28) ---*/ if((pnetdevice->netdev_ops == NULL) || (pnetdevice->netdev_ops->ndo_get_stats == NULL)) { dev_put(pnetdevice); return; } pnetdevicestat = pnetdevice->netdev_ops->ndo_get_stats(pnetdevice); #endif /*--- #else ---*/ /*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28) ---*/ if(pnetdevicestat == NULL) { dev_put(pnetdevice); return; } /*--- printk("NetStat rx %ld tx %ld\n", pnetdevicestat->rx_bytes, pnetdevicestat->tx_bytes); ---*/ *rx_bytes = pnetdevicestat->rx_bytes; *tx_bytes = pnetdevicestat->tx_bytes; dev_put(pnetdevice); } #endif/*--- #if defined(DECTSYNC_PATCH) ---*/