/*
 * Copyright (c) 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)conf.c	2.7 (2.11BSD) 1997/11/7
 */

#include "../h/param.h"
#include "saio.h"

	int	nullsys();

extern	int	xpstrategy(), xpopen(), xpclose(), xplabel();
extern	int	brstrategy(), bropen();
extern	int	rkstrategy(), rkopen();
extern  int	rxstrategy(), rxopen();
extern	int	hkstrategy(), hkopen(), hklabel();
extern	int	rlstrategy(), rlopen(), rllabel();
extern	int	sistrategy(), siopen();
extern	int	rastrategy(), raopen(), raclose(), ralabel();
extern	int	tmstrategy(), tmopen(), tmclose(), tmseek();
extern	int	htstrategy(), htopen(), htclose(), htseek();
extern	int	tsstrategy(), tsopen(), tsclose(), tsseek();
extern	int	tmscpstrategy(), tmscpopen(), tmscpclose(), tmscpseek();
extern  int     vtstrategy(), vtopen(), vtseek();

extern	caddr_t	*XPcsr[], *BRcsr[], *RKcsr[], *HKcsr[], *RLcsr[], *RXcsr[];
extern	caddr_t	*SIcsr[], *RAcsr[], *TMcsr[], *HTcsr[], *TScsr[], *TMScsr[];
extern	caddr_t	*VTcsr[];

/*
 * NOTE!  This table must be in major device number order.  See /sys/pdp/conf.c
 *	  for the major device numbers.
*/

struct devsw devsw[] = {
	"ht",	htstrategy,	htopen,		htclose,	HTcsr, /* 0 */
	nullsys, htseek,
	"tm",	tmstrategy,	tmopen,		tmclose,	TMcsr, /* 1 */
	nullsys, tmseek,
	"ts",	tsstrategy,	tsopen,		tsclose,	TScsr, /* 2 */
	nullsys, tsseek,
	"ram",	nullsys,	nullsys,	nullsys,	0,     /* 3 */
	nullsys, nullsys,
	"hk",	hkstrategy,	hkopen,		nullsys,	HKcsr, /* 4 */
	hklabel, nullsys,
	"ra",	rastrategy,	raopen,		raclose,	RAcsr, /* 5 */
	ralabel, nullsys,
	"rk",	rkstrategy,	rkopen,		nullsys,	RKcsr, /* 6 */
	nullsys, nullsys,
	"rl",	rlstrategy,	rlopen,		nullsys,	RLcsr, /* 7 */
	rllabel, nullsys,
	"rx",	rxstrategy,	rxopen,		nullsys,	RXcsr, /* 8 */
	nullsys, nullsys,
	"si",	sistrategy,	siopen,		nullsys,	SIcsr, /* 9 */
	nullsys, nullsys,
	"xp",	xpstrategy,	xpopen,		xpclose,	XPcsr, /* 10 */
	xplabel, nullsys,
	"br",	brstrategy,	bropen,		nullsys,	BRcsr, /* 11 */
	nullsys, nullsys,
	"tms",  tmscpstrategy,	tmscpopen,	tmscpclose,	TMScsr,/* 12 */
	nullsys, tmscpseek,
	"vt",   vtstrategy,     vtopen,         nullsys,        VTcsr, /* 13 */
	nullsys, vtseek,
	0,	0,		0,		0,		0,
	nullsys, nullsys,
};

	int	ndevsw = (sizeof (devsw) / sizeof (devsw[0])) - 1;

	char	ADJcsr[] =
		{
		0,	/* HT = 0 */
		2,	/* TM = 1 */
		2,	/* TS = 2 */
		0,	/* RAM = 3 */
		0,	/* HK = 4 */
		0,	/* RA = 5 */
		4,	/* RK = 6 */
		0,	/* RL = 7 */
		0,	/* RX = 8 */
		0,	/* XP/SI = 9 */
		0,	/* XP = 10 */
		4,	/* BR =11 */
		0,	/* TMS = 12 */
		0,	/* VT = 13 */
		};

devread(io)
	register struct iob *io;
{
	return((*devsw[io->i_ino.i_dev].dv_strategy)(io, READ));
}

devwrite(io)
	register struct iob *io;
{
	return((*devsw[io->i_ino.i_dev].dv_strategy)(io, WRITE));
}

devopen(io)
	register struct iob *io;
{
	return((*devsw[io->i_ino.i_dev].dv_open)(io));
}

devclose(io)
	register struct iob *io;
{
	(*devsw[io->i_ino.i_dev].dv_close)(io);
}

/*
 * Call the 'seek' entry for a tape device.  Seeking only works for 1kb
 * records - which is how the executables are stored - not for the dump
 * or tar files on a boot tape.
*/
devseek(io, space)
	register struct iob *io;
	int	space;
	{
	return((*devsw[io->i_ino.i_dev].dv_seek)(io, space));
	}

devlabel(io, fnc)
	register struct iob *io;
	int	fnc;
	{
	int	(*dvlab)() = devsw[io->i_ino.i_dev].dv_label;
	int	(*strat)() = devsw[io->i_ino.i_dev].dv_strategy;
	register struct disklabel *lp;
	register struct partition *pi;
	
	switch	(fnc)
		{
		case	WRITELABEL:
			return(writelabel(io, strat));
		case	READLABEL:
			return(readlabel(io, strat));
		case	DEFAULTLABEL:
/*
 * Zero out the label buffer and then assign defaults common to all drivers.
 * Many of these are rarely (if ever) changed.  The 'a' partition is set up
 * to be one sector past the label sector - the driver is expected to change
 * this to span the volume once the size is known.
*/
			lp = &io->i_label;
			pi = &lp->d_partitions[0];
			bzero(lp, sizeof (struct disklabel));
			lp->d_npartitions = 1;
			pi->p_offset = 0;
			pi->p_size = LABELSECTOR + 1;
			pi->p_fsize = DEV_BSIZE;
			pi->p_frag = 1;
			pi->p_fstype = FS_V71K;
			strcpy(lp->d_packname, "DEFAULT");
			lp->d_secsize = 512;
			lp->d_interleave = 1;
			lp->d_rpm = 3600;
/*
 * param.h declares BBSIZE to be DEV_BSIZE which is 1kb.  This is _wrong_,
 * the boot block size (what the bootroms read) is 512.  The disklabel(8)
 * program explicitly sets d_bbsize to 512 so we do the same thing here.
 *
 * What a mess - when the 1k filesystem was created there should have been
 * a (clearer) distinction made between '(hardware) sectors' and 
 * '(filesystem) blocks'.  Sigh.
*/
			lp->d_bbsize = 512;
			lp->d_sbsize = SBSIZE;
			return((*dvlab)(io));
		default:
			printf("devlabel: bad fnc %d\n");
			return(-1);
		}
	}

/*
 * Common routine to print out the full device name in the form:
 *
 *	dev(ctlr,unit,part)
 * 
 * Have to do it the hard way since there's no sprintf to call.  Register
 * oriented string copies are small though.
*/

char	*
devname(io)
	register struct iob *io;
	{
	static	char	dname[16];
	register char *cp, *dp;

	cp = dname;
	dp = devsw[io->i_ino.i_dev].dv_name;
	while	(*cp = *dp++)
		cp++;
	*cp++ = '(';
	dp = itoa(io->i_ctlr);
	while	(*cp = *dp++)
		cp++;
	*cp++ = ',';
	dp = itoa(io->i_unit);
	while	(*cp = *dp++)
		cp++;
	*cp++ = ',';
	dp = itoa(io->i_part);
	while	(*cp = *dp++)
		cp++;
	*cp++ = ')';
	*cp++ = '\0';
	return(dname);
	}
/*
 * Check for end of volume.  Actually this checks for end of partition.
 * Since this is almost always called when reading unlabeled disks (treating
 * a floppy as a short tape for example) it's effectively an EOV check.
*/

deveovchk(io)
	register struct iob *io;
	{
	register struct partition *pi;
	daddr_t  sz, eov;

	pi = &io->i_label.d_partitions[io->i_part];
	sz = io->i_cc / 512;
/*
 * i_bn already has the p_offset added in, thus we have to add in the partition
 * offset when calculating the end point. 
*/
	eov = pi->p_offset + pi->p_size;
	if	(io->i_bn + sz > eov)
		{
		sz = eov - io->i_bn;
		if	(sz == 0)
			return(0);	/* EOF */
/*
 * Probably should call this EOF too since there is no 'errno' to specify
 * what type of error has happened.
*/
		if	(sz < 0)
			return(-1);
		io->i_cc = dbtob(sz);
		}
	return(1);
	}

nullsys()
{
	return(-1);
}
