/*
 *  Code extracted from
 *  linux/kernel/hd.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/*
 *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
 *  in the early extended-partition checks and added DM partitions
 */

#include <linux/config.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/kernel.h>

struct gendisk *gendisk_head = NULL;

static int current_minor = 0;
extern int *blk_size[];
extern void rd_load(void);
extern int ramdisk_size;

/*
 * Create devices for each logical partition in an extended partition.
 * The logical partitions form a linked list, with each entry being
 * a partition table with two entries.  The first entry
 * is the real data partition (with a start relative to the partition
 * table start).  The second is a pointer to the next logical partition
 * (with a start relative to the entire extended partition).
 * We do not create a Linux partition for the partition tables, but
 * only for the actual data partitions.
 */

static void extended_partition(struct gendisk *hd, int dev)
{
	struct buffer_head *bh;
	struct partition *p;
	unsigned long first_sector, this_sector;
	int mask = (1 << hd->minor_shift) - 1;

	first_sector = hd->part[MINOR(dev)].start_sect;
	this_sector = first_sector;

	while (1) {
		if ((current_minor & mask) >= (4 + hd->max_p))
			return;
		if (!(bh = bread(dev,0,1024)))
			return;
	  /*
	   * This block is from a device that we're about to stomp on.
	   * So make sure nobody thinks this block is usable.
	   */
		bh->b_dirt=0;
		bh->b_uptodate=0;
		if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
			p = (struct partition *) (0x1BE + bh->b_data);
		/*
		 * Process the first entry, which should be the real
		 * data partition.
		 */
			if (p->sys_ind == EXTENDED_PARTITION ||
			    !(hd->part[current_minor].nr_sects = p->nr_sects))
				goto done;  /* shouldn't happen */
			hd->part[current_minor].start_sect = this_sector + p->start_sect;
			printk(" %s%c%d", hd->major_name,
				'a'+(current_minor >> hd->minor_shift),
				mask & current_minor);
			current_minor++;
			p++;
		/*
		 * Process the second entry, which should be a link
		 * to the next logical partition.  Create a minor
		 * for this just long enough to get the next partition
		 * table.  The minor will be reused for the real
		 * data partition.
		 */
			if (p->sys_ind != EXTENDED_PARTITION ||
			    !(hd->part[current_minor].nr_sects = p->nr_sects))
				goto done;  /* no more logicals in this partition */
			hd->part[current_minor].start_sect = first_sector + p->start_sect;
			this_sector = first_sector + p->start_sect;
			dev = ((hd->major) << 8) | current_minor;
			brelse(bh);
		} else
			goto done;
	}
done:
	brelse(bh);
}

static void check_partition(struct gendisk *hd, unsigned int dev)
{
	static int first_time = 1;
	int i, minor = current_minor;
	struct buffer_head *bh;
	struct partition *p;
	unsigned long first_sector;
	int mask = (1 << hd->minor_shift) - 1;

	if (first_time)
		printk("Partition check:\n");
	first_time = 0;
	first_sector = hd->part[MINOR(dev)].start_sect;
	if (!(bh = bread(dev,0,1024))) {
		printk("  unable to read partition table of device %04x\n",dev);
		return;
	}
	printk("  %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
	current_minor += 4;  /* first "extra" minor */
	if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
		p = (struct partition *) (0x1BE + bh->b_data);
		for (i=1 ; i<=4 ; minor++,i++,p++) {
			if (!(hd->part[minor].nr_sects = p->nr_sects))
				continue;
			hd->part[minor].start_sect = first_sector + p->start_sect;
			printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i);
			if ((current_minor & 0x3f) >= 60)
				continue;
			if (p->sys_ind == EXTENDED_PARTITION) {
				printk(" <");
				extended_partition(hd, (hd->major << 8) | minor);
				printk(" >");
			}
		}
		/*
		 * check for Disk Manager partition table
		 */
		if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
			p = (struct partition *) (0x1BE + bh->b_data);
			for (i = 4 ; i < 16 ; i++, current_minor++) {
				p--;
				if ((current_minor & mask) >= mask-2)
					break;
				if (!(p->start_sect && p->nr_sects))
					continue;
				hd->part[current_minor].start_sect = p->start_sect;
				hd->part[current_minor].nr_sects = p->nr_sects;
				printk(" %s%c%d", hd->major_name,
					'a'+(current_minor >> hd->minor_shift),
					current_minor & mask);
			}
		}
	} else
		printk(" bad partition table");
	printk("\n");
	brelse(bh);
}

/* This function is used to re-read partition tables for removable disks.
   Much of the cleanup from the old partition tables should have already been
   done */

/* This function will re-read the partition tables for a given device,
and set things back up again.  There are some important caveats,
however.  You must ensure that no one is using the device, and no one
can start using the device while this function is being executed. */

void resetup_one_dev(struct gendisk *dev, int drive)
{
	int i;
	int start = drive<<dev->minor_shift;
	int j = start + dev->max_p;
	int major = dev->major << 8;

	current_minor = 1+(drive<<dev->minor_shift);
	check_partition(dev, major+(drive<<dev->minor_shift));

	for (i=start ; i < j ; i++)
		dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
}

static void setup_dev(struct gendisk *dev)
{
	int i;
	int j = dev->max_nr * dev->max_p;
	int major = dev->major << 8;
	int drive;
	

	for (i = 0 ; i < j; i++)  {
		dev->part[i].start_sect = 0;
		dev->part[i].nr_sects = 0;
	}
	dev->init();	
	for (drive=0 ; drive<dev->nr_real ; drive++) {
		current_minor = 1+(drive<<dev->minor_shift);
		check_partition(dev, major+(drive<<dev->minor_shift));
	}
	for (i=0 ; i < j ; i++)
		dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
	blk_size[dev->major] = dev->sizes;
}
	
/* This may be used only once, enforced by 'static int callable' */
extern "C" int sys_setup(void * BIOS)
{
	static int callable = 1;
	struct gendisk *p;
	int nr=0;

	if (!callable)
		return -1;
	callable = 0;

	for (p = gendisk_head ; p ; p=p->next) {
		setup_dev(p);
		nr += p->nr_real;
	}
		
	if (ramdisk_size)
		rd_load();
	mount_root();
	return (0);
}
