📄 templeend.c
字号:
pDrvCtrl->rxHandling = true;
netJobAdd((FUNCPTR)templateHandleRcvInt,(int)pDrvCtrl,0,0,0,0);
}
}
/*这里可以处理发送中断*/
}
/*****************************************************************
templatePacketGet 此函数用来获取下一个接收的消息。
此函数获取下一个接收的消息失败时返回NULL。
**************************************************************/
char* templatePacketGet(END_DEVICE *pDrvCtrl)
{
/*在这里需要添加获取下一个接收消息的代码*/
return (char*)NULL;
}
/****************************************************
templateRecv 此函数用于处理下一个到达的分组。
此函数一次只能处理一个到达的分组。处理时会对分组做出错检查。
*************************************************/
LOCAL STATUS templateRecv(END_DEVICE *pDrvCtrl,char* pData)
{
int len;
M_BLK_ID pMblk;
char* pCluster;
char* pNewCluster;
CL_BLK_ID pClBlk;
/*在这里可以添加对分组检查的代码*/
/*单播数据计数器增一*/
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_UCAST,+1);
/*将数据传送到上层协议之前,必须进行一次数据拷贝*/
pNewCluster = netClusterGet(pDrvCtrl-end.pNetPool,pDrvCtrl->pClPoolId);
if(pNewCluster == NULL)
{
DRV_LOG(DRV_DEBUG_RX,"Cannot loan!\n",1,2,3,4,5,6);
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_ERRS,+1);
goto cleanRXD;
}
/*获取一个内存段(cluster)*/
if((pClBlk = netClBlkGet(pDrvCtrl->end.pNetPool,M_ONTWAIT)) == NULL)
{
netClFree(pDrvCtrl->end.pNetPoll,pNewClster);
DRV_LOG(DRV_DEBUG_RX,"Out of Cluster Block!\n",1,2,3,4,5,6,);
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_ERRS,+1);
goto cleanRXD;
}
/*获取一个内存块ID(M_BLK_ID)*/
if((pMblk = mBlkGet(pDrvCtrl->end.pNetPool,M_DONTWAIT,MT_DATA)) == NULL)
{
netClBlkFree(pDrvCtrl->end.pNetPool,pClBlk);
netClFree(pDrvCtrl->end.pNetPool,pNewCluster);
DRV_LOG(DRV_DEBUG_RX,"Out of M Blocks!\n",1,2,3,4,5,6);
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_ERRS,+1);
goto cleanRXD;
}
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_UCAST,+1);
len = TEMPLATE_PKT_LEN_GET((PKT*)pData);
pCluster = END_CACHE_PHYS_TO_VIRT(pData);
/*将内存段(cluster)与内存块(MBlock)连接起来*/
netClBlkJoin(pClBlk,pCluster,len,NULL,0,0,0);
netMblkClJoin(pMblk,pClBlk);
pMblk->mBlkHdr.mLen = len;
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = len;
/*保证分组数据的连续性*/
END_CACHE_INVALIDATE(pMblk->mBlkHdr.mData,len);
DRV_LOG(DRV_DEBUG_RX,"Calling upper layer!\n",1,2,3,4,5,6);
/*处理已经完成,可以清除接收缓冲*/
/*首先调用上层协议的处理程序*/
END_RCV_RTN_CALL(&pDrvCtrl->end,pMblk);
cleanRXD:
return (OK);
}
/*******************************************
templateHandleRcvInt函数用来针对输入分组完成任务级中断服务。
这个函数由中断服务程序间接调用,完成对接收消息的任务级处理。
此函数的双循环用于防止资源竞争。中断处理代码发现rxHanding为
true时,任务代码会迅速将其设置为FALSE。这种形式的资源竞争
虽然不是致命的但偶尔也会造成一定的延迟。只有下一个分组到来,
网络处理任务再次调用此函数时竞争才会解除。
*******************************************/
LOCAL void templateHandleRcvInt(END_DEVICE* pDrvCtrl)
{
char* pData;
do
{
pDrvCtrl->rxHandling = true;
while((pData = templatePacketGet(pDrvCtrl)) != NULL)
templateRecv(pDrvctrl,pData);
pDrvCtrl->rxHandling = false;
}
while(templatePacketGet(pDrvCtrl)!=NULL);
}
/***************************************************************
templateSend 函数用于发送数据。
驱动程序调用此程序完成数据发送。函数首先获取一个M_BLK_ID,
然后发送。
****************************************************************/
LOCAL STATUS templateSend(END_DEVICE* pDrvCtrl,M_BLK_ID pMblk)
{
int oldLevel;
bool freeNow = true;
/*获取发送程序的访问权。当系统中有多个协议栈同时发送时,这样做是十分必要的。*/
if(!(pDrvCtrl->flags & TEMPLATE_POLLING))
END_TX_SEM_TAKE(&pDrvCtrl->end,WAIT_FOREVER);
/*下面这种情况是常见的情况即所有数据位于一个M_BLK_ID中*/
/*在本地结构中将指针指向数据*/
/*提出一个发送请求*/
if(!(pDrvCtrl->flags & TEMPLATE_POLLING))
oldLevel = intLock();
/*此处初始化设备发送*/
/*更新管理索引*/
if(!(pDrvCtrl->flags & TEMPLATE_POLLING))
END_TX_SEM_GIVE(&pDrvCtrl->end);
if(!(pDrvCtrl->flags & TEMPLATE_POLLING))
intUnlock(oldLevel);
/*更新统计计数器*/
END_ERR_ADD(&pDrvCtrl->end,MIB2_OUT_UCAST,+1);
/*在此处驱动程序必须释放分组*/
if(freeNow)
netMblkClChainFree(pMblk);
return OK;
}
/***********************************************************
templateIoctl 此函数用于实现驱动程序的I/O控制功能。
**********************************************************/
LOCAL int templateIoctl(END_DEVICE* pDrvCtrl,int cmd,caddr_t data)
{
int error = 0;
long value;
switch(cmd)
{
case EIOCSADDR:
if(data == NULL)
return(EINVAL);
bcopy((char*)data,(char*)END_HADDR(&pDrvCtrl->end),END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCGADDR:
if(data == NULL)
return(EINVAL);
bcopy((char*)END_HADDR(&pDrvCtrl->end),(char*)data,END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCSFLAGS:
value = (long)data;
if(value < 0)
{
value = -(--value);
END_FLAGS_CLS(&pDrvCtrl->end,value);
}
else
{
END_FLAGS_SET(&pDrvCtrl->end,value);
}
templateConfig(pDrvCtrl);
break;
case EIOCGFLAGS:
*(int*)data = END_FLAGS_GET(&pDrvCtrl->end);
break;
case EIOCPOLLSTART: /*开始查询操作*/
templatePollStart(pDrvCtrl);
break;
case EIOCPOLLSTOP: /*结束查询操作*/
templatePollStop(pDrvCtrl);
break;
case EIOCGMIB2: /*返回MIB统计信息*/
if(data == NULL)
return (EINVAL);
bcopy((char*)&pDrvCtrl->end.mib2Tbl,(char*)data,sizeof(pDrvCtrl->end.mib2Tbl));
break;
case EIOCGFBUF: /*返回第一个缓冲区*/
if(data == NULL)
return(EINVAL);
*(int*)data = TEMPLATE_MIN_FBUF;
break;
default:
error = EINVAL;
}
return(error);
}
/*******************************************************************************
templateConfig 函数用于重配物理接口.
此函数的重配操作主要包括对接口模式的设置和多播接口列表的更新。
*******************************************************************************/
LOCAL void templateConfig(END_DEVICE* pDrvCtrl)
{
/*根据需要设置模式*/
if(END_FLAGS_GET(&pDrvCtrl->end) & IFF_PROMISC)
{
DRV_LOG(DRV_DEBUG_IOCTL,"Setting promiscuous mode on!\n",1,2,3,4,5,6);
}
else
{
DRV_LOG(DRV_DEBUG_IOCTL,"Setting promiscuous mode off!\n",1,2,3,4,5,6);
}
/*为多播设置地址过滤*/
if(END_MULTI_LST_CNT(&pDrvCtrl->end) > 0)
{
templateAddrFilterSet(pDrvCtrl);
}
/*再此处完全关闭设备*/
/*在此处复位设备所有的计数器和指针*/
/*在此处根据标记初始化硬件*/
}
/*******************************************************************************
templateAddrFilterSet 此函数用于为多播地址设置地址过滤。
此函数遍历多播地址列表中的所有的地址然后为设备设置准确的过滤。
******************************************************************************/
void templateAddrFilterSet(END_DEVICE* pDrvCtrl)
{
ETHER_MULTI* pCurr;
pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->end);
while(pCurr != NULL)
{
/*此处需要设置多播表*/
pCurr = END_MULTI_LST_NEXT(pCurr);
}
/*此处需要更新设备过滤表*/
}
/********************************************************************************
templatePollRecv
*********************************************************************************/
LOCAL STATUS templatePollRcv(END_DEVICE* pDrvCtrl, M_BLK_ID pMblk)
{
u_short stat;
char* pPacket;
int len;
DRV_LOG(DRV_DEBUG_POLL_RX,"templatePollRcv\n",1,2,3,4,5,6);
stat = templateStatusRead(pDrvCtrl);
/*在此处如果没有分组到来则立即返回*/
if(!(stat & TEMPLATE_RINT))
{
DRV_LOG(DRV_DEBUG_POLL_RX,"templatePollRcv no data\n",1,2,3,4,5,6);
return(EAGAIN);
}
/*从设备缓冲区中获取分组和长度*/
pPacket = NULL;
len = 64;
/*上层应用必须提供一个有效的缓冲区*/
if((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
{
DRV_LOG(DRV_DEBUG_POLL_RX,"PRX bad mblk\n",1,2,3,4,5,6);
return(EAGAIN);
}
/*在此处可清除设置过的所有状态位*/
/*此处可以检查设备和分组的错误*/
END_ERR_ADD(&pDrvCtrl->end,MIB2_IN_UCAST,+1);
/*下面将分组拷贝到网络缓冲区中*/
bcopy(pPacket,pMblk->m_data,len);
pMblk->mblkHdr.mFlags != M_PKTHDR; //设置分组头
pMblk->mBlkHdr.mLen = len; //设置数据长度
pMblk->mBlkHdr.len = len; //设置总长度
//对分组的处理已经完成,在此处交给设备
DRV_LOG(DRV_DEBUG_POLL_RX,"templatePollRcv OK\n",1,2,3,4,5,6);
DRV_LOG(DRV_DEBUG_POLL_RX,"templatePollRcv OK\n",1,2,3,4,5,6);
return (OK);
}
/***************************************************************
templatePollSend 函数用于在查询模式下发送分组。
***************************************************************/
LOCAL STATUS templatePollSend(END_DEVICE* pDrvCtrl,M_BLK_ID pMblk)
{
int len;
u_short stat;
DRV_LOG(DRV_DEBUG_POLL_TX,"templatePollSend\n",1,2,3,4,5,6);
//此处检测tx缓冲是否够用
stat = templateStatusRead(pDrvCtrl);
if((stat & TEMPLATE_TINT) == 0)
return((STATUS)EAGAIN);
//此处将网络缓冲区置入设备的发送分组中
len = max(ETHERSMAIL,pMblk->m_len);
//在此处发送分组
//修改统计计数器
END_ERR_ADD(&pDrvCtrl->end,MIB2_OUT_UCAST,+1);
//数据被设备接收后,则释放内存块
netMblkClFree(pMblk);
DRV_LOG(DRV_DEBUG_POLL_TX,"leaving templatePollSend\n",1,2,3,4,5,6);
return(OK);
}
/*******************************************************************************
templateMCastAdd 此函数用于为设备添加一个多播地址。
此函数为设备添加了多播地址以后,复位地址过滤器。
******************************************************************************/
LOCAL STATUS templateMCastAdd(END_DEVICE* pDrvCtrl,char* pAddress)
{
int error;
if((error = etherMultiAdd(&pDrvCtrl->end.multiList,pAddress)) == ENETRESET)
templateConfig(pDrvCtrl);
reurn(OK);
}
/********************************************************************************
templateMCastDel 函数用于删除设备的多播地址列表。
*******************************************************************************/
LOCAL STATUS templateMCastDel(END_DEVICE* pDrvCtrl,char* pAddress)
{
int error;
if((error = ehterMultiDel(&pDrvCtrl->end.MultiList,(char*)pAddress)) == ENETRESET)
templateConfig(pDrvCtrl);
return (OK);
}
/***********************************************************************************
templateMCastGet 函数用于获取设备的多播地址列表。
***********************************************************************************/
LOCAL STATUS templateMCastGet(END_DEVICE* pDrvCtrl,MULTI_TABLE* pTable)
{
return(etherMultiGet(&pDrvCtrl->end.multiList,pTable));
}
/************************************************************************************
templateStop 函数用于停止一个设备。
这个函数调用BSP函数断开设备的中断,并停止设备在中断模式中的操作。
************************************************************************************/
LOCAL STATUS templateStop(END_DEVICE* pDrvCtrl)
{
STATUS result = OK;
//此处停止和禁用设备
SYS_INT_DISCONNECT(pDrvCtrl,templateInt,(int)pDrvCtrl,&result);
if(result == ERROR)
{
DRV_LOG(DRV_DEBUG_LOAD,"Could not disconnect interrupt!\n",1,2,3,4,5,6);
}
return(result);
}
/************************************************************************************
templateUnload 函数用于从系统中卸载一个驱动程序。
函数首先关闭设备,然后释放驱动程序装载函数中申请的所有资源。
************************************************************************************/
LOCAL STATUS templateUnload(END_DEVICE* pDrvCtrl)
{
END_OBJECT_UNLOAD(&pDrvCrl->end);
//此处释放所有共享的DMA内存
return(OK);
}
/***************************************************************************************
templatePollStart函数用于启动查询模式操作。
***************************************************************************************/
LOCAL STATUS templatePollStart(END_DEVICE* pDrvCtrl)
{
int oldLevel;
oldLevel = intLock();
//此处需要关闭中断
pDrvCtrl->flags |= TEMPLATE_POLLING;
intUnlock(oldLevel);
DRV_LOG(DRV_DEBUG_POLL,"STARTED!",1,2,3,4,5,6);
templateConfig(pDrvCtrl);
return(OK);
}
/*************************************************************************
templatePollStop函数用于停止查询模式操作。
这个函数用于终止查询模式操作,即设备返回到中断模式,设备中断将启用。
此函数在切换过程中实现了中断模式以及并针对中断模式进行了适当的重配。
*****************************************************************************/
LOCAL STATUS templatePollStop(END_DEVICE* pDrvCtrl)
{
int oldLevel;
oldLevel intLock(); //在更新寄存器时禁用中断
//此处需要重新启用中断
pDrvCtrl->flags &= ~TEMPLATE_POLLING;
intUnlock(oldLevel);
templateConfig(pDrvCtrl);
DRV_LOG(DRV_DEBUG_POLL,"STOPED!\n",1,2,3,4,5,6);
return(OK);
}
/***************************************************************************
templateReset 函数用于复位设备。
***************************************************************************/
LOCAL void templateReset(END_DEVICE* pDrvCtrl)
{
//此处复位控制器
}
/***************************************************************************
templateStatusRead 获取当前设备状态
**************************************************************************/
LOCAL UINT templateStatusRead(END_DEVICE* pDrvCtrl)
{
//在此处添加读取状态寄存器的代码
return(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -