/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
*/

#ident	"$Header: usclk.c 1.17 90/04/20 $"

/*
 * Driver for ETC on symmetry systems
 */

/* $Log:	usclk.c,v $
 */

#include "sys/types.h"
#include "sys/devsw.h"
#include "sys/param.h"
#include "sys/debug.h"
#include "sys/systm.h"
#include "sys/mutex.h"
#include "sys/errno.h"
#include "sys/intctl.h"
#include "sys/gate.h"
#include "sys/hwparam.h"
#include "sys/ioctl.h"
#include "sys/signal.h"
#include "sys/user.h"
#include "sys/sysmacros.h"
#include "sys/cmn_err.h"
#include "sys/cfg.h"
#include "sys/arch.h"

#ifndef NULL
#define NULL	0
#endif

#define	MAX_USCLKS	1	       /* max number of usclk boards allowed */

#define usclk_base	(caddr_t)PHYS_ETC

int usclk_alive = 0;			/* flag, is this device alive? */

extern int usclk_c_major;
extern struct devops usclkdevops;

struct dev usclkdev[MAX_USCLKS];


/*ARGSUSED*/
void
usclk_init( ndevs)
	int ndevs;
{
	int dev;

	/*
	 * Disallow systems that we know don't support the ETC.
	 */

	if (arch_type == SYSTYP_S1)
		return;

	usclk_alive = 1;
	/*
	 * Now set up one dev for each of the possible minor devices.
	 */

	for (dev = 0; dev < MAX_USCLKS; dev++) {
		usclkdev[dev].d_dev = makedev(usclk_c_major, dev);
		usclkdev[dev].d_ops = &usclkdevops;
		usclkdev[dev].d_flags = 0;
		if (devsw_add(&usclkdev[dev]) < 0)
			cmn_err(CE_WARN,
			"usclk%d: problem adding dev 0x%x to devsw\n", dev);
			/*
			 *+ Adding the usclk device to the device
			 *+ table has failed.
			 */
	}
}
/*
 * open the device
 */

usclkopen(dp)
	struct	dev *dp;
{
	dev_t dev = dp->d_dev;
	int unit = minor(dev);
	int error = 0;

	if ((unit >= MAX_USCLKS) || (usclk_alive == 0))
		return(ENXIO);

	return(error);
}
	

/*
 * usclkmmap()
 *	Perform mapping functions.
 *
 */

/*ARGSUSED*/
usclkmmap(dp, cmd, off, size, prot)
	struct	dev *dp;
	int	cmd;
	ulong	off;	/* HW pages */
	int	size;	/* HW pages */
	int	prot;	/* PROT_READ|PROT_WRITE */
{
	int val = 0;

	switch(cmd) {

	case MM_MAP:

		/*
		 * map read-only
		 */
		if (prot & PROT_WRITE) {
			val = EINVAL;
			break;
		}

		/*
		 * Allow only ONE page to be mapped.
		 */
		if (off + size > CLSIZE)
			val = ENOSPC;
		else 
			val = MM_PHYS;
			 
		break;

	case MM_REFPG:

		val = (int)usclk_base;
		break;

	case MM_UNMAP:
	case MM_SWPOUT:
	case MM_SWPIN:
		break;

	default:
		cmn_err(CE_CONT, "cmd = %d\n", cmd);
		cmn_err(CE_PANIC, "usclkmmap: bad function");
		/*
		 *+ The usclk driver was called through its mmap entry point
		 *+ to perform an unsupported operation.
		 */
	}
	return(val);
}
