Source to bsd/dev/ppc/drvUSBCMD/driverservices.c


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @[email protected]
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @[email protected]
 */

/*
	File:		DriverServices.c

	Contains:	Native Driver support code for Device Manager

	Version:	xxx put version here xxx

	Written by:	Tom Saulpaugh

	Copyright:	 1994-1997 by Apple Computer, Inc., all rights reserved.

	File Ownership:

		DRI:				xxx put dri here xxx

		Other Contact:		xxx put other contact here xxx

		Technology:			xxx put technology here xxx

	Writers:

		(JM3)	Jim Murphy
		(CSS)	Chas Spillar
		(KW)	Kevin Williams
		(MRN)	Matthew Nelson

	Change History (most recent first):

		<63>   18-Jun-97	JM3		Updated for cleaned up NanoKernelPriv/PPCInfoRecordsPriv.
		<62>	 5/30/97	CSS		Delay() now takes an unsigned long * instead of a long * as its
									second parameter.
		<61>	 3/18/97	KW		DelayFor Hardware was just looking at 5FFF EF80 to get the
									Processor Info structure. Now use the pointer located  at
									ProcessorInfo Ptr to get the pointer to the structure
		<60>	  8/6/96	MRN		Changes to stop using private copy of 64 bit math routines and
									instead link against the real shipping version of the Math64Lib.
		<59>	10/30/95	MRN		Get rid of C version of SynchronizeIO that moved to
									DriverServices.s, and make file buildable with MrC.
		<58>	 4/15/95	tjm		#1238020 - Fix DelayForHardware to handle 601 correctly. Moved
									fix back into DSL.m4
		<57>	 4/14/95	tjm		#1238020 - Fix DelayForHardware to handle 601 correctly.
		<56>	 4/10/95	TS		Fix bug in PBEnqueueLast
		<55>	 4/10/95	TS		Optimize PBEnqueueLast for a queue of 1 or less elements
		<54>	  4/6/95	TS		Fix PBDequeue
		<53>	  4/5/95	TS		Rewrite PBEnqueueLast (Bug #1236338)
		<52>	 3/31/95	TS		Bump preallocated data numbers and comment out debugging names
									before ROM freezes.
		<51>	 3/30/95	TS		Retry CompareAndSwap in PBDequeue if element is at head of queue
		<50>	 3/30/95	TS		Add OSTypes to each Globals Struct and reserve some space here
									as well.
		<49>	 3/29/95	TS		Return last element in PBDequeueLast (Optimized path)
		<48>	 3/28/95	TS		Optimize PBDequeue and PBDequeueLast for the first element
		<47>	 3/27/95	TS		Fix bug #1232734 (IOCommandIsComplete return value)
		<46>	 3/22/95	TS		Optimize fix for bug #1228034
		<45>	 3/14/95	tjm		#1227300 - Insure that PStrNCmp works with all equal strings.
		<44>	 3/14/95	tjm		#1228034 - insure that queueing functions are safe from
									interrupts
		<43>	 2/21/95	tjm		#1220575 - Correct PStrNCat to handle strings > 255.
		<42>	 2/20/95	tjm		#1220560 - Fix PStrCat to correctly handle dest strings > 128.
		<41>	 1/27/95	tjm		#1214980 - PStrNCmp does not return correct value with null
									strings.
		<40>	 1/25/95	tjm		#1214207 - Fix PBDequeueLast to delete if only one item in
									queue.
		<39>	 1/25/95	tjm		#1214730 - Fix PStrCat to only Cat up to 255 chars.
		<38>	 1/19/95	tjm		Break out DSLInit routine to aid in debugging
		<37>	 1/19/95	tjm		#1211193 - Allow Dequeuing from head.
		<36>	 1/18/95	tjm		#1212320 - Insure PBEnqueueLast is re-entrant.
		<35>	 1/18/95	tjm		#1203060 - Make a Global Data Lib for the DSL.
		<34>	 1/16/95	tjm		#1203145 - Add DelayForHardware so drivers can call delay
									routine at InterruptTime.
		<33>	 1/10/95	tjm		#1210156 - Make sure PBQueueDelete correctly deallocated
									preallocated qHdrs.
		<32>	 1/10/95	tjm		#1210154 - return noErr for unaligned qHdr allocation.
		<31>	 1/10/95	tjm		#1207351 - Make sure PStrLen returns correct value.
		<30>	 1/10/95	tjm		#1207081 - Fix the PStr functions to handle lengths correctly
		<29>	  1/9/95	tjm		#1208049 - return paramErr if CSI fails.
		<28>	  1/9/95	tjm		#1209423 - correctly handle empty qHdr when it is empty
		<27>	  1/9/95	MN		Add a call to UpTime in the CFM initialization function to
									initialize the timebase variable in the new timing functions.
		<26>	12/21/94	MN		Restore checkins 18 through 24 and include the fixes checked
									into 25.
		<25>	12/21/94	MN		Added alignment support to PBQueueCreate and PBQueueDelete for Marconi_v16c2
									which would have checked in over the top of checkins 18 through 24.
		<24>	12/20/94	tjm		#1206624 - Fix PBDequeueLastSync to correctly dequeue item.
		<23>	12/19/94	tjm		#1204196 - fix this again.
		<22>	12/16/94	tjm		#1206622 - eliminate reentrantcy problem with PBDequeueSync.
		<21>	12/16/94	tjm		#1203051 - added PBEnqueueLast function
		<20>	12/15/94	tjm		#1204196 - call PBQueueInit when PBQueueCreate is successful.
		<19>	12/15/94	tjm		#1204193 - initialize qFlags in qHeader of PBQueueInit.
		<18>	12/15/94	tjm		#1203057 - increment the number of SWI's to 32
		<17>	 12/5/94	tjm		#1202888 - Fix PBDequeue to not corrupt queue with 2 elements
		<16>	 12/5/94	tjm		#1202776 - Fix PBDequeue to return qErr for nonexistant element.
		<15>	 12/5/94	tjm		#1201314 - correctly queue secondary interrupts
		<14>	11/15/94	tjm		#1195428 - Fix function prototypes to correctly define src ptrs
									as const.
		<13>	 11/3/94	tjm		fix DelayFor to use low end of 64 bit divide, ID#1197350
		<12>	10/25/94	tjm		Call TimerInitialize, SIHInitialize, and MemoryInitialze to fix
									#1192590
		<11>	 9/15/94	MN		Add call in DSL_Init to startup Interrupt Manager and change
									PBQueueInit to return an error code;
		<10>	 8/31/94	TS		Make the DSL_Init check for failures
		 <9>	 8/29/94	TS		Add a call to the CFM init routine to calculate physical RAM
									size using the ROM physical space table
		 <8>	 8/25/94	TS		Add DelayFor and Move BlockCopy to MemoryManagement.c
		 <7>	 8/24/94	TS		Add in checks for correct execution levels
		 <6>	 8/24/94	TS		Make DSL_Init return noErr to library will load
		 <5>	 8/24/94	TS		Build ExecutionLevel Func
		 <4>	 8/23/94	TS		Implement SoftwareInterrupts
		 <3>	 8/18/94	TS		Add more queue functions
		 <2>	 8/17/94	JF		Changes from PCI developer kitchen
		 <1>	  8/5/94	JF		first checked in

*/



