/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2004-2014 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 \*------------------------------------------------------------------------------------------*/ #ifdef CONFIG_SMP #define __SMP__ #endif /*--- #ifdef CONFIG_SMP ---*/ #include #include #include #include /*--- #include ---*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ /*--- #define TFFS_DEBUG ---*/ #include "tffs_local.h" /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ struct tffs3_cfg_funcs cfg_funcs = { #if defined(CONFIG_TFFS_DEV_LEGACY) .legacy = TFFS3_LGCY_Configure, #endif #if defined(CONFIG_TFFS_DEV_MTDNAND) .mtdnand = TFFS3_NAND_Configure, #endif #if defined(CONFIG_TFFS_DEV_CACHE) .cache = TFFS3_CACHE_Configure, #endif #if defined(CONFIG_TFFS_DEV_EFI) .efi = TFFS3_EFI_Configure, #endif #if defined(CONFIG_TFFS_DEV_REMOTE) .remote = TFFS3_REMOTE_Configure, .server = TFFS3_SERVER_Configure, #endif #if defined(CONFIG_TFFS_DEV_MTDNOR) .mtdnor = TFFS3_NOR_Configure, #endif #if defined(CONFIG_TFFS_DEV_BDEV) .bdev = TFFS3_BDEV_Configure, #endif }; #if defined(CONFIG_TFFS_DEV_LEGACY) extern int tffs_mtd[2]; #endif struct tffs_panic_cb { struct mtd_info *mtd; panic_setup_cb panic_setup_fn; unsigned int setup_done; struct list_head panic_cb_list; }; static tffs_device TFFS_device; #define PANIC_LOCK_BIT 0 #define PANIC_USE_BIT 1 #define PANIC_LOCK (1 << PANIC_LOCK_BIT) #define PANIC_USE (1 << PANIC_USE_BIT) static int lock_device(tffs_device *device, struct tffs_core_handle *handle) { int result; result = 0; if(handle != &(device->panic_handle)){ /* normal mode operations need to acquire the outer lock. * This lock implements the waiting queue for non-panic-mode operations */ result = down_interruptible(&(device->outer_lock)); /* TFFS might have been panic locked while we were waiting. * Release semaphore and return without trying to get the inner lock. */ smp_mb(); if(result == 0 && (device->panic_mode & PANIC_LOCK)){ up(&(device->outer_lock)); result = -EBUSY; } if(result != 0){ goto err_out; } } /* the inner lock controls access to the back end. * This one is used to coordinate normal and panic mode accesses, * hence only a down_trylock() */ result = down_trylock(&(device->inner_lock)); if(result != 0){ if(handle != &(device->panic_handle)){ up(&(device->outer_lock)); } result = -EBUSY; } err_out: return result; } static void unlock_device(tffs_device *device, struct tffs_core_handle *handle) { up(&(device->inner_lock)); if(handle != &(device->panic_handle)){ up(&(device->outer_lock)); } } #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) /* Functions to sync urlader env writes back to EFI for puma7. * Remove these when a proper solution is available. */ #include #include #define EFI_TFFS_TOKENSPACE \ EFI_GUID( 0x692cccd4, 0xd3b9, 0x5e94, 0xba, 0x7e, 0x50, 0xaa, 0xac, 0xd8, 0xa3, 0x8d ) struct efi_sync_work { struct work_struct work; unsigned int id; enum tffs3_notify_event event; }; static struct nls_table *efi_sync_nls_tbl; static noinline int ascii2utf(char *ascii, efi_char16_t *utf, size_t len) { unsigned int i; int result; // pr_err("[%s-%d] Called. ctx: %p nls: %p ascii: %s len: %d\n", __func__, __LINE__, ctx, ctx->nls_tbl, ascii, len); result = 0; i = 0; while(ascii[i] != '\0' && len > 0){ #if 1 result = efi_sync_nls_tbl->char2uni(&(ascii[i]), 42, &(utf[i])); if(result < 0){ goto err_out; } #else utf[i] = ascii[i]; #endif ++i; if(--len == 0){ result = -ENOMEM; break; } } utf[i] = '\0'; // pr_err("[%s-%d] Called. utf: %ls len: %d\n", __func__, __LINE__, utf, len); err_out: return result; } static void efi_sync_init(void) { efi_sync_nls_tbl = NULL; if(!efi_enabled(EFI_BOOT)){ pr_err("[%s] EFI services not available\n", __func__); return; } efi_sync_nls_tbl = load_nls("ascii"); if(efi_sync_nls_tbl == NULL){ pr_err("[%s] Unable to load NLS table\n", __func__); } return; } static void efi_sync_do(char *var, char *val) { efi_char16_t efi_name[256]; size_t write_length; int result; result = ascii2utf(var, efi_name, ARRAY_SIZE(efi_name)); if(result < 0){ pr_err("[%s] ascii2utf failed: %d\n", __func__, result); goto err_out; } write_length = val ? strlen(val) + 1 : 0; result = efivar_entry_set_safe(efi_name, EFI_TFFS_TOKENSPACE, (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS), true, write_length, val); if(result == 0){ return; } err_out: pr_err("[%s] EFI sync failed for \"%s\"=\"%s\"; result=%d\n", __func__, var, val, result); return; } static void tffs_efi_sync_work_func(struct work_struct *work) { struct efi_sync_work *es_work = container_of(work, struct efi_sync_work, work); char *var, *val; pr_debug("[%s] Called for ID 0x%x event %s\n", __func__, es_work->id, es_work->event == tffs3_notify_clear ? "clear" : es_work->event == tffs3_notify_update ? "update" : es_work->event == tffs3_notify_reinit ? "reinit" : "unknown"); /* Lookup idx in nametable first. */ val = NULL; var = avm_urlader_env_get_id_name(es_work->id); pr_debug("[%s] env_get_variable=%s\n", __func__, var); if(var == NULL){ goto out; } if(es_work->event == tffs3_notify_update){ /* We don't know what was written/updated here so we need to read it * from TFFS again. */ val = avm_urlader_env_get_value_by_id(es_work->id); } if(es_work->event == tffs3_notify_update || es_work->event == tffs3_notify_clear){ pr_debug("[%s] sync id %x, var=%s, val=%s\n", __func__, es_work->id, var, val); efi_sync_do(var, val); } out: kfree(var); kfree(val); kfree(es_work); } #endif /*--- #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) ---*/ static void __attribute__((unused)) notify_cb(void *priv __attribute__((unused)), unsigned int id, enum tffs3_notify_event event) { pr_debug("[%s] Called for ID 0x%x event %s\n", __func__, id, event == tffs3_notify_clear ? "clear" : event == tffs3_notify_update ? "update" : event == tffs3_notify_reinit ? "reinit" : "unknown"); #if IS_ENABLED(CONFIG_TFFS_DEV_REMOTE) if(TFFS_device.server_state == tffs3_module_running && TFFS_device.server.notify != NULL){ TFFS_device.server.notify(TFFS_device.server.priv, id, event); } #endif /* CONFIG_TFFS_DEV_REMOTE */ #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) /* On ATOM side: lookup name table; write to EFI on match; */ { struct efi_sync_work *es_work = kmalloc(sizeof(*es_work), GFP_KERNEL); if(es_work == NULL){ pr_err("[%s] oom.\n", __func__); } /* Do this later to avoid possible recursion/locking problems * when we need to call into TFFS again. */ es_work->id = id; es_work->event = event; INIT_WORK(&es_work->work, tffs_efi_sync_work_func); schedule_work(&es_work->work); } #endif /*--- #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) ---*/ } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Early_Init(void) { sema_init(&TFFS_device.outer_lock, 1); sema_init(&TFFS_device.inner_lock, 1); INIT_LIST_HEAD(&TFFS_device.panic_cb_list); TFFS_device.panic_mode = 0; init_completion(&TFFS_device.backend_ready); TFFS_device.initialised = 1; pr_debug("[%s] called\n", __func__); return 0; } arch_initcall(TFFS3_Early_Init); /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Register_NAND(struct mtd_info *mtd) { int result; pr_debug("[%s] Called\n", __func__); if(!TFFS_device.initialised){ pr_err("[%s] TFFS_device not initialised\n", __func__); return -EAGAIN; } result = -ENODEV; down(&TFFS_device.inner_lock); if(TFFS_device.backend_state == tffs3_module_init){ if(cfg_funcs.mtdnand){ result = cfg_funcs.mtdnand(&TFFS_device.backend, mtd); if(result == 0){ TFFS_device.backend_state = tffs3_module_configured; } } else { pr_err("[%s] No config function registered for NAND\n", __func__); } } else { pr_err("[%s] Backing device already registered.\n", __func__); result = -EINVAL; } up(&TFFS_device.inner_lock); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Register_LGCY(unsigned int mtd0, unsigned int mtd1) { int result; pr_debug("[%s] Called\n", __func__); if(!TFFS_device.initialised){ pr_err("[%s] TFFS_device not initialised\n", __func__); return -EAGAIN; } result = -ENODEV; down(&TFFS_device.inner_lock); if(TFFS_device.backend_state == tffs3_module_init){ if(cfg_funcs.legacy){ result = cfg_funcs.legacy(&TFFS_device.backend, mtd0, mtd1); if(result == 0){ TFFS_device.backend_state = tffs3_module_configured; } } else { pr_err("[%s] No config function registered for LGCY\n", __func__); } } else { pr_err("[%s] Backing device already registered.\n", __func__); result = -EINVAL; } up(&TFFS_device.inner_lock); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Register_EFI(void) { int result; pr_debug("[%s] Called\n", __func__); if(!TFFS_device.initialised){ pr_err("[%s] TFFS_device not initialised\n", __func__); return -EAGAIN; } result = -ENODEV; down(&TFFS_device.inner_lock); if(TFFS_device.backend_state == tffs3_module_init){ if(cfg_funcs.efi){ result = cfg_funcs.efi(&TFFS_device.backend); if(result == 0){ TFFS_device.backend_state = tffs3_module_configured; } } else { pr_err("[%s] No config function registered for EFI\n", __func__); } } else { pr_err("[%s] Backing device already registered.\n", __func__); result = -EINVAL; } up(&TFFS_device.inner_lock); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Register_REMOTE(unsigned int node_id) { int result; pr_debug("[%s] Called\n", __func__); if(!TFFS_device.initialised){ pr_err("[%s] TFFS_device not initialised\n", __func__); return -EAGAIN; } result = -ENODEV; down(&TFFS_device.inner_lock); if(TFFS_device.backend_state == tffs3_module_init){ if(cfg_funcs.remote){ result = cfg_funcs.remote(&TFFS_device.backend, node_id); if(result == 0){ TFFS_device.backend_state = tffs3_module_configured; } } else { pr_err("[%s] No config function registered for remote access\n", __func__); } } else { pr_err("[%s] Backing device already registered.\n", __func__); result = -EINVAL; } up(&TFFS_device.inner_lock); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Register_SERVER(unsigned int node_id) { int result; pr_err("[%s] Called\n", __func__); result = 0; if(!TFFS_device.initialised){ pr_err("[%s] TFFS_device not initialised\n", __func__); return -EAGAIN; } result = -ENODEV; down(&TFFS_device.inner_lock); if(TFFS_device.server_state == tffs3_module_init){ if(cfg_funcs.server){ result = cfg_funcs.server(&TFFS_device.server, node_id); if(result == 0){ TFFS_device.server_state = tffs3_module_configured; } } else { pr_err("[%s] No config function registered for remote server\n", __func__); } } else { pr_err("[%s] Server already registered.\n", __func__); result = -EINVAL; } up(&TFFS_device.inner_lock); return result; } int TFFS3_Register_Panic_CB(struct mtd_info *mtd, panic_setup_cb panic_setup_fn) { struct tffs_panic_cb *panic_cb; int result = 0; pr_info("[%s] registering panic callback for mtd %s\n", __func__, mtd ? mtd->name : "NULL"); panic_cb = kzalloc(sizeof(*panic_cb), GFP_KERNEL); if(panic_cb == NULL){ pr_err("[%s] Unable to allocate memory.\n", __func__); result = -ENOMEM; goto err_out; } INIT_LIST_HEAD(&panic_cb->panic_cb_list); panic_cb->mtd = mtd; panic_cb->panic_setup_fn = panic_setup_fn; panic_cb->setup_done = 0; list_add_tail(&(panic_cb->panic_cb_list), &TFFS_device.panic_cb_list); err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void TFFS3_Backend_Ready(void) { complete_all(&TFFS_device.backend_ready); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void TFFS3_Wait_For_Backend(void) { if (TFFS_device.backend_state == tffs3_module_configured || IS_ENABLED(CONFIG_TFFS_DEV_CACHE_RAMONLY)) { complete_all(&TFFS_device.backend_ready); } else { pr_info("tffs: Waiting for backend to be available\n"); wait_for_completion(&TFFS_device.backend_ready); } } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Init(void) { int result; result = -ENODEV; pr_info("[%s] Called.\n", __func__); #if defined(CONFIG_TFFS_DEV_LEGACY) if(TFFS_device.backend_state == tffs3_module_init){ pr_err("[%s] No storage module registered, trying legacy fallback\n", __func__); result = TFFS3_Register_LGCY(tffs_mtd[0], tffs_mtd[1]); } #endif #if defined(CONFIG_TFFS_DEV_EFI) if(TFFS_device.backend_state == tffs3_module_init){ pr_err("[%s] No storage module registered, trying EFI fallback\n", __func__); result = TFFS3_Register_EFI(); } #endif #if IS_ENABLED(CONFIG_TFFS_DEV_REMOTE) #if defined(CONFIG_MACH_PUMA7) #if defined(CONFIG_X86_PUMA7) TFFS3_Register_SERVER(AVM_EVENT_TFFS_NODE_ARM); #else //PUMA7_arm TFFS3_Register_REMOTE(AVM_EVENT_TFFS_NODE_ATOM); #endif #endif #endif down(&TFFS_device.inner_lock); #if defined(CONFIG_TFFS_DEV_CACHE_RAMONLY) if(TFFS_device.backend_state ==tffs3_module_init){ TFFS_device.backend_state = tffs3_module_configured; } #endif if(TFFS_device.backend_state == tffs3_module_configured){ #if defined(CONFIG_TFFS_DEV_CACHE) result = TFFS3_CACHE_Configure(&TFFS_device.cache, &TFFS_device.backend); if(result != 0){ pr_err("[%s] Configuration of caching module failed with status %d\n", __func__, result); goto err_out; } TFFS_device.cache_state = tffs3_module_configured; #else // caching not enabled, use backend directly instead TFFS_device.cache = TFFS_device.backend; #endif // defined(CONFIG_TFFS_DEV_CACHE) if(TFFS_device.cache.setup == NULL){ pr_err("[%s] No cache/backend setup function registered.\n", __func__); result = -ENODEV; goto err_out; } result = TFFS_device.cache.setup(&TFFS_device.cache); if(result != 0){ TFFS_device.backend_state = tffs3_module_error; TFFS_device.cache_state = tffs3_module_error; goto err_out; } TFFS_device.backend_state = tffs3_module_running; TFFS_device.cache_state = tffs3_module_running; #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) efi_sync_init(); #endif /*--- #if defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) ---*/ #if IS_ENABLED(CONFIG_TFFS_DEV_REMOTE) // backend device is up. Try starting server if configured if(TFFS_device.server_state == tffs3_module_configured){ if(TFFS_device.server.setup){ result = TFFS_device.server.setup(&TFFS_device.server); if(result == 0){ TFFS_device.server_state = tffs3_module_running; if(TFFS_device.server.notify){ TFFS_device.cache.register_notify(&TFFS_device.cache, NULL, notify_cb); } } else { TFFS_device.server_state = tffs3_module_error; } } else { pr_err("[%s] No server setup function registered.\n", __func__); } // don't abort if server setup fails result = 0; } #elif defined(CONFIG_MACH_PUMA7) && defined(CONFIG_X86_PUMA7) /* Register this cb if either if DEV_REMOTE (see above) or * for atomp7. */ TFFS_device.cache.register_notify(&TFFS_device.cache, NULL, notify_cb); #endif // defined(CONFIG_TFFS_DEV_REMOTE) } else { pr_err("[%s] Backing device either not configured or already set up.\n", __func__); result = -EINVAL; } err_out: up(&TFFS_device.inner_lock); return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void TFFS3_Deinit(void) { pr_debug("[%s] called\n", __func__); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ struct tffs_core_handle *TFFS3_Open(enum _tffs_id id, enum tffs3_handle_mode mode) { struct tffs_core_handle *handle; bool have_outer, have_inner; int result; handle = NULL; result = 0; have_outer = false; have_inner = false; if(mode == tffs3_mode_panic){ TFFS3_Panic_Lock(); } else { /* Normal open. Refuse creating new handles if tha panic lock * has been set. */ smp_mb(); if(TFFS_device.panic_mode & PANIC_LOCK){ result = -EBUSY; } else { /* open calls for normal read/write need to acquire the outer lock. * The outer lock serves as a waiting queue for concurrent accesses. */ result = down_interruptible(&TFFS_device.outer_lock); if(result == 0){ have_outer = true; /* TFFS might have been panic locked while we were waiting. * If so, indicate failure. */ smp_mb(); if(TFFS_device.panic_mode & PANIC_LOCK){ result = -EBUSY; } } else { result = -ERESTARTSYS; } } } if(result != 0){ goto err_out; } /* The inner lock controls access to the back end device. * It coordinates between normal and panic mode operations, hence * the down_trylock() */ result = down_trylock(&TFFS_device.inner_lock); if(result == 0){ have_inner = true; } else { result = -EBUSY; goto err_out; } /* We made it through all the locking business, now we need to * get a handle */ if(mode == tffs3_mode_panic){ /* We are in panic mode, try to grab the special static handle */ if(test_and_set_bit(PANIC_USE_BIT, &TFFS_device.panic_mode) == 0){ handle = &TFFS_device.panic_handle; } } else { handle = kmalloc(sizeof(*handle), GFP_KERNEL); } if(handle == NULL) { pr_debug("[%s] getting %shandle failed\n", __func__, (mode == tffs3_mode_panic) ? "panic " : ""); result = -ENOMEM; goto err_out; } memset(handle, 0x0, sizeof(*handle)); handle->id = id; handle->mode = mode; /* We have our handle, now use it to open a handle on the back end device */ handle->core_priv = TFFS_device.cache.open(&TFFS_device.cache, handle); if(IS_ERR_OR_NULL(handle->core_priv)){ result = handle->core_priv == NULL ? -ENOMEM : PTR_ERR(handle->core_priv); handle->core_priv = NULL; } err_out: if(result != 0 && handle != NULL){ if(!IS_ERR_OR_NULL(handle->core_priv)){ (void) TFFS_device.cache.close(&TFFS_device.cache, handle->core_priv); } if(handle == &TFFS_device.panic_handle){ smp_mb__before_clear_bit(); clear_bit(PANIC_USE_BIT, &TFFS_device.panic_mode); smp_mb__after_clear_bit(); } else { kfree(handle); } handle = NULL; } if(have_inner){ up(&TFFS_device.inner_lock); } if(have_outer){ up(&TFFS_device.outer_lock); } if(result != 0){ handle = ERR_PTR(result); } return handle; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Close(struct tffs_core_handle *handle) { int result; if(handle == NULL){ result = -EBADF; goto err_out; } result = lock_device(&TFFS_device, handle); if(result != 0){ goto err_out; } result = TFFS_device.cache.close(&TFFS_device.cache, handle->core_priv); unlock_device(&TFFS_device, handle); if(result == 0){ /* only release handle if backend close was successful. Upper layer * might retry closing. */ if(handle == &TFFS_device.panic_handle){ smp_mb__before_clear_bit(); clear_bit(PANIC_USE_BIT, &TFFS_device.panic_mode); smp_mb__after_clear_bit(); } else { handle->core_priv = NULL; kfree(handle); } } err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Clear(struct tffs_core_handle *handle) { return TFFS3_Write(handle, NULL, 0, 1); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int TFFS3_Werkseinstellungen(struct tffs_core_handle *handle) { struct tffs_core_handle *tmp_handle; enum _tffs_id id; unsigned int count; int result; smp_mb(); if(TFFS_device.panic_mode & PANIC_LOCK){ return -EBUSY; } pr_debug("TFFS3_Werkseinstellungen(%p)\n", handle); result = 0; count = 0; for(id = FLASH_FS_ID_TICFG ; id <= FLASH_FS_ID_FIRMWARE_CONFIG_LAST ; id++){ tmp_handle = TFFS3_Open(id, tffs3_mode_write); if(IS_ERR_OR_NULL(tmp_handle)){ result = (tmp_handle == NULL) ? -ENOMEM : PTR_ERR(tmp_handle); goto err_out; } result = TFFS3_Clear(tmp_handle); TFFS3_Close(tmp_handle); if(result) { pr_debug("TFFS3_Werkseinstellungen(%p): clear id 0x%x failed (%u cleared)\n", handle, id, count); goto err_out; } ++count; } pr_debug("TFFS3_Werkseinstellungen(%p): success (%u cleared)\n", handle, count); err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Write(struct tffs_core_handle *handle, uint8_t *write_buffer, size_t write_length, unsigned int final) { size_t written; int result; if(write_buffer == NULL && write_length > 0){ result = -EINVAL; goto err_out; } result = lock_device(&TFFS_device, handle); if(result != 0){ goto err_out; } result = TFFS_device.cache.write(&TFFS_device.cache, handle->core_priv, write_buffer, write_length, &written, final); unlock_device(&TFFS_device, handle); err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Read(struct tffs_core_handle *handle, uint8_t *read_buffer, size_t *read_length) { int result; if(read_buffer == NULL || read_length == NULL){ result = -EFAULT; goto err_out; } if(*read_length == 0){ result = 0; goto err_out; } result = lock_device(&TFFS_device, handle); if(result != 0){ goto err_out; } result = TFFS_device.cache.read(&TFFS_device.cache, handle->core_priv, read_buffer, read_length); unlock_device(&TFFS_device, handle); err_out: return result; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int TFFS3_Cleanup(struct tffs_core_handle *handle) { int result; // pr_err("[%s] called\n", __func__); result = lock_device(&TFFS_device, handle); if(result != 0){ goto err_out; } result = TFFS_device.cache.cleanup(&TFFS_device.cache, handle->core_priv); unlock_device(&TFFS_device, handle); err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Create_Index(void) { int result; struct tffs_core_handle dummy; dummy.core_priv = NULL; dummy.id = 42; // does not matter dummy.mode = tffs3_mode_write; result = lock_device(&TFFS_device, &dummy); if(result != 0){ goto err_out; } result = TFFS_device.cache.reindex(&TFFS_device.cache); unlock_device(&TFFS_device, &dummy); err_out: return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int TFFS3_Info(struct tffs_core_handle *handle, unsigned int *Fill) { int result; result = lock_device(&TFFS_device, handle); if(result != 0){ goto err_out; } result = TFFS_device.cache.info(&TFFS_device.cache, Fill); unlock_device(&TFFS_device, handle); err_out: return result; } void TFFS3_Panic_Lock(void) { struct tffs_panic_cb *panic_cb; pr_debug("[%s] Called.\n", __func__); if(test_and_set_bit(PANIC_LOCK_BIT, &TFFS_device.panic_mode) == 0){ list_for_each_entry(panic_cb, &TFFS_device.panic_cb_list, panic_cb_list){ if(panic_cb->setup_done == 0){ panic_cb->panic_setup_fn(panic_cb->mtd); panic_cb->setup_done = 1; } } } } EXPORT_SYMBOL(TFFS3_Backend_Ready); EXPORT_SYMBOL(TFFS3_Register_NAND); EXPORT_SYMBOL(TFFS3_Register_LGCY); EXPORT_SYMBOL(TFFS3_Register_REMOTE); EXPORT_SYMBOL(TFFS3_Register_SERVER); EXPORT_SYMBOL(TFFS3_Open); EXPORT_SYMBOL(TFFS3_Close); EXPORT_SYMBOL(TFFS3_Read); EXPORT_SYMBOL(TFFS3_Write); EXPORT_SYMBOL(TFFS3_Panic_Lock); /* vim: set sw=4 ts=4 et : */