|
|
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: USLhubs.c ! 27: ! 28: Contains: Hub specific functions for the USL (mainly add and subtract devices) ! 29: ! 30: Version: Nepturn 1.0 ! 31: ! 32: Copyright: � 1997-1998 by Apple Computer, Inc., all rights reserved. ! 33: ! 34: File Ownership: ! 35: ! 36: DRI: Barry Twycross ! 37: ! 38: Other Contact: xxx put other contact here xxx ! 39: ! 40: Technology: USB ! 41: ! 42: Writers: ! 43: ! 44: (DF) David Ferguson ! 45: (CJK) Craig Keithley ! 46: (BT) Barry Twycross ! 47: ! 48: Change History (most recent first): ! 49: ! 50: <USB40> 11/4/98 BT Comment inobvious zering of refCon ! 51: <USB39> 10/29/98 BT Close old configurations on reset or reconfiguration. ! 52: <USB38> 10/7/98 BT Fix hub not killing children ! 53: <USB37> 10/3/98 BT Add more port reset stuff ! 54: <USB36> 9/29/98 BT Use real frame timing ! 55: <USB35> 9/28/98 BT Add device reset function ! 56: <USB34> 9/17/98 BT 1.1 rules for captive devices. ! 57: <USB33> 8/25/98 BT Isoc name changes ! 58: <USB32> 8/24/98 BT Cope without #define for reserved4 ! 59: <USB31> 8/13/98 BT Add multibus support ! 60: <USB30> 7/10/98 BT DO secondary interrupt right, set address fail returns ref 0. ! 61: <USB29> 7/9/98 BT Fix previous fixes. Secondary interrupt does not queue secondary ! 62: interrupt ! 63: <USB28> 7/9/98 BT Clean up queues when device deleted ! 64: <USB27> 6/15/98 BT Cope with 1.1 hubs speed detection ! 65: <USB26> 6/14/98 DF Add RemoveRootHub function ! 66: <USB25> 6/5/98 BT Pass pb to delete device ! 67: <USB24> 5/20/98 BT Version 2 PB new names ! 68: <USB23> 4/29/98 BT FIx negative timeout ! 69: <USB22> 4/26/98 BT FIx timeout adding dead device ! 70: <USB21> 4/23/98 BT Add watchdog ! 71: <USB20> 4/21/98 BT Allow requests to device zero, pipe zero. ! 72: <USB19> 4/16/98 BT Eliminate debugger ! 73: <USB18> 4/14/98 BT Impliment device remove ! 74: <USB17> 4/10/98 BT Add device remove ! 75: <USB16> 4/9/98 CJK remove uimpriv.h and uslpriv.h ! 76: <USB15> 4/9/98 BT Use USB.h ! 77: <14> 4/8/98 BT More error checking ! 78: <13> 4/6/98 BT Change w names ! 79: <12> 4/6/98 BT New param block names ! 80: <11> 4/2/98 BT Eliminate obsolete delay function ! 81: <10> 2/23/98 BT Only add device if set address was sucessful ! 82: <9> 2/4/98 BT Fix uslControlPacket to have errors. Add more support for ! 83: usbProbe ! 84: <8> 1/26/98 BT Mangle names after design review ! 85: <7> 1/15/98 CJK Change include of USL.h to USBServicesLib.h ! 86: <6> 1/13/98 BT Change uslPacket to uslControlPacket ! 87: <5> 12/19/97 BT UIM now a Shared lib ! 88: <4> 12/18/97 BT Fix header dependancies and add expert call back ! 89: */ ! 90: ! 91: #include "../USB.h" ! 92: #include "../USBpriv.h" ! 93: ! 94: #include "../uimpriv.h" ! 95: #include "uslpriv.h" ! 96: ! 97: #include "../driverservices.h" ! 98: ! 99: ! 100: static QHdrPtr hubAddQueue; ! 101: static unsigned long hubAddFlag = 0; ! 102: static USBDeviceRef deviceZero; ! 103: static UInt32 busZero; ! 104: static Duration lastAdd; ! 105: static USBPB timeout={0,0, sizeof(USBPB), kUSBCurrentPBVersion}; ! 106: ! 107: void initialiseHubs(void) ! 108: { ! 109: if( (PBQueueCreate(&hubAddQueue) != noErr) || ! 110: (PBQueueInit(hubAddQueue) != noErr) ) ! 111: { ! 112: /* Panic */ ! 113: USBExpertStatus(0,"USL - failed to initialise hub queue", 0); ! 114: } ! 115: } ! 116: ! 117: void finaliseHubs(void) ! 118: { ! 119: // really need to count the busses! ! 120: //RemoveRootHub(0); // This should only happen if bus is removed???? ! 121: //PBQueueDelete(hubAddQueue); ! 122: } ! 123: ! 124: Boolean uslHubValidateDevZero(USBDeviceRef ref, UInt32 *bus) ! 125: { ! 126: if(bus != nil) ! 127: { ! 128: *bus = busZero; ! 129: } ! 130: return(ref == deviceZero); ! 131: } ! 132: ! 133: OSStatus USBHubConfigurePipeZero(USBPB *pb) ! 134: { ! 135: UInt32 bus=0; ! 136: if(!checkPBVersion(pb, 1)) ! 137: { ! 138: return(pb->usbStatus); ! 139: } ! 140: if(pb->pbVersion == 2) // v1.00+ only ! 141: { ! 142: pb->usbStatus = kUSBPBVersionError; ! 143: return(pb->usbStatus); ! 144: } ! 145: if(!uslHubValidateDevZero(pb->usbReference, &bus)) ! 146: { ! 147: pb->usbStatus = kUSBUnknownDeviceErr; ! 148: return(pb->usbStatus); ! 149: } ! 150: ! 151: kprintf("USBHubConfigurePipeZero:calling UIMControlEDCreate\n"); ! 152: pb->usbStatus = UIMControlEDCreate(bus, 0, 0, pb->usb.cntl.WValue, pb->usbFlags); ! 153: (*pb->usbCompletion)(pb); ! 154: return(kUSBPending); ! 155: } ! 156: ! 157: ! 158: void uslCleanHubQueue(USBDeviceRef ref) ! 159: { // This is assuming its called at secondary interrupt time. ! 160: uslCleanAQueue(hubAddQueue, ref); ! 161: } ! 162: ! 163: static void processAddQ(void) ! 164: { ! 165: OSStatus err; ! 166: USBPB *pb; ! 167: if(CompareAndSwap(0, 1, &hubAddFlag)) ! 168: { /* We now have the queue*/ ! 169: if(PBDequeueFirst(hubAddQueue, (void *)&pb) == noErr) ! 170: { ! 171: ! 172: // Could validate ref here. ! 173: ! 174: busZero = pb->usbOther; ! 175: lastAdd = deltaFrames(0, busZero); ! 176: if(pb->pbVersion == 2) ! 177: { ! 178: kprintf("processAddQ:calling UIMControlEDCreate\n"); ! 179: err = UIMControlEDCreate(busZero, 0, 0, 8, pb->usbFlags); ! 180: /* Error checking ??? */ ! 181: } ! 182: ! 183: deviceZero = MakeDevRef(busZero, 0); ! 184: pb->usbReference = deviceZero; ! 185: pb->usbStatus = noErr; ! 186: (*pb->usbCompletion)(pb); ! 187: } ! 188: } ! 189: } ! 190: ! 191: /* Takes bus in reference */ ! 192: ! 193: void uslHubAddDevice(USBPB *pb) ! 194: { ! 195: pb->qType = kUSBHubQType; ! 196: pb->usbStatus = kUSBPending; ! 197: PBEnqueueLast((void *)pb, hubAddQueue); ! 198: processAddQ(); ! 199: } ! 200: ! 201: OSStatus USBHubAddDevice(USBPB *pb) ! 202: { ! 203: UInt32 bus; ! 204: ! 205: pb->usbStatus = validateRef(pb->usbReference, &bus); ! 206: if(pb->usbStatus != noErr) ! 207: { ! 208: return(pb->usbStatus); ! 209: } ! 210: ! 211: if(!checkPBVersion(pb, 1)) ! 212: { ! 213: return(pb->usbStatus); ! 214: } ! 215: ! 216: pb->usbOther = bus; ! 217: uslHubAddDevice(pb); ! 218: ! 219: return(kUSBPending); ! 220: } ! 221: ! 222: /* Takes bus in reference */ ! 223: ! 224: static void setAddressHandler(USBPB *pb) ! 225: { ! 226: UInt32 bus; ! 227: UInt32 power; ! 228: ! 229: bus = busZero; ! 230: ! 231: // UIMEDDelete(0, 0, 0); ! 232: kprintf("setAddressHandler: calling UIMControlEDDelete\n"); ! 233: UIMControlEDDelete(bus, 0, 0); ! 234: deviceZero = 0; ! 235: lastAdd = 0; ! 236: ! 237: if(pb->reserved2 != nil) ! 238: { /* real user call back */ ! 239: if(pb->usbStatus == noErr) ! 240: { ! 241: power = ( (pb->usbFlags & kUSBHubPower) != 0)?pb->usbOther:kUSB500mAAvailable; ! 242: if((pb->usbFlags & kUSBHubReaddress) == 0) ! 243: { ! 244: /* Note, this is relying on having usbValue swapped by uiminterface */ ! 245: pb->usbReference = addNewDevice(bus, pb->usb.cntl.WValue, pb->usbFlags&1, pb->wValueStash, power); ! 246: } ! 247: } ! 248: else ! 249: { ! 250: pb->usbReference = 0; ! 251: USBExpertStatus(0, "USL - Error setting address:", pb->usbReference); ! 252: } ! 253: ! 254: pb->usbCompletion = (void *)pb->reserved2; ! 255: (*pb->usbCompletion)(pb); ! 256: } ! 257: else ! 258: { /* timeout call back */ ! 259: ! 260: /* This really is refcon, not reference, this is not a bug. */ ! 261: /* This is the call back from the watchdog timer */ ! 262: pb->usbRefcon = 0; ! 263: } ! 264: CompareAndSwap(1, 0, &hubAddFlag); /* Unlock the queue */ ! 265: ! 266: if(hubAddQueue->qHead != nil) ! 267: { ! 268: processAddQ(); ! 269: } ! 270: } ! 271: ! 272: ! 273: ! 274: static void uslHubSetAddress(USBPB *pb) ! 275: { ! 276: OSStatus err; ! 277: pb->reserved2 = (UInt32) pb->usbCompletion; ! 278: pb->usbCompletion = setAddressHandler; ! 279: pb->wValueStash = pb->usb.cntl.WValue; ! 280: ! 281: /* Note this does not have to faff around with */ ! 282: /* pbVersion etc its writing a packet directly */ ! 283: pb->usb.cntl.BMRequestType = 0; /* bmRqTyp = 0, bRq = 5 */ ! 284: pb->usb.cntl.BRequest = kUSBRqSetAddress; /* bmRqTyp = 0, bRq = 5 */ ! 285: ! 286: if(pb->usbFlags & kUSBHubReaddress) ! 287: { ! 288: usbDevice *d; ! 289: d = getDevicePtr(pb->usbReference); ! 290: if(d == nil) ! 291: { ! 292: pb->usbStatus = kUSBUnknownDeviceErr; ! 293: setAddressHandler(pb); ! 294: return; ! 295: } ! 296: pb->usb.cntl.WValue = HostToUSBWord(d->usbAddress); ! 297: } ! 298: else ! 299: { ! 300: pb->usb.cntl.WValue = HostToUSBWord(getNewAddress()); ! 301: } ! 302: pb->usb.cntl.WIndex = 0; ! 303: pb->usb.cntl.reserved4 = 0; /* zero length */ ! 304: ! 305: pb->usbStatus = kUSBPending; ! 306: err = usbControlPacket(busZero, pb, 0, 0); ! 307: ! 308: if(err != noErr) ! 309: { /* Even if error, we need to go through handler */ ! 310: pb->usbStatus = err; ! 311: setAddressHandler(pb); ! 312: } ! 313: } ! 314: ! 315: OSStatus USBHubSetAddress(USBPB *pb) ! 316: { ! 317: if(!checkPBVersion(pb, 1|kUSBHubPower|kUSBHubReaddress)) ! 318: { ! 319: return(pb->usbStatus); ! 320: } ! 321: ! 322: if(pb->usbFlags & kUSBHubReaddress) ! 323: { ! 324: if(getDevicePtr(pb->usbReference) == nil) ! 325: { ! 326: pb->usbStatus = kUSBUnknownDeviceErr; ! 327: return(pb->usbStatus); ! 328: } ! 329: } ! 330: else ! 331: { ! 332: if(!uslHubValidateDevZero(pb->usbReference, nil)) ! 333: { ! 334: pb->usbReference = 0; ! 335: pb->usbStatus = paramErr; ! 336: return(pb->usbStatus); ! 337: } ! 338: } ! 339: ! 340: uslHubSetAddress(pb); ! 341: ! 342: return(kUSBPending); ! 343: } ! 344: ! 345: static OSStatus secondaryCleanInternalQueues(void *p1, void *p2) ! 346: { // Any new queues should put an entry in here ! 347: USBDeviceRef ref; ! 348: p2=0; ! 349: ref = (USBDeviceRef)p1; ! 350: ! 351: uslCleanHubQueue(ref); ! 352: uslCleanDelayQueue(ref); ! 353: uslCleanNotifyQueue(ref); ! 354: uslCleanMemQueue(ref); ! 355: ! 356: return(noErr); // no one's listening ! 357: } ! 358: ! 359: static OSStatus uslCleanInternalQueues(USBDeviceRef ref) ! 360: { ! 361: return(CallSecondaryInterruptHandler2(secondaryCleanInternalQueues, nil, (void *)ref, 0)); ! 362: } ! 363: ! 364: OSStatus USBHubDeviceRemoved(USBPB *pb) ! 365: { ! 366: OSStatus err = kUSBPending; ! 367: usbDevice *deviceP; ! 368: OSStatus retVal = noErr; ! 369: Boolean noCallBack; ! 370: ! 371: noCallBack = (pb->usbCompletion == kUSBNoCallBack); ! 372: if(noCallBack) ! 373: { ! 374: pb->usbCompletion = (void *)-2; ! 375: } ! 376: if(!checkPBVersion(pb, 0)) ! 377: { ! 378: return(pb->usbStatus); ! 379: } ! 380: if(noCallBack) ! 381: { ! 382: pb->usbCompletion = kUSBNoCallBack; ! 383: } ! 384: ! 385: deviceP = getDevicePtr(pb->usbReference); ! 386: if(deviceP == nil) ! 387: { ! 388: pb->usbStatus = kUSBUnknownDeviceErr; ! 389: return(kUSBUnknownDeviceErr); ! 390: } ! 391: ! 392: // Must do this before pipes are closed. ! 393: retVal = uslCleanInternalQueues(deviceP->ID); ! 394: if(retVal != noErr) // if this returns an erro we're hosed. ! 395: { ! 396: return(retVal); ! 397: } ! 398: ! 399: uslClosePipe(deviceP->pipe0); ! 400: ! 401: uslCloseNonDefaultPipes(deviceP); ! 402: ! 403: return(uslDeleteDevice(pb, deviceP)); ! 404: } ! 405: ! 406: void uslHubWatchDog(Duration currentMilliSec) ! 407: { ! 408: USBReference currDevZero; ! 409: UInt32 bus; ! 410: ! 411: if((hubAddQueue->qHead != nil) && (lastAdd != 0) ) ! 412: { ! 413: currDevZero = deviceZero; ! 414: bus = deviceZero; ! 415: if(lastAdd < currentMilliSec - 1000) ! 416: { /* Candidate for removal */ ! 417: ! 418: if(CompareAndSwap(currDevZero, 0, (void *)&deviceZero)) ! 419: { /* if we're here, deviceZero didn't change since we checked the time */ ! 420: /* We've also just diabled that device zero */ ! 421: if(timeout.usbRefcon != 0) ! 422: { ! 423: USBExpertStatus(0, "USL hubs - force set address timed out", 0); ! 424: /* timeout in use already */ ! 425: kprintf("uslHubWatchDog: calling UIMControlEDDelete\n"); ! 426: UIMControlEDDelete(bus, 0, 0); ! 427: timeout.usbRefcon = 0; ! 428: } ! 429: else ! 430: { ! 431: USBExpertStatus(0, "USL hubs - timing out add", 0); ! 432: timeout.usbRefcon = 1; ! 433: lastAdd = currentMilliSec + 1000; ! 434: uslHubSetAddress(&timeout); ! 435: } ! 436: } ! 437: ! 438: } ! 439: } ! 440: } ! 441: ! 442: ! 443:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.