/*------------------------------------------------------------------------------------------*\ * * 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 #if defined(CONFIG_PROC_FS) #include #endif /*--- #if defined(CONFIG_PROC_FS) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- #define TFFS_DEBUG ---*/ #include "tffs_local.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(TFFS_DEBUG) static void dump_buffer(char *text, unsigned int len, unsigned char *buffer) { int i; #define dump_buffer_block_size 128 for(i = 0 ; i < len ; i += dump_buffer_block_size) { printk("%s(%u bytes): 0x%x: % *B\n", text, len, len, len - i > dump_buffer_block_size ? dump_buffer_block_size : len - i, buffer + i); } } #endif /*--- #if defined(TFFS_DEBUG) ---*/ /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int tffs_open(struct inode *inode, struct file *filp) { int minor = MINOR(inode->i_rdev); int major = MAJOR(inode->i_rdev); DBG((KERN_INFO "%s: tffs_open: MAJOR %u MINOR %u\n", MODULE_NAME, MAJOR(inode->i_rdev), MINOR(inode->i_rdev))); /*--- printk(KERN_INFO "%s: tffs_open: MAJOR %u MINOR %u\n", MODULE_NAME, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); ---*/ if(down_interruptible(&tffs_sema)) { DBG((KERN_ERR "%s tffs_open: down_interruptible() failed\n", MODULE_NAME)); return -ERESTARTSYS; } if(!filp->private_data) { filp->private_data = TFFS_Open(); } if(!filp->private_data) { DBG((KERN_ERR "%s: tffs_open: TFFS_Open failed\n", MODULE_NAME)); up(&tffs_sema); return -ENOMEM; } if(filp->f_flags & O_APPEND) { DBG((KERN_ERR "%s: tffs_open: TFFS_Open O_APPEND not supported\n", MODULE_NAME)); up(&tffs_sema); return -EFAULT; } if(filp->f_flags & O_RDWR) { DBG(("%s: tffs_open: open O_RDONLY and O_WRONLY simultary not supported\n", MODULE_NAME)); up(&tffs_sema); return -EFAULT; } /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ if(minor) { int status; struct _tffs_open *open_data = (struct _tffs_open *)filp->private_data; memset((void *)open_data, 0, sizeof(*open_data)); open_data->id = minor; open_data->panic_mode = major == 0 ? 1 : 0; if(open_data->panic_mode) { printk("WARING: use tffs in panic mode (minor %d)\n", minor); } open_data->z_length = (32 * 1024) + 12; #ifdef CONFIG_TFFS_PANIC_LOG if(open_data->panic_mode) { static unsigned char static_z_Buffer[(32 * 1024) + 12]; open_data->z_Buffer = static_z_Buffer; } else #endif /*--- #ifdef CONFIG_TFFS_PANIC_LOG ---*/ open_data->z_Buffer = vmalloc(open_data->z_length); if(open_data->z_Buffer == NULL) { DBG((KERN_ERR "%s: tffs_open: no memory for z_buffer\n", MODULE_NAME)); TFFS_Close(filp->private_data); up(&tffs_sema); return -ENOMEM; } open_data->stream.data_type = Z_ASCII; open_data->stream.workspace = NULL; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ if(filp->f_flags & O_WRONLY) { int workspacesize = zlib_deflate_workspacesize(); if(open_data->panic_mode) { open_data->stream.workspace = kmalloc(workspacesize, GFP_ATOMIC); if(open_data->stream.workspace == NULL) { /*--- printk("WARING: no memory (len=%d)\n", workspacesize); ---*/ /*--- return -1; ---*/ open_data->stream.workspace = vmalloc(workspacesize); } } else { open_data->stream.workspace = vmalloc(workspacesize); } if(open_data->stream.workspace == NULL) { DBG((KERN_ERR "%s: tffs_open: no memory for (write) workspace\n", MODULE_NAME)); TFFS_Close(filp->private_data); if(open_data->panic_mode == 0) { vfree(open_data->z_Buffer); } up(&tffs_sema); return -ENOMEM; } else { DBG((KERN_INFO "%s: tffs_open: %u bytes (write) workspace (0x%p)\n", MODULE_NAME, workspacesize, open_data->stream.workspace)); } DBG((KERN_INFO "%s: open for write only\n", MODULE_NAME)); open_data->stream.next_in = NULL; open_data->stream.avail_in = 0; open_data->stream.total_in = 0; open_data->stream.next_out = open_data->z_Buffer; open_data->stream.avail_out = open_data->z_length; open_data->stream.total_out = 0; status = zlib_deflateInit(&open_data->stream, Z_DEFAULT_COMPRESSION); if(status != Z_OK) { DBG((KERN_ERR "%s: tffs_open: zlib_deflateInit failed, status = %d\n", MODULE_NAME, status)); } else { open_data->init_flag = 1; } open_data->init_flag = 1; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ } else { /*--- (filp->f_flags & O_RDONLY) ---*/ int workspacesize = zlib_inflate_workspacesize(); DBG((KERN_INFO "%s: open for read only\n", MODULE_NAME)); status = TFFS_Read(open_data, open_data->id, open_data->z_Buffer, &open_data->z_length); if(status) { vfree(open_data->z_Buffer); TFFS_Close(filp->private_data); up(&tffs_sema); DBG((KERN_INFO "%s: read failed, no file\n", MODULE_NAME)); return status; } #if defined(TFFS_DEBUG) dump_buffer("TFFS", open_data->z_length, open_data->z_Buffer); #endif /*--- #if defined(TFFS_DEBUG) ---*/ open_data->stream.next_in = open_data->z_Buffer; open_data->stream.avail_in = open_data->z_length; open_data->stream.total_in = 0; open_data->stream.next_out = NULL; open_data->stream.avail_out = 0; open_data->stream.total_out = 0; open_data->stream.workspace = vmalloc(workspacesize); if(open_data->stream.workspace == NULL) { DBG((KERN_ERR "%s: tffs_open: no memory for (read) workspace\n", MODULE_NAME)); TFFS_Close(filp->private_data); vfree(open_data->z_Buffer); up(&tffs_sema); return -ENOMEM; } else { DBG((KERN_INFO "%s: tffs_open: %u bytes (read) workspace (0x%p)\n", MODULE_NAME, workspacesize, open_data->stream.workspace)); } status = zlib_inflateInit(&open_data->stream); if(status != Z_OK) { DBG((KERN_ERR "%s: tffs_open: zlib_inflateInit failed, status = %d\n", MODULE_NAME, status)); } else { open_data->init_flag = 1; } /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ } } DBG((KERN_INFO "%s: tffs_open: TFFS_Open success flags=0x%x\n", MODULE_NAME, filp->f_flags)); up(&tffs_sema); return 0; } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int tffs_release(struct inode *inode, struct file *filp) { int status = 0; struct _tffs_open *open_data = (struct _tffs_open *)filp->private_data; if(open_data->id) { if(filp->f_flags & O_WRONLY) { open_data->stream.next_in = NULL; open_data->stream.avail_in = 0; status = zlib_deflate(&open_data->stream, Z_FINISH); DBG((KERN_INFO "Z_FINISH: zlib_deflate(total_in=%u next_in=0x%p avail_in=%u total_out=%u next_out=0x%p avail_out=%u): status = %d\n", (int)open_data->stream.total_in, open_data->stream.next_in, (int)open_data->stream.avail_in, (int)open_data->stream.total_out, open_data->stream.next_out, (int)open_data->stream.avail_out, status)); if(status == Z_STREAM_END) { zlib_deflateEnd(&open_data->stream); if(down_interruptible(&tffs_sema)) { printk(KERN_ERR "%s tffs_release: down_interruptible() failed\n", MODULE_NAME); } else { DBG((KERN_INFO "%s: tffs_release: write %u bytes for id 0x%x\n", MODULE_NAME, (int)open_data->stream.total_out, open_data->id)); #if defined(TFFS_DEBUG) dump_buffer("TFFS", open_data->stream.total_out, open_data->z_Buffer); #endif /*--- #if defined(TFFS_DEBUG) ---*/ TFFS_Write(open_data, open_data->id, open_data->z_Buffer, open_data->stream.total_out, open_data->panic_mode); up(&tffs_sema); } status = 0; /*--- kein Fehler ---*/ } else { status = -EFAULT; } } else { zlib_inflateEnd(&open_data->stream); } if(open_data->panic_mode == 0) { if(open_data->stream.workspace) vfree(open_data->stream.workspace); if(open_data->z_Buffer) vfree(open_data->z_Buffer); } } TFFS_Close(filp->private_data); return status; }