📄 dp_hardware_dispatcher.c
字号:
}
}
else
{
/* The buffer wasn't grabbed while we were working on it, so just */
/* transition it back to 'free', copying the other buffer as a baseline */
DP_eBufferStates [ ui16i ] = DP_DMA_BUFFER_STATE_FREE;
DP_MEMCPY ( &(DP_DispatcherBuffers [( ui16i * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [ ui16i ]]),
&(DP_DispatcherBuffers [( (1-ui16i) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [(1 - ui16i)]]),
sizeof (DP_QueuedMemoryWrite) * DP_ui16DispatcherBufferSize [(1-ui16i)] );
DP_ui16DispatcherBufferSize [ui16i] = DP_ui16DispatcherBufferSize [(1-ui16i)];
}
break;
} /* Case */
} /* Switch */
} /* If */
if ( bBufferToBeFreed [0] && bBufferToBeFreed [1] )
{
for ( ui16i = 0; ui16i < 2; ui16i ++ )
{
/* Clear both the buffers entirely */
DP_ui16DispatcherBufferSize [ ui16i ] = 0;
/* Toggle the offset addresses */
if ( DP_ui8DispatcherBufferOffset [ ui16i ] )
DP_ui8DispatcherBufferOffset [ ui16i ] = 0;
else
DP_ui8DispatcherBufferOffset [ ui16i ] = 2;
}
}
else
{
for ( ui16i = 0; ui16i < 2; ui16i ++ )
{
if ( bBufferToBeFreed [ ui16i ] )
{
/* If there are any entries in the other buffer (the one not being freed), */
/* which have not yet reached hardware, then duplicate them in the buffer */
/* being freed. Only do this if the other buffer is not currently being */
/* serviced (in which case there's little point in copying the data from it as */
/* it will have reached hardware soon enough, anyway). */
if (( DP_eBufferStates [ (1-ui16i) ] != DP_DMA_BUFFER_STATE_SERVICING ) &&
( DP_eBufferStates [ (1-ui16i) ] != DP_DMA_BUFFER_STATE_LIMBO ))
{
/* Toggle the offset address */
if ( DP_ui8DispatcherBufferOffset [ ui16i ] )
DP_ui8DispatcherBufferOffset [ ui16i ] = 0;
else
DP_ui8DispatcherBufferOffset [ ui16i ] = 2;
ui8SizeOfNewBuffer = 0;
/* In the following routine, ui16i indicates the number of the buffer to be */
/* freed. ui16j is used to search through each entry of the other buffer */
/* (the one not being freed). */
for ( ui16j = 0; ui16j < DP_ui16DispatcherBufferSize [ (1-ui16i) ]; ui16j++ )
{
if ( DP_DispatcherBuffers [ ( (1-ui16i) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + (ui16j + DP_ui8DispatcherBufferOffset [ (1-ui16i) ]) ].ui32TargetValue !=
DP_ReadFromMemory ( DP_DispatcherBuffers [ ( (1-ui16i) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + (ui16j + DP_ui8DispatcherBufferOffset [ (1-ui16i)]) ].ui32TargetAddressOffset ) )
{
/* The value in memory did not match the queued value for that */
/* address, so we'd better retain the change for submission to the */
/* DMA Engine. */
DP_MEMCPY ( &(DP_DispatcherBuffers [ ( ui16i * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + (ui8SizeOfNewBuffer + DP_ui8DispatcherBufferOffset [ ui16i ]) ]),
&(DP_DispatcherBuffers [ ( (1-ui16i) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + ui16j + DP_ui8DispatcherBufferOffset [ (1-ui16i)] ]),
sizeof ( DP_QueuedMemoryWrite ) );
ui8SizeOfNewBuffer++;
}
} /* For */
DP_ui16DispatcherBufferSize [ ui16i ] = ui8SizeOfNewBuffer;
/* If the other buffer (the one which has not just been freed) is in the */
/* 'FREE' state then it still contains old data (which has just been */
/* written). In this case, just duplicate that buffer from this one. */
if ( DP_eBufferStates [ (1-ui16i) ] == DP_DMA_BUFFER_STATE_FREE )
{
DP_MEMCPY ( &(DP_DispatcherBuffers [ ( ( 1-ui16i) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [ (1-ui16i) ]]),
&(DP_DispatcherBuffers [ ( ui16i * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [ui16i]]),
sizeof (DP_QueuedMemoryWrite) * DP_ui16DispatcherBufferSize [ui16i] );
DP_ui16DispatcherBufferSize [(1-ui16i)] = DP_ui16DispatcherBufferSize [ui16i];
}
} /* If */
else
{
/* Clear the buffer entirely */
DP_ui16DispatcherBufferSize [ ui16i ] = 0;
/* Toggle the offset address */
if ( DP_ui8DispatcherBufferOffset [ ui16i ] )
DP_ui8DispatcherBufferOffset [ ui16i ] = 0;
else
DP_ui8DispatcherBufferOffset [ ui16i ] = 2;
}
} /* If */
} /* For */
} /* If */
/* Decide how to deal with the new information to be queued. */
/* Are either of the buffers free ? */
for ( ui16i = 0; ui16i < 2; ui16i ++ )
{
if ( DP_eBufferStates [ ui16i ] == DP_DMA_BUFFER_STATE_FREE )
{
i8BufferToUse = (DP_INT_8) ui16i;
break;
}
}
if ( i8BufferToUse == -1 )
{
for ( ui16i = 0; ui16i < 2; ui16i ++ )
{
if ( DP_eBufferStates [ ui16i ] == DP_DMA_BUFFER_STATE_PENDING )
{
i8BufferToUse = (DP_INT_8) ui16i;
break;
}
}
/* We could find neither any free nor any pending buffers. This means that both */
/* buffers must be set to 'servicing' mode. Which is just silly. */
if ( i8BufferToUse != -1 )
{
/* We have found a pending buffer (in the absence of any free ones, so use that) */
/* As we didn't find any free buffers, and we did find a pending one, the other */
/* buffer must be in 'servicing' mode (otherwise it would have been freed by now) */
/* Clear the 'valid' flag */
DP_WriteFieldToAddress ( &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_PENDING_ADDRESS_VALID_FLAG ]),
(DP_UINT_32) NULL,
DP_NULL );
/* Now add all the changes in the submitted queue to the pending buffer */
for ( ui16i = 0; ui16i < ui8LengthOfQueue; ui16i++ )
{
DP_AddToBuffer ( pasQueueToSubmit [ ui16i ],
&(DP_DispatcherBuffers [ ( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [i8BufferToUse] ]),
&(DP_ui16DispatcherBufferSize [ i8BufferToUse ]) );
}
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_NEW_SEQUENCE,
DP_NULL,
DP_NULL );
/* Write the length of the newly created buffer to the 'length of pending */
/* buffer' register. */
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_ADD_COMMAND,
(DP_FieldTarget *) &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_LENGTH_OF_PENDING_BUFFER ]),
(DP_UINT_32) DP_ui16DispatcherBufferSize [ i8BufferToUse ] );
/* Point the 'Pending' register at the (until recently) pending buffer */
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_ADD_COMMAND,
(DP_FieldTarget *) &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_PENDING_ADDRESS ]),
#if defined PCI_BRIDGE_SIM
/* Remove the Windows address offset prior to */
/* writing to the hardware. */
(DP_UINT_32) ( (( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_BYTES ) + (DP_ui8DispatcherBufferOffset [i8BufferToUse] * sizeof ( DP_QueuedMemoryWrite )) ) ) + ( (DP_UINT_32) DP_DispatcherBuffers - (DP_UINT_32) DP_pSharedMemory ));
#else
(DP_UINT_32) &(DP_DispatcherBuffers [ ( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [i8BufferToUse]]) );
#endif
/* Reset the 'valid' flag */
DP_WriteFieldToAddress ( &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_PENDING_ADDRESS_VALID_FLAG ]),
(DP_UINT_32) (DP_TRUE & 0x01),
DP_NULL );
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_SEND_IMMEDIATE,
DP_NULL,
DP_NULL );
}
}
else
{
/* At least one buffer was free, so proceed with that one */
/* Now add all the changes in the submitted queue to the free buffer */
for ( ui16i = 0; ui16i < ui8LengthOfQueue; ui16i++ )
{
DP_AddToBuffer ( pasQueueToSubmit [ ui16i ],
&(DP_DispatcherBuffers [ ( ( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [i8BufferToUse] ) ]),
&(DP_ui16DispatcherBufferSize [i8BufferToUse]) );
}
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_NEW_SEQUENCE,
DP_NULL,
DP_NULL );
/* Point the 'Pending' register at the currently free buffer */
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_ADD_COMMAND,
(DP_FieldTarget *) &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_PENDING_ADDRESS ]),
#if defined PCI_BRIDGE_SIM
/* Remove the Windows address offset prior to writing */
/* hardware. */
(DP_UINT_32) ((( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_BYTES ) + (DP_ui8DispatcherBufferOffset [i8BufferToUse] * sizeof ( DP_QueuedMemoryWrite )) ) ) + ( (DP_UINT_32) DP_DispatcherBuffers - (DP_UINT_32) DP_pSharedMemory ));
#else
(DP_UINT_32) &(DP_DispatcherBuffers [ ( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [i8BufferToUse]]) );
#endif
/* Write the length of the newly created buffer to the 'length of pending */
/* buffer' register. */
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_ADD_COMMAND,
(DP_FieldTarget *) &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_LENGTH_OF_PENDING_BUFFER ]),
(DP_UINT_32) DP_ui16DispatcherBufferSize [i8BufferToUse] );
/* Set the 'valid' flag */
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_ADD_COMMAND,
(DP_FieldTarget *) &(DP_asGlobalFieldTargets [ DP_GLOBAL_FIELD_HARDWARE_DISPATCHER_PENDING_ADDRESS_VALID_FLAG ]),
(DP_UINT_32) (DP_TRUE & 0x01) );
DP_CommandSequence ( DP_COMMAND_SEQUENCE_OPERATIONS_SEND_IMMEDIATE,
DP_NULL,
DP_NULL );
/* Change the states of the two buffers */
DP_eBufferStates [i8BufferToUse] = DP_DMA_BUFFER_STATE_PENDING;
switch ( DP_eBufferStates [(1-i8BufferToUse)] )
{
case DP_DMA_BUFFER_STATE_FREE:
{
/* Keep the other buffer up to date with the latest info. */
DP_MEMCPY ( &(DP_DispatcherBuffers [ ( (1-i8BufferToUse) * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [ (1-i8BufferToUse) ]]),
&(DP_DispatcherBuffers [ ( i8BufferToUse * DP_SIZE_OF_DISPATCHER_BUFFER_IN_ENTRIES ) + DP_ui8DispatcherBufferOffset [ i8BufferToUse ]]),
sizeof (DP_QueuedMemoryWrite) * DP_ui16DispatcherBufferSize [ i8BufferToUse ] );
DP_ui16DispatcherBufferSize [ (1-i8BufferToUse) ] = DP_ui16DispatcherBufferSize [ i8BufferToUse ];
break;
}
case DP_DMA_BUFFER_STATE_PENDING:
{
DP_eBufferStates [(1-i8BufferToUse)] = DP_DMA_BUFFER_STATE_LIMBO;
break;
}
}
}
} /* End of 'DP_QueueNewDMABuffer' */
/***********************************************************************************************
*
* Function Name : DP_AddToBuffer
* Inputs : sFieldToAdd - A pointer to the 'DP_QueuedFieldWrite'
* structure containing details of the field
* target to be added to the specified list
* of memory writes.
*
* pasBufferToAddTo - A pointer to the first
* 'DP_pQueuedMemoryWrite' structure in a
* list of non-field specific memory writes.
*
* pui16SizeOfBuffer - A pointer to the 'DP_UINT_16' containing the
* number of non-field specific memory writes
* in the list passed. A pointer to the value
* is passed so that the function can update the
* size of the list if necessary.
*
* Outputs : pui16SizeOfBuffer - See above.
* Returns : Nothing.
* Globals Used : None.
* Description : This function adds a specified field write to an existing buffer, searching
* to see if the affected memory address is currently in the buffer and, if it
* is, merging the two values, and reading the current value from hardware prior
* to merging and adding to the end of the buffer otherwise.
*
***********************************************************************************************/
DP_VOID DP_AddToBuffer ( DP_QueuedFieldWrite sFieldToAdd,
DP_pQueuedMemoryWrite pasBufferToAddTo,
DP_PUINT_16 pui16SizeOfBuffer )
{
DP_UINT_32 ui32CurrentQueuedValue;
DP_UINT_16 ui16CurrentQueuedPosition;
DP_QueuedMemoryWrite sMemoryWriteToAdd;
/* If the field to add doesn't exist, then proceed no further. */
if ( (sFieldToAdd.pasFieldToWrite)->ui32TargetAddressOffset != DP_NO_REG )
{
/* Is the address containing the specified field already listed in the buffer ? */
if ( DP_SearchBuffer ( pasBufferToAddTo,
*pui16SizeOfBuffer,
(sFieldToAdd.pasFieldToWrite)->ui32TargetAddressOffset,
&ui32CurrentQueuedValue,
&ui16CurrentQueuedPosition ) )
{
/* The address of the field to add is currently listed in the buffer, so the new */
/* field value should be merged into the current buffer position. */
DP_WriteFieldToAddress ( sFieldToAdd.pasFieldToWrite,
sFieldToAdd.ui32ValueToWrite,
&(pasBufferToAddTo [ui16CurrentQueuedPosition].ui32TargetValue) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -