📄 sndshdlcend.c
字号:
/* sndsHdlcEnd.c - SNDS END network interface driver for HDLC */
/* Copyright 1984-1997 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01c,12nov99,ak added INCLUDE_HDLC
01b,07Oct99,nb added documentation
01a,1Oct99,ak adapted from WRS template.
*/
/*
DESCRIPTION
This module implements the Enhanced HDLC driver for Samsung SNDS100 Ver 1.0
Evaluation Board for their KS32C50100 microcontroller.
KS32C50100 is an ARM based processor with several integrated peripherals.
It has an interrupt controller, two 32-bit timers, one Ethernet controller,
two HDLC controllers, one IIC controller, general purpose I/O ports, and a
2-channel DMA controller.
The built-in HDLC controller consists of 2 HDLC channels. 2 HDMA channels
are provided for transferring data to and from the memory. The HDLC controller
supports NRZ, NRZI, FM, and Manchester data formats. An internal baud rate
generator can be used for generating TX and RX clock. A DPLL is also provided
to recover clock from the received data. Up to 10 Mbps data speeds are
supported.
All the internal registers of the HDLC controller are accessible as 32-bit
integers at the internal system register addresses as defined in the
KS32C50100 Microcontroller User's Manual. The register addresses are defined
in sndshdlcend.h include file. MACROS are provided to read and write these
registers.
The driver requires several target-specific values provided as an input
string to the load routine. These target-specific values and the external
support routines are described below.
This network interface driver does not include support for trailer protocols
or data chaining. However, buffer loaning has been implemented in an effort
to boost performance.
This driver maintains cache coherency by setting the Address bit 26 (A26) of
descriptor and buffer addresses. KS32C50100 accesses all memory locations
with A26 set in a non-cached mode. However, A26 is not used for accessing
the memory. See the KS32C50100 Microcontroller User's Manual for details.
Because of this feature, allocating buffer space using the cacheDmaMalloc()
routine is not required.
BOARD LAYOUT
This device is on-chip. No jumpering diagram is necessary.
EXTERNAL INTERFACE
This driver provides the standard END external interface. The only external
interface is the sndsHdlcEndLoad() routine. The parameters are passed
into the sndsHdlcEndLoad() function as a single colon-delimited string.
The sndsHdlcEndLoad() function uses strtok() to parse the string, which it
expects to be of the following format:
<unit>:<channel>:<baudRate>:<dataFormat>
TARGET-SPECIFIC PARAMETERS
.IP <unit>
A convenient holdover from the former model. This parameter is used only
in the string name for the driver.
.IP <channel>
Channel number of the HDLC channel. 0 indicates Channel A and 1 indicates
Channel B
.IP <baudRate>
Indicates the desired network Baud Rate.
.IP "<dataFormat>"
Indicates the data format desired on the medium. 0 indicates NRZ, 1 indicates
NRZI, 2 indicates FM0, 3 indicates FM1, and 4 indicates Manchester
.LP
SYSTEM RESOURCE USAGE
When implemented, each channel requires the following system resources:
- one mutual exclusion semaphore
- tw ointerrupt vectors
The driver allocates the memory to share with the HDLC device unit.
It does so by calling the calloc() routine. As a default, 128 transmit
descriptors (size=16 bytes), 128 transmit buffers (size=END_BUFSIZ),
64 receive descriptors (size=16 bytes) and 64 receive buffers (size=END_BUFSIZ)
are allocated.
As a default, 128 MBLK structures, 128 CLBLK structures and 128 clusters
(size=2048) are allocated in the net pool. END_MBLK_NUM and END_CL_NUM
macros define the number of structures allocated.
The macros SYS_INT_CONNECT, SYS_INT_DISCONNECT, and SYS_INT_ENABLE allow
the driver to be customized for BSPs that use special versions of these
routines.
The macro SYS_INT_CONNECT is used to connect the interrupt handler to
the appropriate vector. By default it is the routine intConnect().
The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
to unloading the module. By default this is a dummy routine that
returns OK.
The macro SYS_INT_ENABLE is used to enable the interrupt level for the
end device. It is called once during initialization. By default this is
the routine intEnable().
The macro SYS_ENET_ADDR_GET is used to get the HDLC address and mask
for the device. The single argument to this routine is the END_DEVICE
pointer. By default this routine copies the HDLC address stored in
the global variable sndsHdlcChanxAddr defined in sndsHdlcend.h into the
HDLC_END_DEVICE structure. The global variable has to be changed for changing
the address and mask of the HDLC channel.
SPECIAL CONSIDERATION
The address and mask of HDLC port is hard-coded in the global array named
sndsHdlcChanxAddr defined in sndsHdlcEnd.h
INCLUDES:
end.h endLib.h etherMultiLib.h sndsHdlcend.h
SEE ALSO: muxLib, endLib
.I "Writing and Enhanced Network Driver"
*/
/* includes */
#include "vxWorks.h"
#include "sndsHdlcEnd.h" /* Common defines. */
#include "etherMultiLib.h" /* multicast stuff. */
#include "end.h" /* Common END structures. */
#include "endLib.h"
#include "lstLib.h" /* Needed to maintain protocol list. */
#include "cacheLib.h"
#include "stdlib.h"
#include "stdio.h"
#include "intLib.h"
#include "iv.h"
#include "netLib.h"
#include "etherLib.h"
#include "config.h"
/* defines */
#define SNDS_CL_SIZE 2048
/* Configuration items */
#define END_BUFSIZ (ETHERMTU + ENET_HDR_REAL_SIZ + 6)
/*
* Default macro definitions for BSP interface.
* These macros can be redefined in a wrapper file, to generate
* a new module with an optimized interface.
*/
/* Macro to connect interrupt handler to vector */
#ifndef SYS_INT_CONNECT
# define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) \
{ \
IMPORT STATUS sysIntConnect(); \
*pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), \
rtn, (int)arg); \
}
#endif
/* Macro to disconnect interrupt handler from vector */
#ifndef SYS_INT_DISCONNECT
# define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) \
{ \
*pResult = OK; /* HELP: need a real routine */ \
}
#endif
/* Macro to enable the appropriate interrupt level */
#ifndef SYS_INT_ENABLE
#define SYS_INT_ENABLE(pDrvCtrl) \
{ \
IMPORT void sysLanIntEnable(); \
sysLanIntEnable (pDrvCtrl->ilevel); \
}
#endif
/* Macro to get the Hdlc address from the BSP */
#ifndef SYS_HDLCSTAT_ADDR_GET
# define SYS_HDLCSTAT_ADDR_GET(pDevice) \
{ \
IMPORT UINT32 sndsHdlcChanBAddr[]; \
IMPORT UINT32 sndsHdlcChanAAddr[]; \
if (pDevice->channel == 0) \
{ \
pDevice->hdlcAddr=sndsHdlcChanAAddr[0];\
pDevice->hdlcHmask=sndsHdlcChanAAddr[1]; \
} \
else \
{ \
pDevice->hdlcAddr=sndsHdlcChanBAddr[0];\
pDevice->hdlcHmask=sndsHdlcChanBAddr[1]; \
} \
}
#endif
/*
* Macros to do a short (UINT16) access to the chip. Default
* assumes a normal memory mapped device.
*/
#ifndef SNDS_HDLC_REG_WRITE
# define SNDS_HDLC_REG_WRITE(pDrvCtrl,addr,value) \
(*(UINT32 *)((pDrvCtrl)->baseAddr+(addr)) = (value))
#endif
#ifndef SNDS_HDLC_REG_READ
# define SNDS_HDLC_REG_READ(pDrvCtrl,addr,pData) \
((pData) = *(UINT32 *)((pDrvCtrl)->baseAddr+(addr)))
#endif
/* A shortcut for getting the hardware address from the MIB II stuff. */
#define END_HADDR(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
#define END_HADDR_LEN(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
/* typedefs */
#define END_MBLK_NUM 128
#define END_CL_NUM 128
#define CLDESCTBL_NUM_ENT 1
/* The definition of the driver control structure */
typedef struct hdlc_end_device
{
END_OBJ end; /* The class we inherit from. */
int unit; /* unit number */
int channel; /* Channel number */
int hdlcVecTx; /* HDLC TX vector */
int hdlcVecRx; /* HDLC RX vector */
int baudRate; /* Baud rate */
int dataFormat; /* Data Format */
UINT32 baseAddr; /* Base addr of HDLC */
long flags; /* Our local flags. */
UINT32 hdlcAddr; /* Hdlc Station address */
UINT32 hdlcHmask; /* Hdlc Mask Address*/
M_CL_CONFIG hdlcEndMclConfig; /* MBLK config */
CL_DESC hdlcEndClDescTbl [CLDESCTBL_NUM_ENT]; /* Cluster config */
SNDSHDLCBD *gpTxBDStart; /* Start of TX BDs */
SNDSHDLCBD *gpRxBDStart; /* Start of RX BDs */
SHTXSTATUS gHTxStatus; /* TX Statistics */
SHRXSTATUS gHRxStatus; /* RX Statistics */
} HDLC_END_DEVICE;
/* Definitions for the flags field */
#define END_PROMISCUOUS_FLAG 0x1
#define END_RCV_HANDLING_FLAG 0x2
#define END_POLLING 0x4
/* DEBUG MACROS */
#undef DEBUG
#ifdef DEBUG
#include "nvLogLib.h" /* Needed to debug polled mode. */
int endDebug = 1;
#define ENDLOGMSG(x) \
if (endDebug) \
{ \
logMsg x; \
}
#else
#define ENDLOGMSG(x)
#endif /* ENDDEBUG */
/* LOCALS */
#ifdef INCLUDE_SNDS_HDLC_END
/* forward static functions */
LOCAL void sndsHdlcEndReset (HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcEndHandleRcvInt (HDLC_END_DEVICE *pDrvCtrl, UINT32 status);
LOCAL STATUS sndsHdlcEndRecv (HDLC_END_DEVICE *pDrvCtrl, char* pData, UINT32 len);
LOCAL void sndsHdlcEndInitialize(HDLC_END_DEVICE *pDevice);
LOCAL void sndsHdlcTxBuffInitialize(HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcRxBuffInitialize(HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcTxInt(HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcRxInt(HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcEndFree(HDLC_END_DEVICE *pDrvCtrl);
LOCAL void sndsHdlcEndConfig (HDLC_END_DEVICE *pDrvCtrl);
/* END Specific interfaces. */
/* This is the only externally visible interface. */
END_OBJ* sndsHdlcEndLoad (char* initString);
LOCAL STATUS sndsHdlcEndStart (HDLC_END_DEVICE* pDrvCtrl);
LOCAL STATUS sndsHdlcEndStop (HDLC_END_DEVICE* pDrvCtrl);
LOCAL STATUS sndsHdlcEndUnload ();
LOCAL int sndsHdlcEndIoctl (HDLC_END_DEVICE* pDrvCtrl, int cmd, caddr_t data);
LOCAL STATUS sndsHdlcEndSend (HDLC_END_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
LOCAL STATUS sndsHdlcEndMCastAdd (HDLC_END_DEVICE* pDrvCtrl, char* pAddress);
LOCAL STATUS sndsHdlcEndMCastDel (HDLC_END_DEVICE* pDrvCtrl, char* pAddress);
LOCAL STATUS sndsHdlcEndMCastGet (HDLC_END_DEVICE* pDrvCtrl,
MULTI_TABLE* pTable);
LOCAL STATUS sndsHdlcEndPollSend (HDLC_END_DEVICE* pDrvCtrl, M_BLK_ID* pBuf);
LOCAL STATUS sndsHdlcEndPollRcv (HDLC_END_DEVICE* pDrvCtrl, M_BLK_ID* pBuf);
LOCAL STATUS sndsHdlcEndPollStart (HDLC_END_DEVICE* pDrvCtrl);
LOCAL STATUS sndsHdlcEndPollStop (HDLC_END_DEVICE* pDrvCtrl);
LOCAL STATUS sndsHdlcEndParse ();
LOCAL STATUS sndsHdlcEndMemInit ();
/*
* Declare our function table. This is static across all driver
* instances.
*/
LOCAL NET_FUNCS endFuncTable =
{
(STATUS (*) (END_OBJ*))sndsHdlcEndStart, /* Function to start the device. */
(STATUS (*) (END_OBJ*))sndsHdlcEndStop, /* Function to stop the device. */
(STATUS (*) (END_OBJ*))sndsHdlcEndUnload, /* Unloading function for the driver. */
(int (*) (END_OBJ*, int, caddr_t))sndsHdlcEndIoctl, /* Ioctl function for the driver. */
(STATUS (*) (END_OBJ* , M_BLK_ID))sndsHdlcEndSend, /* Send function for the driver. */
(STATUS (*) (END_OBJ*, char*))sndsHdlcEndMCastAdd, /* Multicast address add function for the driver. */
(STATUS (*) (END_OBJ*, char*))sndsHdlcEndMCastDel, /* Multicast address delete function for the driver. */
(STATUS (*) (END_OBJ*, MULTI_TABLE*))sndsHdlcEndMCastGet, /* Multicast table retrieve function for the driver. */
(STATUS (*) (END_OBJ*, M_BLK_ID))sndsHdlcEndPollSend, /* Polling send function for the driver. */
(STATUS (*) (END_OBJ*, M_BLK_ID))sndsHdlcEndPollRcv, /* Polling receive function for the driver. */
endEtherAddressForm, /* Put address info into a packet. */
endEtherPacketDataGet, /* Get a pointer to packet data. */
endEtherPacketAddrGet /* Get packet addresses. */
};
/*******************************************************************************
*
* sndsHdlcEndLoad - initialize the driver and device
*
* This routine initializes the driver and the device to the operational state.
* All of the device specific parameters are passed in the initString.
*
* The string contains the target specific parameters like this:
*
* "unit:channel:baudRate:dataFormat"
*
* RETURNS: An END object pointer or NULL on error.
*/
END_OBJ* sndsHdlcEndLoad
(
char* initString /* String to be parsed by the driver. */
)
{
HDLC_END_DEVICE *pDrvCtrl;
if (initString[0] == NULL)
{
strcpy (initString, "hdlc");
return (END_OBJ *)0;
}
/* allocate the device structure */
pDrvCtrl = (HDLC_END_DEVICE *)calloc (sizeof (HDLC_END_DEVICE), 1);
if (pDrvCtrl == NULL)
goto errorExit;
/* parse the init string, filling in the device structure */
if (sndsHdlcEndParse (pDrvCtrl, initString) == ERROR)
goto errorExit;
if (pDrvCtrl->channel == 0)
{
pDrvCtrl->hdlcVecTx = INT_LVL_HDLCTxA;
pDrvCtrl->hdlcVecRx = INT_LVL_HDLCRxA;
pDrvCtrl->baseAddr = ASIC_BASE + HDLC_CHANNELA_BASE;
}
else
{
pDrvCtrl->hdlcVecTx = INT_LVL_HDLCTxB;
pDrvCtrl->hdlcVecRx = INT_LVL_HDLCRxB;
pDrvCtrl->baseAddr = ASIC_BASE + HDLC_CHANNELB_BASE;
}
/* Ask the BSP to provide the hdlc address. */
SYS_HDLCSTAT_ADDR_GET(pDrvCtrl);
strcpy (pDrvCtrl->end.devObject.name, "hdlc");
strcpy (pDrvCtrl->end.devObject.description, "Samsung SNDS100 END HDLC Driver");
/* initialize the END and MIB2 parts of the structure */
if (END_OBJ_INIT (&pDrvCtrl->end, (DEV_OBJ *)pDrvCtrl, "hdlc",
pDrvCtrl->unit, &endFuncTable,
"HDLC Driver.") == ERROR
|| END_MIB_INIT (&pDrvCtrl->end, M2_ifType_sdlc,
(UCHAR *)&pDrvCtrl->hdlcAddr, 4, ETHERMTU,
pDrvCtrl->baudRate)
== ERROR)
goto errorExit;
/* Perform memory allocation/distribution */
if (sndsHdlcEndMemInit (pDrvCtrl) == ERROR)
goto errorExit;
/* reset and reconfigure the device */
sndsHdlcEndReset (pDrvCtrl);
sndsHdlcEndInitialize(pDrvCtrl);
sndsHdlcEndConfig (pDrvCtrl);
/* set the flags to indicate readiness */
END_OBJ_READY (&pDrvCtrl->end,
IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST);
ENDLOGMSG (("Done loading end...", 1, 2, 3, 4, 5, 6));
return (&pDrvCtrl->end);
errorExit:
if (pDrvCtrl != NULL)
free ((char *)pDrvCtrl);
return NULL;
}
/*******************************************************************************
*
* sndsHdlcEndParse - parse the init string
*
* Parse the input string. Fill in values in the driver control structure.
*
* The initialization string format is:
* "unit:channel:baurate:dataFormat"
*
* .bS
* unit Device unit number, a small integer.
* channel Channel number of HDLC
* baudRate HDLC serial baud rate
* dataFormat NRZ/NRZI/FM/Manchester
* .bE
*
* RETURNS: OK or ERROR for invalid arguments.
*/
STATUS sndsHdlcEndParse
(
HDLC_END_DEVICE * pDrvCtrl, /* device pointer */
char * initString /* information string */
)
{
char* tok;
char* pHolder = NULL;
/* Parse the initString */
/* Unit number. */
tok = strtok_r (initString, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->unit = atoi (tok);
/* Tx Interrupt vector. */
tok = strtok_r (NULL, ":", &pHolder);
if (tok == NULL)
return ERROR;
pDrvCtrl->channel = atoi (tok);
/* Rx Interrupt vector. */
tok = strtok_r (NULL, ":", &pHolder);
if (tok == NULL)
return ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -