Source to bsd/dev/ppc/drvUSBCMD/Library/uslPipe.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: uslPipe.c
Contains: xxx put contents here xxx
Version: xxx put version here xxx
Copyright: � 1998 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:
(BT) Barry Twycross
Change History (most recent first):
<USB18> 11/16/98 BT Clear pipe state on open
<USB17> 11/5/98 BT Fix returning noErr instead of pending.
<USB16> 10/22/98 BT Fix wrong status for deleted devices.
<USB15> 10/12/98 BT Add addressed device request
<USB14> 9/29/98 BT Use real frame timing
<USB13> 8/31/98 BT Add isoc pipes
<USB12> 8/25/98 BT Isoc name changes
<USB11> 8/24/98 BT Isoc param block definition
<USB10> 8/13/98 BT Add multibus support
<USB9> 8/13/98 BT Allow zero length transactions
<USB8> 7/23/98 BT Cut annoying message
<USB7> 7/7/98 BT Avoid control reentrancy problem by making sure they're done at
secondary interrupt time.
<USB6> 5/21/98 BT Don't corrupt usbBuffer when diverting to opendevice.
<USB5> 5/20/98 BT Find implicit dev config
<USB4> 5/20/98 BT Fix pipe devidx field
<USB3> 5/17/98 BT Device request doesn't squash reqcount, buffer. Add internal
open pipe for config interface
<USB2> 4/28/98 BT Add bulk performance monitoring.
<USB1> 4/26/98 BT first checked in
*/
#include "../USB.h"
#include "../USBpriv.h"
#include "uslpriv.h"
#include "../uimpriv.h"
#include "../driverservices.h"
static pipe pipeZeroZero; // the default pipe to device zero
#if 0
static OSStatus uslOpenControlEndpoint(struct USBPB *pb)
{
usbDevice *deviceP;
OSStatus retVal = kUSBInternalErr;
pipe *newPipe;
do{ /* For error recovery */
/* Validate device */
deviceP = getDevicePtr(pb->usbReference);
if(deviceP == nil)
{
retVal = kUSBUnknownDeviceErr;
break;
}
#if 0
/* Validate endpoint */
if(deviceP->numberOfEndpoints >= endpoint)
{
retVal = kUSBUnknownEndpointErr;
break;
}
#endif
newPipe = getPipe(deviceP, pb->usbValue2);
if(newPipe != nil)
{
retVal = kUSBAlreadyOpenErr;
break;
}
/* This endpoint has not yet been opened. */
if(pb->usbValue2 == 0) /* Endpoint zero is a control endpoint */
{
retVal = kUSBUnknownEndpointErr;
break;
}
/* Allocate a new pipe */
newPipe = AllocPipe(deviceP, pb->usbValue2);
if(newPipe == nil)
{
retVal = kUSBTooManyPipesErr;
break;
}
/* Fill in pertinent information for this pipe instantiation */
newPipe->deviceIdx = makeDeviceIdx(pb->usbReference);
newPipe->intrfc = pb->usbReference;
newPipe->endPt = pb->usbValue2;
newPipe->devAddress = deviceP->usbAddress;
newPipe->flags = pb->usbFlags;
newPipe->state = kUSBActive;
#if 0
retVal = UIMSetupControlEndpoint(newPipe->addEnd, &newPipe->uimRef,
newPipe->maxPacket, controlCallBack, newPipe->iflags, newPipe->addEnd /* refCon */);
#endif
if(retVal != kUSBNoErr)
{
deallocPipe(deviceP, pb->usbValue2);
break;
}
pb->usbReference = newPipe->ref;
/* Just assume you can have an endpoint zero for now. */
/* Shouldn't this be already open */
#if 0
/* XXXXXXXX In real version should add something here */
if(pipeH->type != kUSBControlType)
{
retVal = kUSBIncorrectTypeErr;
break;
}
#endif
retVal = kUSBNoErr;
break;
}while(0); /* End error checking */
return(retVal);
}
#endif
static OSStatus uslOpenInterruptEndpoint(USBPB *pb)
{
usbDevice *deviceP;
OSStatus retVal = kUSBInternalErr;
pipe *newPipe;
do{ /* For error recovery */
/* Validate device */
deviceP = getDevicePtr(pb->usbReference);
if(deviceP == nil)
{
retVal = kUSBUnknownDeviceErr;
break;
}
#if 0
/* Validate endpoint */
if(deviceP->numberOfEndpoints >= endpoint)
{
retVal = kUSBUnknownEndpointErr;
break;
}
#endif
newPipe = getPipe(deviceP, pb->usbOther, kUSBIn);
if(newPipe != nil)
{
retVal = kUSBAlreadyOpenErr;
break;
}
/* This endpoint has not yet been opened. */
if(pb->usbOther == 0) /* Int pipe can't be zero */
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* Allocate a new pipe */
newPipe = AllocPipe(deviceP, pb->usbOther, kUSBIn);
if(newPipe == nil)
{
retVal = kUSBTooManyPipesErr;
break;
}
/* Fill in pertinent information for this pipe instantiation */
newPipe->bus = deviceP->bus;
newPipe->devIntfRef = pb->usbReference;
newPipe->endPt = pb->usbOther;
newPipe->direction = kUSBIn;
newPipe->devAddress = deviceP->usbAddress;
newPipe->flags = pb->usbFlags;
newPipe->type = kUSBInterrupt;
newPipe->maxPacket = pb->usb.cntl.WValue;
newPipe->state = kUSBActive;
pb->usbReference = 0;
retVal = UIMInterruptEDCreate(newPipe->bus,
newPipe->devAddress,
pb->usbOther, /* User gives Endpoint number here */
pb->usb.cntl.WValue, /* System fills in Max packet size here */
deviceP->speed);
pb->usbStatus = retVal;
if(retVal != kUSBNoErr)
{
deallocPipe(deviceP, pb->usbOther, kUSBIn);
break;
}
pb->usbReference = newPipe->ref;
if(pb->usbCompletion != nil)
{
(*pb->usbCompletion)(pb);
}
break;
}while(0); /* End error checking */
return(retVal);
}
static OSStatus uslOpenIsocEndpoint(USBPB *pb)
{
usbDevice *deviceP;
OSStatus retVal = kUSBInternalErr;
pipe *newPipe;
USBDirection usbDirection;
do{ /* For error recovery */
/* Validate device */
deviceP = getDevicePtr(pb->usbReference);
if(deviceP == nil)
{
retVal = kUSBUnknownDeviceErr;
break;
}
#if 0
/* Validate endpoint */
if(deviceP->numberOfEndpoints >= endpoint)
{
retVal = kUSBUnknownEndpointErr;
break;
}
#endif
usbDirection = pb->usbFlags & 0xff;
newPipe = getPipe(deviceP, pb->usbOther, usbDirection);
if(newPipe != nil)
{
retVal = kUSBAlreadyOpenErr;
break;
}
/* This endpoint has not yet been opened. */
if(pb->usbOther == 0) /* Isoc pipe can't be zero */
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* Allocate a new pipe */
newPipe = AllocPipe(deviceP, pb->usbOther, usbDirection);
if(newPipe == nil)
{
retVal = kUSBTooManyPipesErr;
break;
}
/* Fill in pertinent information for this pipe instantiation */
newPipe->bus = deviceP->bus;
newPipe->devIntfRef = pb->usbReference;
newPipe->endPt = pb->usbOther;
newPipe->direction = usbDirection;
newPipe->devAddress = deviceP->usbAddress;
newPipe->flags = pb->usbFlags;
newPipe->type = kUSBIsoc;
newPipe->maxPacket = pb->usb.cntl.WValue;
newPipe->state = kUSBActive;
pb->usbReference = 0;
retVal = UIMIsocEDCreate(newPipe->bus,
newPipe->devAddress,
pb->usbOther, /* User gives Endpoint number here */
usbDirection,
pb->usb.cntl.WValue); /* System fills in Max packet size here */
pb->usbStatus = retVal;
if(retVal != kUSBNoErr)
{
deallocPipe(deviceP, pb->usbOther, usbDirection);
break;
}
pb->usbReference = newPipe->ref;
if(pb->usbCompletion != nil)
{
(*pb->usbCompletion)(pb);
}
break;
}while(0); /* End error checking */
return(retVal);
}
static OSStatus uslOpenBulkEndpoint(USBPB *pb)
{
usbDevice *deviceP;
OSStatus retVal = kUSBInternalErr;
pipe *newPipe;
USBDirection usbDirection;
do{ /* For error recovery */
/* Validate device */
deviceP = getDevicePtr(pb->usbReference);
if(deviceP == nil)
{
retVal = kUSBUnknownDeviceErr;
break;
}
#if 0
/* Validate endpoint */
if(deviceP->numberOfEndpoints >= endpoint)
{
retVal = kUSBUnknownEndpointErr;
break;
}
#endif
usbDirection = pb->usbFlags & 0xff;
newPipe = getPipe(deviceP, pb->usbOther, usbDirection);
if(newPipe != nil)
{
retVal = kUSBAlreadyOpenErr;
break;
}
/* This endpoint has not yet been opened. */
if(pb->usbOther == 0) /* Not default pipe */
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* Allocate a new pipe */
newPipe = AllocPipe(deviceP, pb->usbOther, usbDirection );
if(newPipe == nil)
{
retVal = kUSBTooManyPipesErr;
break;
}
/* Fill in pertinent information for this pipe instantiation */
newPipe->bus = deviceP->bus;
newPipe->devIntfRef = pb->usbReference;
newPipe->endPt = pb->usbOther;
newPipe->direction = usbDirection;
newPipe->devAddress = deviceP->usbAddress;
newPipe->flags = pb->usbFlags;
newPipe->type = kUSBBulk;
newPipe->maxPacket = pb->usb.cntl.WValue;
newPipe->state = kUSBActive;
retVal = UIMBulkEDCreate(newPipe->bus,
newPipe->devAddress,
pb->usbOther, /* User gives Endpoint number here */
usbDirection,
pb->usb.cntl.WValue);
if(retVal != kUSBNoErr)
{
deallocPipe(deviceP, pb->usbOther, usbDirection );
break;
}
pb->usbReference = newPipe->ref;
retVal = kUSBNoErr;
if(pb->usbCompletion != nil)
{
(*pb->usbCompletion)(pb);
}
break;
}while(0); /* End error checking */
return(retVal);
}
static OSStatus usbSIControlPacket(void *p1, void *addrEp)
{ // p1 is pointer to paramblock
// second param has addr and endpoint munged together
UInt32 p2;
UInt8 addr, endPt;
OSStatus err;
USBPB *pb;
UInt32 bus;
p2 = (UInt32)addrEp;
bus = p2 >> 16;
addr = (p2>>8) & 0xff;
endPt = p2 & 0xf;
err = usbControlPacket(bus, p1, addr, endPt);
if(err != noErr)
{
pb = p1;
if( (pb->usbCompletion != nil) && (pb->usbCompletion != (void *)-1) )
{
pb->usbStatus = err;
(*pb->usbCompletion)(pb);
}
}
return(noErr);
}
/* We need to make sure these are queued as well */
OSStatus xUSLControlRequest(UInt32 bus, USBPB *pb, pipe *thisPipe)
{
setupPacket *packet;
OSStatus err = kUSBPending;
USBDirection direction;
USBRqType type;
USBRqRecipient recipient;
USBRequest request;
UInt16 transferSize;
//kprintf("xUSLControlRequest:ref=0x%x,device=%d\n",thisPipe->ref,thisPipe->devAddress);
do{
direction = pb->usb.cntl.BMRequestType >> 7;
type = (pb->usb.cntl.BMRequestType >> 5) & 3;
recipient = pb->usb.cntl.BMRequestType & 31;
request = pb->usb.cntl.BRequest;
/* FInd the packet in the param block */
packet = (void *)&pb->usb.cntl.BMRequestType;
/* Check the direction flag */
if(kUSBNone == direction || pb->usbReqCount == 0 || pb->usbBuffer == nil)
{
transferSize = 0; /* Don't sit on reqcount and buffer */
direction = kUSBOut;
}
else
{
transferSize = pb->usbReqCount;
}
/* Put together the bitmap request type byte */
if(packet->byte[bmRqType] == 0xff)
{
err = kUSBRqErr;
break;
}
/* Check the request is a valid one */
if( (type == kUSBStandard) &&
(request < kUSBRqGetStatus || request > kUSBRqSyncFrame ||
request == kUSBRqReserved1 || request == kUSBRqReserved2) )
{
err = kUSBUnknownRequestErr;
break;
}
/* Put together the rest of the packet */
packet->word[wValue] = HostToUSBWord(pb->usb.cntl.WValue);
packet->word[wIndex] = HostToUSBWord(pb->usb.cntl.WIndex);
packet->word[wLength] = HostToUSBWord(transferSize);
pb->usbStatus = kUSBPending;
if(CurrentExecutionLevel() == kSecondaryInterruptLevel)
{
err = usbControlPacket(bus, pb, thisPipe->devAddress, thisPipe->endPt);
}
else
{
#if 0
static pipe *rootHub;
// temp hack.
// If we're not being called at secondary int, avoid reentrancy prob
// by arranging to be called at secondary int.
// First try to suppress root hub messages
if(rootHub == nil) // assume first seen pipe is root hub
{
rootHub = thisPipe;
}
if(thisPipe != rootHub)
{
USBExpertStatus(-1, "\pUSL - Queueing secondary interrupt Control", thisPipe->devAddress);
}
#endif
// now queue the call back. address and endpoint munged into second parameter
err = QueueSecondaryInterruptHandler(usbSIControlPacket, nil, pb,
(void *)(
(bus << 16) +
((UInt32)thisPipe->devAddress << 8) +
((UInt32)thisPipe->endPt)
) );
}
/* Processing now continues in controlCallBack */
}while(0);
if(err == noErr)
{
err = kUSBPending;
}
else
{
pb->usbStatus = err;
}
return(err);
}
OSStatus uslDeviceRequest(USBPB *pb)
{
USBReference ref0, ref;
pipe *thisPipe;
OSStatus retVal = noErr;
UInt32 bus=0;
do{
ref = pb->usbReference;
if((pb->usbFlags & kUSBAddressRequest) != 0)
{
USBRqRecipient recipient;
recipient = pb->usb.cntl.BMRequestType & 31;
if(recipient == kUSBInterface)
{
uslInterface *ifc;
retVal = findInterface(ref, &ifc);
if(ifc != nil)
{
pb->usb.cntl.WIndex = ifc->interfaceNum;
}
}
else if(recipient == kUSBEndpoint)
{
thisPipe = GetPipePtr(ref);
if(thisPipe != 0)
{
ref = thisPipe->devIntfRef;
pb->usb.cntl.WIndex = thisPipe->endPt;
if(thisPipe->direction == kUSBIn)
{
pb->usb.cntl.WIndex |= 0x80;
}
}
else
{
retVal = kUSBUnknownPipeErr;
}
}
else
{
retVal = paramErr;
}
if(retVal != noErr)
{
pb->usbStatus = retVal;
break;
}
}
ref0 = getPipeZero(ref);
if(ref0 == nil)
{
if(uslHubValidateDevZero(ref, &bus))
{
thisPipe = &pipeZeroZero;
thisPipe->bus = bus;
}
else
{
retVal = kUSBUnknownDeviceErr;
break;
}
}
else
{
thisPipe = GetPipePtr(ref0);
if(thisPipe == nil)
{
pb->usbStatus = kUSBUnknownPipeErr;
break;
}
}
retVal = xUSLControlRequest(thisPipe->bus, pb, thisPipe);
if(retVal != kUSBPending)
{
break;
}
}while(0);
return(retVal);
}
OSStatus USBDeviceRequest(USBPB *pb)
{
if(!checkPBVersion(pb, kUSBAddressRequest))
{
return(pb->usbStatus);
}
/* Short circuit config device requests */
if( (pb->pbVersion != 1) && // requires 0.02 PB
(pb->usb.cntl.BMRequestType == 0) &&
(pb->usb.cntl.BRequest == kUSBRqSetConfig) )
{
pb->usbReqCount = 0;
pb->usbActCount = 0;
pb->addrStash = (UInt32)pb->usbBuffer;
pb->usbBuffer = 0;
return(uslOpenDevice(pb));
}
return(uslDeviceRequest(pb));
}
/* xxxx do checking that params are correct, now we have config desc */
/* xxxx do checking that params are correct, now we have config desc */
static OSStatus uslOpenPipe(USBPB *pb)
{
switch(pb->usbClassType)
{
case kUSBBulk:
return(uslOpenBulkEndpoint(pb));
break;
case kUSBInterrupt:
return(uslOpenInterruptEndpoint(pb));
break;
case kUSBIsoc:
return(uslOpenIsocEndpoint(pb));
break;
case kUSBControl:
//OSStatus uslOpenControlEndpoint(USBPB *pb);
return(kUSBIncorrectTypeErr);
break;
default:
return(kUSBIncorrectTypeErr);
break;
}
}
OSStatus USBOpenPipe(USBPB *pb)
{
if(!checkPBVersion(pb, kUSBAnyDirn))
{
return(pb->usbStatus);
}
return(uslOpenPipe(pb));
}
OSStatus uslOpenPipeImmed(USBInterfaceRef intrfc, USBEndPointDescriptor *endp)
{
/* this relies on USBOpenPipe, and the bulk and interrupt opens */
/* completing immediatly and not caring if the completion is zero */
USBPB pb;
pb.usbReference = intrfc;
pb.usbCompletion = nil;
if((endp->endpointAddress & 0x80) == 0)
{
pb.usbFlags = kUSBOut;
}
else
{
pb.usbFlags = kUSBIn;
}
pb.usbClassType = endp->attributes&3; // endpoint type
pb.usbOther = endp->endpointAddress & 0xf;
pb.usb.cntl.WValue = USBToHostWord(endp->maxPacketSize);
return(uslOpenPipe(&pb));
}
void resolvePerformance(USBPB *pb)
{
pipe *thisPipe;
OSStatus err;
err = findPipe(pb->usbReference, &thisPipe);
if( (thisPipe != nil) && (thisPipe->monitorPerformance) )
{
pb->usbFrame = deltaFrames(pb->usbFrame, thisPipe->bus);
AddAtomic(pb->usbFrame, (void *)&thisPipe->transferTime);
AddAtomic(pb->usbActCount, (void *)&thisPipe->bytesTransfered);
pb->usbFlags = 0;
}
}
OSStatus USBBulkRead(USBPB *pb)
{
pipe *thisPipe;
OSStatus retVal;
if(!checkPBVersion(pb, 0))
{
return(pb->usbStatus);
}
retVal = kUSBPending;
pb->usbStatus = retVal;
do{
/* Find our pipe structure for this */
retVal = findPipe(pb->usbReference, &thisPipe);
if(retVal != noErr)
{
break;
}
if(thisPipe->monitorPerformance)
{
pb->usbFlags = 1;
pb->usbFrame = deltaFrames(0, thisPipe->bus);
}
/* Validate its a bulk out pipe */
if( (thisPipe->direction != kUSBIn) || (thisPipe->type != kUSBBulk) )
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* BT 13Aug98, allow zero length transactions, they're valid. */
retVal = usbBulkPacket(thisPipe->bus, pb, thisPipe->devAddress, thisPipe->endPt, kUSBIn);
/* Processing now continues in bulkCallBack */
}while(0);
if(retVal == noErr)
{
retVal = kUSBPending;
}
else
{
pb->usbStatus = retVal;
}
return(retVal);
}
OSStatus USBIntRead(USBPB *pb)
{
pipe *thisPipe;
OSStatus retVal;
if(!checkPBVersion(pb, 0))
{
return(pb->usbStatus);
}
retVal = kUSBPending;
pb->usbStatus = retVal;
do{
/* Find our pipe structure for this */
retVal = findPipe(pb->usbReference, &thisPipe);
if(retVal != noErr)
{
break;
}
if(thisPipe->monitorPerformance)
{
pb->usbFrame = deltaFrames(0, thisPipe->bus);
}
/* Validate its a bulk out pipe */
if( (thisPipe->direction != kUSBIn) || (thisPipe->type != kUSBInterrupt) )
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* BT 13Aug98, allow zero length transactions, they're valid. */
kprintf("USBIntRead:calling usbIntPacket\n");
retVal = usbIntPacket(thisPipe->bus, pb, thisPipe->devAddress, thisPipe->endPt, kUSBIn);
/* Processing now continues in intCallBack */
}while(0);
if(retVal == noErr)
{
retVal = kUSBPending;
}
else
{
pb->usbStatus = retVal;
}
return(retVal);
}
OSStatus USBIsocRead(USBPB *pb)
{
pipe *thisPipe;
OSStatus retVal;
if(!checkPBVersionIsoc(pb, 0))
{
return(pb->usbStatus);
}
retVal = kUSBPending;
pb->usbStatus = retVal;
do{
/* Find our pipe structure for this */
retVal = findPipe(pb->usbReference, &thisPipe);
if(retVal != noErr)
{
break;
}
/* Validate its a bulk out pipe */
if( (thisPipe->direction != kUSBIn) || (thisPipe->type != kUSBIsoc) )
{
retVal = kUSBIncorrectTypeErr;
break;
}
retVal = usbIsocPacket(thisPipe->bus, pb, thisPipe->devAddress, thisPipe->endPt, kUSBIn);
/* Processing now continues in bulkCallBack */
}while(0);
if(retVal == noErr)
{
retVal = kUSBPending;
}
else
{
pb->usbStatus = retVal;
}
return(retVal);
}
OSStatus USBBulkWrite(USBPB *pb)
{
pipe *thisPipe;
OSStatus retVal;
if(!checkPBVersion(pb, 0))
{
return(pb->usbStatus);
}
retVal = kUSBPending;
pb->usbStatus = retVal;
do{
/* Find our pipe structure for this */
retVal = findPipe(pb->usbReference, &thisPipe);
if(retVal != noErr)
{
break;
}
if(thisPipe->monitorPerformance)
{
pb->usbFlags = 1;
pb->usbFrame = deltaFrames(0, thisPipe->bus);
}
/* Validate its a bulk out pipe */
if( (thisPipe->direction != kUSBOut) || (thisPipe->type != kUSBBulk) )
{
retVal = kUSBIncorrectTypeErr;
break;
}
/* BT 13Aug98, allow zero length transactions, they're valid. */
retVal = usbBulkPacket(thisPipe->bus, pb, thisPipe->devAddress, thisPipe->endPt, kUSBOut);
/* Processing now continues in controlCallBack */
}while(0);
if(retVal == noErr)
{
retVal = kUSBPending;
}
else
{
pb->usbStatus = retVal;
}
return(retVal);
}
OSStatus USBIsocWrite(USBPB *pb)
{
pipe *thisPipe;
OSStatus retVal;
if(!checkPBVersionIsoc(pb, 0))
{
return(pb->usbStatus);
}
retVal = kUSBPending;
pb->usbStatus = retVal;
do{
/* Find our pipe structure for this */
retVal = findPipe(pb->usbReference, &thisPipe);
if(retVal != noErr)
{
break;
}
/* Validate its a bulk out pipe */
if( (thisPipe->direction != kUSBOut) || (thisPipe->type != kUSBIsoc) )
{
retVal = kUSBIncorrectTypeErr;
break;
}
retVal = usbIsocPacket(thisPipe->bus, pb, thisPipe->devAddress, thisPipe->endPt, kUSBOut);
/* Processing now continues in controlCallBack */
}while(0);
if(retVal == noErr)
{
retVal = kUSBPending;
}
else
{
pb->usbStatus = retVal;
}
return(retVal);
}
OSStatus uslMonitorBulkPerformanceByReference(USBPipeRef ref, UInt32 what,
UInt32 *lastRead, UInt32 *bytesTransfered, UInt32 *transferTime)
{
pipe *thisPipe;
OSStatus err = noErr;
do{
/* Note this can't be a device ref, they're automatically cleared */
/* Find the pipe struct */
err = findPipe(ref, &thisPipe);
if(thisPipe == nil)
{
break;
}
/* Do something here */
switch(what)
{
case 0:
/* stop monitoring this pipe */
if(thisPipe->monitorPerformance)
{
thisPipe->monitorPerformance = false;
}
else
{
err = kUSBNotFound;
}
break;
case 1:
/* Start monitoring pipe */
if(thisPipe->monitorPerformance)
{
err = kUSBAlreadyOpenErr;
}
else
{
thisPipe->monitorPerformance = true;
thisPipe->lastRead = deltaFrames(0, thisPipe->bus);
}
break;
case 2:
/* Get stats, don't clear */
if(thisPipe->monitorPerformance)
{
*lastRead = thisPipe->lastRead;
thisPipe->lastRead = deltaFrames(0, thisPipe->bus);
*bytesTransfered = thisPipe->bytesTransfered;
*transferTime = thisPipe->transferTime;
}
else
{
err = kUSBNotFound;
}
break;
case 3:
/* Get stats clear */
if(thisPipe->monitorPerformance)
{
thisPipe->monitorPerformance = true;
}
*lastRead = thisPipe->lastRead;
thisPipe->lastRead = deltaFrames(0, thisPipe->bus);
*bytesTransfered = thisPipe->bytesTransfered;
*transferTime = thisPipe->transferTime;
AddAtomic(-*bytesTransfered, (void *)&thisPipe->bytesTransfered);
AddAtomic(-*transferTime, (void *)&thisPipe->transferTime);
break;
}
}while(0);
return(err);
}