IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
						  void *target,
						  IOInterruptHandler handler,
						  void *refCon)
{
  IOInterruptSource *interruptSources;
  IOInterruptVectorNumber vectorNumber;
  IOInterruptVector *vector;
  int               wasDisabledSoft;
  IOReturn          error;
  OSData            *vectorData;
  IOOptionBits      options;
  bool              canBeShared, shouldBeShared, wasAlreadyRegisterd;

  IOService         *originalNub = NULL; // Protected by wasAlreadyRegisterd
  int               originalSource = 0; // Protected by wasAlreadyRegisterd
 

  interruptSources = nub->_interruptSources;
  vectorData = interruptSources[source].vectorData;
  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
  vector = &vectors[vectorNumber];
  
  // Get the lock for this vector.
  IOLockLock(vector->interruptLock);
  
  // Check if the interrupt source can/should be shared.
  canBeShared = vectorCanBeShared(vectorNumber, vector);
  IODTGetInterruptOptions(nub, source, &options);
#if defined(__i386__) || defined(__x86_64__)
  int   interruptType;
  if (OSDynamicCast(IOPlatformDevice, getProvider()) &&
      (getInterruptType(nub, source, &interruptType) == kIOReturnSuccess) &&
      (kIOInterruptTypeLevel & interruptType))
  {
    options |= kIODTInterruptShared;
  }
#endif
  shouldBeShared = canBeShared && (options & kIODTInterruptShared);
  wasAlreadyRegisterd = vector->interruptRegistered;
  
  // If the vector is registered and can not be shared return error.
  if (wasAlreadyRegisterd && !canBeShared) {
    IOLockUnlock(vector->interruptLock);
    return kIOReturnNoResources;
  }
  
  // If this vector is already in use, and can be shared (implied),
  // or it is not registered and should be shared,
  // register as a shared interrupt.
  if (wasAlreadyRegisterd || shouldBeShared) {
    // If this vector is not already shared, break it out.
    if (vector->sharedController == 0) {
      // Make the IOShareInterruptController instance
      vector->sharedController = new IOSharedInterruptController;
      if (vector->sharedController == 0) {
        IOLockUnlock(vector->interruptLock);
        return kIOReturnNoMemory;
      }
      
      if (wasAlreadyRegisterd) {
	// Save the nub and source for the original consumer.
	originalNub = vector->nub;
	originalSource = vector->source;
	
	// Physically disable the interrupt, but mark it as being enabled in the hardware.
	// The interruptDisabledSoft now indicates the driver's request for enablement.
	disableVectorHard(vectorNumber, vector);
	vector->interruptDisabledHard = 0;
      }
      
      // Initialize the new shared interrupt controller.
      error = vector->sharedController->initInterruptController(this, vectorData);
      // If the IOSharedInterruptController could not be initalized,
      // if needed, put the original consumer's interrupt back to normal and
      // get rid of whats left of the shared controller.
      if (error != kIOReturnSuccess) {
	if (wasAlreadyRegisterd) enableInterrupt(originalNub, originalSource);
        vector->sharedController->release();
        vector->sharedController = 0;
        IOLockUnlock(vector->interruptLock);
        return error;
      }
      
      // If there was an original consumer try to register it on the shared controller.
      if (wasAlreadyRegisterd) {
	error = vector->sharedController->registerInterrupt(originalNub,
							    originalSource,
							    vector->target,
							    vector->handler,
							    vector->refCon);
	// If the original consumer could not be moved to the shared controller,
	// put the original consumor's interrupt back to normal and
	// get rid of whats left of the shared controller.
	if (error != kIOReturnSuccess) {
	  // Save the driver's interrupt enablement state.
	  wasDisabledSoft = vector->interruptDisabledSoft;
	  
	  // Make the interrupt really hard disabled.
	  vector->interruptDisabledSoft = 1;
	  vector->interruptDisabledHard = 1;
	  
	  // Enable the original consumer's interrupt if needed.
	  if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
	  enableInterrupt(originalNub, originalSource);
	  
	  vector->sharedController->release();
	  vector->sharedController = 0;
	  IOLockUnlock(vector->interruptLock);
	  return error;
	}
      }
      
      // Fill in vector with the shared controller's info.
      vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress();
      vector->nub     = vector->sharedController;
      vector->source  = 0;
      vector->target  = vector->sharedController;
      vector->refCon  = 0;
      
      // If the interrupt was already registered,
      // save the driver's interrupt enablement state.
      if (wasAlreadyRegisterd) wasDisabledSoft = vector->interruptDisabledSoft;
      else wasDisabledSoft = true;
      
      // Do any specific initalization for this vector if it has not yet been used.
      if (!wasAlreadyRegisterd) initVector(vectorNumber, vector);
      
      // Make the interrupt really hard disabled.
      vector->interruptDisabledSoft = 1;
      vector->interruptDisabledHard = 1;
      vector->interruptRegistered   = 1;
      
      // Enable the original consumer's interrupt if needed.
      // originalNub is protected by wasAlreadyRegisterd here (see line 184).
      if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
    }
    
    error = vector->sharedController->registerInterrupt(nub, source, target,
                                                        handler, refCon);
    IOLockUnlock(vector->interruptLock);
    return error;
  }
  
  // Fill in vector with the client's info.
  vector->handler = handler;
  vector->nub     = nub;
  vector->source  = source;
  vector->target  = target;
  vector->refCon  = refCon;
  
  // Do any specific initalization for this vector.
  initVector(vectorNumber, vector);
  
  // Get the vector ready.  It starts hard disabled.
  vector->interruptDisabledHard = 1;
  vector->interruptDisabledSoft = 1;
  vector->interruptRegistered   = 1;
  
  IOLockUnlock(vector->interruptLock);
  return kIOReturnSuccess;
}
IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
						  void *target,
						  IOInterruptHandler handler,
						  void *refCon)
{
  IOInterruptSource *interruptSources;
  long              vectorNumber;
  IOInterruptVector *vector;
  long              wasDisabledSoft;
  IOReturn          error;
  OSData            *vectorData;
  IOService         *originalNub;
  int               originalSource;
  
  interruptSources = nub->_interruptSources;
  vectorData = interruptSources[source].vectorData;
  vectorNumber = *(long *)vectorData->getBytesNoCopy();
  vector = &vectors[vectorNumber];
  
  // Get the lock for this vector.
  IOTakeLock(vector->interruptLock);
  
  // If this vector is already in use, and can be shared,
  // register as a shared interrupt.
  if (vector->interruptRegistered) {
    if (!vectorCanBeShared(vectorNumber, vector)) {
      IOUnlock(vector->interruptLock);
      return kIOReturnNoResources;
    }
    
    // If this vector is not already shared, break it out.
    if (vector->sharedController == 0) {
      // Make the IOShareInterruptController instance
      vector->sharedController = new IOSharedInterruptController;
      if (vector->sharedController == 0) {
        IOUnlock(vector->interruptLock);
        return kIOReturnNoMemory;
      }
      
      // Save the nub and source for the original consumer.
      originalNub = vector->nub;
      originalSource = vector->source;
      
      // Physically disable the interrupt, but mark it as being enables in the hardware.
      // The interruptDisabledSoft now indicates the driver's request for enablement.
      disableVectorHard(vectorNumber, vector);
      vector->interruptDisabledHard = 0;
      
      // Initialize the new shared interrupt controller.
      error = vector->sharedController->initInterruptController(this,
                                                                vectorData);
      // If the IOSharedInterruptController could not be initalized,
      // put the original consumor's interrupt back to normal and
      // get rid of whats left of the shared controller.
      if (error != kIOReturnSuccess) {
        enableInterrupt(originalNub, originalSource);
        vector->sharedController->release();
        vector->sharedController = 0;
        IOUnlock(vector->interruptLock);
        return error;
      }
      
      // Try to register the original consumer on the shared controller.
      error = vector->sharedController->registerInterrupt(originalNub,
                                                          originalSource,
                                                          vector->target,
                                                          vector->handler,
                                                          vector->refCon);
      // If the original consumer could not be moved to the shared controller,
      // put the original consumor's interrupt back to normal and
      // get rid of whats left of the shared controller.
      if (error != kIOReturnSuccess) {
	// Save the driver's interrupt enablement state.
	wasDisabledSoft = vector->interruptDisabledSoft;
	
	// Make the interrupt really hard disabled.
	vector->interruptDisabledSoft = 1;
	vector->interruptDisabledHard = 1;
	
	// Enable the original consumer's interrupt if needed.
	if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
        enableInterrupt(originalNub, originalSource);
	
        vector->sharedController->release();
        vector->sharedController = 0;
        IOUnlock(vector->interruptLock);
        return error;
      }
      
      // Fill in vector with the shared controller's info.
      vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress();
      vector->nub     = vector->sharedController;
      vector->source  = 0;
      vector->target  = vector->sharedController;
      vector->refCon  = 0;
      
      // Save the driver's interrupt enablement state.
      wasDisabledSoft = vector->interruptDisabledSoft;
      
      // Make the interrupt really hard disabled.
      vector->interruptDisabledSoft = 1;
      vector->interruptDisabledHard = 1;
      
      // Enable the original consumer's interrupt if needed.
      if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
    }
    
    error = vector->sharedController->registerInterrupt(nub, source, target,
                                                        handler, refCon);
    IOUnlock(vector->interruptLock);
    return error;
  }
  
  // Fill in vector with the client's info.
  vector->handler = handler;
  vector->nub     = nub;
  vector->source  = source;
  vector->target  = target;
  vector->refCon  = refCon;
  
  // Do any specific initalization for this vector.
  initVector(vectorNumber, vector);
  
  // Get the vector ready.  It starts hard disabled.
  vector->interruptDisabledHard = 1;
  vector->interruptDisabledSoft = 1;
  vector->interruptRegistered   = 1;
  
  IOUnlock(vector->interruptLock);
  return kIOReturnSuccess;
}