/*------------------------------------------------------------------------------------------*\ * * 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 "avm_power.h" #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #define AVM_POWER_UDEV #endif/*--- #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) ---*/ #define LOCAL_MAJOR AVM_POWER_MAJOR /*--- #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) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _avm_power { #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) struct class *osclass; #endif/*--- #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) ---*/ dev_t device; struct cdev *cdev; }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _avm_power_open_data { unsigned int reserved; }; /*-------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------*/ #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 LOAD_MODE "LOAD_MODE" unsigned int avm_power_disp_loadrate = 0; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_power_open(struct inode *, struct file *); static int avm_power_close(struct inode *, struct file *); static ssize_t avm_power_write(struct file *filp, const char *write_buffer, size_t write_length, loff_t *write_pos); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ 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, ---*/ }; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int __init avm_power_file_init(void) { int reason; #if defined(AVM_POWER_UDEV) reason = alloc_chrdev_region(&avm_power.device, 0, 1, MODULE_NAME); #else /*--- #if defined(AVM_POWER_UDEV) ---*/ DEB_INFO("[%s] register_chrdev_region()\n", MODULE_NAME); avm_power.device = MKDEV(LOCAL_MAJOR, 0); reason = register_chrdev_region(avm_power.device, 1, MODULE_NAME); #endif if(reason) { DEB_ERR("[%s] register_chrdev_region failed: reason %d!\n", MODULE_NAME, reason); return -ERESTARTSYS; } avm_power.cdev = cdev_alloc(); if (!avm_power.cdev) { unregister_chrdev_region(avm_power.device, 1); DEB_ERR("[%s] cdev_alloc failed!\n", MODULE_NAME); 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); 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("[%s] cdev_add failed!\n", MODULE_NAME); 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) ---*/ return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #ifdef CONFIG_AVM_POWER_MODULE void avm_power_file_exit(void) { DEB_INFO("[%s]: unregister_chrdev(%u)\n", MODULE_NAME, MAJOR(avm_power.device)); #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); } #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]: %s:\n", MODULE_NAME, __func__); /*-------------------------------------------------------------------------------------------*\ \*-------------------------------------------------------------------------------------------*/ open_data = (struct _avm_power_open_data *)kmalloc(sizeof(struct _avm_power_open_data), GFP_KERNEL); if(!open_data) { DEB_ERR("%s: %s: open malloc failed\n", MODULE_NAME, __func__); return -EFAULT; } memset(open_data, 0, sizeof(*open_data)); filp->private_data = (void *)open_data; DEB_INFO("[%s]: %s: open success flags=0x%x\n", MODULE_NAME, __func__, filp->f_flags); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_power_close(struct inode *inode __attribute__((unused)), struct file *filp) { DEB_INFO("[%s]: %s:\n", MODULE_NAME, __func__); 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; #if defined(AVM_POWER_DEBUG) unsigned int org_write_length; #endif struct _power_managment_dest_entry *powermodetab __attribute__((unused)) = NULL; #if defined(CONFIG_FUSIV_VX180) int Mask; #endif/*--- #if defined(CONFIG_FUSIV_VX180) ---*/ if(write_pos != NULL) { DEB_INFO("[%s]: %s write_length = %u *write_pos = 0x%LX\n", MODULE_NAME, __func__, write_length, *write_pos); } #if defined(AVM_POWER_DEBUG) org_write_length = write_length; #endif if(write_length >= sizeof(Buffer)) { write_length = sizeof(Buffer) - 1; DEB_NOTE("[%s] %s: long line reduce to %u bytes\n", MODULE_NAME, __func__, write_length); } if(filp == NULL) { memcpy(Buffer, write_buffer, write_length); } else { if(copy_from_user(Buffer, write_buffer, write_length)) { DEB_ERR("[%s]: %s avm_power_write: copy_from_user failed\n", MODULE_NAME, __func__); return -EFAULT; } } /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ Buffer[write_length] = '\0'; DEB_NOTE("[%s] %s: avm_power_write org_len=%u len %u = '%s'\n", MODULE_NAME, __func__, org_write_length, write_length, Buffer); p = strchr(Buffer, 0x0A); if(p) { *p = '\0'; write_length = strlen(Buffer) + 1; DEB_NOTE("[%s] %s: multi line reduce to %u bytes\n", MODULE_NAME, __func__, write_length); } p = Buffer; /*--------------------------------------------------------------------------------------*\ * cmd extrahieren \*--------------------------------------------------------------------------------------*/ SKIP_SPACES(p); DEB_NOTE("[%s]: %s process input \"%s\"\n", MODULE_NAME, __func__, p); /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ if(0) { #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) } else 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 defined(CONFIG_FUSIV_VX180) } else if(!strncmp(WE_CMD_MODE, p, sizeof(WE_CMD_MODE) - 1)) { extern void Wyatt_Earp(int Mask); p += sizeof(WE_CMD_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[%s] format error: \""WE_CMD_MODE" = : 0x0: help 0x10000: set only we-mask 0x800: simulate dying gasp\n", MODULE_NAME); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%x", &Mask); Wyatt_Earp(Mask); return write_length; #endif /*--- defined(CONFIG_FUSIV_VX180) ---*/ #if defined(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("[%s] format error: '%s'\n", MODULE_NAME, p); DEB_ERR("[%s] use: \""PMINFO_MODE" = device, norm_rate, multiplier, divider, offset\"\n", MODULE_NAME); /*--- 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("[%s] format error: '%s'\n", MODULE_NAME, p); DEB_ERR("[%s] use: \""PMINFO_SET" = device, power_rate\n", MODULE_NAME); return write_length; } pm_ressourceinfo_parse(p); return write_length; } else if(!strncmp(ETH_MODE, p, sizeof(ETH_MODE) - 1)) { union _powermanagment_ethernet_state eth; unsigned int tmp, throttle = ETH_NORMAL_DEMAND_CON; eth.Register = 0; p += sizeof(ETH_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[%s] format error: '%s'\n", MODULE_NAME, p); DEB_ERR("[%s] use: \""ETH_MODE" = port, state\"\n", MODULE_NAME); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%u", &tmp); if(tmp > 255) { DEB_ERR("[%s] : unknown port %u:\n", MODULE_NAME, 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("[%s] : unknown status - set status to powered(2)\n", MODULE_NAME); tmp = 2; /*--- kein break ---*/ case 0: case 2: eth.Bits.status = tmp; break; case 1: throttle = ETH_THROTTLE_DEMAND_CON; eth.Bits.status = tmp; break; case 3: eth.Bits.status = 1; /*--- powersave ohne throttle ---*/ break; } if(eth.Bits.port < AVMPOWER_MAX_ETHERNETPORTS) { pm_ressourceinfo.eth_status[eth.Bits.port] = ETH_MASK_BITS(pm_ressourceinfo.eth_status[eth.Bits.port], 0x3 | ETH_THROTTLE_DEMAND_CON | ETH_NORMAL_DEMAND_CON, throttle) | eth.Bits.status; tmp = pm_ressourceinfo_limit_set_eth(&pm_ressourceinfo, eth.Bits.port, 1); } else { tmp = 1; } if(tmp == 2) { DEB_ERR("[%s] : ethernet not registered\n", MODULE_NAME); } else if(tmp) { DEB_ERR("[%s] : ethernet switch failed\n", MODULE_NAME); } return write_length; #endif/*--- #if defined(CONFIG_AVM_POWERMETER) ---*/ } else if(!strncmp(LOAD_MODE, p, sizeof(LOAD_MODE) - 1)) { unsigned int val, scale = 1; p += sizeof(LOAD_MODE) - 1; if(avm_power_write_find_special_char(&p, '=')) { DEB_ERR("[%s] format error: '%s'\n", MODULE_NAME, p); DEB_ERR("[%s] use: \""LOAD_MODE" = mode (0 auto, 1 off, > 1 Level\"\n", MODULE_NAME); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%u", &val); if(avm_power_write_find_special_char(&p, ',') == 0) { SKIP_SPACES(p); sscanf(p, "%u", &scale); } avm_powermanager_load_control_set(val, scale); #endif/*--- #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) ---*/ } 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("[%s] format error: '%s'\n", MODULE_NAME, p); DEB_ERR("[%s] use: \""IDLE_MODE" = mode\"\n", MODULE_NAME); /*--- return -EPERM; ---*/ return write_length; } SKIP_SPACES(p); sscanf(p, "%x", &avm_power_disp_loadrate); printk(KERN_ERR"mode=0x%x\n", avm_power_disp_loadrate); return write_length; #if defined(CONFIG_AVM_POWER_REMOTE_SINK) && 0 } else if(!strncmp("sinkinit", p, sizeof("sinkinit") - 1)) { avm_power_remote_sink_init(); } else if(!strncmp("sinkexit", p, sizeof("sinkexit") - 1)) { avm_power_remote_sink_exit(); #endif/*--- #ifdef CONFIG_AVM_POWER_REMOTE_SINK ---*/ } else { #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) avm_power_writeformaterror("[avm_power] format error: \""CMD_MODE" = \""); #endif/*--- #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) ---*/ /*--- return -EPERM; ---*/ return write_length; } #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) if(powermode_action(powermodetab, 0)) { /*--- printk("[avm_power] error on activate powermode"); ---*/ /*--- return -EPERM; ---*/ return write_length; } #endif/*--- #if !defined(CONFIG_AVM_POWER_REMOTE_SOURCE) ---*/ return write_length; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ unsigned int avm_power_read_from_file(char *filename, char *str, int maxlen) { struct file *fp; mm_segment_t oldfs; int bytesRead; fp = filp_open(filename, O_RDONLY, 00); if(IS_ERR(fp) || (fp->f_op == 0)) { str[0] = 0; /*--- printk(KERN_ERR " failed: open: %s\n", filename); ---*/ return 0; } /* Lesezugriff auf File(system) erlaubt? */ if (fp->f_op->read == NULL) { str[0] = 0; /*--- printk(KERN_ERR "[avm_power]failed: read %s\n", filename); ---*/ filp_close(fp, NULL); return 0; } oldfs = get_fs(); set_fs(KERNEL_DS); fp->f_pos = 0; /* Von Anfang an lesen */ bytesRead = fp->f_op->read(fp, str, maxlen, &fp->f_pos); if(bytesRead < 0) { bytesRead = 0; } str[bytesRead] = 0; set_fs(oldfs); filp_close(fp, NULL); /* Close the file */ return bytesRead; }