VOID sndStopDMA( IN PGLOBAL_DEVICE_INFO pGDI ) /*++ Routine Description: Stop the DMA at once by disabling the hardware Free the adapter channel. (Opposite of sndStartDMA). Arguments: pGDI - pointer to global device info Return Value: None --*/ { // // Pass HALT DMA to the MIPSSND // if (pGDI->DMABusy) { KeSynchronizeExecution(pGDI->pInterrupt, StopDMA, pGDI); // // Flush our buffers // sndFlush(pGDI, 0); sndFlush(pGDI, 1); // // Stop the DMA controller // if (pGDI->Usage == SoundInterruptUsageWaveIn) { IoFreeAdapterChannel(pGDI->pAdapterObject[2]); IoFreeAdapterChannel(pGDI->pAdapterObject[3]); } else { IoFreeAdapterChannel(pGDI->pAdapterObject[0]); IoFreeAdapterChannel(pGDI->pAdapterObject[1]); } } dprintf4(" dma_stopped"); // // Note our new state // pGDI->DMABusy = FALSE; }
static VOID NTAPI RWFreeAdapterChannel(PADAPTER_OBJECT AdapterObject) /* * FUNCTION: Free the adapter DMA channel that we allocated * ARGUMENTS: * AdapterObject: the object with the map registers to free * NOTES: * - This function is primarily needed because IoFreeAdapterChannel wants to * be called at DISPATCH_LEVEL */ { KIRQL Irql; ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeRaiseIrql(DISPATCH_LEVEL, &Irql); IoFreeAdapterChannel(AdapterObject); KeLowerIrql(Irql); }
VOID IoFreeMapRegisters( PADAPTER_OBJECT AdapterObject, PVOID MapRegisterBase, ULONG NumberOfMapRegisters ) /*++ Routine Description: This routine deallocates the map registers for the adapter. If there are any queued adapter waiting for an attempt is made to allocate the next entry. Arguments: AdapterObject - The adapter object to where the map register should be returned. MapRegisterBase - The map register base of the registers to be deallocated. NumberOfMapRegisters - The number of registers to be deallocated. Return Value: None --+*/ { PADAPTER_OBJECT MasterAdapter; LONG MapRegisterNumber; PWAIT_CONTEXT_BLOCK Wcb; PLIST_ENTRY Packet; IO_ALLOCATION_ACTION Action; KIRQL Irql; // // Begin by getting the address of the master adapter. // if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) { MasterAdapter = AdapterObject->MasterAdapter; } else { // // There are no map registers to return. // return; } // // Strip no scatter/gather flag. // MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase - (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase; // // Acquire the master adapter spinlock which locks the adapter queue and the // bit map for the map registers. // Irql = KfAcquireSpinLock(&MasterAdapter->SpinLock); // // Return the registers to the bit map. // RtlClearBits( MasterAdapter->MapRegisters, MapRegisterNumber, NumberOfMapRegisters ); // // Process any requests waiting for map registers in the adapter queue. // Requests are processed until a request cannot be satisfied or until // there are no more requests in the queue. // while(TRUE) { if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){ break; } Packet = RemoveHeadList( &MasterAdapter->AdapterQueue ); AdapterObject = CONTAINING_RECORD( Packet, ADAPTER_OBJECT, AdapterQueue ); Wcb = AdapterObject->CurrentWcb; // // Attempt to allocate map registers for this request. Use the previous // register base as a hint. // MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters, AdapterObject->NumberOfMapRegisters, MasterAdapter->NumberOfMapRegisters ); if (MapRegisterNumber == -1) { // // There were not enough free map registers. Put this request back on // the adapter queue where is came from. // InsertHeadList( &MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue ); break; } KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase + MapRegisterNumber); // // Set the no scatter/gather flag if scatter/gather not // supported. // if (!AdapterObject->ScatterGather) { AdapterObject->MapRegisterBase = (PVOID) ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); } // // Invoke the driver's execution routine now. // Action = Wcb->DeviceRoutine( Wcb->DeviceObject, Wcb->CurrentIrp, AdapterObject->MapRegisterBase, Wcb->DeviceContext ); // // If the driver wishes to keep the map registers then set the number // allocated to zero and set the action to deallocate object. // if (Action == DeallocateObjectKeepRegisters) { AdapterObject->NumberOfMapRegisters = 0; Action = DeallocateObject; } // // If the driver would like to have the adapter deallocated, // then deallocate any map registers allocated and then release // the adapter object. // if (Action == DeallocateObject) { // // The map registers registers are deallocated here rather than in // IoFreeAdapterChannel. This limits the number of times // this routine can be called recursively possibly overflowing // the stack. The worst case occurs if there is a pending // request for the adapter that uses map registers and whos // excution routine decallocates the adapter. In that case if there // are no requests in the master adapter queue, then IoFreeMapRegisters // will get called again. // if (AdapterObject->NumberOfMapRegisters != 0) { // // Deallocate the map registers and clear the count so that // IoFreeAdapterChannel will not deallocate them again. // Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock ); RtlClearBits( MasterAdapter->MapRegisters, MapRegisterNumber, AdapterObject->NumberOfMapRegisters ); AdapterObject->NumberOfMapRegisters = 0; KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); } IoFreeAdapterChannel( AdapterObject ); } Irql = KfAcquireSpinLock( &MasterAdapter->SpinLock ); } KfReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); }
dVoid kdi_LockUnlockDMA ( /* INPUT PARAMETERS: */ KdiContextPtr kdi_context, dBoolean lock /* UPDATE PARAMETERS: */ /* OUTPUT PARAMETERS: */ ) /* COMMENTS: ***************************************************************** * * DEFINITIONS: *************************************************************/ { /* DATA: ********************************************************************/ KIRQL old_irql; /* CODE: ********************************************************************/ if (kdi_context->adapter_object) { if (lock) { if (!kdi_context->adapter_locked) { /* Allocate an adapter channel for the I/O. */ (dVoid) KeResetEvent( &kdi_context->allocate_adapter_channel_event ); KeRaiseIrql( DISPATCH_LEVEL, &old_irql ); IoAllocateAdapterChannel( kdi_context->adapter_object, kdi_context->device_object, kdi_context->number_of_map_registers, kdi_AllocateAdapterChannel, kdi_context ); KeLowerIrql( old_irql ); /* Wait for the adapter to be allocated. No */ /* timeout; we trust the system to do it */ /* properly - so KeWaitForSingleObject can't */ /* return an error. */ (dVoid) KeWaitForSingleObject( &kdi_context->allocate_adapter_channel_event, Executive, KernelMode, dFALSE, (dSDDWordPtr) dNULL_PTR ); kdi_context->adapter_locked = dTRUE; } } else { if (kdi_context->adapter_locked) { /* Free the adapter channel that we just used. */ KeRaiseIrql( DISPATCH_LEVEL, &old_irql ); IoFreeAdapterChannel( kdi_context->adapter_object ); KeLowerIrql( old_irql ); kdi_context->adapter_locked = dFALSE; } } } return; }