/*************************************************************
 *                                                           *
 *    ths  Filesystem                  04.10.94      V1.1    *
 *                                                           *
 *    Thomas Scheuermann     ths@ai-lab.fh-furtwangen.de     *
 *                                                           *
 *************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include "ths.h"
#include "ths_i.h"


void fatfree(struct super_block *s)
{
	int i;
	struct ths_sb_info *ths_sb;

	ths_sb = (struct ths_sb_info *)s->u.generic_sbp;

#ifdef DEBUG
	printk("fatfree\n");
#endif
/*
 * Speicher der Clusteradressen freigeben
 */

	for(i=0;i<ths_sb->AnzahlCluster+2;)
	{
		kfree_s(ths_sb->fat[i/2048],4096);
		i+=2048;
	}
}

void fatmem2(struct super_block *s)
{
	struct ths_sb_info *ths_sb;
	struct ths_buffer tbf;
	int i,k,t;
	unsigned short cl1,cl2,cluster,addr;
	unsigned char *data=NULL;

	ths_sb = (struct ths_sb_info *)s->u.generic_sbp;

#ifdef DEBUG
	printk("fatmem2\n");
#endif

/*
 * Speicher fuer alle Clusteradressen holen
 */

	for(i=0;i<ths_sb->AnzahlCluster+2;)
	{
		ths_sb->fat[i/2048] = (short *)kmalloc(4096,GFP_KERNEL);
		i+=2048;
	}

#ifdef DEBUG
	printk("Speicher erhalten : %d\n",i);
#endif


/*
 * k	: Nibble-Zaehler
 * addr : Adresse des Speicherblocks
 * i	: Byte vom Clustersektor
 * addr : Adresse im FAT-Speicher = Clusternummer
 */
	t = ths_sb->BitsProCluster/4;
	cl1 = 0;
	cl2 = 0;
	addr = 0;
	k = 0;

	for(i=0,addr=0;addr<(ths_sb->AnzahlCluster+2);)
	{
		if(!(i & 0x1ff))
		{
			if(ths_read_sektor(s,ths_sb->FatStart+(i>>9),&tbf))
			{
				printk("Fehler\n");
				return;
			}
			data = tbf.data[0];
		}
		cl1 = (short)data[i&0x1ff];
		k=(k+1)%t;
		if(!k)
		{
			cluster = (cl2 | ((cl1<<8)&0x0fff));
			(ths_sb->fat[addr/2048])[addr%2048] = cluster;
			addr++;
		}
		k=(k+1)%t;
		if(!k)
		{
			if(t==3)
			{
				cluster = ((cl2 & 0xf0) >> 4) | (cl1 << 4);
			}
			else
			{
				cluster = cl2 | (cl1 << 8);
			}
			(ths_sb->fat[addr / 2048])[addr % 2048] = cluster;
			addr++;
		}
		cl2 = cl1;
		i++;
		if(!(i & 0x1ff))
			ths_free_sektor(&tbf);
	}
	if(i & 0x1ff)
		ths_free_sektor(&tbf);
}


void cvffill(struct super_block *s)
{
	struct ths_sb_info *ths_sb;
	struct buffer_head *fbh;
	int i,j,clb;
	unsigned short cl1,cluster,test;
	unsigned char *data=NULL,b1=0;
	unsigned long fatsektor;

	ths_sb = (struct ths_sb_info *)s->u.generic_sbp;

#ifdef DEBUG
	printk("cvffill\n");
#endif

	cluster  = ths_sb->StartCluster;
	cl1 = cluster;
	ths_sb->cvf[0] = NULL;
	if(ths_sb->uBitsProCluster==12)
		test = 0x0fff;
	else
		test = 0xffff;
	for(i=0;cl1!=test;)
	{
		clb = (cluster*(ths_sb->uBitsProCluster>>2));
		fatsektor = ths_sb->uFATStart + ((clb>>1)/512);
		fbh = bread(s->s_dev,fatsektor>>1,BLOCK_SIZE);

		j=0;
		if(fatsektor&1)
			j=512;
		data = &(fbh->b_data[j]);
		b1 = data[(clb>>1) & 0x1ff];
		if(clb & 1)
			cluster = (unsigned short)(b1 & 0xf0)>>4;
		else
			cluster = (unsigned short)b1;

		if(((clb>1) & 0x1ff)==511)
		{
			brelse(fbh);
			fbh = bread(s->s_dev,(fatsektor+1)>>1,BLOCK_SIZE);
			j=0;
			if((fatsektor+1)&1)
				j=512;
			data = &(fbh->b_data[j]);
		}

		b1 = data[((clb>>1)+1) & 0x1ff];
		if(clb & 1)
			cluster |= (unsigned short)b1  << 4;
		else
			cluster |= (unsigned short)b1 << 8;

		if(ths_sb->uBitsProCluster == 12)
			cluster &=0xfff;
		brelse(fbh);
		if(cluster != cl1+1)
		{
			if(!(i%2048))
			{
				ths_sb->cvf[i/2048] = (short *)kmalloc(4096,GFP_KERNEL);
				ths_sb->cvf[i/2048+1] = NULL;
			}
			(ths_sb->cvf[i/2048])[i%2048] = cl1;
			i++;
			(ths_sb->cvf[i/2048])[i%2048] = cluster;
			i++;
#ifdef DEBUG
			printk("Nach %d folgt %d\n",cl1,cluster);
#endif
		}
		cl1 = cluster;
	}
#ifdef DEBUG
	printk("Luecken : %d\n",i/2);
#endif

}


void cvffree(struct super_block *s)
{
	int i;
	struct ths_sb_info *ths_sb;

	ths_sb = (struct ths_sb_info *)s->u.generic_sbp;

#ifdef DEBUG
	printk("cvffree\n");
#endif
/*
 * Speicher der Clusteradressen freigeben
 */

	for(i=0;ths_sb->cvf[i/2048]!=NULL;)
	{
		kfree_s(ths_sb->cvf[i/2048],4096);
		i+=2048;
	}
}
