/*------------------------------------------------------------------------------------------*\ * * 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 #include #include #include #include #if defined(CONFIG_PROC_FS) #include #endif /*--- #if defined(CONFIG_PROC_FS) ---*/ #include #include /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- #define TFFS_DEBUG ---*/ #include "tffs_local.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int tffs3_mtd[2] = { CONFIG_TFFS_MTD_DEVICE_0, CONFIG_TFFS_MTD_DEVICE_1 }; MODULE_PARM_DESC (tffs3_mtd, "MTD device used for tiny flash file system with double buffering"); MODULE_DESCRIPTION("TFFS 'tiny flash file system with double buffering' driver version 2.2"); MODULE_SUPPORTED_DEVICE("MTD[0..n]"); MODULE_LICENSE("GPL"); #define TFFS3_MODULE_VERSION "3.0" MODULE_VERSION(TFFS3_MODULE_VERSION); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *tffs_proc; #endif /*--- #ifdef CONFIG_PROC_FS ---*/ #ifdef TFFS_BLOCK_MTD /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _tffs_bdev tffs3_bdev = { use_bdev: 0, size: 0 }; #endif /*--- #ifdef TFFS_BLOCK_MTD ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static void tffs3_cleanup(void); struct file_operations tffs3_fops = { owner: THIS_MODULE, open: tffs3_open, flush: tffs3_flush, release: tffs3_release, read: tffs3_read, write: tffs3_write, ioctl: tffs3_ioctl, }; struct _tffs tffs3; char *panic_log_workspace = NULL; /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static int tffs_thread(void *data) { struct _tffs *my_tffs; int result; void *handle; my_tffs = (struct _tffs *) data; my_tffs->thread_state = tffs3_thread_state_init; handle = TFFS3_Open(tffs3_mode_write); BUG_ON( ! handle); result = 0; do{ pr_debug("[%s] waiting for events\n", __func__); my_tffs->thread_state = tffs3_thread_state_idle; if(wait_event_interruptible(my_tffs->event_wq, test_and_clear_bit(TFFS_EVENT_BIT_TRIGGER, &my_tffs->pending_events))) { pr_err("[%s] interrupted while waiting for events, exiting\n", __func__); result = -EINTR; break; } my_tffs->thread_state = tffs3_thread_state_process; my_tffs->request_count++; /*--- auswerten des Events ---*/ pr_debug("[%s] processing events 0x%08lx\n", __func__, my_tffs->pending_events); if (kthread_should_stop() || test_and_clear_bit(TFFS_EVENT_BIT_CLEANUP, &my_tffs->pending_events)) { pr_debug("[%s] Cleanup\n", __func__); TFFS3_Cleanup(handle); } }while(!kthread_should_stop()); TFFS3_Close(handle); pr_info("[%s] event thread dead\n", __func__); my_tffs->thread_state = tffs3_thread_state_down; my_tffs->kthread = NULL; return result; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ void tffs3_send_event(unsigned int event) { unsigned int i = 0; pr_debug("[%s] Called with event 0x%08x\n", __func__, event); event &= ~(TFFS_EVENT_TRIGGER); if(event == 0){ return; } do{ i = ffs(event); set_bit(i - 1, &tffs3.pending_events); event >>= i; }while(event); set_bit(TFFS_EVENT_BIT_TRIGGER, &tffs3.pending_events); wake_up_interruptible_sync(&tffs3.event_wq); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void tffs3_init_cleanup(void) { #if defined(CONFIG_PROC_FS) if(tffs_proc) remove_proc_entry( "tffs", 0); #endif /*--- #if defined(CONFIG_PROC_FS) ---*/ if(tffs3.cdev_ticfg) { kobject_put(&tffs3.cdev_ticfg->kobj); cdev_del(tffs3.cdev_ticfg); } if(tffs3.cdev) { kobject_put(&tffs3.cdev->kobj); cdev_del(tffs3.cdev); } unregister_chrdev_region(tffs3.device, 1); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int #if defined(CONFIG_TFFS_MODULE) __init #endif tffs3_init(void) { int reason; if(tffs2_active()){ pr_info("[%s] TFFS version 2 running, not starting up version 3\n", __func__); return 0; } memset(&tffs3 , 0x0, sizeof(tffs3)); tffs3.device = MKDEV(0, 0); /*--- reason = register_chrdev_region(tffs3.device, 1, "tffs"); ---*/ reason = alloc_chrdev_region(&tffs3.device, 0, 1, "tffs"); if(reason < 0) { /*--- DBG((KERN_ERR "[tffs] alloc_chrdev_region failed: reason %d!\n", reason)); ---*/ DBG((KERN_ERR "[tffs3] register_chrdev_region failed: reason %d!\n", reason)); return -ERESTARTSYS; } tffs3.cdev_ticfg = 0; tffs3.cdev = cdev_alloc(); if (!tffs3.cdev) { DBG((KERN_ERR "[tffs3] cdev_alloc failed!\n")); tffs3_cleanup(); return -ERESTARTSYS; } tffs3.cdev->owner = tffs3_fops.owner; tffs3.cdev->ops = &tffs3_fops; kobject_set_name(&(tffs3.cdev->kobj), "tffs0"); if(cdev_add(tffs3.cdev, tffs3.device, 256)) { DBG((KERN_ERR "[tffs3] cdev_add failed!\n")); tffs3_cleanup(); tffs3_init_cleanup(); return -ERESTARTSYS; } if(TFFS3_Init()) { tffs3_cleanup(); tffs3_init_cleanup(); DBG((KERN_ERR "[tffs3] TFFS_Init failed!\n")); return -ERESTARTSYS; } init_waitqueue_head(&tffs3.event_wq); DBG((KERN_INFO "[tffs3] Character device init successfull \n")); # ifdef CONFIG_PROC_FS if ((tffs_proc = create_proc_entry( "tffs", 0, 0 ))) { tffs_proc->read_proc = tffs3_read_proc; tffs_proc->write_proc = tffs3_write_proc; } # endif tffs3.thread_state = tffs3_thread_state_off; tffs3.kthread = kthread_run(tffs_thread, (void *)&tffs3, "tffs3d"); BUG_ON((tffs3.kthread == NULL) || IS_ERR((void *)tffs3.kthread)); printk("TFFS: tiny flash file system driver. GPL (c) AVM Berlin (Version %s)\n", TFFS3_MODULE_VERSION); # ifdef CONFIG_SYSCTL avm_urlader_env_init3(); # endif /* CONFIG_SYSCTL */ panic_log_workspace = kmalloc(PANIC_LOG_WRKSPC_SIZE, GFP_ATOMIC); if(panic_log_workspace == NULL) { pr_err("[%s] WARNING - no panic log buffer reserved\n", __FUNCTION__); } return 0; } #if defined(CONFIG_TFFS3_MODULE) module_init(tffs3_init); #endif #if defined(CONFIG_TFFS3) late_initcall(tffs3_init); #endif /*--- #if defined(CONFIG_TFFS) ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ static void tffs3_cleanup(void) { #if 0 #if defined(MODLE) DBG((KERN_INFO "%s: unregister_chrdev(%u)\n", MODULE_NAME, tffs3.major)); if(down_interruptible(&tffs3_sema)) { DBG((KERN_ERR "%s: tffs3_cleanup: down_interruptible() failed\n", MODULE_NAME)); return; } #ifdef CONFIG_SYSCTL avm_urlader_env_exit3(); #endif /* CONFIG_SYSCTL */ if (tffs_kthread) { DBG((KERN_INFO "%s: Terminating thread ", MODULE_NAME)); kthread_stop((struct task_struct *)tffs_kthread); DBG(("done.\n")); } TFFS_Deinit(); tffs_init_cleanup(); up(&tffs3_sema); kfree(panic_log_buf3); panic_log_buf3 = NULL; #endif /*--- #if defined(MODLE) ---*/ return; #endif } module_exit(tffs3_cleanup);