Source to bsd/dev/ppc/drvUSBCMD/Library/rootHubSimulation.c


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

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "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."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
	File:		rootHubSimulation.c

	Contains:	Packet level simulation of root hub functions

	Version:	Neptune 1.0

	Copyright:	� 1998 by Apple Computer, Inc., all rights reserved.

	File Ownership:

		DRI:				Barry Twycross

		Other Contact:		xxx put other contact here xxx

		Technology:			USB

	Writers:

		(DF)	David Ferguson
		(DKF)	David Ferguson
		(CJK)	Craig Keithley
		(BT)	Barry Twycross

	Change History (most recent first):

	 <USB27>	 6/14/98	DF		change implemented spelling.
	 <USB26>	 5/20/98	BT		Fix alt settings field of interface descriptor
	 <USB25>	 5/17/98	BT		Make get conf descriptor more forgiving. Fix hub endpoint desc
	 <USB24>	 5/14/98	DF		Add status messages for unimplemented root hub stuff, also use
									info from the UIM when getting the hub status.
	 <USB23>	 4/23/98	BT		Fix reset portsuspend change feature
	 <USB22>	 4/20/98	BT		Add device status
	 <USB21>	 4/16/98	BT		Eliminate debugger
	 <USB20>	 4/15/98	BT		More root hub capabilities
	 <USB19>	  4/9/98	BT		Use USB.h
		<18>	  4/2/98	BT		Do OPTI chip gang switching, fix sim stall error number
		<17>	 3/19/98	BT		Split UIM into UIM and root hub parts
		<16>	 3/18/98	BT		Add port enable and clear port enable change features
		<15>	 3/11/98	BT		interrupt transaction simulation
		<14>	  3/9/98	BT		Eliminate one set of redundant descriptors
		<13>	 2/27/98	BT		Add string descriptors
		<12>	 2/25/98	BT		Add Apple product codes.
		<11>	 2/24/98	BT		Change Apple vendor ID.
		<10>	 2/23/98	BT		Simulate root hub to not corrupt reqCount
	  <USB9>	  2/9/98	DKF		Byte swap configuration descriptor totalLength field
		 <8>	  2/8/98	BT		More Power allocation stuff
		 <7>	  2/4/98	BT		Cope with multiple configs
		 <6>	 1/30/98	BT		Put Apple vendor ID in root hub device descriptor
		 <5>	 1/26/98	CJK		Change to use USBDeviceDescriptor (instead of just
									devicedescriptor)
		 <4>	 1/26/98	BT		Mangle names after design review
		 <3>	 1/20/98	BT		Endian swap port status, and other fixes
		 <2>	 1/20/98	BT		More root hub simulation
		 <1>	 1/19/98	BT		first checked in
*/

#include <USB.h>
#include <USBpriv.h>
#include "OHCIUIM.h"
#include "OHCIRootHub.h"
#include "uimpriv.h"
#include "uslpriv.h"
#include "hub.h"
#include <DriverServices.h>

static UInt16 configuration;

static Boolean SimulateSetConfiguration(UInt16 value)
{
	if((value == 1) || (value == 0) )
	{
		configuration = value;
		return(false);
	}
	return(true);
}

static Boolean SimulateGetDeviceDescriptor(UInt8 *buf, UInt32 *bufLen, UInt32 descIndex)
{
UInt32 length;
static USBDeviceDescriptor desc ={
	18,					// UInt8 length;
	kUSBDeviceDesc,		// UInt8 descType;
	USB_CONSTANT16(kUSBRel10),			// UInt16 usbRel;
	kUSBHubClass,		// UInt8 class;
	kUSBHubSubClass,	// UInt8 subClass;
	0,					// UInt8 protocol;
	8,					// UInt8 maxPacketSize;
	USB_CONSTANT16(kAppleVendorID),		// UInt16 vendor; 	Apple = 1452 (decimal, swapped)
	USB_CONSTANT16(kPrdRootHubCMD),		// UInt16 product;	0x8001
	USB_CONSTANT16(0x0100),				// UInt16 devRel;	1.00
	0,					// UInt8 manuIdx;
	0,					// UInt8 prodIdx;
	0,					// UInt8 serialIdx;
	1,					// UInt8 numConf;
	0					// UInt16 end;
	};

	if(descIndex != 0)
	{
		return(true);
	}

	length = sizeof(desc);
	if(*bufLen < length)
	{
		length = *bufLen;
	}
	usb_BlockMoveData(&desc, buf, length);
	*bufLen -= length;
	
	return(false);
}