//
// Source to the NuDriver Support Services Library
//

//#include <Types.h>
//#include <Strings.h>
//#include <Files.h>
//#include <MixedMode.h>
//#include <LowMem.h>
//#include <Math64.h>

// Get Prototypes of the Exported Services First,...

#include "driverservices.h"
#include "driverservicespriv.h"
#include "PPCInfoRecordsPriv.h"
#include "rhap_local.h"

// The Driver Services Follow,...


OSErr InitSwis (void);

/////////////////////////////////////////////////////////////////////////////////
//
//	Command Processing
//
//

/*-------------------------------------------------------------------------------

Routine:	IOCommandIsComplete	-	Marks I/O Command as Done.

Function:	Returns IODone result from Device Manager

Input:		theID		- ID of the in-progress I/O command.
			theResult	- the result value of the command. (Low 16-bits are placed in IOPB)

Result:		noErr	or 
-------------------------------------------------------------------------------*/
/*naga
enum {
	uppIODoneProcInfo =		kRegisterBased
						|	REGISTER_ROUTINE_PARAMETER(1,kRegisterA1,kFourByteCode)
						|	REGISTER_ROUTINE_PARAMETER(2,kRegisterD0,kFourByteCode)
};


OSErr	IOCommandIsComplete		(	IOCommandID		theID,
									OSErr			theResult)
{
	ParmBlkPtr	 The_Pb		= (ParmBlkPtr)theID;
	OSErr		*The_Result = (OSErr *)(&The_Pb -> ioParam.ioCmdAddr);
	
	if (theID == nil)
		return paramErr;

	*The_Result = theResult;
	
	(void)CallUniversalProc (	LMGetJIODone(),
								uppIODoneProcInfo,
								The_Pb,
								1 );
	return noErr;
}
naga */
/*-------------------------------------------------------------------------------

Routine:	GetIOCommandInfo	-	Returns info about an in-progress I/O command.

Function:	Returns IOCommandContents, IOCommandCode, and IOCommandKind.

Input:		theID	- ID of the in-progress I/O command.

Output:		theContents		- pointer to the IOPB or Initialize/Finalize Contents.
			theCommand		- the command code
			theKind			- the kind of I/O (Sync, Async, or Immed)
			
Result:		noErr	
-------------------------------------------------------------------------------*/
/*naga
OSErr	GetIOCommandInfo		(	IOCommandID				theID,
								    IOCommandContents	*	theContents,
									IOCommandCode		*	theCommand,
									IOCommandKind		*	theKind )
{
	IOCommandContents	The_Contents;
	ParmBlkPtr			The_Pb		= (ParmBlkPtr)theID;

	if (theID == nil)
		return paramErr;

	The_Contents . pb = The_Pb;
	
	*theContents = The_Contents;
	*theCommand  = (The_Pb  -> ioParam.ioTrap & 0x00ff);
	*theKind	 = ((The_Pb -> ioParam.ioTrap & 0xff00) >> 8);
	
	return noErr;
}
*/

/////////////////////////////////////////////////////////////////////////////////
//
//	Queues
//
//

/*-------------------------------------------------------------------------------

Routine:	PBQueueInit	-	Initialize a Queue (@ NON-Interrupt-lvl and SIH-lvl)

-------------------------------------------------------------------------------*/

OSErr PBQueueInit(QHdrPtr qHeader)
{
	qHeader -> qHead = nil;
	qHeader -> qTail = nil;
	qHeader -> qFlags = 0x0000;
	
	return noErr;
}

/*-------------------------------------------------------------------------------

Routine:	PBQueueCreate	-	Initialize a Queue (@ NON-Interrupt lvl)

-------------------------------------------------------------------------------*/

OSErr PBQueueCreate(QHdrPtr *qHeader)
{
	Ptr **theQueue;
	
	if (CurrentExecutionLevel() != kTaskLevel)
	{
		// SysDebugStr ((StringPtr)"\pPBQueueCreate not called at Task Level!");
		// 11/30/98 Adam return -1;
	}
	
	*qHeader = nil;
	theQueue = (Ptr **)PoolAllocateResident (sizeof(QHdr)+sizeof(short)+sizeof(Ptr),true);
	if (theQueue != nil)
	{
		// Store orig ptr in first 4 bytes.
		*theQueue = (Ptr *)theQueue;
		theQueue++;
		
		// Are we not aligned?
		if ( ((UInt32)theQueue & 3) == 0 )
		{
			short *pattern = (short *)theQueue;
			
			*pattern++	= 0x4D4E;
			*qHeader	= (QHdrPtr)pattern;
			return noErr;
		}
		else
		{
			*qHeader	= (QHdrPtr)theQueue;
			return noErr;
		}
	}
	else
		return mFulErr;
}

/*-------------------------------------------------------------------------------

Routine:	PBQueueDelete	-	Finalize a Queue (@ NON-Interrupt lvl)

-------------------------------------------------------------------------------*/

OSErr PBQueueDelete(QHdrPtr qHeader)
{
	Ptr	  **theMemory;
	UInt16 *pattern = (UInt16 *)qHeader;
	
	if (CurrentExecutionLevel() != kTaskLevel)
	{
		// SysDebugStr ((StringPtr)"\pPBQueueDelete not called at Task Level!");
		return -1;
	}
	
	if (*--pattern == 0x4D4E)
		qHeader = (QHdrPtr)((UInt32)(qHeader) - sizeof(UInt16));
		
	theMemory = (Ptr **)qHeader;
	theMemory--;
	
	if (*theMemory != (Ptr *)theMemory)
	{
		// SysDebugStr ((StringPtr)"\pPBQueueDelete not a Queue Header!");
		return -1;
	}

	(void)PoolDeallocate(theMemory);
	return noErr;
}

/*-------------------------------------------------------------------------------

Routine:	PBEnqueueLast	-	Add an IOPB to the end of a Request Queue. (@ Any Exec-lvl)
								(Optimized for queue size of 1 or less)

-------------------------------------------------------------------------------*/

OSErr PBEnqueueLast(QElemPtr qElement, QHdrPtr qHeader)
{
	QElemPtr currElemPtr;
	UInt16 sr;
	
	// New element will be at end of queue.
	qElement -> qLink = nil;

	// Currently an empty queue?
	while ( qHeader -> qHead == nil )
	{
		if (CompareAndSwap ((UInt32) nil, (UInt32) qElement, (UInt32 *) &qHeader->qHead))
			return noErr;
	}
	
	// Multi-element queue,...
	
	// Do it the sure, but slow way.
	sr = Disable68kInterrupts();

	// Entire queue empty?
	if ( qHeader -> qHead == nil )
	{
		// Add at head of queue
		qHeader -> qHead = qElement;
	}
	else
	{
		// Else, Get first element in queue.
		currElemPtr	= (QElemPtr)qHeader->qHead;
		
		// Move toward the end of the queue,...
		while ( currElemPtr -> qLink != nil )
		{	
			currElemPtr	= currElemPtr -> qLink;
		}
	
		currElemPtr -> qLink = qElement;
	}
	
	Restore68kInterrupts(sr);
	return noErr;
}

/*-------------------------------------------------------------------------------

Routine:	PBEnqueue	-	Add an IOPB to Head of Request Queue. (@ Any Exec-lvl)

Function:	Returns (nothing)
			
Result:		void	
-------------------------------------------------------------------------------*/

void PBEnqueue(QElemPtr qElement, QHdrPtr qHeader)
{
	do {
		qElement -> qLink = qHeader->qHead;
	} while (CompareAndSwap ((UInt32) qElement->qLink, (UInt32) qElement,
											(UInt32 *) &qHeader->qHead) == false);
}


/*-------------------------------------------------------------------------------

Routine:	PBDequeue	-	Remove an IOPB from a Request Queue.  (@ Any Exec-lvl)

Function:	Returns (nothing)
			
Result:		void	
-------------------------------------------------------------------------------*/

static OSErr PBDequeueSync(QElemPtr qElement, QHdrPtr qHeader)
{
	QElemPtr prevElemPtr, currElemPtr;
	OSErr	 result = noErr;
	UInt16	sr;
	
	// Validate params.
	if ( (qElement == nil) || (qHeader == nil) )
		return paramErr;
		
	sr = Disable68kInterrupts();
	
	currElemPtr = (QElemPtr)qHeader->qHead;
	prevElemPtr = nil;
	
	// Find the one we want.
	while ( currElemPtr && (currElemPtr != qElement) )
	{
		// Advance the cause.
		prevElemPtr = currElemPtr;
		currElemPtr = currElemPtr -> qLink;
	}
	
	// We find it?
	if ( currElemPtr )
	{
		// Middle of the queue somewhere?
		if ( prevElemPtr )
			prevElemPtr -> qLink = currElemPtr ->qLink;
		else
			qHeader->qHead = currElemPtr ->qLink;
		
		currElemPtr -> qLink = nil;
	}
	else
		result = qErr; // not on the list.
	
	Restore68kInterrupts(sr);
	return result;
}


OSErr PBDequeue(QElemPtr qElement, QHdrPtr qHeader)
{
	// Optimize for common case of 1 element on the queue.
	
	// First one on the queue?
	while ( qHeader -> qHead == qElement )
	{
		// If the element is still at the head of the queue,... Remove it, and we are done.
		if (CompareAndSwap ((UInt32) qElement,
							(UInt32) qElement -> qLink,
							(UInt32 *) &qHeader->qHead) == true)
		{
			qElement -> qLink = nil;

			return noErr;
		}
	}
	
	// Multiple elements on the queue.
	return PBDequeueSync (qElement, qHeader);
}

/*-------------------------------------------------------------------------------

Routine:	PBDequeueFirst	-	Remove First Element on a Queue  (@ Any Exec-lvl)

Result:		noErr or qErr
-------------------------------------------------------------------------------*/

OSErr PBDequeueFirst(QHdrPtr qHeader, QElemPtr *theFirstqElem)
{
	QElemPtr qElement;

	do {
		// Get Queue Head Ptr
		qElement = qHeader -> qHead;
		
		// Empty Queue?
		if ( qElement == nil )
		{
			if ( theFirstqElem )
				*theFirstqElem = nil;
				
			return qErr;	
		}
		
		// If the element is still at the head of the queue,... Remove it, and we are done.
		if (CompareAndSwap ((UInt32) qElement,
							(UInt32) qElement -> qLink,
							(UInt32 *) &qHeader->qHead) == true)
		{
			if ( theFirstqElem )
				*theFirstqElem = qElement;
				
			qElement -> qLink = nil;

			return noErr;
		}
	} while (1);
}

/*-------------------------------------------------------------------------------

Routine:	PBDequeueLast	-	Remove Last Element on a Queue  (@ Any Exec-lvl)

Result:		noErr or qErr
-------------------------------------------------------------------------------*/

OSErr PBDequeueLast(QHdrPtr qHeader, QElemPtr *theLastqElem)
{
	QElemPtr currElemPtr, prevElemPtr;
	OSErr	result = noErr;
	UInt16 sr;
	
	if ( theLastqElem )
		*theLastqElem = nil;
		
	sr = Disable68kInterrupts();

	// Get Queue Head Ptr and our initial previous ptr
	if ((prevElemPtr = qHeader -> qHead) == nil)
		result = qErr; // q is empty
	else
	{
		// Get head of queue
		currElemPtr	= (QElemPtr)qHeader->qHead;
		
		// Move toward the end of the queue,...
		while ( currElemPtr -> qLink != nil )
		{	
			prevElemPtr	= currElemPtr;
			currElemPtr	= currElemPtr ->qLink;
		}
	
		// Remove last one from the queue.
		prevElemPtr->qLink = nil;
		
		// If last was also the first, nil out qheader.
		if ( currElemPtr == qHeader -> qHead )
			qHeader -> qHead = nil;
	
		// Return last element to caller.
		if ( theLastqElem )
			*theLastqElem = currElemPtr;
	}
	
	Restore68kInterrupts(sr);
	return result;
}

/////////////////////////////////////////////////////////////////////////////////
//
//	Strings
//
//

/*-------------------------------------------------------------------------------

Routine:	CStrCopy	-	Copy string of chars from src to dst.

Function:	Copies characters upto and including the null character from 'src' to
			'dst' char strings.

Note:		This routine assumes the two strings do not overlap. It would be bad.
			
Input:		src		- pointer to the source string of char's to copy.

Output:		dst		- pointer to the destination string of char's.
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

char	*CStrCopy	(char *dst,	const char	*src)
{
	char	*pos = dst;
	
	while ( (*pos++ = *src++) != 0)				// copy src to dst
		;
		
	return dst;
}


/*-------------------------------------------------------------------------------

Routine:	PStrCopy	-	Copy string of chars from src to dst.

Function:	Copies characters upto and including the null character from 'src' to
			'dst' char strings.

Note:		This routine assumes the two strings do not overlap. It would be bad.
			
Input:		src		- pointer to the source string of char's to copy.

Output:		dst		- pointer to the destination string of char's.
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

StringPtr	PStrCopy	(StringPtr dst,	ConstStr255Param src)
{
	UInt8 	  len;
	char     *s,*d;
	
	s		= (char *)src;
	d		= (char *)dst;
	len		= *src;
	
	*d++ = *s++;
	while (len-- != 0)
		*d++ = *s++;
	
	return dst;
}


/*-------------------------------------------------------------------------------

Routine:	CStrNCopy	-	Copy at most n characters.

Function:	Copies upto 'max' characters from 'src' to 'dst' char strings.
			If 'src' string is shorter than 'max', the 'dst string will be
			padded with null characters. If 'src' string is longer than 'max'
			the 'dst' string will NOT be null terminated.
			
			See ANSI X3.159-1989 p.106 - "strncpy"


Input:		src		- pointer to the source string of char's to copy.
			max		- maximum number of characters to copy.
			

Output:		dst		- pointer to the destination string of char's.
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

char	*CStrNCopy	(char *dst,	const char	*src,	UInt32	max)
{
	char	*pos = dst;
	
	max++;									// bump up max so we can predecrement in tests
	do {									// copy upto max chars to dst
		if (--max == 0)		return dst;		// exit if we've copied max chars
	} while ( (*pos++ = *src++) != 0);				// copy char & test

	while ( --max )	*pos++ = 0;				// pad remainder of string with nulls
											// unless we have already reached max.
	return dst;
}



/*-------------------------------------------------------------------------------

Routine:	PStrNCopy	-	Copy string of chars from src to dst.

Function:	Copies max characters from 'src' to 'dst' char strings.

Input:		src		- pointer to the source string of char's to copy.

Output:		dst		- pointer to the destination string of char's.
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

StringPtr	PStrNCopy	(StringPtr dst,	ConstStr255Param src, UInt32	max)
{
	UInt8	len;
	char	*s,*d;
	char	count = 0;
	
	s		= (char *)src;
	d		= (char *)dst;
	len		= *s;
	
	do {							
		if ( (max-- == 0) || (len-- == 0))
			break;				

		*++d = *++s;
		count += 1;

	} while ( 1 );
	
	if ( count )
		*dst = count;
		
	return dst;
}


/*-------------------------------------------------------------------------------

Routine:	CStrCat	-	Append 'src' char string onto 'dst'.

Function:	Appends characters from 'src' to 'dst' char strings.
			The initial character of 'src' overwrites the null character at
			the end of 'dst'. A terminating null character is ALWAYS appended.
			

Input:		src		- pointer to the source string of char's to append.

Output:		dst		- pointer to the destination string of char's.
			
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

char	*CStrCat	(char *dst,	const char *src)
{
	char	*pos = dst;
	
	while ( *pos++ )						// find the end of dst string
		;
		
	--pos;									// backup to point to null word

	while ( (*pos++ = *src++) != 0)			// copy src to dst	
		;
		
	return dst;
}




/*-------------------------------------------------------------------------------

Routine:	PStrCat	-	Append 'src' char string onto 'dst'.

Function:	Appends characters from 'src' to 'dst' char strings.			

Input:		src		- pointer to the source string of char's to append.

Output:		dst		- pointer to the destination string of char's.
			
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

StringPtr PStrCat	(StringPtr dst,	ConstStr255Param src)
{
	UInt8	*pos = (UInt8 *)dst;
	UInt8	*d	 = (UInt8 *)dst;
	UInt8	*s	 = (UInt8 *)src;
	UInt8	len  = *s++;
	UInt8	dlen  = *d;


	if (((UInt32)len + (UInt32)dlen) > (UInt32)255)
	{
		len = 255 - dlen;
	}
	pos += (*pos) + 1;						// pos at end of string.
	
	while ( len-- != 0 )
	{
		*pos++ = *s++;						// car src to dst	
		(*d) += 1;							// dump new string length
	}
	
	return dst;
}



/*-------------------------------------------------------------------------------

Routine:	CStrNCat	-	Append at most n characters.

Function:	Appends upto 'max' characters from 'src' to 'dst' char strings.
			The initial character of 'src' overwrites the null character at
			the end of 'dst'. A terminating null character is ALWAYS appended.
			Thus, the maximum length of 'dst' could be CStrLen(dst)+max+1.
			
			See ANSI X3.159-1989 p.164 - "strncat"


Input:		src		- pointer to the source string of char's to append.
			max		- maximum number of characters to append.
			

Output:		dst		- pointer to the destination string of char's.
			
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

char	*CStrNCat	(char *dst,	const char *src,	UInt32	max)
{
	char	*pos = dst;
	
	while ( *pos++ )						// find the end of dst string
		;
		
	--pos;									// backup to point to null char
	++max;									// bump up max so we can predecrement test
	while ( --max && ( (*pos++ = *src++) != 0))	// append upto max chars to dst
		;
		
	if (max == 0)							// if we reached max chars
		*pos = 0;							// append null character
		
	return dst;
}



/*-------------------------------------------------------------------------------

Routine:	PStrNCat	-	Append 'src' char string onto 'dst'.

Function:	Appends characters from 'src' to 'dst' char strings.			

Input:		src		- pointer to the source string of char's to append.

Output:		dst		- pointer to the destination string of char's.
			
			
Result:		dst		- a pointer to the destination string is returned.
-------------------------------------------------------------------------------*/

StringPtr PStrNCat	(StringPtr dst,	ConstStr255Param src, UInt32	max)
{
	UInt8	*pos = (UInt8 *)dst;
	UInt8	*d	 = (UInt8 *)dst;
	UInt8	*s	 = (UInt8 *)src;
	UInt8	len  = *s++;
	

	len = (((UInt32)*src + (UInt32)*dst) < (UInt32)255) ? (UInt32)*src : (UInt32)255 - (UInt32)*dst;
	
	pos += (*pos) + 1;						// pos at end of string.

	while ( (max-- != 0) && (len-- != 0) )
	{
		*pos++ = *s++;						// car src to dst	
		(*d) += 1;							// dump new string length
	}
	
	return dst;
}


/*-------------------------------------------------------------------------------

Routine:	PStrToCStr	-	convert Pascal string 'src' to char string 'dst'.

Function:	Converts 1 byte Pascal string chars to 2 byte char string by prefixing
			the ASCII byte with 0x00. The char string is terminated with a 2 byte
			null character, 0x0000.
			

Input:		src		- pointer to the Pascal source string.

Output:		dst		- pointer to the destination string of char's.
-------------------------------------------------------------------------------*/

void	PStrToCStr	(char	*dst,	ConstStr255Param src)
{
	unsigned char	len;
	
	len = 1 + *src++;							// add 1 so we can predecrement
	while (--len)								// for each char in src...
	{
		*dst++ = (char) *src++;					// cast & copy chars
	}
	
	*dst = 0;									// append null char
}



/*-------------------------------------------------------------------------------

Routine:	CStrToPStr	-	convert char string 'src' to Pascal string 'dst'.

Function:	Converts 2 byte char string chars to 1 byte Pascal string by lopping
			off the high byte. This is NOT considered sound foreign policy, and we
			will have to accomodate our international brethren lest they be displeased
			with us. But, it is useful for development and debugging.
			

Input:		src		- pointer to the char source string.

Output:		dst		- pointer to the Pascal destination string.
-------------------------------------------------------------------------------*/

void	CStrToPStr	(Str255		dst,	const char	*src)
{
	UInt32			 len	= 0;
	const char	*s2	= src;
	
	while (*src++)							// how long is it?
		++len;
	
	if (len > 255)	len = 255;				// truncate to 255 chars
	
	*dst++ = (unsigned char) len++;			// stuff length byte &
											// increment so we can predecrement
	while (--len)
		*dst++ = *s2++;						// copy len chars
}



/////////////////////////////// Compare Routines ////////////////////////////////


/*-------------------------------------------------------------------------------

Routine:	CStrCmp	-	Compare two char strings.

Function:	Compares the char strings s1 and s2 by comparing the values of
			corresponding characters in each string. It does NOT take into
			consideration case, diacriticals, or other localization requirements.


Input:		s1		- pointer to char string.
			s2		- pointer to char string.

			
Result:		-1		- s1 < s2
			 0		- s1 = s2
			 1		- s1 > s2
-------------------------------------------------------------------------------*/

short	CStrCmp	(const char *s1,	const char	*s2)
{
	char		chr;
	
	while ( (chr = *s1++) != 0)
	{ 
		if ( *s2++ != chr )
		{
			if ( chr < *--s2 )
				return -1;
			return 1;
		}
	}
						// here chr==0 and s2 has not advanced
	if(*s2 == 0)
		return 0;
	return -1;
}



/*-------------------------------------------------------------------------------

Routine:	PStrCmp	-	Compare two char strings.

Function:	Compares the char strings s1 and s2 by comparing the values of
			corresponding characters in each string. It does NOT take into
			consideration case, diacriticals, or other localization requirements.


Input:		s1		- pointer to Pascal string.
			s2		- pointer to Pascal string.

			
Result:		-1		- s1 < s2
			 0		- s1 = s2
			 1		- s1 > s2
-------------------------------------------------------------------------------*/

short	PStrCmp	(ConstStr255Param str1, ConstStr255Param str2)
{
	UInt8		s1len,s2len;
	char		chr, *s1, *s2;
	
	s1		= (char *)str1;
	s2		= (char *)str2;
	s1len   = *s1++;
	s2len   = *s2++;
	
	while (s1len && s2len)
	{ 
		s1len--; s2len--;
		chr = *s1++;
		if ( *s2++ != chr )
		{
			if ( chr < *--s2 )
				return -1;
			return 1;
		}
	}
						
	if((s2len == 0) && (s1len == 0))
		return 0;

	if(s1len)
		return 1;
	return -1;
}



/*-------------------------------------------------------------------------------

Routine:	CStrNCmp	-	Compare the first N characters of two char strings.

Function:	Compares the first N char strings s1 and s2 by comparing the values
			of corresponding characters in each string. It does NOT take into
			consideration case, diacriticals, or other localization requirements.


Input:		s1		- pointer to char string.
			s2		- pointer to char string.
			max		- the number of characters to compare.

			
Result:		-1		- s1 < s2
			 0		- s1 = s2
			 1		- s1 > s3
-------------------------------------------------------------------------------*/

short	CStrNCmp	(const char *s1,	const char	*s2,	UInt32	max)
{
	register char c1, c2;		/* s1[] may be shorter s2[] or
										  their length may be equal */

	while (max--)
	{ 
		c1 = *s1++;
		c2 = *s2++;

		if ( c1 != c2 )
		{	
			if ( c1 < c2 )	return -1;
			else			return	1;
		}

		if(c1 == 0)		return	0;
	}
	
	return	0;
}



/*-------------------------------------------------------------------------------

Routine:	PStrNCmp	-	Compare two char strings.

Function:	Compare the first N characters of two char strings.


Input:		s1		- pointer to Pascal string.
			s2		- pointer to Pascal string.
			max		- N chars to compare

			
Result:		-1		- s1 < s2
			 0		- s1 = s2
			 1		- s1 > s2
-------------------------------------------------------------------------------*/

short	PStrNCmp	(ConstStr255Param str1, ConstStr255Param str2, UInt32	max)
{
	char c1, c2;		
	UInt8 l1, l2;
	char *s1,*s2;

	l1 = str1[0]; s1 = (char *)str1; s1++;
	l2 = str2[0]; s2 = (char *)str2; s2++;
	
	if ((l1 == 0) && (l2 == 0))
		return	0;
		
	while (max && l1 && l2)
	{ 
		max--; l1--; l2--;
		c1 = *s1++;
		c2 = *s2++;

		if ( c1 != c2 )
		{	
			if ( c1 < c2 )	return -1;
			else			return	1;
		}
	}
	
	if ((max == 0) || ((l1 == 0) && (l2 == 0)))
		return	0;
		
	if (l1)
		return 1;
	return -1;
}


/*-------------------------------------------------------------------------------

Routine:	CStrLen	-	returns length of char string in characters.

Function:	Returns the length of char string 'src' in characters. This does
			NOT include the terminating null character.


Input:		src		- pointer to a char string.
			
Result:		number of characters in char string 'src'

-------------------------------------------------------------------------------*/

UInt32	CStrLen	(const char	*src)
{
	UInt32 len = 0;
	
	while (*src++)
		++len;
		
	return len;
}

/*-------------------------------------------------------------------------------

Routine:	PStrLen	-	returns length of Pascal string in characters.

Function:	Returns the length of Pascal string 'src' in characters.

Input:		src		- pointer to a Pascal string.
			
Result:		number of characters in Pascal string 'src'

-------------------------------------------------------------------------------*/

UInt32	PStrLen	(ConstStr255Param src)
{
	UInt8	strlen;
	char	*s = (char *)src;
	
	strlen = *s;
	
	return (UInt32)strlen;
}


/////////////////////////////////////////////////////////////////////////////////
//
//	Software Interrupts
//
//

OSErr InitSwis (void)
{
	long	i;
	Swi_Information	*swi;
	
	PBQueueCreate (&CreatedSwis);
	
	PBQueueCreate (&AvailableSwis);
	
	AllSwis = PoolAllocateResident( sizeof(Swi_Information) * N_SWIS, true );
	if ( !AllSwis )
		return memFullErr;
	
	swi = AllSwis;	
	for (i=0;i<N_SWIS;i++)
	{
		// swi->Name = 'SWI!';
		PBEnqueue ( &swi->Link, AvailableSwis);
		swi++;
	}
		
	return noErr;
}

/*-------------------------------------------------------------------------------

Routine:	CurrentTaskID	-	Returns ID of the Current Task. (@NON-Int Lvl)

-------------------------------------------------------------------------------*/

TaskID	CurrentTaskID (void)
{
	if (CurrentExecutionLevel() != kTaskLevel)
	{
		// SysDebugStr ((StringPtr)"\pCurrentTaskID not called at Task Level!");
		return (TaskID)-1;
	}
	
	return (TaskID)0;
}

/*-------------------------------------------------------------------------------

Routine:	DelayFor	-	Block Current Task for a Duration. (@NON-Int Lvl)

-------------------------------------------------------------------------------*/
/*naga
OSStatus DelayFor ( Duration expirationTime )
{
	AbsoluteTime	abt;
	Nanoseconds		nano;
	SInt64			divisor;
	SInt64			remainder;
	SInt64			numTicks;
	unsigned long	finalTicks;
	
	if (CurrentExecutionLevel() != kTaskLevel)
	{
		// SysDebugStr ((StringPtr)"\pDelayFor not called at Task Level!");
		return -1;
	}
	
	abt		= DurationToAbsolute	( expirationTime );
	nano	= AbsoluteToNanoseconds ( abt );
	
	divisor.hi = 0;
	divisor.lo = 16666666;

	numTicks = S64Divide( *(SInt64*)(&nano), divisor, &remainder );
	
	Delay ( numTicks.lo, &finalTicks );
	
	return noErr;
}
naga */
#if 0   //naga
/*-------------------------------------------------------------------------------

Routine:	DelayForHardware	-	Delay for an AbsoluteTime. (Int Lvl)

-------------------------------------------------------------------------------*/

OSStatus DelayForHardware ( AbsoluteTime absoluteTime )
{
	// Obtain the NanoKernel's private pointer to the ProcessorInfo structure.
	// This pointer is contained in the location defined by the private enum
	// 'ProcessorInfoPtr'
	NKProcessorInfo *processorInfo = *((NKProcessorInfo **) nkProcessorInfoPtr);

	if (gDelayForHdwrProc == nil)
	{
		
		// First Time Initialization
		
		if ((processorInfo->ProcessorVersionReg >> 16) == 0x0001)
		{
			// PowerPC 601 Chip (Use RTC, not TimeBase)
			
			gDelayForHdwrProc = DelayForHardware601;
		}
		else
		{
			// Non-PowerPC 601 (Use TimeBase, not RTC)
			
			gDelayForHdwrProc = DelayForHardwarePPC;
		}
	}
	
	return gDelayForHdwrProc(absoluteTime);
}
#endif
/*-------------------------------------------------------------------------------

Routine:	CreateSoftwareInterrupt	-	Makes a SWI. (@any exec-Lvl)

-------------------------------------------------------------------------------*/

OSStatus CreateSoftwareInterrupt	(	SoftwareInterruptHandler	theHandler,
										TaskID						theTask,
										void			*			theParameter,
										Boolean						persistent,
										SoftwareInterruptID *		theSoftwareInterrupt)
{
	Swi_Info	aSwi;
	
	if ( PBDequeueFirst (AvailableSwis, (QElemPtr *)&aSwi) != noErr )
		return paramErr;
		
	aSwi -> Handler		= theHandler;
	aSwi -> The_Id		= (SoftwareInterruptID)aSwi;
	aSwi -> The_Task	= theTask;
	aSwi -> Temporary	= !persistent;
	aSwi -> Sent		= false;
	aSwi -> P1			= (void *)theParameter;
	
	if (theSoftwareInterrupt != nil)
		*theSoftwareInterrupt = (SoftwareInterruptID)aSwi;
		
	PBEnqueue ( &aSwi->Link, CreatedSwis);
	
	return noErr;
}


/*-------------------------------------------------------------------------------

Routine:	SendSoftwareInterrupt	-	Runs a SWI. (@any exec-Lvl)

-------------------------------------------------------------------------------*/

OSStatus SendSoftwareInterrupt		(	SoftwareInterruptID			theSoftwareInterrupt,
										void			*			theParameter)
{
	Swi_Info	aSwi;
	SoftwareInterruptHandler handler;
	Boolean		temp;
	void 		*p1;
	OSErr		Result = PBDequeue ( (QElemPtr)theSoftwareInterrupt, CreatedSwis);
	
	if (Result != noErr)
		return (OSStatus)Result;
		
	aSwi = (Swi_Info)theSoftwareInterrupt;
	
	// Store away swi info in locals.
	handler = aSwi -> Handler;
	p1		= aSwi -> P1;
	temp	= aSwi -> Temporary;
	
	// Return temp swis now.
	if ( temp )
		PBEnqueue ( &aSwi->Link, AvailableSwis );
		
	// Call the handler
	(*handler) (p1, (void *)theParameter);
	
	// Return persistant swis later.
	if ( !temp )
		PBEnqueue ( &aSwi->Link, CreatedSwis );
		
	return noErr;
}

/*-------------------------------------------------------------------------------

Routine:	DeleteSoftwareInterrupt	-	Destroys a SWI. (@any exec-Lvl)

-------------------------------------------------------------------------------*/

OSStatus DeleteSoftwareInterrupt	( SoftwareInterruptID theSoftwareInterrupt )
{
	Swi_Info	aSwi;
	OSErr		Result = PBDequeue ( (QElemPtr)theSoftwareInterrupt, CreatedSwis);

	if (Result != noErr)
		return (OSStatus)Result;
		
	aSwi = (Swi_Info)theSoftwareInterrupt;
	
	PBEnqueue ( &aSwi->Link, AvailableSwis );
	
	return noErr;
}