723 lines
19 KiB
C
723 lines
19 KiB
C
/***************************************************************************\
|
||
|* Copyright (c) 1994 Microsoft Corporation *|
|
||
|* Developed for Microsoft by TriplePoint, Inc. Beaverton, Oregon *|
|
||
|* *|
|
||
|* This file is part of the HT Communications DSU41 WAN Miniport Driver. *|
|
||
\***************************************************************************/
|
||
#include "version.h"
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Module Name:
|
||
|
||
card.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the low-level hardware control functions used by
|
||
the NDIS Minport driver on the HT DSU41 controller. You will need to
|
||
replace this module with the control functions required to support your
|
||
hardware.
|
||
CardIdentify()
|
||
CardDoCommand()
|
||
CardInitialize()
|
||
CardLineConfig()
|
||
CardLineDisconnect()
|
||
CardLineDisconnect()
|
||
CardPrepareTransmit()
|
||
CardGetReceiveInfo()
|
||
CardDialNumber()
|
||
|
||
This driver conforms to the NDIS 3.0 Miniport interface.
|
||
|
||
Author:
|
||
|
||
Larry Hattery - TriplePoint, Inc. (larryh@tpi.com) Jun-94
|
||
|
||
Environment:
|
||
|
||
Windows NT 3.5 kernel mode Miniport driver or equivalent.
|
||
|
||
Revision History:
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
#define __FILEID__ 2 // Unique file ID for error logging
|
||
|
||
#include "htdsu.h"
|
||
|
||
|
||
NDIS_STATUS
|
||
CardIdentify(
|
||
IN PHTDSU_ADAPTER Adapter
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will attempt to verify that the controller is located in
|
||
memory where the driver has been configured to expect it.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
Return Values:
|
||
|
||
NDIS_STATUS_SUCCESS
|
||
NDIS_STATUS_ADAPTER_NOT_FOUND
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardIdentify")
|
||
|
||
NDIS_STATUS Status;
|
||
|
||
/*
|
||
// These values are read from the adapter to make sure this driver will
|
||
// work with the firmware on the adapter.
|
||
*/
|
||
USHORT CoProcessorId;
|
||
USHORT CoProcessorVersion;
|
||
USHORT DsuId;
|
||
USHORT DsuVersion;
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
/*
|
||
// Read the configuration values from the card.
|
||
*/
|
||
CoProcessorId = READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId);
|
||
CoProcessorVersion = READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorVersion);
|
||
DsuId = READ_REGISTER_USHORT(&Adapter->AdapterRam->DsuId);
|
||
DsuVersion = READ_REGISTER_USHORT(&Adapter->AdapterRam->DsuVersion);
|
||
|
||
/*
|
||
// Make sure these values are what we expect.
|
||
*/
|
||
if ((CoProcessorId == HTDSU_COPROCESSOR_ID) &&
|
||
(CoProcessorVersion >= HTDSU_COPROCESSOR_VERSION) &&
|
||
((DsuId & 0x00FF) == HTDSU_DSU_ID) &&
|
||
(DsuVersion >= HTDSU_DSU_VERSION))
|
||
{
|
||
/*
|
||
// Record the number of lines on this adapter.
|
||
*/
|
||
Adapter->NumLineDevs = HTDSU_NUM_LINKS;
|
||
if ((DsuId & 0xFF00) == 0)
|
||
{
|
||
--Adapter->NumLineDevs;
|
||
}
|
||
DBG_NOTICE(Adapter,("NumLineDevs=%d\n",Adapter->NumLineDevs));
|
||
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
DBG_ERROR(Adapter,("Adapter not found or invalid firmware:\n"
|
||
"CoProcessorId = %Xh\n"
|
||
"CoProcessorVersion = %Xh\n"
|
||
"DsuId = %Xh\n"
|
||
"DsuVersion = %Xh\n",
|
||
CoProcessorId,
|
||
CoProcessorVersion,
|
||
DsuId,
|
||
DsuVersion
|
||
));
|
||
|
||
Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
||
/*
|
||
// Log error message and return.
|
||
*/
|
||
NdisWriteErrorLogEntry(
|
||
Adapter->MiniportAdapterHandle,
|
||
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
||
7,
|
||
CoProcessorId,
|
||
CoProcessorVersion,
|
||
DsuId,
|
||
DsuVersion,
|
||
Status,
|
||
__FILEID__,
|
||
__LINE__
|
||
);
|
||
}
|
||
|
||
DBG_LEAVE(Adapter);
|
||
|
||
return (Status);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
CardDoCommand(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
IN USHORT CommandValue
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine routine will execute a command on the card after making
|
||
sure the previous command has completed properly.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
|
||
|
||
CommandValue _ HTDSU_CMD_??? command to be executed.
|
||
|
||
Return Values:
|
||
|
||
NDIS_STATUS_SUCCESS
|
||
NDIS_STATUS_HARD_ERRORS
|
||
|
||
---------------------------------------------------------------------------*/
|
||
{
|
||
DBG_FUNC("CardDoCommand")
|
||
|
||
ULONG TimeOut = 0;
|
||
|
||
DBG_ENTER(Adapter);
|
||
DBG_FILTER(Adapter, DBG_PARAMS_ON,("Line=%d, Command=%04X, LineStatus=%Xh\n",
|
||
CardLine, CommandValue,
|
||
READ_REGISTER_USHORT(&Adapter->AdapterRam->StatusLine1)
|
||
));
|
||
|
||
/*
|
||
// Wait for command register to go idle - but don't wait too long.
|
||
// If we timeout here, there's gotta be something wrong with the adapter.
|
||
*/
|
||
while ((READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) !=
|
||
HTDSU_CMD_NOP) ||
|
||
(READ_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId) !=
|
||
HTDSU_COPROCESSOR_ID))
|
||
{
|
||
if (TimeOut++ > HTDSU_SELFTEST_TIMEOUT)
|
||
{
|
||
DBG_ERROR(Adapter,("Timeout waiting for %04X command to clear\n",
|
||
READ_REGISTER_USHORT(&Adapter->AdapterRam->Command)));
|
||
/*
|
||
// Ask for reset, and disable interrupts until we get it.
|
||
*/
|
||
Adapter->NeedReset = TRUE;
|
||
Adapter->InterruptEnableFlag = HTDSU_INTR_DISABLE;
|
||
CardDisableInterrupt(Adapter);
|
||
|
||
return (NDIS_STATUS_HARD_ERRORS);
|
||
}
|
||
NdisStallExecution(_100_MICROSECONDS);
|
||
}
|
||
DBG_NOTICE(Adapter,("Timeout=%d waiting to submit %04X\n",
|
||
TimeOut, CommandValue));
|
||
|
||
/*
|
||
// Before starting a reset command, we clear the the co-processor ID
|
||
// which then gets set to the proper value when the reset is complete.
|
||
*/
|
||
if (CommandValue == HTDSU_CMD_RESET)
|
||
{
|
||
WRITE_REGISTER_USHORT(&Adapter->AdapterRam->CoProcessorId, 0);
|
||
}
|
||
|
||
/*
|
||
// Send the command to the adapter.
|
||
*/
|
||
WRITE_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->Command,
|
||
(USHORT) (CommandValue + CardLine)
|
||
);
|
||
|
||
DBG_LEAVE(Adapter);
|
||
|
||
return (NDIS_STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
CardInitialize(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN BOOLEAN PerformSelfTest
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will attempt to initialize the controller, but will not
|
||
enable transmits or receives.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
PerformSelfTest _ TRUE if caller wants to run selftest diagnostics.
|
||
This normally takes about 4 seconds to complete, so you
|
||
wouldn't want to do it every time you start up.
|
||
|
||
Return Values:
|
||
|
||
NDIS_STATUS_HARD_ERRORS
|
||
NDIS_STATUS_SUCCESS
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardInitialize")
|
||
|
||
NDIS_STATUS Status;
|
||
|
||
USHORT SelfTestStatus;
|
||
|
||
UINT TimeOut;
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
/*
|
||
// First we make sure the adapter is where we think it is.
|
||
*/
|
||
Status = CardIdentify(Adapter);
|
||
if (Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
return (Status);
|
||
}
|
||
|
||
/*
|
||
// Reset the hardware to make sure we're in a known state.
|
||
*/
|
||
Status = CardDoCommand(Adapter, 0, HTDSU_CMD_RESET);
|
||
|
||
if (PerformSelfTest)
|
||
{
|
||
/*
|
||
// Wait for the reset to complete before starting the self-test.
|
||
// Then issue the self-test command to see if the adapter firmware
|
||
// is happy with the situation.
|
||
*/
|
||
Status = CardDoCommand(Adapter, 0, HTDSU_CMD_SELFTEST);
|
||
if (Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
DBG_ERROR(Adapter,("Failed HTDSU_CMD_RESET\n"));
|
||
/*
|
||
// Log error message and return.
|
||
*/
|
||
NdisWriteErrorLogEntry(
|
||
Adapter->MiniportAdapterHandle,
|
||
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
||
3,
|
||
Status,
|
||
__FILEID__,
|
||
__LINE__
|
||
);
|
||
return (Status);
|
||
}
|
||
|
||
/*
|
||
// Wait for the self test to complete, but don't wait forever.
|
||
*/
|
||
TimeOut = 0;
|
||
while (Status == NDIS_STATUS_SUCCESS &&
|
||
READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) !=
|
||
HTDSU_CMD_NOP)
|
||
{
|
||
if (TimeOut++ > HTDSU_SELFTEST_TIMEOUT)
|
||
{
|
||
DBG_ERROR(Adapter,("Timeout waiting for SELFTEST to complete\n"));
|
||
Status = NDIS_STATUS_HARD_ERRORS;
|
||
}
|
||
else
|
||
{
|
||
NdisStallExecution(_100_MICROSECONDS);
|
||
}
|
||
}
|
||
if (Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
DBG_ERROR(Adapter,("Failed HTDSU_CMD_SELFTEST\n"));
|
||
/*
|
||
// Log error message and return.
|
||
*/
|
||
NdisWriteErrorLogEntry(
|
||
Adapter->MiniportAdapterHandle,
|
||
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
||
3,
|
||
Status,
|
||
__FILEID__,
|
||
__LINE__
|
||
);
|
||
return (Status);
|
||
}
|
||
|
||
/*
|
||
// Verify that self test was successful.
|
||
*/
|
||
SelfTestStatus = READ_REGISTER_USHORT(&Adapter->AdapterRam->SelfTestStatus);
|
||
if (SelfTestStatus != 0 && SelfTestStatus != HTDSU_SELFTEST_OK)
|
||
{
|
||
DBG_ERROR(Adapter,("Failed HTDSU_CMD_SELFTEST (Status=%X)\n",
|
||
SelfTestStatus));
|
||
/*
|
||
// Log error message and return.
|
||
*/
|
||
NdisWriteErrorLogEntry(
|
||
Adapter->MiniportAdapterHandle,
|
||
NDIS_ERROR_CODE_HARDWARE_FAILURE,
|
||
3,
|
||
SelfTestStatus,
|
||
__FILEID__,
|
||
__LINE__
|
||
);
|
||
return (NDIS_STATUS_HARD_ERRORS);
|
||
}
|
||
}
|
||
|
||
DBG_LEAVE(Adapter);
|
||
|
||
return (NDIS_STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
VOID
|
||
CardLineConfig(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN USHORT CardLine /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will ready the controller to send and receive packets.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardLineConfig")
|
||
|
||
USHORT ClockCommand;
|
||
USHORT LineCommand;
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
|
||
|
||
/*
|
||
// Configure the line for HDLC framing and for leased or dialup mode.
|
||
*/
|
||
if (Adapter->LineType == HTDSU_LINEMODE_LEASED)
|
||
{
|
||
ClockCommand = HTDSU_CMD_INTERNAL_TX_CLOCK;
|
||
LineCommand = HTDSU_CMD_LEASED_LINE;
|
||
}
|
||
else
|
||
{
|
||
ClockCommand = HTDSU_CMD_DDS_TX_CLOCK;
|
||
LineCommand = HTDSU_CMD_DIALUP_LINE;
|
||
}
|
||
|
||
CardDoCommand(Adapter, CardLine, ClockCommand);
|
||
CardDoCommand(Adapter, CardLine, HTDSU_CMD_HDLC_PROTOCOL);
|
||
CardDoCommand(Adapter, CardLine, LineCommand);
|
||
CardDoCommand(Adapter, CardLine, Adapter->LineRate);
|
||
|
||
/*
|
||
// Clear any pending interrupts.
|
||
*/
|
||
CardDoCommand(Adapter, 0, HTDSU_CMD_CLEAR_INTERRUPT);
|
||
CardClearInterrupt(Adapter);
|
||
|
||
DBG_LEAVE(Adapter);
|
||
}
|
||
|
||
|
||
VOID
|
||
CardLineDisconnect(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN USHORT CardLine /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will disconnect any call currently on the line.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardLineDisconnect")
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
|
||
|
||
/*
|
||
// Disconnect the line and reconfigure the line for next time.
|
||
*/
|
||
CardDoCommand(Adapter, CardLine, HTDSU_CMD_DISCONNECT);
|
||
CardLineConfig(Adapter, CardLine);
|
||
|
||
DBG_LEAVE(Adapter);
|
||
}
|
||
|
||
|
||
VOID
|
||
CardPrepareTransmit(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
IN USHORT BytesToSend
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will write the packet header information into the
|
||
transmit buffer. This assumes that the controller has notified the
|
||
driver that the transmit buffer is empty.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
|
||
|
||
BytesToSend _ Number of bytes to transmit.
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardPrepareTransmit")
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
ASSERT((CardLine==HTDSU_CMD_LINE1) || (CardLine==HTDSU_CMD_LINE2));
|
||
ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty));
|
||
ASSERT(BytesToSend > 0);
|
||
|
||
/*
|
||
// Tell the adapter how many bytes are to be sent, and which line to use.
|
||
*/
|
||
WRITE_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->TxBuffer.Address,
|
||
(USHORT) (CardLine - HTDSU_CMD_LINE1)
|
||
);
|
||
WRITE_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->TxBuffer.Length,
|
||
BytesToSend
|
||
);
|
||
|
||
/*
|
||
// Mark the end of packet and end of packet list.
|
||
*/
|
||
WRITE_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->TxBuffer.Data[(BytesToSend+1)/sizeof(USHORT)],
|
||
HTDSU_DATA_TERMINATOR
|
||
);
|
||
WRITE_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->TxBuffer.Data[(BytesToSend+3)/sizeof(USHORT)],
|
||
HTDSU_DATA_TERMINATOR
|
||
);
|
||
|
||
DBG_LEAVE(Adapter);
|
||
}
|
||
|
||
|
||
VOID
|
||
CardGetReceiveInfo(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
OUT PUSHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
OUT PUSHORT BytesReceived,
|
||
OUT PUSHORT RxErrors
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
This routine will retrieve the packet header information from the
|
||
receive buffer. This assumes that the controller has notified the
|
||
driver that a packet has been received.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line the packet was received on (HTDSU_LINEx_ID).
|
||
|
||
BytesReceived _ Number of bytes received.
|
||
|
||
RxErrors _ Receive error flags non-zero if packet has errors.
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
---------------------------------------------------------------------------*/
|
||
{
|
||
DBG_FUNC("CardGetReceiveInfo")
|
||
|
||
USHORT Length;
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
/*
|
||
// This should be true if we're here, but there are race conditions
|
||
// on hangup where I've seen this condition hit.
|
||
*/
|
||
if (READ_REGISTER_USHORT(&Adapter->AdapterRam->RxDataAvailable) == 0)
|
||
{
|
||
*RxErrors = 0;
|
||
*BytesReceived = 0;
|
||
*CardLine = HTDSU_CMD_LINE1; // Don't return a bad line #
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
// The length field tells us how many bytes are in the packet, and
|
||
// the most significant bit tells us whether the packet has a CRC error.
|
||
*/
|
||
Length = READ_REGISTER_USHORT(&Adapter->AdapterRam->RxBuffer.Length);
|
||
*BytesReceived = Length & ~HTDSU_CRC_ERROR;
|
||
*RxErrors = Length & HTDSU_CRC_ERROR;
|
||
|
||
/*
|
||
// The least significant nibble of the address tells us what line the
|
||
// packet was received on -- at least it better...
|
||
*/
|
||
*CardLine = (READ_REGISTER_USHORT(
|
||
&Adapter->AdapterRam->RxBuffer.Address) &
|
||
0x000F) + HTDSU_CMD_LINE1;
|
||
|
||
if ((*CardLine != HTDSU_CMD_LINE1) && (*CardLine != HTDSU_CMD_LINE2))
|
||
{
|
||
*RxErrors |= HTDSU_RX_ERROR;
|
||
*CardLine = HTDSU_CMD_LINE1; // Don't return a bad line #
|
||
}
|
||
else if (*BytesReceived > HTDSU_MAX_PACKET_SIZE)
|
||
{
|
||
*RxErrors |= HTDSU_RX_ERROR;
|
||
}
|
||
}
|
||
|
||
DBG_LEAVE(Adapter);
|
||
}
|
||
|
||
|
||
VOID
|
||
CardDialNumber(
|
||
IN PHTDSU_ADAPTER Adapter,
|
||
IN USHORT CardLine, /* HTDSU_CMD_LINE1 or HTDSU_CMD_LINE2 */
|
||
IN PUCHAR DialString,
|
||
IN ULONG DialStringLength
|
||
)
|
||
|
||
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Functional Description:
|
||
|
||
Place a dial string on the adapter and start the dialing sequence.
|
||
|
||
Parameters:
|
||
|
||
Adapter _ A pointer ot our adapter information structure.
|
||
|
||
CardLine _ Specifies which line to use for the transmit (HTDSU_LINEx_ID).
|
||
|
||
DialString _ A pointer to an ASCII null-terminated string of digits.
|
||
|
||
DialStringLength _ Number of bytes in dial string.
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
---------------------------------------------------------------------------*/
|
||
|
||
{
|
||
DBG_FUNC("CardDialNumber")
|
||
|
||
UINT Index;
|
||
UINT NumDigits;
|
||
|
||
PUSHORT DialRam;
|
||
|
||
DBG_ENTER(Adapter);
|
||
|
||
ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->TxDataEmpty));
|
||
ASSERT(READ_REGISTER_USHORT(&Adapter->AdapterRam->Command) == HTDSU_CMD_NOP);
|
||
|
||
/*
|
||
// Copy the digits to be dialed onto the adapter.
|
||
// The adapter interprets phone numbers as high byte is valid digit,
|
||
// low byte is ignored, the last digit gets bit 15 set.
|
||
*/
|
||
DialRam = (PUSHORT) &Adapter->AdapterRam->TxBuffer;
|
||
|
||
for (NumDigits = Index = 0; Index < DialStringLength && *DialString; Index++)
|
||
{
|
||
if ((*DialString >= '0') && (*DialString <= '9'))
|
||
{
|
||
WRITE_REGISTER_USHORT(
|
||
DialRam,
|
||
(USHORT) ((*DialString - '0') << 8)
|
||
);
|
||
DialRam++;
|
||
|
||
/*
|
||
// Make sure dial string is within the limit of the adapter.
|
||
*/
|
||
if (++NumDigits >= HTDSU_MAX_DIALING_DIGITS)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
DialString++;
|
||
}
|
||
|
||
/*
|
||
// Set the MSB in the last digit.
|
||
*/
|
||
DialRam--;
|
||
WRITE_REGISTER_USHORT(
|
||
DialRam,
|
||
(USHORT) (READ_REGISTER_USHORT(DialRam) | 0x8000)
|
||
);
|
||
|
||
/*
|
||
// Initiate the dial sequence.
|
||
*/
|
||
CardDoCommand(Adapter, CardLine, HTDSU_CMD_DIAL);
|
||
|
||
DBG_LEAVE(Adapter);
|
||
}
|
||
|