/*------------------------------------------------------------------------------------------*\ * * 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 /*--- #include ---*/ #include #include #include #include #if defined(CONFIG_TFFS_ENV) #define TFFS3_NAME_TABLE #include #include "tffs_local.h" static int avm_urlader_init(void); static int initialised = 0; /*--- #define TFFS_CONFIG ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(TFFS_CONFIG) #define DBG_TRC(args...) printk(KERN_INFO args) #else /*--- #if defined(TFFS_CONFIG) ---*/ #define DBG_TRC(args...) #endif /*--- #else ---*/ /*--- #if defined(TFFS_CONFIG) ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static void avm_urlader_extract_name_table(unsigned char *buffer, int len) { unsigned int index = 0; unsigned int name_len; memset(&TFFS3_Name_Table[0], 0, sizeof(TFFS3_Name_Table)); DBG_TRC("avm_urlader_extract_name_table(buffer=%x, len=%x)\n", (unsigned int)buffer, len); while(len > 0 && index < MAX_ENV_ENTRY){ TFFS3_Name_Table[index].id = *(unsigned int *) buffer; buffer += sizeof(unsigned int); len -= sizeof(unsigned int); name_len = strlen(buffer) + 1; name_len = (name_len + 3) & ~0x03; memcpy(TFFS3_Name_Table[index].Name, buffer, name_len); len -= name_len; buffer += name_len; index++; } } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static size_t avm_urlader_build_name_table(unsigned char *buffer, size_t max_len) { unsigned int index = 0; size_t name_len, output_len = 0; memset(&TFFS3_Name_Table[0], 0, sizeof(TFFS3_Name_Table)); memcpy(&TFFS3_Name_Table[0], &T3_Init[0], sizeof(T3_Init)); DBG_TRC("avm_urlader_build_name_table(buffer=%x, max_len=%x)\n", (unsigned int)buffer, max_len); while(index < MAX_ENV_ENTRY && TFFS3_Name_Table[index].id && output_len + 64 < max_len){ if(TFFS3_Name_Table[index].Name && TFFS3_Name_Table[index].Name[0]){ *(unsigned int *) buffer = TFFS3_Name_Table[index].id; buffer += sizeof(unsigned int); output_len += sizeof(unsigned int); name_len = strlen(TFFS3_Name_Table[index].Name) + 1; name_len = (name_len + 3) & ~0x03; memcpy(buffer, TFFS3_Name_Table[index].Name, name_len); output_len += name_len; buffer += name_len; } index++; } return output_len; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static unsigned int avm_urlader_get_name(char *Name) { struct _TFFS_Name_Table *T = &TFFS3_Name_Table[0]; DBG_TRC("avm_urlader_get_name(%s)\n", Name); while(T->id){ if(Name[0] == T->Name[0] && !strcmp(Name, T->Name)){ return T->id; /*--- gefunden ---*/ } if(Name[0] < T->Name[0]){ return (unsigned int) -1; /*--- hat keine Zweck mehr ---*/ } T++; } DBG_TRC("avm_urlader_get_name(%s): not found\n", Name); return (unsigned int) -1; } /*-----------------------------------------------------------------------------------------------*\ * liefert den Namen für den Index der Variable * * Get the variable referenced by index * * NOTE: Caller is responsibe for freeing the memory. \*-----------------------------------------------------------------------------------------------*/ char *avm_urlader_env_get_variable3(int idx) { char *buffer, *result; struct _tffs_open *handle; int status; DBG_TRC("avm_urlader_env_get_variable(%u)\n", idx); if(idx < 0){ DBG_TRC("avm_urlader_env_get_variable(%d) failed, invalid handle\n", idx); return NULL ; } status = 0; if(initialised == 0){ status = avm_urlader_init(); } if(status != 0){ DBG_TRC("avm_urlader_env_get_variable(%u) failed, not initialised\n", idx); return NULL ; } handle = TFFS3_Open(tffs3_mode_read); if(handle == NULL ){ return NULL ; } result = NULL; if(idx < ARRAY_SIZE(TFFS3_Name_Table) - 1){ if(TFFS3_Name_Table[idx].Name && TFFS3_Name_Table[idx].Name[0]){ buffer = kmalloc(strlen(TFFS3_Name_Table[idx].Name) + 1, GFP_KERNEL); if(buffer == NULL ){ DBG_TRC("avm_urlader_env_get_variable(%u) found, but no memory\n", idx); goto err_out; } strcpy(buffer, TFFS3_Name_Table[idx].Name); result = buffer; } } /*--- DBG_TRC("avm_urlader_env_get_variable(%u) not found\n", idx); ---*/ err_out: TFFS3_Close(handle); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int avm_urlader_init(void) { unsigned char *buffer; unsigned int need_rebuild; size_t ret_length, total_len, written; struct _tffs_open *handle; int result; buffer = NULL; if(initialised){ return 1; } handle = TFFS3_Open(tffs3_mode_read); if(handle == NULL ){ DBG_TRC("avm_urlader_open(): open TFFS failed\n"); result = -EIO; goto err_out; } result = 0; buffer = kmalloc(FLASH_ENV_ENTRY_SIZE * MAX_ENV_ENTRY, GFP_KERNEL); if(buffer == NULL ){ DBG_TRC("avm_urlader_open(): out of memory\n"); result = -ENOMEM; goto err_out; } total_len = 0; do{ ret_length = (FLASH_ENV_ENTRY_SIZE * MAX_ENV_ENTRY) - total_len; result = TFFS3_Read(handle, FLASH_FS_NAME_TABLE, buffer, &ret_length); total_len += ret_length; }while(result == 0 && ret_length > 0); if(result != 0 && result != -ENOENT){ goto err_out; } // need to re-open the handle for write access TFFS3_Close(handle); handle = TFFS3_Open(tffs3_mode_write); if(handle == NULL ){ DBG_TRC("avm_urlader_open(): open TFFS failed\n"); result = -EIO; goto err_out; } DBG_TRC("avm_urlader_open(): read name table success (%u bytes)\n", ret_length); avm_urlader_extract_name_table(buffer, total_len); DBG_TRC("avm_urlader_open(): extract name table success\n"); need_rebuild = 0; if((T3_Init[0].id != TFFS3_Name_Table[0].id) || (T3_Init[0].Name[1] != TFFS3_Name_Table[0].Name[1])){ printk("WARNING: TFFS Name Table update ! (current %s new %s)\n", TFFS3_Name_Table[0].Name, T3_Init[0].Name); need_rebuild = 1; /*--- rebuild name table ---*/ }else{ printk("TFFS Name Table %c\n", TFFS3_Name_Table[0].Name[1]); } if(need_rebuild != 0){ DBG_TRC("avm_urlader_open(): read name table failed\n"); total_len = avm_urlader_build_name_table(buffer, FLASH_ENV_ENTRY_SIZE * MAX_ENV_ENTRY); DBG_TRC("avm_urlader_open(): build name table success (%u bytes)\n", ret_length); written = 0; do{ ret_length = min(total_len - written, handle->max_segment_size); result = TFFS3_Write(handle, FLASH_FS_NAME_TABLE, buffer + written, ret_length, (written + ret_length >= total_len)); written += ret_length; }while(result == 0 && total_len > written); if(result != 0){ DBG_TRC("avm_urlader_open(): write name table failed\n"); goto err_out; } DBG_TRC("avm_urlader_open(): write name table success (%u bytes)\n", ret_length); } initialised = 1; err_out: if(buffer != NULL ){ kfree(buffer); } if(handle != NULL ){ TFFS3_Close(handle); } return result; } /*-----------------------------------------------------------------------------------------------*\ * liefert den Inhalt der Variable * * Get the value associated with an environment variable * * NOTE: Caller is responsibe for freeing the memory. \*-----------------------------------------------------------------------------------------------*/ char *avm_urlader_env_get_value_by_id3(unsigned int id) { struct _tffs_open *handle; unsigned int length, total_len; unsigned char *buffer; int result; DBG_TRC("avm_urlader_env_get_value_by_id(%u)\n", id); result = 0; buffer = NULL; handle = NULL; if(!initialised){ result = avm_urlader_init(); } if(result != 0){ goto err_out; } buffer = kmalloc(FLASH_ENV_ENTRY_SIZE + 1, GFP_KERNEL); if(buffer == NULL ){ goto err_out; } handle = TFFS3_Open(tffs3_mode_read); if(handle == NULL ){ goto err_out; } total_len = 0; do{ length = FLASH_ENV_ENTRY_SIZE - total_len; result = TFFS3_Read(handle, id, buffer + total_len, &length); total_len += length; }while(result == 0 && length > 0); if(result != 0){ goto err_out; } buffer[total_len] = '\0'; TFFS3_Close(handle); DBG_TRC("avm_urlader_env_get_value_by_id(%u) : '%s'\n", id, buffer); return buffer; err_out: if(buffer != NULL ){ kfree(buffer); } if(handle != NULL ){ TFFS3_Close(handle); } return NULL ; } /*-----------------------------------------------------------------------------------------------*\ * liefert den Inhalt der Variable * * Get the value associated with an environment variable * * NOTE: Caller is responsibe for freeing the memory. \*-----------------------------------------------------------------------------------------------*/ char *avm_urlader_env_get_value3(char *var) { unsigned int id; int result; DBG_TRC("avm_urlader_env_get_value(%s)\n", var); result = 0; if(!initialised){ result = avm_urlader_init(); } if(result != 0){ return NULL ; } id = avm_urlader_get_name(var); if(id == (unsigned int) -1){ return NULL ; } DBG_TRC("avm_urlader_env_get_value(%s) id=%u\n", var, id); return avm_urlader_env_get_value_by_id3(id); } /*-----------------------------------------------------------------------------------------------*\ * Set the variable to a specific value. * * NOTE: If the value is NULL, the variable will be unset. Otherwise, the * variable-value pair will be written to flash. \*-----------------------------------------------------------------------------------------------*/ int avm_urlader_env_set_variable3(char *var, char *val) { struct _tffs_open *handle; unsigned int id; size_t written, seg_len, total_len; int result; DBG_TRC("[%s] %s=%s\n", __func__, var, val); result = 0; if(!initialised){ result = avm_urlader_init(); } if(result != 0){ return result; } id = avm_urlader_get_name(var); if(id == (unsigned int) -1){ return -ENOENT; } handle = TFFS3_Open(tffs3_mode_write); if(handle == NULL){ return -EIO; } if(val == NULL ){ result = TFFS3_Clear(handle, id); } else { total_len = strlen(val) + 1; written = 0; do{ seg_len = min(total_len - written, handle->max_segment_size); result = TFFS3_Write(handle, id, val + written, seg_len, (written + seg_len >=total_len)); written += seg_len; }while(result == 0 && total_len > written); } TFFS3_Close(handle); return result; } /*-----------------------------------------------------------------------------------------------*\ * Unset the variable to a specific value. \*-----------------------------------------------------------------------------------------------*/ int avm_urlader_env_unset_variable3(char *var) { return avm_urlader_env_set_variable3(var, NULL ); } /*-----------------------------------------------------------------------------------------------*\ * Defrag the block associated with the Adam2 environment variables. \*-----------------------------------------------------------------------------------------------*/ int avm_urlader_env_defrag3(void) { struct _tffs_open *handle; int result; handle = TFFS3_Open(tffs3_mode_write); if(handle == NULL){ return -EIO; } result = TFFS3_Cleanup(handle); TFFS3_Close(handle); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ EXPORT_SYMBOL(avm_urlader_env_get_value3); EXPORT_SYMBOL(avm_urlader_env_unset_variable3); EXPORT_SYMBOL(avm_urlader_env_set_variable3); #endif /*--- #if defined(CONFIG_TFFS_ENV) ---*/