/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2013 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 * * Export-Funktionen (fuer Remote) PowerManagmentRessourceInfo PowerManagmentActivatePowerMode PowerManagmentRegister PowerManagmentRelease \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include "avm_power.h" /*--- #define DEBUG_AVM_POWER ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ struct _pw_remote_source { unsigned int Changes; volatile struct task_struct *kthread; wait_queue_head_t wait_queue; void *remote_event_handle; } pw_remote_source; #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void avm_event_powermanagment_remote_notify(void *context __attribute__((unused)), enum _avm_event_id id __attribute__((unused))) { } #endif/*--- #if defined(CONFIG_AVM_EVENT) || defined(CONFIG_AVM_EVENT_MODULE) ---*/ #if defined(DEBUG_AVM_POWER) #define DBG_TRC(args...) printk(KERN_INFO args) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void dump_data(const char *prefix, const unsigned char *data, unsigned int len) { printk(KERN_ERR"%s: data len=%d:", prefix, len); while(len--) { printk(KERN_CONT"%02x,",*data++); } printk(KERN_ERR"\n"); } #else #define DBG_TRC(args...) #endif/*--- #if defined(DEBUG_AVM_POWER) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int remote_source_thread(void *data) { struct _pw_remote_source *pwrs = (struct _pw_remote_source *)data; /*--- DEB_ERR("[%s]: start\n", __func__); ---*/ while (!kthread_should_stop()) { if(wait_event_interruptible_timeout( pwrs->wait_queue, pwrs->Changes, 5 * HZ)){ break; } pwrs->Changes = 0; PowerManagmentRessourceInfo(powerdevice_temperature, avm_power_temperature()); } pwrs->kthread = NULL; /*--- DEB_ERR("[%s]: exit\n", __func__); ---*/ return 0; } #if 0 /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void remote_source_thread_trigger(void) { if(pw_remote_source.kthread) { pw_remote_source.Changes++; wake_up_interruptible(&pw_remote_source.wait_queue); } } #endif /*--------------------------------------------------------------------------------*\ * old_model: von der x86-Seite cpuidle-, wlan- und usb-Status zum arm * new_model: von der arm-Seite cpuidle-Status (powerdevice_loadrate2) zum x86 \*--------------------------------------------------------------------------------*/ int avm_power_remote_source_init(void) { #if defined(CONFIG_AVM_EVENT) struct _avm_event_id_mask id_mask; int ret = 0; if(pw_remote_source.remote_event_handle) { return ret; } pw_remote_source.remote_event_handle = avm_event_source_register( "powermanagment_remote", avm_event_build_id_mask(&id_mask, 1, avm_event_id_powermanagment_remote), avm_event_powermanagment_remote_notify, NULL ); if(pw_remote_source.remote_event_handle == NULL) { ret = -1; printk(KERN_ERR"[avm_power]%s not registered\n", __func__); } return ret; #else/*--- #if defined(CONFIG_AVM_EVENT) ---*/ return -1; #endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_EVENT) ---*/ } /*--------------------------------------------------------------------------------*\ * old_model: x86: die Temperatur regelmaessig abfragen, da hier kein pm_info-Thread * new_model: nicht verwenden \*--------------------------------------------------------------------------------*/ int avm_power_remote_source_temperature_init(void) { #if defined(CONFIG_AVM_EVENT) int ret = 0; if(pw_remote_source.kthread) { return ret; } init_waitqueue_head(&pw_remote_source.wait_queue); pw_remote_source.kthread = kthread_run(remote_source_thread, (void *) &pw_remote_source, "pm_remote"); BUG_ON((pw_remote_source.kthread == NULL) || IS_ERR((void *)pw_remote_source.kthread)); return ret; #else/*--- #if defined(CONFIG_AVM_EVENT) ---*/ return -1; #endif/*--- #else ---*//*--- #if defined(CONFIG_AVM_EVENT) ---*/ } #ifdef CONFIG_AVM_POWER_MODULE /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void avm_power_remote_source_exit(void) { if(pw_remote_source.remote_event_handle) { avm_event_source_release(pw_remote_source.remote_event_handle); pw_remote_source.remote_event_handle = NULL; } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void avm_power_temperature_remote_source_exit(void) { if(pw_remote_source.kthread) { kthread_stop((struct task_struct *)pw_remote_source.kthread); } } #endif/*--- #ifdef CONFIG_AVM_POWER_MODULE ---*/ /*--------------------------------------------------------------------------------*\ * Funktion wird von Treibern aufgerufen um Infos ueber den aktuellen Power-Status zu liefern \*--------------------------------------------------------------------------------*/ int PowerManagmentRessourceInfo(enum _powermanagment_device device, int power_rate){ #if defined(CONFIG_AVM_EVENT) struct _avm_event_powermanagment_remote *event; /*--- auf Remote-Seite lokal speichern z.B. fuer cpuidle-Event: ---*/ pm_ressourceinfo.deviceinfo[device].power_rate = power_rate; if(device == powerdevice_loadrate) { /*--- damit kein Konflikt mit Host-CPU ---*/ device = powerdevice_loadrate2; } if(pw_remote_source.remote_event_handle == NULL) { /*--- printk(KERN_WARNING "%s: can't execute %d(%x), because remote_event-device not ready \n", __func__, device, power_rate); ---*/ return -EAGAIN; } event = (struct _avm_event_powermanagment_remote *)kmalloc(sizeof(struct _avm_event_powermanagment_remote), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "%s (remote): can't alloc event\n", __func__); return -ENOMEM; } event->header.id = avm_event_id_powermanagment_remote; event->remote_action = avm_event_powermanagment_ressourceinfo; event->param.ressourceinfo.device = device; event->param.ressourceinfo.power_rate = power_rate; DBG_TRC("%s(remote)(%s, 0x%x)\n", __func__, pm_name_device(device), power_rate); #if defined(DEBUG_AVM_POWER) /*--- dump_data(__func__, event, sizeof(*event)); ---*/ #endif/*--- #if defined(DEBUG_AVM_POWER) ---*/ return avm_event_source_trigger(pw_remote_source.remote_event_handle, avm_event_id_powermanagment_remote, sizeof(struct _avm_event_powermanagment_remote), event); #else return -ENODEV; #endif/*--- #if defined(CONFIG_AVM_EVENT) ---*/ } EXPORT_SYMBOL(PowerManagmentRessourceInfo); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int PowerManagmentActivatePowerMode(char *powermode_name){ #if defined(CONFIG_AVM_EVENT) struct _avm_event_powermanagment_remote *event; if((pw_remote_source.remote_event_handle == NULL) || (powermode_name == NULL)) { return -1; } event = (struct _avm_event_powermanagment_remote *)kmalloc(sizeof(struct _avm_event_powermanagment_remote), GFP_ATOMIC); if(event == NULL) { printk(KERN_WARNING "%s (remote): can't alloc event\n", __func__); return -ENOMEM; } event->header.id = avm_event_id_powermanagment_remote; event->remote_action = avm_event_powermanagment_activatepowermode; strncpy(event->param.powermode, powermode_name, sizeof(event->param.powermode)); DBG_TRC("%s(remote)(%s)\n", __func__, powermode_name); return avm_event_source_trigger(pw_remote_source.remote_event_handle, avm_event_id_powermanagment_remote, sizeof(struct _avm_event_powermanagment_remote), event); #else return -1; #endif/*--- #if defined(CONFIG_AVM_EVENT) ---*/ } EXPORT_SYMBOL(PowerManagmentActivatePowerMode); /*--------------------------------------------------------------------------------*\ * dummy \*--------------------------------------------------------------------------------*/ void *PowerManagmentRegister(char *client_name __attribute__((unused)), int (*CallBackPowerManagmentControl)(int state) __attribute__((unused))){ printk(KERN_WARNING "%s(%s) (remote) not implemented \n", __func__, client_name); return NULL; } EXPORT_SYMBOL(PowerManagmentRegister); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void PowerManagmentRelease(void *Handle __attribute__((unused))){ } EXPORT_SYMBOL(PowerManagmentRelease);