diff options
Diffstat (limited to 'drivers/isdn/eicon/eicon_io.c')
-rw-r--r-- | drivers/isdn/eicon/eicon_io.c | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c new file mode 100644 index 000000000..1c69d37cd --- /dev/null +++ b/drivers/isdn/eicon/eicon_io.c @@ -0,0 +1,755 @@ +/* $Id: eicon_io.c,v 1.1 1999/03/29 11:19:45 armin Exp $ + * + * ISDN low-level module for Eicon.Diehl active ISDN-Cards. + * Code for communicating with hardware. + * + * Copyright 1999 by Armin Schindler (mac@melware.de) + * Copyright 1999 Cytronics & Melware (info@melware.de) + * + * Thanks to Eicon Technology Diehl 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. + * + * $Log: eicon_io.c,v $ + * Revision 1.1 1999/03/29 11:19:45 armin + * I/O stuff now in seperate file (eicon_io.c) + * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented. + * + * + */ + + +#include "eicon.h" + +void +eicon_io_rcv_dispatch(eicon_card *ccard) { + struct sk_buff *skb, *skb2, *skb_new; + eicon_IND *ind, *ind2, *ind_new; + eicon_chan *chan; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_io_rcv_dispatch: NULL card!\n"); + return; + } + + while((skb = skb_dequeue(&ccard->rcvq))) { + ind = (eicon_IND *)skb->data; + + if ((chan = ccard->IdTable[ind->IndId]) == NULL) { + if (DebugVar & 1) { + switch(ind->Ind) { + case IDI_N_DISC_ACK: + /* doesn't matter if this happens */ + break; + default: + printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId); + printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%d 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; + } + + 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; + if (DebugVar & 1) + printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n"); + dev_kfree_skb(skb); + dev_kfree_skb(skb2); + continue; + } + ind2 = (eicon_IND *)skb2->data; + skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), + GFP_ATOMIC); + 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; + } + } + } +} + +void +eicon_io_ack_dispatch(eicon_card *ccard) { + struct sk_buff *skb; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_io_ack_dispatch: NULL card!\n"); + return; + } + while((skb = skb_dequeue(&ccard->rackq))) { + idi_handle_ack(ccard, skb); + } +} + + +/* + * IO-Functions for different card-types + */ + +u8 ram_inb(eicon_card *card, void *adr) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + return(inb((u16)pcard->PCIreg + M_DATA)); + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + return(readb(addr)); + } + return(0); +} + +u16 ram_inw(eicon_card *card, void *adr) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + return(inw((u16)pcard->PCIreg + M_DATA)); + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + return(readw(addr)); + } + return(0); +} + +void ram_outb(eicon_card *card, void *adr, u8 data) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + outb((u8)data, (u16)pcard->PCIreg + M_DATA); + break; + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + writeb(data, addr); + break; + } +} + +void ram_outw(eicon_card *card, void *adr , u16 data) { + eicon_pci_card *pcard; + eicon_isa_card *icard; + u32 addr = (u32) adr; + + pcard = &card->hwif.pci; + icard = &card->hwif.isa; + + switch(card->type) { + case EICON_CTYPE_MAESTRA: + outw((u16)addr, (u16)pcard->PCIreg + M_ADDR); + outw((u16)data, (u16)pcard->PCIreg + M_DATA); + break; + case EICON_CTYPE_MAESTRAP: + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + writew(data, addr); + break; + } +} + +void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) { + int i; + switch(card->type) { + case EICON_CTYPE_MAESTRA: + for(i = 0; i < len; i++) { + writeb(ram_inb(card, adr + i), adrto + i); + } + break; + case EICON_CTYPE_MAESTRAP: + memcpy(adrto, adr, len); + break; + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + memcpy_fromio(adrto, adr, len); + break; + } +} + +void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { + int i; + switch(card->type) { + case EICON_CTYPE_MAESTRA: + for(i = 0; i < len; i++) { + ram_outb(card, adrto + i, readb(adr + i)); + } + break; + case EICON_CTYPE_MAESTRAP: + memcpy(adrto, adr, len); + break; + case EICON_CTYPE_S2M: + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + memcpy_toio(adrto, adr, len); + break; + } +} + +/* + * Transmit-Function + */ +void +eicon_io_transmit(eicon_card *ccard) { + eicon_pci_card *pci_card; + eicon_isa_card *isa_card; + struct sk_buff *skb; + struct sk_buff *skb2; + unsigned long flags; + char *ram, *reg, *cfg; + 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 quloop = 1; + + pci_card = &ccard->hwif.pci; + isa_card = &ccard->hwif.isa; + + if (!ccard) { + if (DebugVar & 1) + printk(KERN_WARNING "eicon_transmit: NULL card!\n"); + return; + } + + switch(ccard->type) { + 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; + case EICON_CTYPE_MAESTRAP: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + prram = (eicon_pr_ram *)ram; + break; + case EICON_CTYPE_MAESTRA: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + prram = 0; + break; + default: + printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n"); + return; + } + + ReqCount = 0; + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + while(quloop) { + save_flags(flags); + cli(); + if (scom) { + if (ram_inb(ccard, &com->Req)) { + if (!ccard->ReadyInt) { + tmp = ram_inb(ccard, &com->ReadyInt) + 1; + ram_outb(ccard, &com->ReadyInt, tmp); + ccard->ReadyInt++; + } + restore_flags(flags); + skb_queue_head(&ccard->sndq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: Card not ready\n"); + return; + } + } else { + if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) { + restore_flags(flags); + skb_queue_head(&ccard->sndq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: Card not ready\n"); + return; + } + } + restore_flags(flags); + chan2 = (eicon_chan_ptr *)skb2->data; + chan = chan2->ptr; + if (!chan->e.busy) { + if((skb = skb_dequeue(&chan->e.X))) { + save_flags(flags); + cli(); + reqbuf = (eicon_REQ *)skb->data; + if (scom) { + 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); + + } else { + /* 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); + } + + if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */ + + if (!reqbuf->Reference) { /* Signal Layer */ + if (scom) + ram_outb(ccard, &com->ReqId, chan->e.D3Id); + else + ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); + + chan->e.ReqCh = 0; + } + else { /* Net Layer */ + if (scom) + ram_outb(ccard, &com->ReqId, chan->e.B2Id); + else + ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); + + chan->e.ReqCh = 1; + if (((reqbuf->Req & 0x0f) == 0x08) || + ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */ + chan->waitq = reqbuf->XBuffer.length; + chan->waitpq += reqbuf->XBuffer.length; + } + } + + } else { /* It is an ASSIGN */ + + if (scom) + ram_outb(ccard, &com->ReqId, reqbuf->ReqId); + else + ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); + + if (!reqbuf->Reference) + chan->e.ReqCh = 0; + else + chan->e.ReqCh = 1; + } + if (scom) + chan->e.ref = ccard->ref_out++; + else + chan->e.ref = ram_inw(ccard, &ReqOut->Reference); + + chan->e.Req = reqbuf->Req; + ReqCount++; + if (scom) + ram_outb(ccard, &com->Req, reqbuf->Req); + else + ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); + + chan->e.busy = 1; + restore_flags(flags); + if (DebugVar & 32) + printk(KERN_DEBUG "eicon: Req=%x Id=%x Ch=%x Len=%x Ref=%d\n", + reqbuf->Req, + ram_inb(ccard, &ReqOut->ReqId), + reqbuf->ReqCh, reqbuf->XBuffer.length, + chan->e.ref); + dev_kfree_skb(skb); + } + dev_kfree_skb(skb2); + } + else { + skb_queue_tail(&ccard->sackq, skb2); + if (DebugVar & 32) + printk(KERN_INFO "eicon: transmit: busy chan %d\n", chan->No); + } + + if (scom) + quloop = 0; + else + if (!(skb2 = skb_dequeue(&ccard->sndq))) + quloop = 0; + + } + if (!scom) + ram_outb(ccard, &prram->ReqInput, (__u8)(ram_inb(ccard, &prram->ReqInput) + ReqCount)); + + while((skb = skb_dequeue(&ccard->sackq))) { + skb_queue_tail(&ccard->sndq, skb); + } +} + + +/* + * IRQ handler + */ +void +eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { + eicon_card *ccard = (eicon_card *)dev_id; + eicon_pci_card *pci_card; + eicon_isa_card *isa_card; + char *ram = 0; + char *reg = 0; + char *cfg = 0; + eicon_pr_ram *prram = 0; + eicon_isa_com *com = 0; + eicon_RC *RcIn; + eicon_IND *IndIn; + struct sk_buff *skb; + int Count = 0; + int Rc = 0; + int Ind = 0; + unsigned char *irqprobe = 0; + int scom = 0; + int tmp = 0; + + + if (!ccard) { + printk(KERN_WARNING "eicon_irq: spurious interrupt %d\n", irq); + return; + } + + if (ccard->type == EICON_CTYPE_QUADRO) { + tmp = 4; + while(tmp) { + com = (eicon_isa_com *)ccard->hwif.isa.shmem; + if ((readb(ccard->hwif.isa.intack))) { /* quadro found */ + break; + } + ccard = ccard->qnext; + tmp--; + } + } + + pci_card = &ccard->hwif.pci; + isa_card = &ccard->hwif.isa; + + switch(ccard->type) { + 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; + irqprobe = &isa_card->irqprobe; + break; + case EICON_CTYPE_S2M: + scom = 0; + prram = (eicon_pr_ram *)isa_card->shmem; + irqprobe = &isa_card->irqprobe; + break; + case EICON_CTYPE_MAESTRAP: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + irqprobe = &pci_card->irqprobe; + prram = (eicon_pr_ram *)ram; + break; + case EICON_CTYPE_MAESTRA: + scom = 0; + ram = (char *)pci_card->PCIram; + reg = (char *)pci_card->PCIreg; + cfg = (char *)pci_card->PCIcfg; + irqprobe = &pci_card->irqprobe; + prram = 0; + break; + default: + printk(KERN_WARNING "eicon_irq: unsupported card-type!\n"); + return; + } + + if (*irqprobe) { + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + if (readb(isa_card->intack)) { + writeb(0, &com->Rc); + writeb(0, isa_card->intack); + } + (*irqprobe)++; + break; + case EICON_CTYPE_S2M: + if (readb(isa_card->intack)) { + writeb(0, &prram->RcOutput); + writeb(0, isa_card->intack); + } + (*irqprobe)++; + break; + case EICON_CTYPE_MAESTRAP: + if (readb(&ram[0x3fe])) { + writeb(0, &prram->RcOutput); + writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); + writew(0, &cfg[MP_IRQ_RESET + 2]); + writeb(0, &ram[0x3fe]); + } + *irqprobe = 0; + break; + case EICON_CTYPE_MAESTRA: + outb(0x08, pci_card->PCIreg + M_RESET); + *irqprobe = 0; + break; + } + return; + } + + switch(ccard->type) { + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_S2M: + if (!(readb(isa_card->intack))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + case EICON_CTYPE_MAESTRAP: + if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + case EICON_CTYPE_MAESTRA: + outw(0x3fe, pci_card->PCIreg + M_ADDR); + if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */ + if (DebugVar & 1) + printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n"); + return; + } + break; + } + + if (scom) { + + /* if a return code is available ... */ + if ((tmp = ram_inb(ccard, &com->Rc))) { + eicon_RC *ack; + if (tmp == READY_INT) { + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=READY_INT\n"); + if (ccard->ReadyInt) { + ccard->ReadyInt--; + ram_outb(ccard, &com->Rc, 0); + } + } else { + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = tmp; + ack->RcId = ram_inb(ccard, &com->RcId); + ack->RcCh = ram_inb(ccard, &com->RcCh); + ack->Reference = ccard->ref_in++; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n", + tmp,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + ram_outb(ccard, &com->Req, 0); + ram_outb(ccard, &com->Rc, 0); + } + + } else { + + /* if an indication is available ... */ + if ((tmp = ram_inb(ccard, &com->Ind))) { + eicon_IND *ind; + int len = ram_inw(ccard, &com->RBuffer.length); + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = tmp; + ind->IndId = ram_inb(ccard, &com->IndId); + ind->IndCh = ram_inb(ccard, &com->IndCh); + ind->MInd = ram_inb(ccard, &com->MInd); + ind->MLength = ram_inw(ccard, &com->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", + tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + ram_outb(ccard, &com->Ind, 0); + } + } + + } else { + + /* if return codes are available ... */ + if((Count = ram_inb(ccard, &prram->RcOutput))) { + eicon_RC *ack; + /* get the buffer address of the first return code */ + RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &prram->NextRc)]; + /* for all return codes do ... */ + while(Count--) { + + if((Rc=ram_inb(ccard, &RcIn->Rc))) { + skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = Rc; + ack->RcId = ram_inb(ccard, &RcIn->RcId); + ack->RcCh = ram_inb(ccard, &RcIn->RcCh); + ack->Reference = ram_inw(ccard, &RcIn->Reference); + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n", + Rc,ack->RcId,ack->RcCh,ack->Reference); + ram_outb(ccard, &RcIn->Rc, 0); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } + /* get buffer address of next return code */ + RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)]; + } + /* clear all return codes (no chaining!) */ + ram_outb(ccard, &prram->RcOutput, 0); + } + + /* if indications are available ... */ + if((Count = ram_inb(ccard, &prram->IndOutput))) { + eicon_IND *ind; + /* get the buffer address of the first indication */ + IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &prram->NextInd)]; + /* for all indications do ... */ + while(Count--) { + Ind = ram_inb(ccard, &IndIn->Ind); + if(Ind) { + int len = ram_inw(ccard, &IndIn->RBuffer.length); + skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = Ind; + ind->IndId = ram_inb(ccard, &IndIn->IndId); + ind->IndCh = ram_inb(ccard, &IndIn->IndCh); + ind->MInd = ram_inb(ccard, &IndIn->MInd); + ind->MLength = ram_inw(ccard, &IndIn->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", + Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + ram_outb(ccard, &IndIn->Ind, 0); + } + /* get buffer address of next indication */ + IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &IndIn->next)]; + } + ram_outb(ccard, &prram->IndOutput, 0); + } + + } + + /* clear interrupt */ + switch(ccard->type) { + case EICON_CTYPE_QUADRO: + writeb(0, isa_card->intack); + writeb(0, &com[0x401]); + break; + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_S2M: + writeb(0, isa_card->intack); + break; + case EICON_CTYPE_MAESTRAP: + writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]); + writew(0, &cfg[MP_IRQ_RESET + 2]); + writeb(0, &ram[0x3fe]); + break; + case EICON_CTYPE_MAESTRA: + outb(0x08, pci_card->PCIreg + M_RESET); + outw(0x3fe, pci_card->PCIreg + M_ADDR); + outb(0, pci_card->PCIreg + M_DATA); + break; + } + + return; +} + |