/*------------------------------------------------------------------------------------------*\ * * 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) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ /*--- #define TFFS_DEBUG ---*/ #include "tffs_local.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void *tffs_alloc(voidpf opaque, uInt items, uInt size) { void *ptr; DBG((KERN_INFO "tffs_alloc(%s, 0x%x, 0x%x):\n", opaque, items, size)); ptr = kmalloc(items * size, GFP_KERNEL); if(ptr) { memset(ptr, 0, items * size); DBG((KERN_INFO " ptr=0x%x\n", ptr)); } else { DBG((KERN_ERR " failed\n")); } return ptr; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void tffs_free(voidpf opaque, voidpf address) { DBG((KERN_INFO "tffs_free(%s, 0x%x)\n", opaque, address)); kfree(address); } /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ int tffs_open(struct inode *inode, struct file *filp) { int minor = inode->i_rdev & 0xFF; DBG((KERN_INFO "%s: tffs_open: MAJOR %u MINOR %u\n", MODULE_NAME, (inode->i_rdev >> 8), minor)); 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->z_length = (32 * 1024) + 12; 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.zalloc = tffs_alloc; open_data->stream.zfree = tffs_free; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ if(filp->f_flags & O_WRONLY) { DBG((KERN_INFO "%s: open for write only\n", MODULE_NAME)); open_data->stream.opaque = "write"; open_data->stream.next_in = Z_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 = deflateInit2 (&open_data->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 9, /*--- (fast) smallest buffers ---*/ 2, /*--- use little memory ---*/ Z_DEFAULT_STRATEGY ); open_data->init_flag = 1; } else { /*--- (filp->f_flags & O_RDONLY) ---*/ DBG((KERN_INFO "%s: open for read only\n", MODULE_NAME)); open_data->stream.opaque = "read"; 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; } 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 = Z_NULL; open_data->stream.avail_out = 0; open_data->stream.total_out = 0; status = inflateInit2(&open_data->stream, 9); open_data->init_flag = 1; /*----------------------------------------------------------------------------------*\ \*----------------------------------------------------------------------------------*/ } } MOD_INC_USE_COUNT; 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 = Z_NULL; open_data->stream.avail_in = 0; status = deflate(&open_data->stream, Z_FINISH); DBG((KERN_INFO "Z_FINISH: 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) { 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)); TFFS_Write(open_data, open_data->id, open_data->z_Buffer, open_data->stream.total_out, 0); up(&tffs_sema); } status = 0; /*--- kein Fehler ---*/ } else { status = -EFAULT; } } vfree(open_data->z_Buffer); } TFFS_Close(filp->private_data); MOD_DEC_USE_COUNT; return status; }