Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

715 lines
14 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
command.c
Abstract:
This file contains the code for managing command and transmit blocks on
the TOK162's queues. It is based loosely on the NE3200 driver.
Author:
Kevin Martin(KevinMa) 04-Jan-1993
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include <tok162sw.h>
VOID
TOK162SendCommandBlock(
PTOK162_ADAPTER Adapter,
PTOK162_SUPER_COMMAND_BLOCK CommandBlock
);
VOID
TOK162SubmitCommandBlock(
IN PTOK162_ADAPTER Adapter,
IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
/*++
Routine Description:
Submit a complete Command Block for execution by the TOK162.
Arguments:
Adapter - The adapter that points to the ring entry structures.
CommandBlock - Holds the pointer to the Command Block to be
submitted.
Return Value:
None.
--*/
{
//
// Pointer to the most recently submitted Command Block.
//
PTOK162_SUPER_COMMAND_BLOCK PreviousCommandBlock;
// Ensure that our command block is on an even boundary.
//
ASSERT(!(NdisGetPhysicalAddressLow(CommandBlock->Self) & 1));
//
// Timestamp the command block.
//
CommandBlock->Timeout = FALSE;
CommandBlock->Hardware.State = TOK162_STATE_WAIT_FOR_ADAPTER;
//
// If the adapter is currently executing a command add this to
// the end of the waiting list. Otherwise submit this command to the card.
//
if (Adapter->CommandOnCard != NULL) {
//
// Pend this command
//
IF_LOG('i');
PreviousCommandBlock = Adapter->WaitingCommandTail;
Adapter->WaitingCommandTail = CommandBlock;
//
// Check if there are any other pendings. If not, we are
// the first pending. If there are others, tack this one on
// the end.
//
if (PreviousCommandBlock == NULL) {
Adapter->WaitingCommandHead = CommandBlock;
} else {
PreviousCommandBlock->NextCommand = CommandBlock;
}
} else {
//
// Set this command as the active one
//
Adapter->CommandOnCard = CommandBlock;
//
// Log that we are sending the command to the card
//
IF_LOG('I');
//
// send the command out to the card
//
TOK162SendCommandBlock(Adapter,CommandBlock);
}
}
VOID
TOK162SubmitTransmitBlock(
IN PTOK162_ADAPTER Adapter,
IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
/*++
Routine Description:
Submit a complete Command Block for execution by the TOK162.
Arguments:
Adapter - The adapter that points to the ring entry structures.
CommandBlock - Holds the pointer to the transmit block to be
submitted.
Return Value:
None.
--*/
{
//
// Pointer to the most recently submitted Transmit Block.
//
PTOK162_SUPER_COMMAND_BLOCK PreviousCommandBlock;
// Ensure that our command block is on an even boundary.
//
ASSERT(!(NdisGetPhysicalAddressLow(CommandBlock->Self) & 1));
//
// Timestamp the transmit block.
//
CommandBlock->Timeout = FALSE;
CommandBlock->Hardware.State = TOK162_STATE_WAIT_FOR_ADAPTER;
//
// If the adapter is currently executing a transmit add this to
// the end of the waiting list. Otherwise submit this transmit to
// the card.
//
if (Adapter->TransmitOnCard != NULL) {
//
// Log that we have to pend the transmit
IF_LOG('w');
//
// Pend this transmit
//
PreviousCommandBlock = Adapter->WaitingTransmitTail;
Adapter->WaitingTransmitTail = CommandBlock;
//
// Check if there are any other pendings
//
if (PreviousCommandBlock == NULL) {
Adapter->WaitingTransmitHead = CommandBlock;
} else {
PreviousCommandBlock->NextCommand = CommandBlock;
}
} else {
//
// Mark this transmit as the active one.
//
Adapter->TransmitOnCard = CommandBlock;
//
// Log that we are sending the transmit over the wire
//
IF_LOG('W');
//
// send the transmit to the card
//
TOK162SendCommandBlock(Adapter,CommandBlock);
}
}
BOOLEAN
TOK162AcquireTransmitBlock(
IN PTOK162_ADAPTER Adapter,
OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
)
/*++
Routine Description:
Sees if a Transmit Block is available and if so returns its index.
Arguments:
Adapter - The adapter that has the transmit queue
CommandBlock - Will receive a pointer to a Command Block if one is
available.
Return Value:
Returns FALSE if there are no free Command Blocks.
--*/
{
//
// Pointer to the available transmit block
//
PTOK162_SUPER_COMMAND_BLOCK temp;
//
// Get a pointer to the Transmit Block.
//
temp = Adapter->TransmitQueue + Adapter->NextTransmitBlock;
//
// If there aren't any available transmits, we return FALSE
//
if (Adapter->NumberOfAvailableTransmitBlocks == 0) {
//
// Log that there weren't any available
//
IF_LOG('x');
return FALSE;
}
//
// Decrement the number of available transit blocks.
//
Adapter->NumberOfAvailableTransmitBlocks--;
//
// Initialize the Transmit Command Block.
//
temp->Hardware.NextPending = TOK162_NULL;
temp->CommandBlock = FALSE;
//
// Increment to next transmit command block
//
if (Adapter->NextTransmitBlock == (Adapter->NumberOfTransmitLists - 1)) {
Adapter->NextTransmitBlock = 0;
} else {
Adapter->NextTransmitBlock++;
}
//
// Return the transmit block pointer.
//
*CommandBlock = temp;
//
// Log that we returned a transmit block.
//
IF_LOG('X');
return(TRUE);
}
VOID
TOK162AcquireCommandBlock(
IN PTOK162_ADAPTER Adapter,
OUT PTOK162_SUPER_COMMAND_BLOCK * CommandBlock
)
/*++
Routine Description:
Gets the command block.
Arguments:
Adapter - The adapter that points to the ring entry structures.
CommandBlock - Will receive a pointer to a Command Block.
Return Value:
None.
--*/
{
//
// Pointer to the command block to be returned.
//
PTOK162_SUPER_COMMAND_BLOCK temp;
//
// This is a pointer to the Command Block.
//
temp = Adapter->CommandQueue + Adapter->NextCommandBlock;
ASSERT(Adapter->NumberOfAvailableCommandBlocks > 0);
IF_LOG('l');
//
// Decrement the number of available command blocks
//
Adapter->NumberOfAvailableCommandBlocks--;
//
// Initialize the Command Block.
//
NdisZeroMemory(
temp,
sizeof(TOK162_SUPER_COMMAND_BLOCK)
);
//
// There aren't any linked command blocks right now.
//
temp->Hardware.NextPending = TOK162_NULL;
//
// This is a command block and not a transmit block
//
temp->CommandBlock = TRUE;
//
// Set the self-referential pointer.
//
NdisSetPhysicalAddressLow(
temp->Self,
NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) +
Adapter->NextCommandBlock * sizeof(TOK162_SUPER_COMMAND_BLOCK)
);
//
// Increment to next command block
//
if (Adapter->NextCommandBlock == (TOK162_NUMBER_OF_CMD_BLOCKS - 1)) {
Adapter->NextCommandBlock = 0;
} else {
Adapter->NextCommandBlock++;
}
//
// Return the Command Block pointer.
//
*CommandBlock = temp;
//
// Log that we returned a command block
//
IF_LOG('L');
}
VOID
TOK162RelinquishCommandBlock(
IN PTOK162_ADAPTER Adapter,
IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
/*++
Routine Description:
Relinquish the Command Block resource.
Arguments:
Adapter - The adapter that owns the Command Block.
CommandBlock - The Command Block to relinquish.
Return Value:
None.
--*/
{
//
// If there is a waiting chain of commands -- submit the first one
//
if (Adapter->WaitingCommandHead != NULL) {
//
// Log that we found pending commands
//
IF_LOG('j');
//
// Mark the next one as the active one.
//
Adapter->CommandOnCard = Adapter->WaitingCommandHead;
//
// Update the waiting command head.
//
Adapter->WaitingCommandHead =
Adapter->WaitingCommandHead->NextCommand;
//
// Update the waiting command tail pointer
//
if (Adapter->WaitingCommandHead == NULL) {
Adapter->WaitingCommandTail = NULL;
}
//
// Send out the new command
//
TOK162SendCommandBlock(Adapter,Adapter->CommandOnCard);
} else {
//
// Indicate that the queue was empty.
//
IF_LOG('J');
//
// No commands on the card. We're done for now.
//
Adapter->CommandOnCard = NULL;
}
//
// Free the command block
//
CommandBlock->Hardware.State = TOK162_STATE_FREE;
CommandBlock->NextCommand = NULL;
//
// Increment the number of available command blocks
//
Adapter->NumberOfAvailableCommandBlocks++;
}
VOID
TOK162RelinquishTransmitBlock(
IN PTOK162_ADAPTER Adapter,
IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
/*++
Routine Description:
Relinquish the Transmit Command Block resource.
Arguments:
Adapter - The adapter that owns the Command Block.
CommandBlock - The transmit block to relinquish.
Return Value:
None.
--*/
{
//
// If there is a waiting chain of commands -- submit the first one
//
if (Adapter->WaitingTransmitHead != NULL) {
//
// Log that there is a waiting send.
//
IF_LOG('y');
//
// Update the queue pointers
//
Adapter->TransmitOnCard = Adapter->WaitingTransmitHead;
Adapter->WaitingTransmitHead =
Adapter->WaitingTransmitHead->NextCommand;
if (Adapter->WaitingTransmitHead == NULL) {
Adapter->WaitingTransmitTail = NULL;
}
//
// Submit this command to the card.
//
TOK162SendCommandBlock(Adapter,Adapter->TransmitOnCard);
} else {
//
// Log that the waiting queue was empty.
//
IF_LOG('Y');
//
// We are done with submits
//
Adapter->TransmitOnCard = NULL;
}
//
// Free the transmit block
//
CommandBlock->Hardware.State = TOK162_STATE_FREE;
CommandBlock->NextCommand = NULL;
//
// Increment the number of available transmit blocks
//
Adapter->NumberOfAvailableTransmitBlocks++;
//
// Decrement the number of queued transmit blocks
//
Adapter->TransmitsQueued--;
}
void
TOK162SendCommandBlock(
IN PTOK162_ADAPTER Adapter,
IN PTOK162_SUPER_COMMAND_BLOCK CommandBlock
)
{
/*++
Routine Description:
Submits the command block passed in to the card.
Arguments:
Adapter - The adapter that owns the Command Block.
CommandBlock - The command/transmit block to submit.
Return Value:
None.
--*/
//
// This is the "execution" variable for the SCB. The standard is to just
// send the interrupt adapter, execute, and don't reset the
// adapter-to-system interrupt bits. The initial init open command will
// add in the scb clear bit.
ULONG ScbExecute = EXECUTE_SCB_COMMAND;
//
// First figure out the SCB, based on the command
//
Adapter->Scb->Command = CommandBlock->Hardware.CommandCode;
switch(Adapter->Scb->Command) {
//
// We have a transmit.
//
case CMD_DMA_XMIT:
//
// Point the Scb to the transmit list
//
Adapter->Scb->Parm1 =
BYTE_SWAP(HIGH_WORD(CommandBlock->PhysicalTransmitEntry));
Adapter->Scb->Parm2 =
BYTE_SWAP(LOW_WORD(CommandBlock->PhysicalTransmitEntry));
break;
//
// These are the Immediate Data commands. Close doesn't care what
// is passed, however.
//
case CMD_DMA_CLOSE:
case CMD_DMA_SET_GRP_ADDR:
case CMD_DMA_SET_FUNC_ADDR:
//
// The parameter is set according to the ImmediateData field of
// the command block.
//
Adapter->Scb->Parm1 =
BYTE_SWAP(HIGH_WORD(CommandBlock->Hardware.ImmediateData));
Adapter->Scb->Parm2 =
BYTE_SWAP(LOW_WORD(CommandBlock->Hardware.ImmediateData));
break;
//
// The rest use a pointer.
//
//
// In the case of an open, we have to check to see if this is part
// of the initial init. If so, we need to get the SCB Clear bit
// set so we have proper timing for the receieve command. After
// that decision has been made, the open command is treated like
// any other pointer command.
//
case CMD_DMA_OPEN:
if (Adapter->InitialInit == TRUE) {
ScbExecute |= CMD_PIO_SCB_REQUEST;
}
case CMD_DMA_READ_ERRLOG:
case CMD_DMA_READ:
case CMD_DMA_RCV:
case CMD_DMA_IMPL_ENABLE:
//
// The parameter is set according to the ParmPointer field of
// the command block.
//
Adapter->Scb->Parm1 =
BYTE_SWAP(HIGH_WORD(CommandBlock->Hardware.ParmPointer));
Adapter->Scb->Parm2 =
BYTE_SWAP(LOW_WORD(CommandBlock->Hardware.ParmPointer));
break;
}
//
// Mark the command block as executing
//
CommandBlock->Hardware.State = TOK162_STATE_EXECUTING;
//
// Log that we are sending an SCB to the card.
//
IF_LOG('Z');
//
// Display the SCB on the debugger
//
EXTRA_LOUD_DEBUG(DbgPrint("SCB going out is %x,%x,%x\n",
Adapter->Scb->Command,
Adapter->Scb->Parm1,
Adapter->Scb->Parm2);)
//
// Finally, send the command out to the card
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ScbExecute
);
}