static Boolean SimulateGetConfDescriptor(UInt8 *buf, UInt32 *bufLen, UInt32 descIndex)
{
UInt32 length;
#define totalLen  (9+9+7)
static USBConfigurationDescriptor confDesc ={
	9,							//UInt8 length;
	kUSBConfDesc,				//UInt8 descriptorType;
	USB_CONSTANT16(totalLen),	//UInt16 totalLength;
	1,							//UInt8 numInterfaces;
	1,							//UInt8 configValue;
	0,							//UInt8 configStrIndex;
	0x60,						//UInt8 attributes; self powered, supports remote wkup
	0,							//UInt8 maxPower;
	};
static USBInterfaceDescriptor intfDesc ={
	9,						//UInt8 length;
	kUSBInterfaceDesc,		//UInt8 descriptorType;
	1,						//UInt8 interfaceNumber;
	0,						//UInt8 alternateSetting;
	1,						//UInt8 numEndpoints;
	kUSBHubClass,			//UInt8 interfaceClass;
	kUSBHubSubClass,		//UInt8 interfaceSubClass;
	1,						//UInt8 interfaceProtocol;
	0						//UInt8 interfaceStrIndex;
	};
static USBEndPointDescriptor endptDesc ={
	7,						//UInt8 length;
	kUSBEndpointDesc,		//UInt8 descriptorType;
	0x81,					//UInt8	 endpointAddress; In, 1
	kUSBInterrupt,			//UInt8 attributes;
	USB_CONSTANT16(8),		//UInt16 maxPacketSize;
	255,					//UInt8 interval;
	};
UInt8 confBuf[totalLen];
	
	if(descIndex != 0)
	{
		//return(true);	// temp don't make this fail while debugging root hub
	}
	if(totalLen != confDesc.length+intfDesc.length+endptDesc.length)
	{
		return(true);
	}
	usb_BlockMoveData(&confDesc, &confBuf[0], confDesc.length);
	usb_BlockMoveData(&intfDesc, &confBuf[confDesc.length], intfDesc.length);
	usb_BlockMoveData(&endptDesc, &confBuf[confDesc.length+intfDesc.length], endptDesc.length);
	
	length = totalLen;
	if(*bufLen < length)
	{
		length = *bufLen;
	}
	usb_BlockMoveData(&confBuf, buf, length);
	*bufLen -= length;
	
	return(false);
}

static Boolean SimulateGetADeviceDescriptor(setupPacket *packet, UInt8 *buf, UInt32 *bufLen)
{
UInt8 descType, descIndex;
	descType = USBToHostWord(packet->word[wValue]) >> 8;
	descIndex = USBToHostWord(packet->word[wValue]) & 0xff;
	if( (packet->word[wIndex] != 0) || (descType != kUSBStringDesc) )
	{
		/* This is not a string descriptor and its is not a string descriptor */
		if(descType == kUSBDeviceDesc)
		{
			return(SimulateGetDeviceDescriptor(buf, bufLen, descIndex));
		}
		else if(descType == kUSBConfDesc)
		{
			return(SimulateGetConfDescriptor(buf, bufLen, descIndex));
		}
		else
		{
			return(true);	/* Unknown dscriptor */
		}
	}
	else if(descType == kUSBStringDesc)
	{
		/* cope with string descriptor */
		return(true);
	}

	/* Non zero index with non string descriptor */
	return(true);
 
}

static Boolean SimulateGetHubDescriptor(setupPacket *packet, UInt8 *buf, UInt32 *bufLen)
{
uslRootHubDescriptor 	descr;
int bytesOfFlags, copy, length;

	if(packet->word[wValue] == 0)
	{
	
		if(UIMGetRootDescriptor(&descr) != noErr)
		{
			return(true);
		}
		
		length = *bufLen;
		
		if(length > 0)
		{
			/* Descriptor length */
			bytesOfFlags = (descr.numPorts+1)/8+1;
			buf[0] = bytesOfFlags*2 + 7;
			length--;
		}
		if(length > 0)
		{
			/* Descriptor type */
			buf[1] = kUSBHubDescriptorType;
			length--;
		}
		if(length > 0)
		{
			buf[2] = descr.numPorts;
			length--;
		}
		if(length > 0)
		{
			if(descr.powerSwitching)
			{
				buf[3] = !descr.gangedSwitching;
			}
			else
			{
				buf[3] = 2;
			}
			if(descr.compoundDevice)
			{
				buf[3] |= 4;
			}
			if(descr.overCurrent)
			{
				buf[3] = (!descr.globalOverCurrent) << 3;
			}
			else
			{
				buf[3] |= 0x10;
			}
			length--;
		}
		if(length > 0)
		{
			/* Flags high byte */			
			buf[4] = 0;
			length--;
		}
		if(length > 0)
		{
			/* power on to good */
			buf[5] = 50;	/* 100 ms? */
			length--;
		}
		if(length > 0)
		{
			/* Hub controller current */
			buf[6] = 0;	/* no cuurrent from bus */
			length--;
		}
		if(length > 0)
		{
			copy = length;
			if(copy > bytesOfFlags)
			{
				copy = bytesOfFlags;
			}
			usb_BlockMoveData(&descr.portFlags[0], &buf[7], copy);
			length -= copy;
		}
		if(length > 0)
		{
		int copy2;
			copy2 = length;
			if(copy2 > bytesOfFlags)
			{
				copy2 = bytesOfFlags;
			}
			usb_BlockMoveData(&descr.portFlags[copy], &buf[7+copy], copy2);
			length -= copy2;
		}
		
		*bufLen -= length;
		return(false);
	}
	
	return(true);


}
static Boolean SimulateClearPortFeature(setupPacket *packet)
{
UInt16 feature, port;
OSStatus err = -1;
	feature = USBToHostWord(packet->word[wValue]);
	port = USBToHostWord(packet->word[wIndex]);
	
	switch(feature)
	{
		case kUSBHubPortConnectionChangeFeature :
			err =UIMRootHubResetChangeConnection(port);
		break;
		
		case kUSBHubPortSuspendChangeFeature :
			err =UIMRootHubResetChangeSuspend(port);
		break;
		
		case kUSBHubPortEnablenFeature :
			err =UIMRootHubPortEnable(port, false);
		break;
		
		case kUSBHubPortPowerFeature :
			err =UIMRootHubPortPower(port, false);
			// Now need to check if all ports are switched off and 
			// gang off if in gang mode
		break;

		case kUSBHubPortResetChangeFeature :
			err =UIMRootHubResetResetChange(port);
		break;

		case kUSBHubPortEnableChangeFeature :
			err =UIMRootHubResetEnableChange(port);
		break;
		
		case kUSBHubPortOverCurrentChangeFeature :
			err =UIMRootHubResetOverCurrentChange(port);
		break;
		

	defualt:
		//DebugStr("\pUnknown port clear");
		USBExpertStatus(0,"\pUSL - Unknown port clear in root hub simulation", 0);
		break;
	}
	return(err != noErr);
}

static Boolean SimulateGetHubStatus(setupPacket *packet, UInt8 *buf, UInt32 *bufLen)
{
OSStatus err = -1;
static struct{
	UInt16 status;
	UInt16 change;
	}hubStatus = {0,0};	/* Change this is overcurrent is implimeneted */
UInt32	rhStatus;

	if( (packet->word[wValue] == 0) && (packet->word[wIndex] == 0) )
	{
		if ((err = UIMGetRhStatus(&rhStatus)) == noErr){
		
			// wouldn't it be handy to have HostToUSBLong
			hubStatus.status = HostToUSBWord(rhStatus & 0x0FFFF);
			hubStatus.change = HostToUSBWord((rhStatus >> 16) & 0x0FFFF);
			
			if(*bufLen > sizeof(hubStatus))
			{
				*bufLen = sizeof(hubStatus);
			}
			usb_BlockMoveData(&hubStatus, buf, *bufLen);
			err = noErr;
		}
	}
	return(err != noErr);
}


static Boolean SimulateGetPortStatus(setupPacket *packet, UInt8 *buf, UInt32 *bufLen)
{
uslRootHubPortStatus stat;
OSStatus err = -1;
UInt32 length;

	if(packet->word[wValue] == 0)
	{
		err = UIMRootHubGetPortStatus(USBToHostWord(packet->word[wIndex]), &stat);
		stat.portChangeFlags = USBToHostWord(stat.portChangeFlags);
		stat.portFlags = USBToHostWord(stat.portFlags);
		if(err == noErr)
		{
			length = *bufLen;
			if(length > sizeof(stat))
			{
				length = sizeof(stat);
			}
			usb_BlockMoveData(&stat, buf, length);
			*bufLen -= length;
		}
	}
	return(err != noErr);
}
static Boolean SimulateSetPortFeature(setupPacket *packet)
{
UInt16 feature, port;
OSStatus err = -1;
	feature = USBToHostWord(packet->word[wValue]);
	port = USBToHostWord(packet->word[wIndex]);
	switch(feature)
	{
		case kUSBHubPortSuspecdFeature :
			err = UIMRootHubPortSuspend(port, true);
		break;
		
		case kUSBHubPortResetFeature :
			err = UIMRootHubResetPort(port);
		break;
		
		case kUSBHubPortEnablenFeature :
			err = UIMRootHubPortEnable(port, true);
		break;
		
		case kUSBHubPortPowerFeature :
			err = UIMRootHubPortPower(port, true);
			if(err == noErr)
			{
				err = UIMRootHubPower(true);
			}
		break;
	
	default:
		//	DebugStr("\pUnknown port set");
		USBExpertStatus(0,"\pUSL - Unknown port set in root hub simulation", 0);
		break;
	}
	return(err != noErr);
}

static Boolean SimulateHubClearFeature(setupPacket *packet)
{
OSStatus err = -1;
	if(packet->word[wValue] == kUSBHubLocalPowerChangeFeature)
	{	
		USBExpertStatus(0,"\pRoot hub simulation - unimplemented Clear Power Change Feature", 0);
		// err = UIMRootHubLPSChange(false);	// not implemented yet
	}
	if(packet->word[wValue] == kUSBHubOverCurrentChangeFeature)
	{	
		USBExpertStatus(0,"\pRoot hub simulation - unimplemented Clear Overcurrent Change Feature", 0);
		// err = UIMRootHubOCChange(false);	// not implemented yet
	}	
	return(err != noErr);
}
static Boolean SimulateHubSetFeature(setupPacket *packet)
{
OSStatus err = -1;
	if(packet->word[wValue] == kUSBHubLocalPowerChangeFeature)
	{	
		USBExpertStatus(0,"\pRoot hub simulation - unimplemented Set Power Change Feature", 0);
		// err = UIMRootHubLPSChange(true);	// not implemented yet
	}
	if(packet->word[wValue] == kUSBHubOverCurrentChangeFeature)
	{	
		USBExpertStatus(0,"\pRoot hub simulation - unimplemented Set Overcurrent Change Feature", 0);
		// err = UIMRootHubOCChange(true);	// not implemented yet
	}	
	return(err != noErr);
}

typedef struct{
	UInt8 *buf;
	UInt32 bufLen;
	CallBackFuncPtr handler;
	UInt32 refCon;
	}intTrans;
#define kMaxOutstandingTrans 4

static intTrans outstanding[kMaxOutstandingTrans];

static UInt32 intLock;


static void rootHubStatusChangeHandler(void)
{	/* Only called if the RHSC bit is set at int. */
UInt16 statusChanged;	/* only have 15 ports in OHCI */
UInt32 status, statusBit;
uslRootHubDescriptor 	descr;
static numPorts;
int index, move;
uslRootHubPortStatus stat;
intTrans last;
	
	last = outstanding[0];
	if(last.handler == nil)
	{
		return;
	}
	
	if(CompareAndSwap(0, 1, &intLock))
	{
		for(index = 1; index < kMaxOutstandingTrans ; index++)
		{
			outstanding[index-1] = outstanding[index];
			if(outstanding[index].handler == nil)
			{
				break;
			}
		}
	
		statusChanged = 0;
		statusBit = 1;
		if(UIMGetRhStatus(&status) == noErr)
		{
			if( (status & kOHCIHcRhStatus_Change ) != 0)
			{
				statusChanged |= statusBit;	/* Hub status change bit */
			}
			
			if(numPorts == 0)
			{
				if(UIMGetRootDescriptor(&descr) == noErr)
				{
					numPorts = descr.numPorts;
				}
				else
				{
					//DebugStr("\pRoot hub int simulation hosed. No ports, tell Barry");
					USBExpertStatus(0,"\pUSL - Root hub int simulation hosed. No ports, tell Barry", 0);
				}
			}

			for(index = 1; index <= numPorts; index++)
			{
				statusBit <<= 1;	/* Next bit */
				
				if(UIMRootHubGetPortStatus(index, &stat) == noErr)
				{
					if(stat.portChangeFlags != 0)
					{
						statusChanged |= statusBit;	/* Hub status change bit */
					}
				}
				
			}
			
		}
		
		move = last.bufLen;
		if(move > sizeof(statusChanged))
		{
			move = sizeof(statusChanged);
		}
		if(numPorts < 8)
		{
			move = 1;
		}
		statusChanged = HostToUSBWord(statusChanged);
		usb_BlockMoveData(&statusChanged, last.buf, move);
		CompareAndSwap(1, 0, &intLock);	/* Unlock the queue */
		(*last.handler)(last.refCon, noErr, last.bufLen - move);
	}
}




void pollRootHubSim(void)
{
UInt32 intrStatus;

	if(outstanding[0].handler != nil)
	{
		if( (UIMGetInterruptStatus(&intrStatus) == noErr) &&
		    ((intrStatus & kOHCIHcInterrupt_RHSC) != 0) )
		{
			UIMClearInterruptStatus(kOHCIHcInterrupt_RHSC);
			rootHubStatusChangeHandler();
		}
	}
}

void SimulateRootHubInt(UInt8 endpoint, UInt8 *buf, UInt32 bufLen,
						CallBackFuncPtr handler, UInt32 refCon)
{
int index;

	if(endpoint != 1)
	{
		(*handler)(refCon, -1, bufLen);
		return;
	}

	if(!CompareAndSwap(0, 1, &intLock))
	{	/* Busy */
		(*handler)(refCon, -1, bufLen);
		return;
	}

	for(index = 0; index < kMaxOutstandingTrans; index++)
	{
		if(outstanding[0].handler == nil)
		{
			/* found free trans */
			outstanding[0].buf = buf;
			outstanding[0].bufLen = bufLen;
			outstanding[0].handler = handler;
			outstanding[0].refCon = refCon;
			CompareAndSwap(1, 0, &intLock);	/* Unlock the queue */
			return;
		}
	}

	CompareAndSwap(1, 0, &intLock);	/* Unlock the queue */
	(*handler)(refCon, -1, bufLen);	/* too many trans */
	
}

void SimulateRootHub(setupPacket *packet, UInt8 endpoint, UInt8 *buf, UInt32 inBufLen,
						CallBackFuncPtr handler, UInt32 refCon)
{
UInt8 dirn, type, recipient;
Boolean stall;
UInt32 *bufLen;
	if(endpoint != 0)
	{
		return;
	}
	bufLen = &inBufLen;	/* Barry, was stamping on param block field */

#if 0
typedef union{
	UInt8 byte[8];
	UInt16 word[4];
	}setupPacket;

enum{
/* Byte offsets */
	bmRqType = 0,
	bUsedFlag = bmRqType,
	bRequest,
/* Word offsets */
	wValue =1,	
	wIndex,
	wLength
	};
#endif

	stall = false;
	dirn = (packet->byte[bmRqType] >> kUSBRqDirnShift) & kUSBRqDirnMask;
	type = (packet->byte[bmRqType] >> kUSBRqTypeShift) & kUSBRqTypeMask;
	recipient = packet->byte[bmRqType] & kUSBRqRecipientMask;

	if(type == kUSBStandard)
	{

#if 0
Standard Requests

bmRequestType bRequest wValue wIndex wLength Data
00000000B		CLEAR_FEATURE	device
00000001B						Interface
00000010B						Endpoint

10000000B GET_CONFIGURATION Zero Zero One Configuration
10000000B GET_DESCRIPTOR Descriptor
10000001B GET_INTERFACE Zero Interface One Alternate

10000000B		GET_STATUS		device
10000001B						Interface
10000010B						Endpoint

00000000B SET_ADDRESS Device
00000000B SET_CONFIGURATION Configuration
00000000B SET_DESCRIPTOR Descriptor

00000000B		SET_FEATURE		device
00000001B						Interface
00000010B						Endpoint

00000001B SET_INTERFACE Alternate
10000010B SYNCH_FRAME Zero Endpoint Two Frame Number#endif
#endif
		switch(packet->byte[bRequest])
		{
			case kUSBRqClearFeature:
				if(packet->byte[bmRqType] == 0x00)
				{
					/* Clear Device Feature */
					stall = SimulateHubClearFeature(packet);
				}
				else if(packet->byte[bmRqType] == 0x01)
				{
					/* Clear Interface Feature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 2");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 2", 0);
				}
				else if(packet->byte[bmRqType] == 0x02)
				{
					/* Clear Endpoint Feature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 3");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 3", 0);
				}
				else
				{
					stall = true;
				}
			break;
		
			case kUSBRqGetConfig:
				if(packet->byte[bmRqType] == 0x80)
				{
					/* Get configuration */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 4");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 4", 0);
				}
				else
				{
					stall = true;
				}
			break;
		
			case kUSBRqGetDescriptor:
				if(packet->byte[bmRqType] == 0x80)
				{
					/* Get descriptor */
					stall = SimulateGetADeviceDescriptor(packet, buf, bufLen);
				}
				else
				{
					stall = true;
				}
			
			break;
		
			case kUSBRqGetInterface:
				if(packet->byte[bmRqType] == 0x81)
				{
					/* Get interface */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 6");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 6", 0);
				}
				else
				{
					stall = true;
				}
			break;
		
			case kUSBRqGetStatus:
				if(packet->byte[bmRqType] == 0x80)
				{
				UInt16 status;
				int copy;
					/* Get Device Status */
					stall = false;
					status = USB_CONSTANT16(1);		// self powered
					copy = sizeof(status);
					if(copy > *bufLen)
					{
						copy = *bufLen;
					}
					usb_BlockMoveData(&status, buf, copy);
					*bufLen -= copy;
					
				}
				else if(packet->byte[bmRqType] == 0x81)
				{
					/* Get Interface Status */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 8");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 8", 0);
				}
				else if(packet->byte[bmRqType] == 0x82)
				{
					/* Get Endpoint Status */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 9");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 9", 0);
				}
				else
				{
					stall = true;
				}
			break;
		
			case kUSBRqSetAddress:
				if(packet->byte[bmRqType] == 0x00)
				{
					/* Set address */
					stall = UIMSetOurAddress(USBToHostWord(packet->word[wValue]));
				}
				else
				{
					stall = true;
				}			
			break;
		
			case kUSBRqSetConfig:
				if(packet->byte[bmRqType] == 0x00)
				{
					/* Set configuration */
					stall = SimulateSetConfiguration(USBToHostWord(packet->word[wValue]));
				}
				else
				{
					stall = true;
				}			
			break;
		
			case kUSBRqSetDescriptor:
				if(packet->byte[bmRqType] == 0x00)
				{
					/* Set descriptor */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 12");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 12", 0);
				}
				else
				{
					stall = true;
				}			
			break;
		
			case kUSBRqSetFeature:
				if(packet->byte[bmRqType] == 0x00)
				{
					/* Set Device Feature */
					stall = SimulateHubSetFeature(packet);
				}
				else if(packet->byte[bmRqType] == 0x01)
				{
					/* Set Interface Feature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 14");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 14", 0);
				}
				else if(packet->byte[bmRqType] == 0x02)
				{
					/* Set Endpoint Feature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 15");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 15", 0);
				}
				else
				{
					stall = true;
				}
			break;
		
			case kUSBRqSetInterface:
				if(packet->byte[bmRqType] == 0x01)
				{
					/* Set interface */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 16");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 16", 0);
				}
				else
				{
					stall = true;
				}			
			break;
		
			case kUSBRqSyncFrame:
				stall = true;
			break;

			default:
				stall = true;
			break;

		}
	}
	else if(type == kUSBClass)
	{

#if 0
Class-specific Requests

ClearHubFeature  0010 0000B CLEAR_FEATURE Feature
ClearPortFeature 0010 0011B CLEAR_FEATURE Feature
GetBusState      1010 0011B GET_STATE Zero Port One Per Port
GetHubDescriptor 1010 0000B GET_DESCRIPTOR Descriptor
GetHubStatus     1010 0000B GET_STATUS Zero Zero Four Hub Status
GetPortStatus    1010 0011B GET_STATUS Zero Port Four Port Status
SetHubDescriptor 0010 0000B SET_DESCRIPTOR Descriptor
SetHubFeature    0010 0000B SET_FEATURE Feature
SetPortFeature   0010 0011B SET_FEATURE Feature
#endif		
		switch(packet->byte[bRequest])
		{
			case kUSBRqClearFeature:
				if(packet->byte[bmRqType] == 0x20)
				{
					/* ClearHubFeature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 17");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 17", 0);
				}
				else if(packet->byte[bmRqType] == 0x23)
				{
					stall = SimulateClearPortFeature(packet);
				}
				else
				{
					stall = true;
				}
			
			break;
				
			case kUSBRqReserved1 /*GET_STATE*/:
				if(packet->byte[bmRqType] == 0xA3)
				{
					/* GetBusState */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 18");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 18", 0);
				}
				else
				{
					stall = true;
				}
			break;
				
			case kUSBRqGetDescriptor:
				if(packet->byte[bmRqType] == 0xA0)
				{
					/* GetHubDescriptor */
					SimulateGetHubDescriptor(packet, buf, bufLen);
				}
				else
				{
					stall = true;
				}
			
			break;
				
			case kUSBRqGetStatus:
				if(packet->byte[bmRqType] == 0xA0)
				{
					/* GetHubStatus */
					stall = SimulateGetHubStatus(packet, buf, bufLen);
				}
				else if(packet->byte[bmRqType] == 0xA3)
				{
					stall = SimulateGetPortStatus(packet, buf, bufLen);
				}
				else
				{
					stall = true;
				}
			
			break;
				
			case kUSBRqSetDescriptor:
				if(packet->byte[bmRqType] == 0x20)
				{
					/* SetHubDescriptor */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 20");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 20", 0);
				}
				else
				{
					stall = true;
				}
			
			break;
				
			case kUSBRqSetFeature :
				if(packet->byte[bmRqType] == 0x20)
				{
					/* SetHubFeature */
					stall = true;
					//DebugStr("\pRoot hub not implemented yet 21");
					USBExpertStatus(0,"\pUSL - Root hub not implemented yet 21", 0);
				}
				else if(packet->byte[bmRqType] == 0x23)
				{
					stall = SimulateSetPortFeature(packet);
				}
				else
				{
					stall = true;
				}
			break;

			default:
				stall = true;
			break;
		}

	}
	else
	{
		stall = true;
	}
	
	if(stall)
	{
		//DebugStr("\pSim Stall");
		USBExpertStatus(0,"\pUSL - Root hub simulated stall", 0);
	}
	(*handler)(refCon, stall?4:noErr, *bufLen);
}

void ResetRootHubSimulation(void)
{
	int	index;
	
	for(index = 0; index < kMaxOutstandingTrans; index++)
	{
		outstanding[0].handler = nil; // clear out any outstanding transactions
	}
	intLock = 0;
}