/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2004 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 #if defined(CONFIG_PROC_FS) #include #endif /*--- #if defined(CONFIG_PROC_FS) ---*/ #include #include #include "tffs_local.h" #ifdef CONFIG_SYSCTL #define DEV_ADAM2 6 #define DEV_ADAM2_ENV 1 #define ADAM2_ENV_STR_SIZE 80 static char info[ADAM2_ENV_STR_SIZE]; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int avm_urlader_getenv_proc(ctl_table *ctl, int write, struct file *filp, void *buffer, size_t *lenp, loff_t *ppos) { char *val, len; char *default_val = NULL; int free_val; /*--- printk("[avm_urlader_getenv_proc]: filp->f_pos=%u ctl->ctl_name=%u, write=%u *lenp=%u *ppos=%u\n", ---*/ /*--- (int)filp->f_pos, (int)ctl->ctl_name, (int)write, (int)*lenp, (int)*ppos); ---*/ if(write) { printk("write not supported\n"); return -EFAULT; } if (!*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } switch(ctl->ctl_name) { case FLASH_FS_ANNEX: default_val = "B"; break; case FLASH_FS_FIRMWARE_VERSION: default_val = ""; break; default: printk("avm_urlader_getenv_proc: id %x not supported\n", ctl->ctl_name); return -EFAULT; } free_val = 1; val = avm_urlader_env_get_value_by_id(ctl->ctl_name); if(val == NULL) { if(default_val) { val = default_val; } else { val = ""; } free_val = 0; } len = 0; /* Scan thru the flash, looking for each possible variable index */ len = strlen(val); /*--- printk("[avm_urlader_getenv_proc] val=%s len=%u\n", val, len); ---*/ memcpy(info, val, len + 1); if(free_val) kfree(val); if(len > *lenp) len = *lenp; if(len) { if(copy_to_user(buffer, info, len)) return -EFAULT; } *lenp = len; filp->f_pos += len; *ppos += len; /*--- printk("[avm_urlader_getenv_proc] *lenp=%u f_pos=%u *ppos\n", *lenp, filp->f_pos, (int)*ppos); ---*/ return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int avm_urlader_setenv_sysctl(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp, loff_t *ppos) { char *var, *val, *ptr; int ret, i; size_t total, len; if (!*lenp || (filp->f_pos && !write)) { *lenp = 0; return 0; } if(ctl->ctl_name != DEV_ADAM2_ENV) { return -ENODEV; } if(write) { ret = proc_dostring(ctl, write, filp, buffer, lenp, ppos); ptr = strpbrk(info, " \t"); if(!ptr) { /* We have no way to distinguish between unsetting a * variable and setting a non-value variable. * * Consequently, we will treat any variable * without a value as an unset request. */ avm_urlader_env_unset_variable(info); } else { /* Set the variable-value pair in flash */ *ptr++ = 0; if(avm_urlader_env_set_variable(info, ptr) != 0) { printk(KERN_NOTICE "Defragging the environment variable region.\n"); avm_urlader_env_defrag(); if( avm_urlader_env_set_variable(info, ptr) != 0 ) printk(KERN_WARNING "Failed to write %s to environment variable region.\n", info); } } } else { total=0; len=0; /* Scan thru the flash, looking for each possible variable index */ for(i = 0; i < MAX_ENV_ENTRY; i++) { if( (var=avm_urlader_env_get_variable(i))!=NULL ) { if( (val=avm_urlader_env_get_value(var)) != NULL) { len = sprintf(info, "%s\t%s\n", var, val); kfree(val); } kfree(var); if(len > *lenp - total) len = *lenp - total; if(len) { if(copy_to_user(buffer+total, info, len)) return -EFAULT; } #if !defined(CONFIG_TFFS_ENV) else { break; } #endif /*--- #if !defined(CONFIG_TFFS_ENV) ---*/ total += len; len = 0; } } *lenp = total; *ppos += total; filp->f_pos += total; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ ctl_table avm_urlader_env_table[] = { {DEV_ADAM2_ENV, "environment", info, ADAM2_ENV_STR_SIZE, 0644, NULL, &avm_urlader_setenv_sysctl }, {FLASH_FS_FIRMWARE_VERSION, "firmware_version", info, ADAM2_ENV_STR_SIZE, 0644, NULL, &avm_urlader_getenv_proc}, {FLASH_FS_ANNEX, "annex", info, ADAM2_ENV_STR_SIZE, 0644, NULL, &avm_urlader_getenv_proc}, {0} }; ctl_table avm_urlader_root_table[] = { {DEV_ADAM2_ENV, "urlader", NULL, 0, 0555, avm_urlader_env_table }, {0} }; static struct ctl_table_header *avm_urlader_sysctl_header; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void avm_urlader_env_sysctl_register(void) { static int initialized; if (initialized == 1) return; avm_urlader_sysctl_header = register_sysctl_table(avm_urlader_root_table, 1); avm_urlader_root_table->child->de->owner = THIS_MODULE; /* set the defaults */ info[0] = 0; initialized = 1; } #if defined(MODULE) static void avm_urlader_env_sysctl_unregister(void) { unregister_sysctl_table(avm_urlader_sysctl_header); } #endif /*--- #if defined(MODULE) ---*/ int avm_urlader_env_init(void) { avm_urlader_env_sysctl_register(); printk(KERN_INFO "Adam2 environment variables API installed.\n"); return 0; } #if defined(MODULE) void avm_urlader_env_exit(void) { avm_urlader_env_sysctl_unregister(); } #endif /*--- #if defined(MODULE) ---*/ #endif /* CONFIG_SYSCTL */ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #ifdef CONFIG_PROC_FS unsigned int tffs_info_value; int tffs_read_proc ( char *page, char **start, off_t off,int count, int *eof, void *data_unused) { int len = 0; off_t begin = 0; if(tffs_lock()) { printk("tffs_read_proc: lock() failed\n"); return -EINVAL; } len = sprintf(page + len, "TFFS \n"); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } len += sprintf(page + len, "mount=mtd%u\n", tffs_mtd[0]); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } len += sprintf(page + len, "mount=mtd%u\n", tffs_mtd[1]); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } len += sprintf(page + len, "request=%u\n", tffs_request_count); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } if(tffs_info_value) { len += sprintf(page + len, "fill=%u\n", tffs_info_value); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } } if(tffs_thread_event) { len += sprintf(page + len, "event panding\n"); if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } } #if defined(CONFIG_TFFS_EXCLUSIVE) len += sprintf(page + len, "mode: read/write: exclusive\n"); #else /*--- #if defined(CONFIG_TFFS_EXCLUSIVE) ---*/ len += sprintf(page + len, "mode: read/write: sheared\n"); #endif /*--- #else ---*/ /*--- #if defined(CONFIG_TFFS_EXCLUSIVE) ---*/ if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } switch(tffs_thread_state) { case tffs_thread_state_off: len += sprintf(page + len, "thread state=off\n"); break; case tffs_thread_state_init: len += sprintf(page + len, "thread state=init\n"); break; case tffs_thread_state_idle: len += sprintf(page + len, "thread state=idle\n"); break; case tffs_thread_state_process: len += sprintf(page + len, "thread state=process\n"); break; case tffs_thread_state_down: len += sprintf(page + len, "thread state=down\n"); break; } if(len + begin > off + count) goto tffs_read_proc_done; if(len + begin < off) { begin += len; len = 0; } *eof = 1; tffs_read_proc_done: tffs_unlock(); if (off >= len + begin) return 0; *start = page + (begin - off); return ((count < begin + len - off) ? count : begin + len - off); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int tffs_atoi(char *p) { int value = 0; while(*p && *p >= '0' && *p <= '9') { value *= 10; value += *p - '0'; p++; } return value; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int tffs_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { char page[80]; char *p = page; int type = -1; void *Handle; int status = 0; if( copy_from_user(page, buffer, count) ) { return -EFAULT; } if( count ) page[count-1]='\0'; else page[count]='\0'; if(!strncmp(p, "info", sizeof("info") - 1)) { type = _TFFS_INFO; } else if(!strncmp(p, "index", sizeof("index") - 1)) { type = _TFFS_REINDEX; } else if(!strncmp(p, "cleanup", sizeof("cleanup") - 1)) { type = _TFFS_CLEANUP; } else if(!strncmp(p, "clear_id", sizeof("clear_id") - 1)) { type = _TFFS_CLEAR_ID; } else if(!strncmp(p, "werkseinstellung", sizeof("werkseinstellung") - 1)) { type = _TFFS_WERKSEINSTELLUNG; } if(type != -1) { if(tffs_lock()) { printk("tffs_write_proc: lock() failed\n"); return -EINVAL; } Handle = TFFS_Open(); switch(type) { case _TFFS_INFO: status = TFFS_Info(Handle, &tffs_info_value); printk("/proc/tffs: info request: %s\n", status ? "failed" : "success"); break; case _TFFS_REINDEX: status = TFFS_Create_Index(); printk("/proc/tffs: index request: %s\n", status ? "failed" : "success"); break; case _TFFS_CLEANUP: status = TFFS_Cleanup(Handle); printk("/proc/tffs: cleanup request: %s\n", status ? "failed" : "success"); break; case _TFFS_WERKSEINSTELLUNG: status = TFFS_Werkseinstellungen(Handle); printk("/proc/tffs: werkseinstellungen request: %s\n", status ? "failed" : "success"); break; case _TFFS_CLEAR_ID: while(*p && *p != ' ' && *p != '\t') p++; while(*p && ( *p == ' ' || *p == '\t')) p++; type = tffs_atoi(p); if(p) { status = TFFS_Clear(Handle, type); printk("/proc/tffs: clear id 0x%x request: %s\n", type, status ? "failed" : "success"); } else { printk("/proc/tffs: clear id request: invallid id 0x%x\n", type); } break; } TFFS_Close(Handle); tffs_unlock(); } return status == 0 ? count : -EFAULT; } #endif /*--- #ifdef CONFIG_PROC_FS ---*/