Coherent4.2.10/coh.386/lib/ddi_devno.c

/* $Header: $ */

#define	_DDI_DKI	1
#define	_SYSV4		1

/*
 * Routines for manipulating device numbers.
 *
 * System V defines "dev_t" as 32-bit, which makes some things problematic
 * when attempting to run SVR4 drivers in an iBCS2 environment. The concept
 * of external and internal numbers, introduced at the same time as the 32-
 * bit "dev_t", provides an effective solution.
 *
 * This is of primary importance to clone devices which may want to support
 * more than 256 connections, but any driver which wants or needs to encode
 * more that 8 bits of information in the minor number may also benefit from
 * use of the external/internal mapping regime.
 *
 * $Log: $
 */

/*
 *-IMPORTS:
 *	<sys/types.h>
 *		dev_t
 *	<limits.h>
 *		CHAR_BIT
 */

#include <sys/types.h>
#include <limits.h>

/*
 * Define this symbol to make the code in this module ignore the _max_minor,
 * _major [], and _minor [] configuration tables, and simply map internal and
 * external major and minor numbers one-to-one.
 */
/* #define ONE_TO_ONE */

/*
 * If we are dealing with a situation where we are trying to run DDI/DKI code
 * side-by-side with code that uses a different "dev_t", we rely on a layer
 * that can may the pre-SVR4 or alien calling sequence for the DDI/DKI entry
 * points. This code must deal with converting the old-style "dev_t" to a
 * new-style "dev_t" and vice-versa.
 *
 * In particular, if a device generates a minor number outside the range of
 * precision of the old-style system, the mapping layer must use these
 * functions to select an appropriate major number to overflow to.
 */

#define	DSHIFT			(sizeof (dev_t) * CHAR_BIT / 2)

#define	GETEMAJOR(dev)		((major_t) ((dev) >> DSHIFT))
#define	GETEMINOR(dev)		((minor_t) ((dev) & ~ (1L << DSHIFT)))
#define	MAKEDEVICE(maj,min) 	(((dev_t) (maj) << DSHIFT) + (min))


/*
 * The following external reference is to a table generated by the kernel
 * configuration process for all the devices configured in the system. It
 * defines a many-to-one mapping between external and internal major device
 * numbers.
 *
 * This mapping can also affect internal device numbers; for instance,
 * external major device 10, minor 5 might map to internal 2, minor 30.
 */

#ifndef	ONE_TO_ONE

extern major_t	_maxmajor;
extern major_t	_major [];	/* internal major number for external major */
extern minor_t	_minor [];	/* value added to external minor number */

#endif

/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	etoimajor	Convert external to internal major device number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	major_t etoimajor (major_t emaj);
 *
 *-ARGUMENTS:
 *	emaj		External major number.
 *
 *-DESCRIPTION:
 *	etoimajor () converts the external major number (emaj) to an internal
 *	major number. See getemajor () for a description of external and
 *	internal major numbers.
 *
 *-RETURN VALUE:
 *	etoimajor () returns the internal major number or NODEV if the
 *	external major number is not valid.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	getemajor (), geteminor (), getmajor (), getminor (), itoemajor (),
 *	makedevice ().
 */

#if	__USE_PROTO__
major_t (etoimajor) (major_t emaj)
#else
major_t
etoimajor __ARGS ((emaj))
major_t		emaj;
#endif
{
#ifdef ONE_TO_ONE
	return emaj;
#else
	return (emaj >= _maxmajor ? NODEV : _major [emaj]);
#endif
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	getemajor	Get external major device number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	major_t getemajor (dev_t dev);
 *
 *-ARGUMENTS:
 *	dev		External device number.
 *
 *-DESCRIPTION:
 *	getemajor () returns the external major number given a device number,
 *	"dev". External major numbers are visible to the user. Internal major
 *	numbers are only visible in the kernel. Since the range of major
 *	numbers may be large and sparsely populated, the kernel keeps a
 *	mapping between external and internal major numbers to save space.
 *
 *	All driver entry points are passed device numbers using external
 *	major numbers.
 *
 *	Usually, a driver with more than one external major number will have
 *	only one internal major number. However, some system implementations
 *	map one-to-one between internal and external major numbers. Here, the
 *	internal major number is the same as the external major number and the
 *	driver may have more than one internal major number.
 *
 *-RETURN VALUE:
 *	The external major number.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	etoimajor (), geteminor (), getmajor (), getminor (), makedevice ().
 */

#if	__USE_PROTO__
major_t (getemajor) (n_dev_t dev)
#else
major_t
getemajor __ARGS ((dev))
n_dev_t		dev;
#endif
{
	return GETEMAJOR (dev);
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	geteminor	Get external minor device number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	minor_t geteminor (dev_t dev);
 *
 *-ARGUMENTS:
 *	dev		External device number.
 *
 *-DESCRIPTION:
 *	geteminor () returns the external minor number given a device number,
 *	"dev". External minor numbers are visible to the user. Internal minor
 *	numbers are only visible in the kernel. Since a driver can support
 *	more than one external major device that maps to the same internal
 *	major device, the kernel keeps a mapping between external minor
 *	numbers and internal minor numbers to allow drivers to index arrays
 *	more easily. For example, a driver may support two devices, each with
 *	five minor numbers. The user may see each set of minor numbers
 *	numbered from zero to four, but the driver sees them as one set of
 *	minor numbers numbered zero to nine.
 *
 *	All driver entry points are passed device numbers using external minor
 *	numbers.
 *
 *	Systems that map external major numbers one-to-one with internal major
 *	numbers also map external minor numbers one-to-one with internal minor
 *	numbers.
 *
 *-RETURN VALUE:
 *	The external minor number.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	etoimajor (), getemajor (), getmajor (), getminor (), makedevice ()
 */

#if	__USE_PROTO__
minor_t (geteminor) (n_dev_t dev)
#else
minor_t
geteminor __ARGS ((dev))
n_dev_t		dev;
#endif
{
	return GETEMINOR (dev);
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	getmajor	Get internal major device number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	major_t getemajor (dev_t dev);
 *
 *-ARGUMENTS:
 *	dev		Device number.
 *
 *-DESCRIPTION:
 *	The getmajor () function extracts the internal major number from a
 *	device number. See getemajor () for an explanation of external and
 *	internal major numbers.
 *
 *-RETURN VALUE:
 *	The internal major number.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	No validity checking is performed. If "dev" is invalid, an invalid
 *	number is returned.
 *
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	etoimajor (), getemajor (), geteminor (), getminor (), makedevice ()
 */

#if	__USE_PROTO__
major_t (getmajor) (n_dev_t dev)
#else
major_t
getmajor __ARGS ((dev))
n_dev_t		dev;
#endif
{
#ifdef ONE_TO_ONE
	return GETEMAJOR (dev);
#else
	return _major [GETEMAJOR (dev)];
#endif
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	getminor	Get internal minor device number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	minor_t getminor (dev_t dev);
 *
 *-ARGUMENTS:
 *	dev		Device number.
 *
 *-DESCRIPTION:
 *	The getminor () function extracts the internal minor number from a
 *	device number. See getemajor () for an explanation of external and
 *	internal major numbers.
 *
 *-RETURN VALUE:
 *	The internal minor number.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	No validity checking is performed. If "dev" is invalid, an invalid
 *	number is returned.
 *
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	etoimajor (), getemajor (), geteminor (), getmajor (), makedevice ()
 */

#if	__USE_PROTO__
minor_t (getminor) (n_dev_t dev)
#else
minor_t
getminor __ARGS ((dev))
n_dev_t		dev;
#endif
{
#ifdef ONE_TO_ONE
	return GETEMINOR (dev);
#else
	return GETEMINOR (dev) + _minor [GETEMAJOR (dev)];
#endif
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	itoemajor	Convert internal to external major number.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	major_t itoemajor (major_t imaj, major_t prevemaj);
 *
 *-ARGUMENTS:
 *	imaj		Internal major number.
 *
 *	prevemaj	Most recently obtained external major number (or
 *			NODEV, if this is the first time the function has been
 *			called).
 *
 *-DESCRIPTION:
 *	itoemajor () converts the internal major number to the external major
 *	number. The external-to-internal major number mapping can be many-to-
 *	one, and so any internal major number may correspond to more than one
 *	external major number. By repeatedly invoking this function, the
 *	driver can obtain all possible external major number values. See
 *	getemajor () for an explanation of external and internal major
 *	numbers.
 *
 *-RETURN VALUE:
 *	External major number, or NODEV if all have been searched.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	etoimajor (), getemajor (), geteminor (), getmajor (), getminor (),
 *	makedevice ()
 */

#if	__USE_PROTO__
major_t (itoemajor) (major_t imaj, major_t prevemaj)
#else
major_t
itoemajor __ARGS ((imaj, prevemaj))
major_t		imaj;
major_t		prevemaj;
#endif
{
#ifdef ONE_TO_ONE
	return prevemaj == NODEV ? imaj : NODEV;
#else
	if (prevemaj == NODEV)
		prevemaj = 0;
	else
		prevemaj ++;

	while (prevemaj ++ < _maxmajor)
		if (_major [prevemaj] == imaj)
			return  prevemaj;

	return NODEV;
#endif
}


/*
 *-STATUS:
 *	DDI/DKI
 *
 *-NAME:
 *	makedevice	Make device number from major and minor numbers.
 *
 *-SYNOPSIS:
 *	#include <sys/types.h>
 *	#include <sys/ddi.h>
 *
 *	dev_t makedevice (major_t majnum, minor_t minnum);
 *
 *-ARGUMENTS:
 *	majnum		Major number.
 *
 *	minnum		Minor number.
 *
 *-DESCRIPTION:
 *	The makedevice () function creates a device number from a major and
 *	minor device number. makedevice () should be used to create device
 *	numbers so that the driver will port easily to releases that treat
 *	device numbers differently.
 *
 *-RETURN VALUE:
 *	The device number, containing both the major number and the minor
 *	number, is returned. No validation of the major or number numbers is
 *	performed.
 *
 *-LEVEL:
 *	Base or interrupt.
 *
 *-NOTES:
 *	Does not sleep.
 *
 *	Driver-defined basic locks, read/write locks, and sleep locks may be
 *	held across calls to this function.
 *
 *-SEE ALSO:
 *	getemajor (), geteminor (), getmajor (), getminor ()
 */

#if	__USE_PROTO__
n_dev_t (makedevice) (major_t majnum, minor_t minnum)
#else
n_dev_t
makedevice __ARGS ((majnum, minnum))
major_t		majnum;
minor_t		minnum;
#endif
{
	return MAKEDEVICE (majnum, minnum);
}