/*
* Copyright (C) 1994-1997 Claus-Justus Heine
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, 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; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
USA.
*
* This file implements a "generic" interface between the *
* zftape-driver and a compression-algorithm. The *
* compression-algorithm currently used is a LZ77. I use the *
* implementation lzrw3 by Ross N. Williams (Renaissance *
* Software). The compression program itself is in the file
* lzrw3.c * and lzrw3.h. To adopt another compression algorithm
* the functions * zft_compress() and zft_uncompress() must be
* changed * appropriately. See below.
*/
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/zftape.h>
#include <asm/uaccess.h>
#include "../zftape/zftape-init.h"
#include "../zftape/zftape-eof.h"
#include "../zftape/zftape-ctl.h"
#include "../zftape/zftape-write.h"
#include "../zftape/zftape-read.h"
#include "../zftape/zftape-rw.h"
#include "../compressor/zftape-compress.h"
#include "../zftape/zftape-vtbl.h"
#include "../compressor/lzrw3.h"
/*
* global variables
*/
/* I handle the allocation of this buffer as a special case, because
* it's size varies depending on the tape length inserted.
*/
/* local variables
*/
static void *zftc_wrk_mem = NULL;
static __u8 *zftc_buf = NULL;
static void *zftc_scratch_buf = NULL;
/* compression statistics
*/
static unsigned int zftc_wr_uncompressed = 0;
static unsigned int zftc_wr_compressed = 0;
static unsigned int zftc_rd_uncompressed = 0;
static unsigned int zftc_rd_compressed = 0;
/* forward */
static int zftc_write(int *write_cnt,
__u8 *dst_buf, const int seg_sz,
const __u8 __user *src_buf, const int req_len,
const zft_position *pos, const zft_volinfo *volume);
static int zftc_read(int *read_cnt,
__u8 __user *dst_buf, const int to_do,
const __u8 *src_buf, const int seg_sz,
const zft_position *pos, const zft_volinfo *volume);
static int zftc_seek(unsigned int new_block_pos,
zft_position *pos, const zft_volinfo *volume,
__u8 *buffer);
static void zftc_lock (void);
static void zftc_reset (void);
static void zftc_cleanup(void);
static void zftc_stats (void);
/* compressed segment. This conforms to QIC-80-MC, Revision K.
*
* Rev. K applies to tapes with `fixed length format' which is
* indicated by format code 2,3 and 5. See below for format code 4 and 6
*
* 2 bytes: offset of compression segment structure
* 29k > offset >= 29k-18: data from previous segment ens in this
* segment and no compressed block starts
* in this segment
* offset == 0: data from previous segment occupies entire
* segment and continues in next segment
* n bytes: remainder from previous segment
*
* Rev. K:
* 4 bytes: 4 bytes: files set byte offset
* Post Rev. K and QIC-3020/3020:
* 8 bytes: 8 bytes: files set byte offset
* 2 bytes: byte count N (amount of data following)
* bit 15 is set if data is compressed, bit 15 is not
* set if data is uncompressed
* N bytes: data (as much as specified in the byte count)
* 2 bytes: byte count N_1 of next cluster
* N_1 bytes: data of next cluset
* 2 bytes: byte count N_2 of next cluster
* N_2 bytes: ...
*
* Note that the `N' byte count accounts only for the bytes that in the
* current segment if the cluster spans to the next segment.
*/
typedef struct
{
int cmpr_pos; /* actual position in compression buffer */
int cmpr_sz; /* what is left in the compression buffer
* when copying the compressed data to the
* deblock buffer
*/
unsigned int first_block; /* location of header information in
* this segment
*/
unsigned int count; /* amount of data of current block
* contained in current segment
*/
unsigned int offset; /* offset in current segment */
unsigned int spans:1; /* might continue in next segment */
unsigned int uncmpr; /* 0x8000 if thi