Source to bsd/dev/ppc/drvUSBCMD/UIMrootHubSimulation.c
/*
* 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: UIMRootHubSimulation.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):
<USB4> 8/25/98 BT Isoc name changes
<USB3> 8/12/98 BT Allow more than 1 control at a time.
<USB2> 6/30/98 BT Tidy up
<USB1> 6/30/98 BT first checked in
*/
/*
// UIMrootHubSimulation is USL's rootHubSimulation moved across
<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 "driverservices.h" //naga
#include "USB.h"
#include "USBpriv.h"
#include "OHCIUIM.h"
#include "OHCIRootHub.h"
//naga#include "driverservices.h"
// Need some way of talking to the outside here
#define USBExpertStatus(a,b, c)
// This isn't used at the moment
#define UIM_Bus 0
// Put these in globals struct????
typedef struct{
UInt8 *buf;
UInt32 bufLen;
CallBackFuncPtr handler;
UInt32 refCon;
}intTrans;
#define kMaxOutstandingTrans 4
static intTrans outstanding[kMaxOutstandingTrans];
static UInt32 intLock;
//naga typedef UInt32 *QHdrPtr; //naga temporary
static QHdrPtr simCallbackQueue;
static UInt16 configuration;
UInt16 Swap16(UInt16 value);
UInt16 Swap16(UInt16 value)
{
return( (value << 8) | (value >> 8) );
}
#define HostToUSBWord Swap16
#define USBToHostWord Swap16
#if 0
if(simCallbackQueue == nil)
{
if( (PBQueueCreate(&simCallbackQueue) != noErr) ||
(PBQueueInit(simCallbackQueue) != noErr) )
{
/* Panic */
USBExpertStatus(0,"\pUSL - failed to initialise root simulation queue", 0);
}
}
OSStatus UIMProcessDoneQueue(void)
{
USBPB *pb;
if( (simCallbackQueue != nil) && (simCallbackQueue->qHead != nil) )
{
while(PBDequeueFirst(simCallbackQueue, (void *)&pb) == noErr)
{
uslInterruptPriority(-1);
if(pb == nil)
{
USBExpertStatus(-1, "\pNil pb", 0);
}
else
{
if (pb->usbCompletion && (pb->usbCompletion != kUSBNoCallBack))
(*pb->usbCompletion)(pb);
}
}
}
#if 0
#if CHECK_UIM
static void **UIM, *UIM1;
checkUIMMoved(&UIM, &UIM1, (void *)&UIMPlugIn->uimProcessDoneQueueProc);
#endif
if(UIMPlugIn != nil)
{
return(*UIMPlugIn->uimProcessDoneQueueProc)();
}
return(-1);
#else
return(noErr);
#endif
}
static void simIntPktHandler(long refCon, OSStatus status, short shortfall)
{
USBPB *pb;
if(refCon == 0)
{
return;
}
pb = (void *)refCon;
status = doUSLStatus(status, pb->usbReference);
pb->usbStatus = status;
pb->usbActCount = pb->usbReqCount - shortfall;
uslInterruptPriority(+1);
PBEnqueueLast((void *)pb, simCallbackQueue);
}
static void simPktHandler(long refCon, OSStatus status, short shortfall)
{
USBPB *pb;
if(refCon == 0)
{
return;
}
pb = (void *)refCon;
status = doUSLStatus(status, pb->usbReference);
pb->usbStatus = status;
pb->usbActCount = pb->usbReqCount - shortfall;
pb->usb.cntl.WIndex = USBToHostWord(pb->usb.cntl.WIndex);
pb->usb.cntl.WValue = USBToHostWord(pb->usb.cntl.WValue);
uslInterruptPriority(+1);
PBEnqueueLast((void *)pb, simCallbackQueue);
}
#endif
// *********
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)
{
struct uslRootHubDescriptor descr; //naga struct added
int bytesOfFlags, copy, length;
if(packet->word[wValue] == 0)
{
if(OHCIGetRootDescriptor(UIM_Bus, &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 =OHCIRootHubResetChangeConnection(UIM_Bus, port);
break;
case kUSBHubPortSuspendChangeFeature :
err =OHCIRootHubResetSuspendChange(UIM_Bus, port);
break;
case kUSBHubPortEnablenFeature :
err =OHCIRootHubPortEnable(UIM_Bus, port, false);
break;
case kUSBHubPortPowerFeature :
err =OHCIRootHubPortPower(UIM_Bus, port, false);
// Now need to check if all ports are switched off and
// gang off if in gang mode
break;
case kUSBHubPortResetChangeFeature :
err =OHCIRootHubResetResetChange(UIM_Bus, port);
break;
case kUSBHubPortEnableChangeFeature :
err =OHCIRootHubResetEnableChange(UIM_Bus, port);
break;
case kUSBHubPortOverCurrentChangeFeature :
err =OHCIRootHubResetOverCurrentChange(UIM_Bus, port);
break;
default:
//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 = OHCIGetRhStatus(UIM_Bus, &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)
{
struct uslRootHubPortStatus stat; //naga added struct
OSStatus err = -1;
UInt32 length;
if(packet->word[wValue] == 0)
{
err = OHCIRootHubGetPortStatus(UIM_Bus, 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 = OHCIRootHubPortSuspend(UIM_Bus, port, true);
break;
case kUSBHubPortResetFeature :
err = OHCIRootHubResetPort(UIM_Bus, port);
break;
case kUSBHubPortEnablenFeature :
err = OHCIRootHubPortEnable(UIM_Bus, port, true);
break;
case kUSBHubPortPowerFeature :
err = OHCIRootHubPortPower(UIM_Bus, port, true);
if(err == noErr)
{
err = OHCIRootHubPower(UIM_Bus, 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 = OHCIRootHubLPSChange(UIM_Bus, false); // not implemented yet
}
if(packet->word[wValue] == kUSBHubOverCurrentChangeFeature)
{
USBExpertStatus(0,"\pRoot hub simulation - unimplemented Clear Overcurrent Change Feature", 0);
// err = OHCIRootHubOCChange(UIM_Bus, 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 = OHCIRootHubLPSChange(UIM_Bus, true); // not implemented yet
}
if(packet->word[wValue] == kUSBHubOverCurrentChangeFeature)
{
USBExpertStatus(0,"\pRoot hub simulation - unimplemented Set Overcurrent Change Feature", 0);
// err = OHCIRootHubOCChange(UIM_Bus, true); // not implemented yet
}
return(err != noErr);
}
void rootHubStatusChangeHandler(void)
{ /* Only called if the RHSC bit is set at int. */
UInt16 statusChanged; /* only have 15 ports in OHCI */
UInt32 status, statusBit;
struct uslRootHubDescriptor descr; //naga added struct
static numPorts=0;
int index, move;
struct uslRootHubPortStatus stat; //naga added struct
intTrans last;
last = outstanding[0];
/*naga
*/
if(last.handler == nil)
{
kprintf("rootHubStatusChangeHandler: last handler = nil\n");
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(OHCIGetRhStatus(UIM_Bus, &status) == noErr)
{
if( (status & kOHCIHcRhStatus_Change ) != 0)
{
kprintf("Hub status change bit set to 1 \n");
statusChanged |= statusBit; /* Hub status change bit */
}
if(numPorts == 0)
{
if(OHCIGetRootDescriptor(UIM_Bus, &descr) == noErr)
{
numPorts = descr.numPorts;
kprintf("#ports=%d\n",numPorts);
}
else
{
//DebugStr("\pRoot hub int simulation hosed. No ports, tell Barry");
kprintf("USL - Root hub int simulation hosed. No ports, tell Barry");
}
}
for(index = 1; index <= numPorts; index++)
{
statusBit <<= 1; /* Next bit */
if(OHCIRootHubGetPortStatus(UIM_Bus, 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 */
//naga (*last.handler)(last.refCon, noErr, last.bufLen - move);
(*last.handler)(last.refCon, noErr, last.bufLen - move);
}
}
void pollRootHubSim(void)
{
UInt32 intrStatus;
//naga if(outstanding[0].handler != nil)
if(outstanding[0].handler != nil)
{
if( (OHCIGetInterruptStatus(UIM_Bus, &intrStatus) == noErr) &&
((intrStatus & kOHCIHcInterrupt_RHSC) != 0) )
{
OHCIClearInterruptStatus(UIM_Bus, kOHCIHcInterrupt_RHSC);
//kprintf("calling rootHubStatusChange handler\n");
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 */
}
static Boolean SimulateRootHub(setupPacket *packet, UInt8 *buf, UInt32 *bufLen)
{
UInt8 dirn, type, recipient;
Boolean stall;
#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;
//kprintf("SimulateRootHub:request=0x%x,type=0x%x\n",packet->byte[bRequest],type);
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 = OHCISetOurAddress(UIM_Bus, 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);
}
return(stall);
}
typedef struct{
setupPacket *packet;
UInt8 *buf;
UInt32 bufLen;
CallBackFuncPtr handler1;
UInt32 refCon1;
CallBackFuncPtr handler2;
UInt32 refCon2;
CallBackFuncPtr handler3;
UInt32 refCon3;
Boolean stall;
int state;
} RHTransaction;
static RHTransaction tr;
#define kMaxRHtr 16
static RHTransaction RHDone[kMaxRHtr];
static UInt32 inUse[kMaxRHtr];
enum{
kNone = 0,
kSetupReceived,
kDataRecevied,
kStatusDone
};
static void cleanState(RHTransaction *tr)
{
if( (tr->state != kDataRecevied) && (tr->state != kStatusDone) )
{
tr->buf = nil;
tr->bufLen = 0;
tr->handler2 = nil;
tr->refCon2 = 0;
tr->handler3 = nil;
tr->refCon3 = 0;
if(tr->state != kSetupReceived)
{
tr->handler1 = nil;
tr->refCon1 = 0;
tr->packet = nil;
tr->state = kNone;
}
}
}
static RHTransaction *queueTR(RHTransaction *tr)
{
int i;
for(i = 0; i< kMaxRHtr; i++)
{
if(CompareAndSwap(0, 1, &inUse[i]))
{
RHDone[i] = *tr;
tr->state = kNone;
cleanState(tr);
inUse[i]++;
return(&RHDone[i]);
}
}
return(tr);
}
OSStatus UIMSimulateRootHubStages(
UInt32 refcon,
CallBackFuncPtr handler,
UInt32 CBP,
Boolean bufferRounding,
short endpointNumber,
short bufferSize,
short direction);
OSStatus UIMSimulateRootHubStages(
UInt32 refcon,
CallBackFuncPtr handler,
UInt32 CBP,
Boolean bufferRounding,
short endpointNumber,
short bufferSize,
short direction)
{
static directionReceived;
RHTransaction *trOut;
if(endpointNumber != 0)
{
bufferRounding = 0; // stop annoying warning
return(-1);
}
if( (direction != kUSBIn) && (direction != kUSBOut)) // setup packet
{ /* Setup packet over rides any previous state */
if(tr.state != kNone) // no queues we only cope with one (complete) control per frame.
{
return(kUSBDeviceBusy);
}
cleanState(&tr);
if(bufferSize != 8)
{
tr.state = kNone;
}
tr.packet = (void *)CBP;
tr.handler1 = handler;
tr.refCon1 = refcon;
tr.state = kSetupReceived;
directionReceived = (((*(UInt8 *)CBP) & 0x80) == 0)?kUSBOut:kUSBIn;
}
else
{
if(directionReceived != direction) // status phase is reverse data
{
tr.handler3 = handler;
tr.refCon3 = refcon;
trOut = queueTR(&tr);
trOut->stall = SimulateRootHub(trOut->packet, trOut->buf, &trOut->bufLen);
directionReceived = 0;
trOut->state = kStatusDone;
OHCISetFrameInterrupt();
return(noErr);
}
else if(tr.state == kSetupReceived)
{
tr.buf = (void *)CBP;
tr.bufLen = bufferSize;
tr.handler2 = handler;
tr.refCon2 = refcon;
tr.state = kDataRecevied;
}
else
{
tr.state = kNone;
}
}
cleanState(&tr);
return(noErr);
}
static void rootHubDispatch(RHTransaction *tr)
{
CallBackFuncPtr handler;
UInt32 refCon;
UInt32 retBufLen;
if(tr->state != kStatusDone)
{
return;
}
// need to sync to end of frame here
if(tr->handler1 != nil)
(*tr->handler1)(tr->refCon1, noErr, 0);
if(tr->handler2 != nil)
(*tr->handler2)(tr->refCon2, noErr, 0);
handler = tr->handler3;
refCon = tr->refCon3;
retBufLen = tr->bufLen;
tr->state = kNone;
cleanState(tr);
if(handler != nil)
{
(*handler)(refCon, tr->stall?4:noErr, retBufLen);
}
}
OSStatus RootHubFrame(void *p1, void *p2)
{
int i;
p1 = 0;
p2 = 0;
for(i = 0; i< kMaxRHtr; i++)
{
if(inUse[i] == 2)
{
rootHubDispatch(&RHDone[i]);
cleanState(&RHDone[i]);
inUse[i] = 0;
}
}
rootHubDispatch(&tr);
return(noErr);
}
OSStatus RootHubStatusChange(void *p1, void *p2)
{
p1 = 0;
p2 = 0;
//SysDebug();
if(outstanding[0].handler != nil)
{
rootHubStatusChangeHandler();
}
return(noErr);
}
void OHCIPollRootHubSim(uslBusRef bus)
{
bus = 0;
RootHubFrame(nil, nil);
pollRootHubSim();
}
void ResetRootHubSimulation(void)
{
int index;
for(index = 0; index < kMaxOutstandingTrans; index++)
{
outstanding[0].handler = nil; // clear out any outstanding transactions
}
intLock = 0;
OHCISetOurAddress(0, 0);
}