📄 ul_base.c
字号:
/******************************************************************* uLan Communication - uL_DRV - multiplatform uLan driver ul_base.c - functions common for all kinds of the driver (C) Copyright 1996-2004 by Pavel Pisa - project originator http://cmp.felk.cvut.cz/~pisa (C) Copyright 1996-2004 PiKRON Ltd. http://www.pikron.com (C) Copyright 2002-2004 Petr Smolik The uLan driver project can be used and distributed in compliance with any of next licenses - GPL - GNU Public License See file COPYING for details. - LGPL - Lesser GNU Public License - MPL - Mozilla Public License - and other licenses added by project originator Code can be modified and re-distributed under any combination of the above listed licenses. If contributor does not agree with some of the licenses, he/she can delete appropriate line. WARNING: if you delete all lines, you are not allowed to distribute code or sources in any form. *******************************************************************/void ulan_stroke(ul_drv *udrv, int force){ UL_DRV_LOCK_FINI if(!uld_test_dfl(udrv,CHIPOK)) return; if(force) uld_set_dfl(udrv,WDFORCED); else if(udrv->prep_bll.first==NULL) return; if(udrv->fnc_stroke) { udrv->fnc_stroke(udrv); return; } UL_DRV_LOCK; #ifndef _WIN32 { int delay; delay=udrv->last_ctrl&0x80?0:ULD_HZ/100+2; SCHEDULE_UDRV_WDTIM(udrv,jiffies+delay); } #else /* _WIN32 */ { LARGE_INTEGER delay; delay=udrv->last_ctrl&0x80?RtlConvertLongToLargeInteger(-1): RtlConvertLongToLargeInteger(-40*10000); KeSetTimer(&udrv->wd_timer,delay,&udrv->wd_timer_dpc); } #endif /* _WIN32 */ UL_DRV_UNLOCK;};static void add_to_opchain(ul_opchain **chain,ul_opchain *member){ UL_DRV_LOCK_FINI UL_DRV_LOCK; if(!*chain) *chain=member->next=member->prev=member; else { ((volatile ul_opchain*)member)->next=*chain; ((volatile ul_opchain*)member)->prev=(*chain)->prev; UL_MB(); ((volatile ul_opchain*)(*chain))->prev->next=member; ((volatile ul_opchain*)(*chain))->prev=member; }; UL_DRV_UNLOCK;};static void add_to_opchain_front(ul_opchain **chain,ul_opchain *member){ UL_DRV_LOCK_FINI UL_DRV_LOCK; if(!*chain) *chain=member->next=member->prev=member; else { ((volatile ul_opchain*)member)->next=*chain; ((volatile ul_opchain*)member)->prev=(*chain)->prev; UL_MB(); ((volatile ul_opchain*)(*chain))->prev->next=member; ((volatile ul_opchain*)(*chain))->prev=member; *(volatile ul_opchain**)chain=member; }; UL_DRV_UNLOCK;};static void del_from_opchain(ul_opchain **chain,ul_opchain *member){ UL_DRV_LOCK_FINI UL_DRV_LOCK; member->next->prev=member->prev; member->prev->next=member->next; if(*chain==member) { if(member->next==member) *chain=NULL; else *chain=member->next; }; UL_DRV_UNLOCK;};/* free message form ulan operator */static int ulan_freemsg(ul_opdata* opdata){ int stamp; ul_mem_blk *mes; ul_opchain *opmember; if(!opdata->udrv) return -ENODEV; if(!(mes=opdata->message)) return -ENOMSG; if(!UL_BLK_HEAD(mes).stamp) { opdata->message=NULL; stamp=ul_gen_stamp(); UL_BLK_HEAD(mes).stamp=stamp; if(UL_BLK_HEAD(mes).flg&UL_BFL_M2IN) { opmember=(ul_opchain*)MALLOC(sizeof(ul_opchain)); if(opmember) { memset(opmember,0,sizeof(ul_opchain)); opmember->stamp=stamp; opmember->state=UL_OPST_ONCE; add_to_opchain_front(&opdata->filtchain,opmember); }; }; ul_bll_move_mes(&opdata->udrv->prep_bll,mes); ulan_stroke(opdata->udrv, 0); return stamp; }else{ ul_dec_ref_cnt(mes); opdata->message=NULL; return 0; };};/* abort preparation of message */static int ulan_abortmsg(ul_opdata* opdata){ ul_mem_blk *mes; if(!opdata->udrv) return -ENODEV; if(!(mes=opdata->message)) return -ENOMSG; opdata->message=NULL; if(!UL_BLK_HEAD(mes).stamp) { ul_free_mes(opdata->udrv,mes); return 1; }else{ ul_dec_ref_cnt(mes); return 0; };};/* rewind of message */static int ulan_rewmsg(ul_opdata* opdata){ ul_mem_blk *mes; if(!opdata->udrv) return -ENODEV; if(!(mes=opdata->message)) return -ENOMSG; opdata->message=NULL; ul_di_init(&opdata->data,opdata->message); return 0;};/* create new outgoing message */static int ulan_newmsg(ul_opdata* opdata,const ul_msginfo *msginfo){ int flg=msginfo->flg; flg &= ~(UL_BFL_LOCK | UL_BFL_FAIL | UL_BFL_TAIL | UL_BFL_REC); flg |= UL_BFL_SND; if(!opdata->udrv) return -ENODEV; if (opdata->message) ulan_freemsg(opdata); opdata->message=ul_new_frame_head(opdata->udrv, msginfo->dadr, opdata->udrv->my_adr, msginfo->cmd,flg); if(!opdata->message) return -ENOMEM; memset(UL_BLK_FDATA(opdata->message),0,UL_BLK_FSIZE); ul_di_init(&opdata->data,opdata->message); return 0;}static int ulan_tailmsg(ul_opdata* opdata,const ul_msginfo *msginfo){ ul_mem_blk *mes; ul_mem_blk *tail; int flg=msginfo->flg; if(!opdata->udrv) return -ENODEV; if(!(mes=opdata->message)) return -ENOMSG; if(UL_BLK_HEAD(mes).stamp) return -EPERM; flg &= ~(UL_BFL_LOCK | UL_BFL_FAIL | UL_BFL_TAIL); if(!flg&UL_BFL_REC) flg|=UL_BFL_SND; tail=ul_new_frame_head(opdata->udrv, msginfo->dadr, opdata->udrv->my_adr, msginfo->cmd,flg); if(!tail) return -ENOMEM; memset(UL_BLK_FDATA(tail),0,UL_BLK_FSIZE); UL_BLK_HEAD(tail).len=msginfo->len; ul_tail_frame_head(mes,tail); ul_di_init(&opdata->data,tail); return 0;}static int ulan_acceptmsg(ul_opdata* opdata,ul_msginfo *msginfo){ ul_mem_blk *mes; ul_opchain *opmember; if(!opdata->udrv) return -ENODEV; if (opdata->message) ulan_freemsg(opdata); memset(msginfo,0,sizeof(ul_msginfo)); if(!(opmember=opdata->recchain)) return -ENOMSG; del_from_opchain(&opdata->recchain,opmember); mes=opmember->message; if(opmember->state==UL_OPST_MES) FREE(opmember); opdata->message=mes; ul_di_init(&opdata->data,mes); msginfo->flg=UL_BLK_HEAD(mes).flg; msginfo->dadr=UL_BLK_HEAD(mes).dadr; msginfo->sadr=UL_BLK_HEAD(mes).sadr; msginfo->cmd=UL_BLK_HEAD(mes).cmd; msginfo->len=UL_BLK_HEAD(mes).len; msginfo->stamp=UL_BLK_HEAD(mes).stamp; return 0;}static int ulan_actailmsg(ul_opdata* opdata,ul_msginfo *msginfo){ ul_mem_blk *mes; ul_mem_blk *tail; if(!opdata->udrv) return -ENODEV; memset(msginfo,0,sizeof(ul_msginfo)); if(!(mes=opdata->message)) return -ENOMSG; if(!UL_BLK_HEAD(mes).stamp) return -EPERM; tail=UL_BLK_HEAD(opdata->data.head_blk).next; if(!tail) return -ENOMSG; ul_di_init(&opdata->data,tail); msginfo->flg=UL_BLK_HEAD(tail).flg; msginfo->dadr=UL_BLK_HEAD(tail).dadr; msginfo->sadr=UL_BLK_HEAD(tail).sadr; msginfo->cmd=UL_BLK_HEAD(tail).cmd; msginfo->len=UL_BLK_HEAD(tail).len; msginfo->stamp=UL_BLK_HEAD(tail).stamp; return 0;}/* create new outgoing message */static int ulan_addfilt(ul_opdata* opdata,const ul_msginfo *msginfo){ ul_drv *udrv; ul_opchain *opmember; int filtonce; if(!opdata->udrv) return -ENODEV; opmember=(ul_opchain*)MALLOC(sizeof(ul_opchain)); udrv=opdata->udrv; if(!opmember) return -ENOMEM; memset(opmember,0,sizeof(ul_opchain)); opmember->dadr=msginfo->dadr; opmember->sadr=msginfo->sadr; opmember->cmd=msginfo->cmd; filtonce=msginfo->flg&UL_BFL_NORE; opmember->state=filtonce?UL_OPST_FILTNEW:UL_OPST_FILT; add_to_opchain(&opdata->filtchain,opmember); if(filtonce){ uld_set_dfl(udrv,CHECK_FILT); SCHEDULE_BH(udrv); } LOG_FILTS("ulan_addfilt : filter %d %d %d %s\n", opmember->dadr,opmember->sadr,opmember->cmd,filtonce?"once":""); return 0;}static int ulan_inepoll(ul_opdata* opdata){ return opdata->recchain!=NULL?1:0;}static int ulan_hwtest(ul_opdata* opdata,unsigned long fnc){ int ret; ul_drv *udrv; UL_DRV_LOCK_FINI if(!opdata->udrv) return -ENODEV; udrv=opdata->udrv; UL_DRV_LOCK; ret=udrv->fnc_cctrl(udrv,UL_CC_HWTEST,fnc); if(ret<0) ret=-EINVAL; UL_DRV_UNLOCK; return ret;}static int ulan_setmyadr(ul_opdata* opdata, int newadr){ int ret; ul_drv *udrv; if(!opdata->udrv) return -ENODEV; udrv=opdata->udrv; ret=udrv->fnc_cctrl(udrv,UL_CC_SETMYADR,newadr); if(ret==UL_RC_ENOFNC){ if(newadr) udrv->my_adr=newadr; ret=udrv->my_adr; }else if(ret<0) ret=-EINVAL; return ret;}static int ulan_setidstr(ul_opdata* opdata, const char *idstr){#ifdef UL_WITH_IAC #define UL_CMD_SID 0xF0 /* Send identification */ ul_drv *udrv; char *cidstr; int len; if(!opdata->udrv) return -ENODEV; udrv=opdata->udrv; len=strlen(idstr); if(!(cidstr=MALLOC(len))) return ENOMEM; memcpy(cidstr,idstr,len); ul_drv_del_iac(udrv,UL_CMD_SID); ul_drv_add_iac(udrv,UL_CMD_SID,UL_IAC_OP_SNDBUFF,NULL,cidstr,len,UL_IAC_BFL_FREEBUFF,NULL); return 0;#else /*UL_WITH_IAC*/ return -EINVAL;#endif /*UL_WITH_IAC*/}/* this function is responsible to inform all ulan client operators about message of waited type -- !!!!! it is not SMP clean still */static int ulan_proc_arrived(ul_drv *udrv, ul_mem_blk *message){ ul_opdata *opdata; ul_opchain **opchain; ul_opchain *opmember; ul_opchain *opmember2; UL_DRV_LOCK_FINI ul_inc_ref_cnt(message); UL_DRV_LOCK; opdata=udrv->operators; UL_DRV_UNLOCK; while(opdata) { opchain=&opdata->filtchain; opmember=*opchain; if(opmember) do { if((!opmember->stamp||opmember->stamp==UL_BLK_HEAD(message).stamp)&& (!opmember->cmd||opmember->cmd==UL_BLK_HEAD(message).cmd)&& (!opmember->dadr||opmember->dadr==UL_BLK_HEAD(message).dadr)&& (!opmember->sadr||opmember->sadr==UL_BLK_HEAD(message).sadr)) { if(opmember->state==UL_OPST_ONCE) { del_from_opchain(opchain,opmember); opmember->state=UL_OPST_MES; ul_inc_ref_cnt(message); opmember->message=message; add_to_opchain(&opdata->recchain,opmember); }else if(opmember->state==UL_OPST_FILT){ #ifdef FOR_LINUX_KERNEL #ifdef ENABLE_UL_MEM_CHECK atomic_inc(&ul_mem_check_counter); #endif opmember2=(ul_opchain*)kmalloc(sizeof(ul_opchain),GFP_ATOMIC); #else /* FOR_LINUX_KERNEL */ opmember2=(ul_opchain*)MALLOC(sizeof(ul_opchain)); #endif /* FOR_LINUX_KERNEL */ if(opmember2) { memset(opmember2,0,sizeof(ul_opchain)); opmember2->state=UL_OPST_MES; ul_inc_ref_cnt(message); opmember2->message=message; add_to_opchain(&opdata->recchain,opmember2); } else UL_PRINTF(KERN_CRIT "ulan_proc_arrived : no kernel memory : FIXME handling\n"); }; #ifdef FOR_LINUX_KERNEL wake_up_interruptible(&opdata->wqrec); #elif defined(_WIN32) wake_and_xch_pending_irp(&opdata->wait_irp,NULL,STATUS_SUCCESS); #endif /* FOR_LINUX_KERNEL */ break; }; } while((opmember=opmember->next)!=*opchain); opdata=opdata->opnext; }; /* if no one interested in message, it is discarded */ return ul_dec_ref_cnt(message);};/* check for UL_OPST_FILTNEW and change them to single instance of UL_OPST_FILT */void check_for_filtnew(ul_drv *udrv){ ul_opdata *opdata; ul_opchain **opchain; ul_opchain *opmember; ul_opchain *opmember2; ul_opchain *opnext; UL_DRV_LOCK_FINI LOG_FILTS("check_for_filtnew : called\n"); UL_DRV_LOCK; opdata=udrv->operators; UL_DRV_UNLOCK; for(;opdata;opdata=opdata->opnext) { opchain=&opdata->filtchain; opmember=*opchain; if(opmember) do { opnext=opmember->next; if(opnext==*opchain) opnext=NULL; if(opmember->state==UL_OPST_FILTNEW){ LOG_FILTS("check_for_filtnew : processing UL_OPST_FILTNEW\n"); opmember2=*opchain; while(opmember2){ if((opmember->cmd==opmember2->cmd)&& (opmember->sadr==opmember2->sadr)&& (opmember->dadr==opmember2->dadr)&& (opmember->stamp==opmember2->stamp)&& (opmember2->state==UL_OPST_FILT)) break; opmember2=opmember2->next; if(opmember2==*opchain){ opmember2=NULL; } }; if(opmember2){ LOG_FILTS("check_for_filtnew : deletting UL_OPST_FILTNEW\n"); del_from_opchain(opchain,opmember); FREE(opmember); }else{ LOG_FILTS("check_for_filtnew : changing to UL_OPST_FILT\n"); opmember->state=UL_OPST_FILT; } } } while((opmember=opnext)!=NULL); };};#ifndef _WIN32/* notice about new message in udrv->proc_bll */void ulan_do_bh(ulan_do_bh_data_type data){ ul_mem_blk *message; ul_drv *udrv=(ul_drv *)data; #ifdef ENABLE_UL_IRQ_STALE_WDG ul_irq_stale_wdg_cnt=0; #endif /* ENABLE_UL_IRQ_STALE_WDG */ if(udrv->magic!=UL_DRV_MAGIC) { #ifdef FOR_LINUX_KERNEL panic("ulan_do_bh : BAD udrv magic !!!"); #else /* FOR_LINUX_KERNEL */ return; #endif /* FOR_LINUX_KERNEL */ } LOG_MESSAGES("ulan_do_bh : announcing messages\n"); while(udrv->proc_bll.first||uld_test_dfl(udrv,ASK_BOTTOM)) { if(uld_test_and_set_dfl(udrv,IN_BOTTOM)) { LOG_MESSAGES("ulan_do_bh : else is already in"); return; } uld_clear_dfl(udrv,ASK_BOTTOM); if(uld_test_dfl(udrv,CHECK_FILT)){ uld_clear_dfl(udrv,CHECK_FILT); check_for_filtnew(udrv); } while((message=udrv->proc_bll.first)) { int i; ul_bll_move_mes(&udrv->opan_bll,message); i=ulan_proc_arrived(udrv,message); LOG_MESSAGES("ulan_do_bh : message sent to %d recchains\n",i); }; uld_atomic_clear_dfl(udrv,IN_BOTTOM); };};#endif /* _WIN32 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -