📄 eicon_io.c
字号:
/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. * * Copyright 1999,2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * * Thanks to Eicon Technology GmbH & Co. oHG for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/config.h>#include "eicon.h"#include "uxio.h"voideicon_io_rcv_dispatch(eicon_card *ccard) { ulong flags; struct sk_buff *skb, *skb2, *skb_new; eicon_IND *ind, *ind2, *ind_new; eicon_chan *chan; if (!ccard) { eicon_log(ccard, 1, "eicon_err: NULL card in rcv_dispatch !\n"); return; } while((skb = skb_dequeue(&ccard->rcvq))) { ind = (eicon_IND *)skb->data; spin_lock_irqsave(&eicon_lock, flags); if ((chan = ccard->IdTable[ind->IndId]) == NULL) { spin_unlock_irqrestore(&eicon_lock, flags); if (DebugVar & 1) { switch(ind->Ind) { case N_DISC_ACK: /* doesn't matter if this happens */ break; default: eicon_log(ccard, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId); eicon_log(ccard, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } } dev_kfree_skb(skb); continue; } spin_unlock_irqrestore(&eicon_lock, flags); if (chan->e.complete) { /* check for rec-buffer chaining */ if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 1; idi_handle_ind(ccard, skb); continue; } else { chan->e.complete = 0; ind->Ind = ind->MInd; skb_queue_tail(&chan->e.R, skb); continue; } } else { if (!(skb2 = skb_dequeue(&chan->e.R))) { chan->e.complete = 1; eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n"); dev_kfree_skb(skb); continue; } ind2 = (eicon_IND *)skb2->data; skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), GFP_ATOMIC); if (!skb_new) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n"); dev_kfree_skb(skb); dev_kfree_skb(skb2); continue; } ind_new = (eicon_IND *)skb_put(skb_new, ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length)); ind_new->Ind = ind2->Ind; ind_new->IndId = ind2->IndId; ind_new->IndCh = ind2->IndCh; ind_new->MInd = ind2->MInd; ind_new->MLength = ind2->MLength; ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length; memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length); memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length); dev_kfree_skb(skb); dev_kfree_skb(skb2); if (ind->MLength == ind->RBuffer.length) { chan->e.complete = 2; idi_handle_ind(ccard, skb_new); continue; } else { chan->e.complete = 0; skb_queue_tail(&chan->e.R, skb_new); continue; } } }}voideicon_io_ack_dispatch(eicon_card *ccard) { struct sk_buff *skb; if (!ccard) { eicon_log(ccard, 1, "eicon_err: NULL card in ack_dispatch!\n"); return; } while((skb = skb_dequeue(&ccard->rackq))) { idi_handle_ack(ccard, skb); }}/* * IO-Functions for ISA cards */u8 ram_inb(eicon_card *card, void *adr) { u32 addr = (u32) adr; return(readb(addr));}u16 ram_inw(eicon_card *card, void *adr) { u32 addr = (u32) adr; return(readw(addr));}void ram_outb(eicon_card *card, void *adr, u8 data) { u32 addr = (u32) adr; writeb(data, addr);}void ram_outw(eicon_card *card, void *adr , u16 data) { u32 addr = (u32) adr; writew(data, addr);}void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { memcpy_fromio(adrto, adr, len);}void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { memcpy_toio(adrto, adr, len);}#ifdef CONFIG_ISDN_DRV_EICON_PCI/* * IDI-Callback function */voideicon_idi_callback(ENTITY *de){ eicon_card *ccard = (eicon_card *)de->R; struct sk_buff *skb; eicon_RC *ack; eicon_IND *ind; int len = 0; if (de->complete == 255) { /* Return Code */ skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); if (!skb) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); } else { ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); ack->Rc = de->Rc; if (de->Rc == ASSIGN_OK) { ack->RcId = de->Id; de->user[1] = de->Id; } else { ack->RcId = de->user[1]; } ack->RcCh = de->RcCh; ack->Reference = de->user[0]; skb_queue_tail(&ccard->rackq, skb); eicon_schedule_ack(ccard); eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n", de->user[0], de->Rc, ack->RcId, de->RLength, de->complete); } } else { /* Indication */ if (de->complete) { len = de->RLength; } else { len = 270; if (de->RLength <= 270) eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n"); } skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); if (!skb) { eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n"); } else { ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); ind->Ind = de->Ind; ind->IndId = de->user[1]; ind->IndCh = de->IndCh; ind->MInd = de->Ind; ind->RBuffer.length = len; ind->MLength = de->RLength; memcpy(&ind->RBuffer.P, &de->RBuffer->P, len); skb_queue_tail(&ccard->rcvq, skb); eicon_schedule_rx(ccard); eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n", de->user[0], de->Ind, ind->IndId, de->RLength, de->complete); } } de->RNum = 0; de->RNR = 0; de->Rc = 0; de->Ind = 0;}#endif /* CONFIG_ISDN_DRV_EICON_PCI *//* * Transmit-Function */voideicon_io_transmit(eicon_card *ccard) { eicon_isa_card *isa_card; struct sk_buff *skb; struct sk_buff *skb2; unsigned long flags; eicon_pr_ram *prram = 0; eicon_isa_com *com = 0; eicon_REQ *ReqOut = 0; eicon_REQ *reqbuf = 0; eicon_chan *chan; eicon_chan_ptr *chan2; int ReqCount; int scom = 0; int tmp = 0; int tmpid = 0; int quloop = 1; int dlev = 0; ENTITY *ep = 0; isa_card = &ccard->hwif.isa; if (!ccard) { eicon_log(ccard, 1, "eicon_transmit: NULL card!\n"); return; } switch(ccard->type) {#ifdef CONFIG_ISDN_DRV_EICON_ISA case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: case EICON_CTYPE_QUADRO: scom = 1; com = (eicon_isa_com *)isa_card->shmem; break; case EICON_CTYPE_S2M: scom = 0; prram = (eicon_pr_ram *)isa_card->shmem; break;#endif#ifdef CONFIG_ISDN_DRV_EICON_PCI case EICON_CTYPE_MAESTRAP: scom = 2; break; case EICON_CTYPE_MAESTRAQ: scom = 2; break; case EICON_CTYPE_MAESTRA: scom = 2; break;#endif default: eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n"); return; } ReqCount = 0; if (!(skb2 = skb_dequeue(&ccard->sndq))) quloop = 0; while(quloop) { spin_lock_irqsave(&eicon_lock, flags); switch (scom) { case 1: if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) { if (!ccard->ReadyInt) { tmp = ram_inb(ccard, &com->ReadyInt) + 1; ram_outb(ccard, &com->ReadyInt, tmp); ccard->ReadyInt++; } spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } break; case 0: if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { spin_unlock_irqrestore(&eicon_lock, flags); skb_queue_head(&ccard->sndq, skb2); eicon_log(ccard, 32, "eicon: transmit: Card not ready\n"); return; } break; } spin_unlock_irqrestore(&eicon_lock, flags); chan2 = (eicon_chan_ptr *)skb2->data; chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { reqbuf = (eicon_REQ *)skb->data; if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); } else { spin_lock_irqsave(&eicon_lock, flags); switch (scom) { case 1: ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh); break; case 0: /* get address of next available request buffer */ ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)]; ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh); ram_outb(ccard, &ReqOut->Req, reqbuf->Req); break; } dlev = 160; if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ switch (scom) { case 1: ram_outb(ccard, &com->ReqId, chan->e.D3Id); break; case 0: ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); break; case 2: ep = &chan->de; break; } tmpid = chan->e.D3Id; chan->e.ReqCh = 0; } else { /* Net Layer */ switch(scom) { case 1: ram_outb(ccard, &com->ReqId, chan->e.B2Id);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -