/*------------------------------------------------------------------------------------------*\ * * 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 #ifdef CONFIG_SMP #define __SMP__ #endif /*--- #ifdef CONFIG_SMP ---*/ #include #include #include #include #include #include #include #include #include /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ /*--- #define TFFS_DEBUG ---*/ #include "tffs_local.h" /*--- static unsigned int test_count; ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static unsigned int TFFS_mtd_number = (unsigned int)-1; static unsigned int TFFS_mtd_number2 = (unsigned int)-1; #define MAX_PAR 8 static struct _TFFS_Entry *TFFS_Global_Index[FLASH_FS_ID_LAST]; static unsigned int TFFS_Global_Index_created = 0; struct mtd_info *TFFS_mtd; unsigned int current_mtd = 0; unsigned int avail_mtd[2]; unsigned char *TFFS_Cleanup_Buffer = NULL; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Init(unsigned int mtd_number, unsigned int mtd_number2) { DBG((KERN_INFO "TFFS_Init(mtd%u, mtd%u)\n", mtd_number, mtd_number2)); TFFS_mtd_number = mtd_number; TFFS_mtd = get_mtd_device(NULL, TFFS_mtd_number); if(TFFS_mtd == 0) { DBG((KERN_ERR "TFFS_Init: can't get mtd%u\n", TFFS_mtd_number)); return (unsigned int)-ENXIO; } /*------------------------------------------------------------------------------------------*\ * prüfen welcher buffer der "richtige" ist \*------------------------------------------------------------------------------------------*/ TFFS_mtd_number2 = mtd_number2; if(TFFS_mtd) { int ret, retlen; unsigned int segment[2] = { 0, 0 }; union _tffs_segment_entry u; ret = MTD_READ(TFFS_mtd, 0, sizeof(union _tffs_segment_entry), &retlen, u.Buffer); if(u.Entry.ID == FLASH_FS_ID_SEGMENT) { segment[0] = TFFS_GET_SEGMENT_VALUE(&u); DBG((KERN_INFO "double_buffer(0): segment value %u\n", segment[0])); } else { DBG((KERN_INFO "double_buffer(0): no SEGMENT VALUE\n")); } put_mtd_device(TFFS_mtd); TFFS_mtd = get_mtd_device(NULL, TFFS_mtd_number2); if(TFFS_mtd == 0) { DBG((KERN_ERR "TFFS_Init: can't get mtd%u\n", TFFS_mtd_number2)); return (unsigned int)-ENXIO; } current_mtd = TFFS_mtd_number2; ret = MTD_READ(TFFS_mtd, 0, sizeof(union _tffs_segment_entry), &retlen, u.Buffer); if(u.Entry.ID == FLASH_FS_ID_SEGMENT) { segment[1] = TFFS_GET_SEGMENT_VALUE(&u); DBG((KERN_INFO "double_buffer(1): segment value %u\n", segment[1])); } else { DBG((KERN_INFO "double_buffer(1): no SEGMENT VALUE\n")); } if(segment[0] > segment[1]) { put_mtd_device(TFFS_mtd); TFFS_mtd = get_mtd_device(NULL, TFFS_mtd_number); current_mtd = TFFS_mtd_number; } if(segment[0] == 0 && segment[1] == 0) { panic("TFFS: no vallid filesystem"); } avail_mtd[0] = TFFS_mtd_number; avail_mtd[1] = TFFS_mtd_number2; DBG((KERN_INFO "double_buffer: use segment %u (avail: %u + %u)\n", current_mtd, avail_mtd[0], avail_mtd[1])); } DBG((KERN_INFO "mtd%u size=0x%x erasesize=0x%x\n", TFFS_mtd_number, TFFS_mtd->size, TFFS_mtd->erasesize)); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void TFFS_Deinit(void) { DBG((KERN_INFO "TFFS_Deinit()\n")); if(TFFS_mtd) put_mtd_device(TFFS_mtd); TFFS_mtd_number = (unsigned int)-1; TFFS_mtd = NULL; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void *TFFS_Open(void) { struct _tffs_open *TFFS; if(TFFS_mtd_number < 1 || TFFS_mtd_number > 6) { DBG((KERN_ERR "TFFS_Open() failed mtd_name number not correkt (is: mtd%u)\n", TFFS_mtd_number)); return 0; } TFFS = kmalloc(sizeof(struct _tffs_open), GFP_KERNEL); if(TFFS == NULL) { DBG((KERN_ERR "TFFS_Open: malloc(%u) failed\n", sizeof(struct _tffs_open))); return 0; } memset(TFFS, 0, sizeof(struct _tffs_open)); DBG((KERN_INFO "TFFS_Open: mtd open success (erasesize 0x%x size 0x%x flags 0x%x)\n", TFFS_mtd->erasesize, TFFS_mtd->size, TFFS_mtd->flags)); if(TFFS_Global_Index_created == 0) { TFFS_Create_Index(); TFFS_Global_Index_created = 1; } DBG((KERN_INFO "TFFS_Open: handle: 0x%x\n", (int)TFFS)); return TFFS; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void TFFS_Close(void *handle) { struct _tffs_open *TFFS = (struct _tffs_open *)handle; DBG((KERN_INFO "TFFS_Close(0x%x):", (int)handle)); if( TFFS_mtd->sync ) TFFS_mtd->sync(TFFS_mtd); kfree(TFFS); DBG((KERN_INFO " success\n")); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static void TFFS_Format_Callback(struct erase_info *instr) { DBG(("TFFS: mtd_erase_callback\n")); wake_up((wait_queue_head_t *)instr->priv); return; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Format(void *handle) { struct erase_info *erase; int ret=0; DECLARE_WAITQUEUE(wait,current); wait_queue_head_t wait_q; init_waitqueue_head(&wait_q); erase = (struct erase_info *)kmalloc(sizeof(struct erase_info), GFP_KERNEL); if(erase == NULL) { DBG((KERN_ERR "TFFS_Format: malloc(%u) failed\n", sizeof(struct erase_info))); return (unsigned int)-ENOMEM; } DBG((KERN_INFO "TFFS_Format: malloc(%u) success\n", sizeof(struct erase_info))); memset(erase, 0, sizeof(struct erase_info)); erase->mtd = TFFS_mtd; erase->addr = 0; erase->len = TFFS_mtd->size; erase->callback = TFFS_Format_Callback; erase->priv = (u_long)&wait_q; erase->next = 0; DBG((KERN_INFO "TFFS_Format(handle=0x%x): erase: addr %x len %x\n", (unsigned int)handle, erase->addr, erase->len)); ret = TFFS_mtd->erase(TFFS_mtd, erase); if( !ret ) { set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue( &wait_q, &wait); if( erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) { schedule(); } remove_wait_queue(&wait_q, &wait); set_current_state(TASK_RUNNING); ret = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0; if(ret) { DBG((KERN_ERR "Failed (callback) to erase mtd, region [0x%x, 0x%x]\n", erase->addr,erase->len)); } } else { DBG((KERN_ERR "Failed to erase mtd, region [0x%x, 0x%x]\n", erase->addr,erase->len)); ret = -EIO; } kfree(erase); return (unsigned int)ret; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Clear(void *handle, enum _tffs_id id) { return TFFS_Write(handle, id, NULL, 0, 0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int TFFS_Werkseinstellungen(void *handle) { enum _tffs_id id; unsigned int count = 0; DBG((KERN_INFO "TFFS_Werkseinstellungen(0x%x)\n", (int)handle)); for(id = FLASH_FS_ID_TICFG ; id <= FLASH_FS_ID_FIRMWARE_CONFIG_LAST ; id++) { if(TFFS_Global_Index[id] != (struct _TFFS_Entry *)FLASH_FS_ID_FREE) { unsigned int error = TFFS_Write(handle, id, NULL, 0, 0); if(error) { DBG((KERN_INFO "TFFS_Werkseinstellungen(0x%x): clear id 0x%x failed (%u cleared)\n", (int)handle, (int)id, count)); return error; } count++; } } DBG((KERN_INFO "TFFS_Werkseinstellungen(0x%x): success (%u cleared)\n", (int)handle, count)); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ enum _tffs_memcmp { tffs_memcmp_equal, tffs_memcmp_writeable, tffs_memcmp_clear_required }; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static enum _tffs_memcmp TFFS_Memcmp(unsigned char *FlashMemory, unsigned char *NewMemory, unsigned int Length) { unsigned int ret; unsigned short *_Flash = (unsigned short *)FlashMemory; unsigned short *_neuerWert = (unsigned short *)NewMemory; ret = memcmp(FlashMemory, NewMemory, Length); if(ret == 0) return tffs_memcmp_equal; #if 1 Length = (Length + 1) >> 1; while(Length--) { if((((*_Flash++) | ((~(*_neuerWert++)) & 0xFFFF)) != 0xFFFF)) { return tffs_memcmp_clear_required; } } return tffs_memcmp_writeable; #else return tffs_memcmp_clear_required; #endif } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Write(void *handle, enum _tffs_id Id, unsigned char *write_buffer, unsigned int write_length, unsigned int level) { int ret, retlen; struct _TFFS_Entry *E, Entry; struct _TFFS_Entry *E_ToClear = NULL, Entry_ToClear; unsigned int Len = 0; E = (struct _TFFS_Entry *)0; while((unsigned int)E + sizeof(struct _TFFS_Entry) + write_length < TFFS_mtd->size) { ret = MTD_READ(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret) return ret; /*---------------------------------------------------------------------------------------*\ * ID gefunden \*---------------------------------------------------------------------------------------*/ if(Entry.ID == (unsigned short)Id && Id < FLASH_FS_DROPABLE_DATA) { /*--- Alter Eintrag gefunden ----*/ DBG((KERN_INFO "alter Eintrag mit ID=%x gefunden ", Id)); /*-----------------------------------------------------------------------------------*\ * prüfen ob eintrag identisch oder überschreibbar \*-----------------------------------------------------------------------------------*/ if(Entry.Length == write_length) { unsigned char *buff = kmalloc(Entry.Length, GFP_KERNEL); if(!buff) { DBG((KERN_ERR "TFFS_Write: malloc(%u) failed\n", Entry.Length)); return (unsigned int)-ENOMEM; } DBG((KERN_INFO "TFFS_Write: malloc(%u) success\n", Entry.Length)); ret = MTD_READ(TFFS_mtd, (unsigned long)E + sizeof(struct _TFFS_Entry), Entry.Length, &retlen, buff); if(ret) return ret; switch(TFFS_Memcmp(buff, write_buffer, Entry.Length)) { case tffs_memcmp_equal: DBG((KERN_INFO "alter Eintrag mit neuem identisch\n")); kfree(buff); return 0; #if 1 case tffs_memcmp_writeable: DBG((KERN_INFO "alter Eintrag durch neuen überschreibbar\n")); ret = MTD_WRITE(TFFS_mtd, (unsigned long)E + sizeof(struct _TFFS_Entry), Entry.Length, &retlen, write_buffer); kfree(buff); return ret; #endif default: case tffs_memcmp_clear_required: break; } kfree(buff); } /*-----------------------------------------------------------------------------------*\ * gefundenen Eintrag auf FLASH_FS_ID_SKIP setzen \*-----------------------------------------------------------------------------------*/ Entry.ID = FLASH_FS_ID_SKIP; if(write_buffer == NULL) { ret = MTD_WRITE(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret || (retlen != sizeof(struct _TFFS_Entry))) { DBG((KERN_ERR "TFFS: write TFFS_Entry (id=SKIP) failed\n")); return ret || (unsigned int)-EIO; } DBG((KERN_INFO "geloescht\n")); TFFS_Global_Index[Id] = (struct _TFFS_Entry *)FLASH_FS_ID_FREE; } else { E_ToClear = E; Entry_ToClear = Entry; } /*-----------------------------------------------------------------------------------*\ * sollte es keine Daten für neuen satz geben dann sind wir fertig \*-----------------------------------------------------------------------------------*/ if(write_buffer == NULL) { DBG((KERN_INFO "(1) nur loeschen kein neuer Eintrag\n")); return 0; } } /*---------------------------------------------------------------------------------------*\ * freie ID gefunden \*---------------------------------------------------------------------------------------*/ if(Entry.ID == FLASH_FS_ID_FREE) { /*--- Freier Eintrag gefunden ----*/ DBG((KERN_INFO "freier Eintrag gefunden\n")); if(write_buffer == NULL) { DBG((KERN_INFO "(2) nur loeschen kein neuer Eintrag\n")); return 0; } Entry.ID = (unsigned short)Id; Entry.Length = (unsigned short)write_length; TFFS_Global_Index[Entry.ID] = E; ret = MTD_WRITE(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret || (retlen != sizeof(struct _TFFS_Entry))) { DBG((KERN_ERR "TFFS: write TFFS_Entry (id=0x%x) failed\n", Id)); return ret ? ret : (unsigned int)-EIO; } DBG((KERN_INFO "header mit id %x geschrieben\n", Id)); ret = MTD_WRITE(TFFS_mtd, (unsigned long)E + sizeof(struct _TFFS_Entry), Entry.Length, &retlen, write_buffer); if(ret || (retlen != Entry.Length)) { DBG((KERN_ERR "TFFS: write data (id=0x%x) failed\n", Id)); return ret ? ret : (unsigned int)-EIO; } DBG((KERN_INFO "%d bytes daten geschrieben\n", write_length)); if(E_ToClear != NULL) { ret = MTD_WRITE(TFFS_mtd, (unsigned long)E_ToClear, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry_ToClear); if(ret || (retlen != sizeof(struct _TFFS_Entry))) { DBG((KERN_ERR "TFFS: write TFFS_Entry (id=SKIP) failed\n")); return ret ? ret : (unsigned int)-EIO; } DBG((KERN_INFO "geloescht (postum) ID=0x%x Len=%u\n", Entry_ToClear.ID, Entry_ToClear.Length)); } /*-------------------------------------------------------------------------*\ Prüfen ob Filesystem mehr als 75% Voll ist \*-------------------------------------------------------------------------*/ { unsigned int Fuell = (unsigned int)E + Entry.Length; /*--- aktueller Fuellstand ---*/ Fuell *= 100; Fuell /= TFFS_mtd->size; DBG((KERN_INFO "fuellstand %u%%\n", Fuell)); if(Fuell > 75) { tffs_send_event(TFFS_EVENT_CLEANUP); } } return 0; } Len = (Entry.Length + 3) & ~0x03; E = (struct _TFFS_Entry *)((unsigned int)E + sizeof(struct _TFFS_Entry) + Len); } if(level == 0) { if(TFFS_Cleanup(handle) == 0) return TFFS_Write(handle, Id, write_buffer, write_length, 1); } return (unsigned int)-EIO; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Read(void *handle, enum _tffs_id Id, unsigned char *read_buffer, unsigned int *read_length) { unsigned int retlen, ret; struct _TFFS_Entry *E, Entry; unsigned int Len; DBG((KERN_INFO "TFFS_Read(handle=%x): id = 0x%x, max_length = %u\n", (unsigned int)handle, (unsigned int)Id, *read_length)); E = TFFS_Global_Index[Id]; if(E != (struct _TFFS_Entry *)FLASH_FS_ID_FREE) { DBG((KERN_INFO "Eintrag gefunden\n")); ret = MTD_READ(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret) return ret; Len = min((unsigned int)Entry.Length, *read_length); ret = MTD_READ(TFFS_mtd, (unsigned long)E + sizeof(struct _TFFS_Entry), Len, &retlen, read_buffer); if(ret) return ret; *read_length = retlen; DBG((KERN_INFO "daten kopiert\n")); return 0; } DBG((KERN_INFO "Eintrag %i nicht gefunden\n", Id)); return (unsigned int)-ENOENT; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Create_Index(void) { unsigned int retlen, ret; struct _TFFS_Entry *E, Entry; unsigned int Len; unsigned int i; for(i = 0 ; i < FLASH_FS_ID_LAST ; i++) { TFFS_Global_Index[i] = (struct _TFFS_Entry *)FLASH_FS_ID_FREE; } E = (struct _TFFS_Entry *)0; DBG((KERN_INFO "TFFS_Create_Index(): ")); while((unsigned int)E + sizeof(struct _TFFS_Entry) < TFFS_mtd->size) { ret = MTD_READ(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret) return ret; if(Entry.ID >= (unsigned short)FLASH_FS_ID_LAST) { /*--- Eintrag gefunden ----*/ DBG((KERN_INFO " [end found]\n")); return 0; } DBG((KERN_INFO " [<0x%x> %u bytes]\n", Entry.ID, Entry.Length)); /*--- doppelter Eintrag gefunden, diesen Eintrag löschen ---*/ if(TFFS_Global_Index[Entry.ID] != (struct _TFFS_Entry *)FLASH_FS_ID_FREE) { if(Entry.ID != FLASH_FS_ID_SKIP) { DBG((KERN_ERR " [<0x%x> %u bytes, cleared]\n", Entry.ID, Entry.Length)); Entry.ID = FLASH_FS_ID_SKIP; ret = MTD_WRITE(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret) return ret; } } else { TFFS_Global_Index[Entry.ID] = E; } Len = (Entry.Length + 3) & ~0x03; E = (struct _TFFS_Entry *)((unsigned int)E + sizeof(struct _TFFS_Entry) + Len); } DBG((KERN_INFO " [filesystem full]\n")); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Cleanup(void *handle) { unsigned int retlen, ret; struct _TFFS_Entry *E, *pEntry; unsigned int Len, SkipCount = 0; unsigned char *P; unsigned int current_number = 0; DBG((KERN_INFO "TFFS_Cleanup(handle=%x): ", (unsigned int)handle)); if(TFFS_Cleanup_Buffer == NULL) { TFFS_Cleanup_Buffer = vmalloc(TFFS_mtd->size); if(TFFS_Cleanup_Buffer == NULL) { DBG((KERN_ERR "TFFS_Cleanup: malloc(%u) failed\n", TFFS_mtd->size)); return (unsigned int)-ENOMEM; } DBG((KERN_INFO "TFFS_Cleanup: malloc(%u) success\n", TFFS_mtd->size)); } E = (struct _TFFS_Entry *)0; P = TFFS_Cleanup_Buffer; while((unsigned int)E + sizeof(struct _TFFS_Entry) < TFFS_mtd->size) { pEntry = (struct _TFFS_Entry *)P; ret = MTD_READ(TFFS_mtd, (unsigned long)E, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)pEntry); if(ret) { return ret; } if(pEntry->ID >= (unsigned short)FLASH_FS_ID_LAST) { /*--- Eintrag gefunden ----*/ DBG((KERN_INFO " [end found]\n")); break; } Len = (pEntry->Length + 3) & ~0x03; if(pEntry->ID != FLASH_FS_ID_SKIP) { P += sizeof(struct _TFFS_Entry *); ret = MTD_READ(TFFS_mtd, (unsigned long)E + sizeof(struct _TFFS_Entry), pEntry->Length, &retlen, (unsigned char *)P); if(ret) { return ret; } DBG((KERN_INFO " [<0x%x> %u bytes]\n", pEntry->ID, pEntry->Length)); P += Len; } else { SkipCount++; DBG((KERN_INFO " [SKIP %u bytes]\n", pEntry->Length)); } E = (struct _TFFS_Entry *)((unsigned int)E + sizeof(struct _TFFS_Entry) + Len); } DBG((KERN_INFO " [%u data records skiped]\n", SkipCount)); if(SkipCount == 0) { DBG((KERN_INFO "TFFS_Cleanup: no IDs skiped, leave it as it is\n")); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ { union _tffs_segment_entry *pu; unsigned int other = current_mtd == avail_mtd[0] ? avail_mtd[1] : avail_mtd[0]; DBG((KERN_INFO " [double buffer: close old mtd, open mtd%u]\n", other)); put_mtd_device(TFFS_mtd); TFFS_mtd = get_mtd_device(NULL, other); if(TFFS_mtd == 0) { panic("TFFS_Cleanup: can't get mtd%u\n", other); return (unsigned int)-ENXIO; } pu = (union _tffs_segment_entry *)TFFS_Cleanup_Buffer; if(pu->Entry.ID != FLASH_FS_ID_SEGMENT) { panic("TFFS_Cleanup: flash segment %u file invallid\n", current_mtd); } current_mtd = other; current_number = TFFS_GET_SEGMENT_VALUE(pu); DBG((KERN_INFO " [double buffer: read current number %u]\n", current_number)); TFFS_SET_SEGMENT_VALUE(pu, 0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ DBG((KERN_INFO " [erase filesystem]\n")); ret = TFFS_Format(handle); if(ret) { DBG((KERN_ERR "TFFS_Cleanup: format failed\n")); return ret; } DBG((KERN_INFO " [write filesystem]\n")); ret = MTD_WRITE(TFFS_mtd, 0, (unsigned int)P - (unsigned int)TFFS_Cleanup_Buffer, &retlen, (unsigned char *)TFFS_Cleanup_Buffer); if(ret) return ret; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ { union _tffs_segment_entry u; u.Entry.ID = FLASH_FS_ID_SEGMENT; u.Entry.Length = sizeof(unsigned int); current_number++; DBG((KERN_INFO " [double buffer: write current number %u]\n", current_number)); TFFS_SET_SEGMENT_VALUE(&u, current_number); ret = MTD_WRITE(TFFS_mtd, 0, sizeof(union _tffs_segment_entry), &retlen, (unsigned char *)&u); if(ret) { return ret; } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ DBG((KERN_INFO " [recreate index]\n")); TFFS_Create_Index(); DBG((KERN_INFO "TFFS_Cleanup: success\n")); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ unsigned int TFFS_Info(void *handle, unsigned int *Fill) { unsigned int retlen, ret; struct _TFFS_Entry *E, Entry; unsigned int Count, Max = 0; DBG((KERN_INFO "TFFS_Info(handle=%x): ", (unsigned int)handle)); for(Count = 0, E = 0 ; Count < FLASH_FS_ID_LAST ; Count++) { E = TFFS_Global_Index[Count]; if(E != (struct _TFFS_Entry *)FLASH_FS_ID_FREE) { DBG((KERN_INFO "E = 0x%x", (unsigned int)E)); if(Max < (unsigned int)E) { Max = (unsigned int)E; } } } if(!Max) { *Fill = 0; return 0; } DBG((KERN_INFO "Header des hoechsten Eintrags lesen (0x%x)\n", Max)); ret = MTD_READ(TFFS_mtd, (unsigned long)Max, sizeof(struct _TFFS_Entry), &retlen, (unsigned char *)&Entry); if(ret) return ret; DBG((KERN_INFO " [<0x%x> %u bytes]\n", Entry.ID, Entry.Length)); Max += Entry.Length; *Fill = (Max * 100) / TFFS_mtd->size; DBG((KERN_INFO "TFFS_Info: Fill=%u%% success\n", *Fill)); return 0; } EXPORT_SYMBOL(TFFS_Open); EXPORT_SYMBOL(TFFS_Close); EXPORT_SYMBOL(TFFS_Read); EXPORT_SYMBOL(TFFS_Write);