|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: File: uslUtility.c ! 27: ! 28: Contains: xxx put contents here xxx ! 29: ! 30: Version: xxx put version here xxx ! 31: ! 32: Copyright: � 1998 by Apple Computer, Inc., all rights reserved. ! 33: ! 34: File Ownership: ! 35: ! 36: DRI: xxx put dri here xxx ! 37: ! 38: Other Contact: xxx put other contact here xxx ! 39: ! 40: Technology: xxx put technology here xxx ! 41: ! 42: Writers: ! 43: ! 44: (TC) Tom Clark ! 45: (DF) David Ferguson ! 46: (DKF) David Ferguson ! 47: (BT) Barry Twycross ! 48: ! 49: Change History (most recent first): ! 50: ! 51: <USB33> 10/29/98 BT Close old configurations on reset or reconfiguration. ! 52: <USB32> 10/7/98 BT Fix callback at task time. ! 53: <USB31> 10/7/98 BT Add 32bit endian functions ! 54: <USB30> 9/29/98 BT Use real frame timing ! 55: <USB29> 9/28/98 BT Add device reset function ! 56: <USB28> 8/24/98 BT Eliminate old checkPB version, add new one for Isoc ! 57: <USB27> 8/13/98 BT Add multibus support ! 58: <USB26> 8/12/98 BT Move root hub into UIM again ! 59: <USB25> 7/28/98 BT Dev zero is valid ref ! 60: <USB24> 7/10/98 TC Essentially take out <USB19>. ! 61: <USB23> 7/9/98 BT Clean up queues when device deleted. Merge in branch ! 62: <USB22> 7/2/98 BT Fix dealloc mem to zero buffer ptr. ! 63: <USB21> 7/2/98 BT Use UIM time for internal timing ! 64: <USB20> 7/2/98 BT Return the right framenumber from USBDelay. Let framecount take ! 65: kNoCallBack. ! 66: <USB19> 6/30/98 BT Move Root hub sim into UIM ! 67: <USB18> 6/15/98 DF Remove compiler build problem. It didn't like passing a pointer ! 68: to a struct pointer that was declared volatile. ! 69: <USB17> 6/14/98 DF Cancel InterruptTimer when being replaced. ! 70: <USB16> 6/5/98 BT DeallocMem will work immediatlty ! 71: <USB15> 6/5/98 BT Use UIM time ! 72: <USB14> 4/30/98 BT Add real interrupt driven timer ! 73: <USB13> 4/23/98 BT Add hub watchdog function ! 74: <USB12> 4/16/98 BT Eliminate debugger ! 75: <USB11> 4/10/98 BT add USB to host word ! 76: <USB10> 4/9/98 BT Use USB.h ! 77: <9> 4/8/98 BT More error checking ! 78: <8> 4/2/98 BT Error checking for nil call backs. Also Ferg's Use DSL Timing ! 79: Services directly ! 80: <7> 3/11/98 BT Give time to root hub int sim ! 81: <6> 3/2/98 BT Back out timer changes ! 82: <5> 2/24/98 BT Change timer to non-persistant ! 83: <4> 2/19/98 BT Make timer non task time. ! 84: <3> 2/16/98 BT Fix calling processdone queue and timer too often. ! 85: <USB2> 2/9/98 DKF add USBIdleTask for handling events that need file I/O safe ! 86: time. ! 87: <1> 1/29/98 BT first checked in ! 88: */ ! 89: ! 90: #include "../driverservices.h" ! 91: #include "../USB.h" ! 92: #include "../USBpriv.h" ! 93: #include "uslpriv.h" ! 94: #include "../uimpriv.h" ! 95: #import <sys/callout.h> ! 96: #import <kernserv/ns_timer.h> ! 97: ! 98: ! 99: static QHdrPtr delayQueue; ! 100: static QHdrPtr notifyQueue; ! 101: static QHdrPtr memoryQueue; ! 102: static unsigned long notifyFlag = 0; ! 103: volatile TimerID curTimerID; ! 104: ! 105: static UInt32 idled; ! 106: #define ONE_MILLI_SECOND 1000000ULL /* nanoseconds/10**6 */ ! 107: void timerHandler(void *p1); //naga ! 108: static SInt32 interruptPriority; ! 109: ! 110: ! 111: void uslCleanAQueue(QHdrPtr queue, USBDeviceRef ref) ! 112: { // This is assuming its called at secondary interrupt time. ! 113: USBPB *pb, *pbNext; ! 114: ! 115: if(CurrentExecutionLevel() != kSecondaryInterruptLevel) ! 116: { ! 117: USBExpertStatus(0, "USL - clean Q call at wrong time", ref); ! 118: return; ! 119: } ! 120: ! 121: if(queue == nil) ! 122: { ! 123: return; ! 124: } ! 125: pb = (void *)queue->qHead; ! 126: ! 127: while(pb != nil) ! 128: { ! 129: pbNext = (void *)pb->qlink; ! 130: if(isSameDevice(pb->usbReference, ref)) ! 131: { ! 132: USBExpertStatus(0, "USL - killing Q element", ref); ! 133: PBDequeue((void *)pb, queue); // unqueue it an forget it ! 134: } ! 135: pb = pbNext; ! 136: } ! 137: } ! 138: ! 139: void uslCleanDelayQueue(USBDeviceRef ref) ! 140: { // This is assuming its called at secondary interrupt time. ! 141: uslCleanAQueue(delayQueue, ref); ! 142: } ! 143: ! 144: ! 145: void uslCleanNotifyQueue(USBDeviceRef ref) ! 146: { // This is assuming its called at secondary interrupt time. ! 147: uslCleanAQueue(notifyQueue, ref); ! 148: } ! 149: ! 150: ! 151: void uslCleanMemQueue(USBDeviceRef ref) ! 152: { // This is assuming its called at secondary interrupt time. ! 153: uslCleanAQueue(memoryQueue, ref); ! 154: } ! 155: ! 156: ! 157: ! 158: ! 159: ! 160: void uslInterruptPriority(UInt32 delta) ! 161: { ! 162: AddAtomic(delta, &interruptPriority); ! 163: if(interruptPriority < 0) ! 164: { ! 165: USBExpertStatus(0, "USL - interrrupt prority gone negative", interruptPriority); ! 166: } ! 167: } ! 168: ! 169: ! 170: OSStatus USBResetDevice(USBPB *pb) ! 171: { ! 172: // --> usbReference device/interface/endpoint - which device. ! 173: usbDevice *dev; ! 174: pipe *p; ! 175: OSStatus err; ! 176: ! 177: if(!checkPBVersion(pb, kUSBPowerReset)) ! 178: { ! 179: return(pb->usbStatus); ! 180: } ! 181: ! 182: dev = getDevicePtr(pb->usbReference); ! 183: if(dev == nil) ! 184: { ! 185: err = findPipe(pb->usbReference, &p); ! 186: if(p != nil) ! 187: { ! 188: dev = getDevicePtr(p->devIntfRef); ! 189: } ! 190: } ! 191: if(dev == nil) ! 192: { ! 193: pb->usbStatus = kUSBUnknownDeviceErr; ! 194: return(pb->usbStatus); ! 195: } ! 196: ! 197: uslUnconfigureDevice(dev); ! 198: ! 199: pb->usbStatus = kUSBPending; ! 200: pb->usb.hub.Request = kUSBHubPortResetRequest; ! 201: err = USBExpertNotifyParentMsg(dev->ID, pb); ! 202: if(err != noErr) ! 203: { ! 204: pb->usbStatus = err; ! 205: return(err); ! 206: } ! 207: else ! 208: { ! 209: return(kUSBPending); ! 210: } ! 211: } ! 212: ! 213: ! 214: OSStatus USBGetFrameNumberImmediate(USBPB *pb) ! 215: { ! 216: // --> usbReference device/interface/endpoint. Specifies which bus ! 217: // --> usbReqCount size of buffer (should be 0 or sizeof(UInt64) ! 218: // --> usbBuffer nil/point to UInt64 structure for full count ! 219: // <-- usbActCount size of data returned. ! 220: // <-- usbFrame low 32 bits of current frame number. ! 221: union{ ! 222: UInt64 u; ! 223: UnsignedWide s; ! 224: }frame; ! 225: Boolean nocallBack = false; ! 226: UInt32 bus; ! 227: ! 228: // Oops, forgot to validate this ! 229: pb->usbStatus = validateRef(pb->usbReference, &bus); ! 230: if(pb->usbStatus != noErr) ! 231: { ! 232: return(pb->usbStatus); ! 233: } ! 234: ! 235: if(pb->usbCompletion == kUSBNoCallBack) ! 236: { ! 237: nocallBack = true; ! 238: pb->usbCompletion = (void *)-2; ! 239: } ! 240: if(!checkPBVersion(pb, 0)) ! 241: { ! 242: return(pb->usbStatus); ! 243: } ! 244: if(nocallBack) ! 245: { ! 246: pb->usbCompletion = kUSBNoCallBack; ! 247: } ! 248: frame.u = UIMGetCurrentFrame(bus); ! 249: pb->usbFrame = frame.s.lo; ! 250: if( (pb->usbBuffer != nil) && (pb->usbReqCount != 0) ) ! 251: { ! 252: pb->usbActCount = pb->usbReqCount; ! 253: if(pb->usbActCount > sizeof(frame)) ! 254: { ! 255: pb->usbActCount = sizeof(frame); ! 256: } ! 257: usb_BlockMoveData(&frame, pb->usbBuffer, pb->usbActCount); ! 258: } ! 259: return(noErr); ! 260: ! 261: } ! 262: ! 263: UInt32 deltaFrames(UInt32 previous, UInt32 bus) ! 264: { ! 265: union{ ! 266: UInt64 u; ! 267: UnsignedWide s; ! 268: }frame; ! 269: ! 270: frame.u = UIMGetCurrentFrame(bus); ! 271: if(previous > frame.s.lo) ! 272: { ! 273: previous -= frame.s.lo; ! 274: return(~previous+1); ! 275: } ! 276: else ! 277: { ! 278: return(frame.s.lo - previous); ! 279: } ! 280: } ! 281: ! 282: ! 283: void finaliseNotifications(void) ! 284: { ! 285: AbsoluteTime wastedTime; ! 286: ! 287: PBQueueDelete(notifyQueue); ! 288: PBQueueDelete(memoryQueue); ! 289: while (curTimerID) { ! 290: if (CancelTimer(curTimerID, &wastedTime) == noErr) ! 291: curTimerID = 0; ! 292: } ! 293: } ! 294: ! 295: void initialiseNotifications(void) ! 296: { ! 297: if( (PBQueueCreate(¬ifyQueue) != noErr) || ! 298: (PBQueueInit(notifyQueue) != noErr) ) ! 299: { ! 300: /* Panic */ ! 301: USBExpertStatus(0,"USL - failed to initialise notification queue", 0); ! 302: } ! 303: if( (PBQueueCreate(&memoryQueue) != noErr) || ! 304: (PBQueueInit(memoryQueue) != noErr) ) ! 305: { ! 306: /* Panic */ ! 307: USBExpertStatus(0,"USL - failed to initialise memory queue", 0); ! 308: } ! 309: ! 310: idled = 0; ! 311: timerHandler(0); ! 312: ! 313: } ! 314: ! 315: static void taskTimeDoMemory(USBPB *pb) ! 316: { ! 317: Boolean dealloc; ! 318: dealloc = (pb->usbFlags & (1 << kUSLTTMemDeAllocFlagShift)) != 0; ! 319: pb->usbFlags &= ~(1 << kUSLTTMemDeAllocFlagShift); ! 320: ! 321: if(dealloc) ! 322: { ! 323: pb->usbStatus = PoolDeallocate(pb->usbBuffer); ! 324: pb->usbBuffer = nil; ! 325: } ! 326: else ! 327: { ! 328: pb->usbBuffer = PoolAllocateResident(pb->usbReqCount, true /*Boolean clear*/); ! 329: if(pb->usbBuffer != nil) ! 330: { ! 331: pb->usbActCount = pb->usbReqCount; ! 332: pb->usbStatus = noErr; ! 333: } ! 334: else ! 335: { ! 336: pb->usbActCount = 0; ! 337: pb->usbStatus = memFullErr; /* How do you find the right error code???? */ ! 338: } ! 339: } ! 340: (pb->usbCompletion)(pb); ! 341: } ! 342: ! 343: static void NotifyHandlerProc( ) ! 344: { ! 345: USBPB *pb; ! 346: ! 347: notifyFlag = false; /* Queue Processed */ ! 348: ! 349: /* Note these don't use interrupt priority, they do not happen at int time */ ! 350: while(PBDequeueFirst(notifyQueue, (void *)&pb) == noErr) ! 351: { ! 352: pb->usbStatus = noErr; /* Call back with right error status */ ! 353: (pb->usbCompletion)(pb); ! 354: } ! 355: while(PBDequeueFirst(memoryQueue, (void *)&pb) == noErr) ! 356: { ! 357: taskTimeDoMemory(pb); ! 358: } ! 359: ! 360: } ! 361: ! 362: static void startNotifier(void) ! 363: { ! 364: notifyFlag = true; ! 365: } ! 366: ! 367: static OSStatus uslTTCallBack(USBPB *pb) ! 368: { ! 369: pb->usbStatus = PBEnqueueLast((void *)pb, notifyQueue); ! 370: startNotifier(); ! 371: return(pb->usbStatus); /* safe, this is synchronised */ ! 372: } ! 373: ! 374: static OSStatus uslTTmem(USBPB *pb) ! 375: { ! 376: pb->usbStatus = PBEnqueueLast((void *)pb, memoryQueue); ! 377: startNotifier(); ! 378: return(pb->usbStatus); /* safe, this is synchronised */ ! 379: } ! 380: ! 381: OSStatus uslAllocMem(USBPB *pb) ! 382: { ! 383: pb->usbFlags &= ~(1 << kUSLTTMemDeAllocFlagShift); ! 384: return(uslTTmem(pb)); ! 385: } ! 386: ! 387: OSStatus USBAllocMem(USBPB *pb) ! 388: { ! 389: pb->usbStatus = validateRef(pb->usbReference, nil); ! 390: if(pb->usbStatus != noErr) ! 391: { ! 392: return(pb->usbStatus); ! 393: } ! 394: ! 395: if(!checkPBVersion(pb, kUSBTaskTimeFlag)) ! 396: { ! 397: return(pb->usbStatus); ! 398: } ! 399: ! 400: return(uslAllocMem(pb)); ! 401: } ! 402: ! 403: OSStatus uslDeallocMem(USBPB *pb) ! 404: { ! 405: pb->usbFlags |= (1 << kUSLTTMemDeAllocFlagShift); ! 406: return(uslTTmem(pb)); ! 407: } ! 408: ! 409: OSStatus USBDeallocMem(USBPB *pb) ! 410: { ! 411: Boolean nocallBack = false; ! 412: ! 413: if(pb->usbCompletion == kUSBNoCallBack) ! 414: { ! 415: nocallBack = true; ! 416: pb->usbCompletion = (void *)-2; ! 417: } ! 418: else ! 419: { ! 420: pb->usbStatus = validateRef(pb->usbReference, nil); ! 421: if(pb->usbStatus != noErr) ! 422: { ! 423: return(pb->usbStatus); ! 424: } ! 425: } ! 426: if(!checkPBVersion(pb, kUSBTaskTimeFlag)) ! 427: { ! 428: return(pb->usbStatus); ! 429: } ! 430: if(nocallBack) ! 431: { ! 432: void *buffer; ! 433: if(CurrentExecutionLevel() != kTaskLevel) ! 434: { ! 435: return(kUSBCompletionError); ! 436: } ! 437: pb->usbCompletion = kUSBNoCallBack; ! 438: buffer = pb->usbBuffer; ! 439: pb->usbBuffer = nil; // BT 2Jun98, don't forget to zero this, its in the spec ! 440: return(PoolDeallocate(buffer)); ! 441: } ! 442: return(uslDeallocMem(pb)); ! 443: } ! 444: ! 445: void initialiseDelays(void) ! 446: { ! 447: if( (PBQueueCreate(&delayQueue) != noErr) || ! 448: (PBQueueInit(delayQueue) != noErr) ) ! 449: { ! 450: /* Panic */ ! 451: USBExpertStatus(0,"USL - failed to initialise delay queue", 0); ! 452: } ! 453: } ! 454: ! 455: void finaliseDelays(void) ! 456: { ! 457: PBQueueDelete(delayQueue); ! 458: } ! 459: ! 460: static OSStatus uslDelay(USBPB *pb, UInt32 bus) ! 461: { ! 462: OSStatus err = noErr; ! 463: ! 464: /* waits the specified number of frames then calls the handler */ ! 465: /* length (soon to be usbReqCount) - required frame count to delay */ ! 466: if( (delayQueue == nil) || (notifyQueue == nil) ) ! 467: { ! 468: pb->usbStatus = kUSBInternalErr; ! 469: return(kUSBInternalErr); ! 470: } ! 471: ! 472: pb->usbActCount = pb->usbReqCount + deltaFrames(0, bus); ! 473: pb->qType = kUSBDelayQType; ! 474: pb->usbStatus = kUSBPending; ! 475: ! 476: err = PBEnqueueLast((void *)pb, delayQueue); ! 477: uslInterruptPriority(+1); ! 478: ! 479: if(err != noErr) ! 480: { ! 481: pb->usbStatus = err; ! 482: } ! 483: else ! 484: { ! 485: err = kUSBPending; ! 486: } ! 487: return(err); ! 488: } ! 489: ! 490: OSStatus USBDelay(USBPB *pb) ! 491: { ! 492: OSStatus err = noErr; ! 493: UInt32 bus; ! 494: ! 495: pb->usbStatus = validateRef(pb->usbReference, &bus); ! 496: if(pb->usbStatus != noErr) ! 497: { ! 498: return(pb->usbStatus); ! 499: } ! 500: ! 501: /* waits the specified number of frames then calls the handler */ ! 502: /* length (soon to be usbReqCount) - required frame count to delay */ ! 503: if(delayQueue == nil) ! 504: { ! 505: return(kUSBInternalErr); ! 506: } ! 507: ! 508: if(!checkPBVersion(pb, kUSBTaskTimeFlag)) ! 509: { ! 510: return(pb->usbStatus); ! 511: } ! 512: return(uslDelay(pb, bus)); ! 513: } ! 514: ! 515: static void processDelayQ( Duration currentDuration) ! 516: { ! 517: USBPB *pb, *pbNext; ! 518: UInt32 bus=0; ! 519: ! 520: if(delayQueue == nil) ! 521: { ! 522: return; ! 523: } ! 524: /* Walk the que, safe, we're the only thing to take elements off */ ! 525: ! 526: pb = (void *)delayQueue->qHead; ! 527: ! 528: while(pb != nil) ! 529: { ! 530: pbNext = (void *)pb->qlink; ! 531: ! 532: if(pb->usbActCount <= currentDuration) ! 533: { ! 534: if(PBDequeue((void *)pb, delayQueue) == noErr) ! 535: { ! 536: if( ( (pb->usbFlags & kUSBTaskTimeFlag) != 0) && ! 537: (CurrentExecutionLevel() != kTaskLevel) ) ! 538: { ! 539: uslTTCallBack(pb); ! 540: } ! 541: else ! 542: { ! 543: uslInterruptPriority(-1); ! 544: pb->usbStatus = noErr; ! 545: (*pb->usbCompletion)(pb); ! 546: } ! 547: } ! 548: } ! 549: ! 550: pb = pbNext; ! 551: } ! 552: ! 553: } ! 554: ! 555: static Boolean uslInterruptSafeIdle(UInt32 currFrame) ! 556: { ! 557: static UInt32 nextRootHub, lastRootHub; ! 558: static UInt32 lastDone = 0; ! 559: ! 560: if(currFrame != lastDone) // don't run more than once per millisecond. ! 561: { ! 562: ! 563: lastDone = currFrame; ! 564: //UIMProcessDoneQueue(); /* Note this is simulated only */ ! 565: ! 566: if( (currFrame > nextRootHub) || (currFrame < lastRootHub) ) ! 567: { ! 568: UIMPollRootHubSim(); ! 569: uslHubWatchDog(currFrame); ! 570: lastRootHub = currFrame; ! 571: nextRootHub = currFrame + 50; ! 572: } ! 573: processDelayQ(currFrame); ! 574: return(true); ! 575: } ! 576: return(false); ! 577: } ! 578: ! 579: void USBIdleTask(void) ! 580: { ! 581: UInt32 currentFrame; ! 582: idled = 0; ! 583: ! 584: currentFrame = UIMGetAFrame(); ! 585: ! 586: if(uslInterruptSafeIdle(currentFrame) && notifyFlag) ! 587: { ! 588: NotifyHandlerProc(); ! 589: } ! 590: ! 591: } ! 592: ! 593: ! 594: void timerHandler(void *p1) //naga it used to be void *p1,void *p2) ! 595: { ! 596: TimerID timerID; ! 597: Duration currentFrame, delay; ! 598: AbsoluteTime expirationTime; ! 599: AbsoluteTime currentTime = UpTime(); ! 600: ! 601: p1 = 0; ! 602: // p2 = 0; ! 603: ! 604: if(idled != 0) ! 605: { ! 606: //USBExpertStatus(0, "USL - Interrupt task idle", idled); ! 607: currentFrame = UIMGetAFrame(); ! 608: uslInterruptSafeIdle(currentFrame); ! 609: if(idled > 18) ! 610: { ! 611: idled = 18; ! 612: } ! 613: } ! 614: ! 615: if(interruptPriority > 0) ! 616: { ! 617: //USBExpertStatus(0, "USL - interruptPriority:", interruptPriority); ! 618: delay = 20 - idled; // milliseconds ! 619: idled++; ! 620: } ! 621: else ! 622: { ! 623: delay = 100; ! 624: } ! 625: expirationTime = AddAbsoluteToAbsolute(currentTime, ! 626: DurationToAbsolute(delay)); ! 627: //kprintf("***timerhandler:Setting timerHandler delay=%d\n",delay); ! 628: ns_timeout(timerHandler,p1,delay*ONE_MILLI_SECOND,CALLOUT_PRI_SOFTINT0); ! 629: // SetInterruptTimer(&expirationTime, timerHandler, nil, &timerID); ! 630: curTimerID = timerID; ! 631: return(0); ! 632: } ! 633: ! 634: ! 635: ! 636: ! 637: ! 638: ! 639: /* ************* Endianisms ************* */ ! 640: ! 641: UInt16 HostToUSBWord(UInt16 value) ! 642: { ! 643: return( (value << 8) | (value >> 8) ); ! 644: } ! 645: ! 646: /* This is identical to above, but can't make defining it language independant */ ! 647: UInt16 USBToHostWord(UInt16 value) ! 648: { ! 649: return( (value << 8) | (value >> 8) ); ! 650: } ! 651: ! 652: UInt32 HostToUSBLong(UInt32 value) ! 653: { ! 654: return( ! 655: (((UInt32) value) >> 24) | ! 656: ((((UInt32) value) >> 8) & 0xFF00) | ! 657: ((((UInt32) value) << 8) & 0xFF0000) | ! 658: (((UInt32) value) << 24) ! 659: ); ! 660: ! 661: } ! 662: ! 663: UInt32 USBToHostLong(UInt32 value) ! 664: { ! 665: return( ! 666: (((UInt32) value) >> 24) | ! 667: ((((UInt32) value) >> 8) & 0xFF00) | ! 668: ((((UInt32) value) << 8) & 0xFF0000) | ! 669: (((UInt32) value) << 24) ! 670: ); ! 671: ! 672: } ! 673: ! 674: ! 675: Boolean immediateError(OSStatus err) ! 676: { ! 677: return((err != kUSBPending) && (err != noErr) ); ! 678: } ! 679: ! 680:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.