Path: blob/master/drivers/isdn/hisax/hisax_fcpcipnp.c
15115 views
/*1* Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards2*3* Author Kai Germaschewski4* Copyright 2001 by Kai Germaschewski <[email protected]>5* 2001 by Karsten Keil <[email protected]>6*7* based upon Karsten Keil's original avm_pci.c driver8*9* This software may be used and distributed according to the terms10* of the GNU General Public License, incorporated herein by reference.11*12* Thanks to Wizard Computersysteme GmbH, Bremervoerde and13* SoHaNet Technology GmbH, Berlin14* for supporting the development of this driver15*/161718/* TODO:19*20* o POWER PC21* o clean up debugging22* o tx_skb at PH_DEACTIVATE time23*/2425#include <linux/module.h>26#include <linux/init.h>27#include <linux/pci.h>28#include <linux/isapnp.h>29#include <linux/kmod.h>30#include <linux/slab.h>31#include <linux/skbuff.h>32#include <linux/netdevice.h>33#include <linux/delay.h>3435#include <asm/io.h>3637#include "hisax_fcpcipnp.h"3839// debugging cruft40#define __debug_variable debug41#include "hisax_debug.h"4243#ifdef CONFIG_HISAX_DEBUG44static int debug = 0;45/* static int hdlcfifosize = 32; */46module_param(debug, int, 0);47/* module_param(hdlcfifosize, int, 0); */48#endif4950MODULE_AUTHOR("Kai Germaschewski <[email protected]>/Karsten Keil <[email protected]>");51MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");5253static struct pci_device_id fcpci_ids[] = {54{ .vendor = PCI_VENDOR_ID_AVM,55.device = PCI_DEVICE_ID_AVM_A1,56.subvendor = PCI_ANY_ID,57.subdevice = PCI_ANY_ID,58.driver_data = (unsigned long) "Fritz!Card PCI",59},60{ .vendor = PCI_VENDOR_ID_AVM,61.device = PCI_DEVICE_ID_AVM_A1_V2,62.subvendor = PCI_ANY_ID,63.subdevice = PCI_ANY_ID,64.driver_data = (unsigned long) "Fritz!Card PCI v2" },65{}66};6768MODULE_DEVICE_TABLE(pci, fcpci_ids);6970#ifdef CONFIG_PNP71static struct pnp_device_id fcpnp_ids[] __devinitdata = {72{73.id = "AVM0900",74.driver_data = (unsigned long) "Fritz!Card PnP",75},76{ .id = "" }77};7879MODULE_DEVICE_TABLE(pnp, fcpnp_ids);80#endif8182static int protocol = 2; /* EURO-ISDN Default */83module_param(protocol, int, 0);84MODULE_LICENSE("GPL");8586// ----------------------------------------------------------------------8788#define AVM_INDEX 0x0489#define AVM_DATA 0x109091#define AVM_IDX_HDLC_1 0x0092#define AVM_IDX_HDLC_2 0x0193#define AVM_IDX_ISAC_FIFO 0x0294#define AVM_IDX_ISAC_REG_LOW 0x0495#define AVM_IDX_ISAC_REG_HIGH 0x069697#define AVM_STATUS0 0x029899#define AVM_STATUS0_IRQ_ISAC 0x01100#define AVM_STATUS0_IRQ_HDLC 0x02101#define AVM_STATUS0_IRQ_TIMER 0x04102#define AVM_STATUS0_IRQ_MASK 0x07103104#define AVM_STATUS0_RESET 0x01105#define AVM_STATUS0_DIS_TIMER 0x02106#define AVM_STATUS0_RES_TIMER 0x04107#define AVM_STATUS0_ENA_IRQ 0x08108#define AVM_STATUS0_TESTBIT 0x10109110#define AVM_STATUS1 0x03111#define AVM_STATUS1_ENA_IOM 0x80112113#define HDLC_FIFO 0x0114#define HDLC_STATUS 0x4115#define HDLC_CTRL 0x4116117#define HDLC_MODE_ITF_FLG 0x01118#define HDLC_MODE_TRANS 0x02119#define HDLC_MODE_CCR_7 0x04120#define HDLC_MODE_CCR_16 0x08121#define HDLC_MODE_TESTLOOP 0x80122123#define HDLC_INT_XPR 0x80124#define HDLC_INT_XDU 0x40125#define HDLC_INT_RPR 0x20126#define HDLC_INT_MASK 0xE0127128#define HDLC_STAT_RME 0x01129#define HDLC_STAT_RDO 0x10130#define HDLC_STAT_CRCVFRRAB 0x0E131#define HDLC_STAT_CRCVFR 0x06132#define HDLC_STAT_RML_MASK 0xff00133134#define HDLC_CMD_XRS 0x80135#define HDLC_CMD_XME 0x01136#define HDLC_CMD_RRS 0x20137#define HDLC_CMD_XML_MASK 0xff00138139#define AVM_HDLC_FIFO_1 0x10140#define AVM_HDLC_FIFO_2 0x18141142#define AVM_HDLC_STATUS_1 0x14143#define AVM_HDLC_STATUS_2 0x1c144145#define AVM_ISACSX_INDEX 0x04146#define AVM_ISACSX_DATA 0x08147148// ----------------------------------------------------------------------149// Fritz!PCI150151static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset)152{153struct fritz_adapter *adapter = isac->priv;154unsigned char idx = (offset > 0x2f) ?155AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;156unsigned char val;157unsigned long flags;158159spin_lock_irqsave(&adapter->hw_lock, flags);160outb(idx, adapter->io + AVM_INDEX);161val = inb(adapter->io + AVM_DATA + (offset & 0xf));162spin_unlock_irqrestore(&adapter->hw_lock, flags);163DBG(0x1000, " port %#x, value %#x",164offset, val);165return val;166}167168static void fcpci_write_isac(struct isac *isac, unsigned char offset,169unsigned char value)170{171struct fritz_adapter *adapter = isac->priv;172unsigned char idx = (offset > 0x2f) ?173AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;174unsigned long flags;175176DBG(0x1000, " port %#x, value %#x",177offset, value);178spin_lock_irqsave(&adapter->hw_lock, flags);179outb(idx, adapter->io + AVM_INDEX);180outb(value, adapter->io + AVM_DATA + (offset & 0xf));181spin_unlock_irqrestore(&adapter->hw_lock, flags);182}183184static void fcpci_read_isac_fifo(struct isac *isac, unsigned char * data,185int size)186{187struct fritz_adapter *adapter = isac->priv;188unsigned long flags;189190spin_lock_irqsave(&adapter->hw_lock, flags);191outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);192insb(adapter->io + AVM_DATA, data, size);193spin_unlock_irqrestore(&adapter->hw_lock, flags);194}195196static void fcpci_write_isac_fifo(struct isac *isac, unsigned char * data,197int size)198{199struct fritz_adapter *adapter = isac->priv;200unsigned long flags;201202spin_lock_irqsave(&adapter->hw_lock, flags);203outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);204outsb(adapter->io + AVM_DATA, data, size);205spin_unlock_irqrestore(&adapter->hw_lock, flags);206}207208static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr)209{210u32 val;211int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;212unsigned long flags;213214spin_lock_irqsave(&adapter->hw_lock, flags);215outl(idx, adapter->io + AVM_INDEX);216val = inl(adapter->io + AVM_DATA + HDLC_STATUS);217spin_unlock_irqrestore(&adapter->hw_lock, flags);218return val;219}220221static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which)222{223struct fritz_adapter *adapter = bcs->adapter;224int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;225226DBG(0x40, "hdlc %c wr%x ctrl %x",227'A' + bcs->channel, which, bcs->ctrl.ctrl);228229outl(idx, adapter->io + AVM_INDEX);230outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL);231}232233static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which)234{235struct fritz_adapter *adapter = bcs->adapter;236unsigned long flags;237238spin_lock_irqsave(&adapter->hw_lock, flags);239__fcpci_write_ctrl(bcs, which);240spin_unlock_irqrestore(&adapter->hw_lock, flags);241}242243// ----------------------------------------------------------------------244// Fritz!PCI v2245246static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset)247{248struct fritz_adapter *adapter = isac->priv;249unsigned char val;250unsigned long flags;251252spin_lock_irqsave(&adapter->hw_lock, flags);253outl(offset, adapter->io + AVM_ISACSX_INDEX);254val = inl(adapter->io + AVM_ISACSX_DATA);255spin_unlock_irqrestore(&adapter->hw_lock, flags);256DBG(0x1000, " port %#x, value %#x",257offset, val);258259return val;260}261262static void fcpci2_write_isac(struct isac *isac, unsigned char offset,263unsigned char value)264{265struct fritz_adapter *adapter = isac->priv;266unsigned long flags;267268DBG(0x1000, " port %#x, value %#x",269offset, value);270spin_lock_irqsave(&adapter->hw_lock, flags);271outl(offset, adapter->io + AVM_ISACSX_INDEX);272outl(value, adapter->io + AVM_ISACSX_DATA);273spin_unlock_irqrestore(&adapter->hw_lock, flags);274}275276static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char * data,277int size)278{279struct fritz_adapter *adapter = isac->priv;280int i;281unsigned long flags;282283spin_lock_irqsave(&adapter->hw_lock, flags);284outl(0, adapter->io + AVM_ISACSX_INDEX);285for (i = 0; i < size; i++)286data[i] = inl(adapter->io + AVM_ISACSX_DATA);287spin_unlock_irqrestore(&adapter->hw_lock, flags);288}289290static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char * data,291int size)292{293struct fritz_adapter *adapter = isac->priv;294int i;295unsigned long flags;296297spin_lock_irqsave(&adapter->hw_lock, flags);298outl(0, adapter->io + AVM_ISACSX_INDEX);299for (i = 0; i < size; i++)300outl(data[i], adapter->io + AVM_ISACSX_DATA);301spin_unlock_irqrestore(&adapter->hw_lock, flags);302}303304static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr)305{306int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;307308return inl(adapter->io + offset);309}310311static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which)312{313struct fritz_adapter *adapter = bcs->adapter;314int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;315316DBG(0x40, "hdlc %c wr%x ctrl %x",317'A' + bcs->channel, which, bcs->ctrl.ctrl);318319outl(bcs->ctrl.ctrl, adapter->io + offset);320}321322// ----------------------------------------------------------------------323// Fritz!PnP (ISAC access as for Fritz!PCI)324325static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr)326{327unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;328u32 val;329unsigned long flags;330331spin_lock_irqsave(&adapter->hw_lock, flags);332outb(idx, adapter->io + AVM_INDEX);333val = inb(adapter->io + AVM_DATA + HDLC_STATUS);334if (val & HDLC_INT_RPR)335val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8;336spin_unlock_irqrestore(&adapter->hw_lock, flags);337return val;338}339340static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)341{342struct fritz_adapter *adapter = bcs->adapter;343unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;344345DBG(0x40, "hdlc %c wr%x ctrl %x",346'A' + bcs->channel, which, bcs->ctrl.ctrl);347348outb(idx, adapter->io + AVM_INDEX);349if (which & 4)350outb(bcs->ctrl.sr.mode,351adapter->io + AVM_DATA + HDLC_STATUS + 2);352if (which & 2)353outb(bcs->ctrl.sr.xml,354adapter->io + AVM_DATA + HDLC_STATUS + 1);355if (which & 1)356outb(bcs->ctrl.sr.cmd,357adapter->io + AVM_DATA + HDLC_STATUS + 0);358}359360static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)361{362struct fritz_adapter *adapter = bcs->adapter;363unsigned long flags;364365spin_lock_irqsave(&adapter->hw_lock, flags);366__fcpnp_write_ctrl(bcs, which);367spin_unlock_irqrestore(&adapter->hw_lock, flags);368}369370// ----------------------------------------------------------------------371372static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg)373{374struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;375376DBG(2, "pr %#x", pr);377ifc->l1l2(ifc, pr, arg);378}379380static void hdlc_fill_fifo(struct fritz_bcs *bcs)381{382struct fritz_adapter *adapter = bcs->adapter;383struct sk_buff *skb = bcs->tx_skb;384int count;385unsigned long flags;386unsigned char *p;387388DBG(0x40, "hdlc_fill_fifo");389390BUG_ON(skb->len == 0);391392bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;393if (bcs->tx_skb->len > bcs->fifo_size) {394count = bcs->fifo_size;395} else {396count = bcs->tx_skb->len;397if (bcs->mode != L1_MODE_TRANS)398bcs->ctrl.sr.cmd |= HDLC_CMD_XME;399}400DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len);401p = bcs->tx_skb->data;402skb_pull(bcs->tx_skb, count);403bcs->tx_cnt += count;404bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count);405406switch (adapter->type) {407case AVM_FRITZ_PCI:408spin_lock_irqsave(&adapter->hw_lock, flags);409// sets the correct AVM_INDEX, too410__fcpci_write_ctrl(bcs, 3);411outsl(adapter->io + AVM_DATA + HDLC_FIFO,412p, (count + 3) / 4);413spin_unlock_irqrestore(&adapter->hw_lock, flags);414break;415case AVM_FRITZ_PCIV2:416fcpci2_write_ctrl(bcs, 3);417outsl(adapter->io +418(bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),419p, (count + 3) / 4);420break;421case AVM_FRITZ_PNP:422spin_lock_irqsave(&adapter->hw_lock, flags);423// sets the correct AVM_INDEX, too424__fcpnp_write_ctrl(bcs, 3);425outsb(adapter->io + AVM_DATA, p, count);426spin_unlock_irqrestore(&adapter->hw_lock, flags);427break;428}429}430431static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count)432{433struct fritz_adapter *adapter = bcs->adapter;434unsigned char *p;435unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;436437DBG(0x10, "hdlc_empty_fifo %d", count);438if (bcs->rcvidx + count > HSCX_BUFMAX) {439DBG(0x10, "hdlc_empty_fifo: incoming packet too large");440return;441}442p = bcs->rcvbuf + bcs->rcvidx;443bcs->rcvidx += count;444switch (adapter->type) {445case AVM_FRITZ_PCI:446spin_lock(&adapter->hw_lock);447outl(idx, adapter->io + AVM_INDEX);448insl(adapter->io + AVM_DATA + HDLC_FIFO,449p, (count + 3) / 4);450spin_unlock(&adapter->hw_lock);451break;452case AVM_FRITZ_PCIV2:453insl(adapter->io +454(bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),455p, (count + 3) / 4);456break;457case AVM_FRITZ_PNP:458spin_lock(&adapter->hw_lock);459outb(idx, adapter->io + AVM_INDEX);460insb(adapter->io + AVM_DATA, p, count);461spin_unlock(&adapter->hw_lock);462break;463}464}465466static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat)467{468struct fritz_adapter *adapter = bcs->adapter;469struct sk_buff *skb;470int len;471472if (stat & HDLC_STAT_RDO) {473DBG(0x10, "RDO");474bcs->ctrl.sr.xml = 0;475bcs->ctrl.sr.cmd |= HDLC_CMD_RRS;476adapter->write_ctrl(bcs, 1);477bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS;478adapter->write_ctrl(bcs, 1);479bcs->rcvidx = 0;480return;481}482483len = (stat & HDLC_STAT_RML_MASK) >> 8;484if (len == 0)485len = bcs->fifo_size;486487hdlc_empty_fifo(bcs, len);488489if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {490if (((stat & HDLC_STAT_CRCVFRRAB)== HDLC_STAT_CRCVFR) ||491(bcs->mode == L1_MODE_TRANS)) {492skb = dev_alloc_skb(bcs->rcvidx);493if (!skb) {494printk(KERN_WARNING "HDLC: receive out of memory\n");495} else {496memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf,497bcs->rcvidx);498DBG_SKB(1, skb);499B_L1L2(bcs, PH_DATA | INDICATION, skb);500}501bcs->rcvidx = 0;502} else {503DBG(0x10, "ch%d invalid frame %#x",504bcs->channel, stat);505bcs->rcvidx = 0;506}507}508}509510static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)511{512struct fritz_adapter *adapter = bcs->adapter;513514515/* Here we lost an TX interrupt, so516* restart transmitting the whole frame.517*/518bcs->ctrl.sr.xml = 0;519bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;520adapter->write_ctrl(bcs, 1);521bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;522523if (!bcs->tx_skb) {524DBG(0x10, "XDU without skb");525adapter->write_ctrl(bcs, 1);526return;527}528/* only hdlc restarts the frame, transparent mode must continue */529if (bcs->mode == L1_MODE_HDLC) {530skb_push(bcs->tx_skb, bcs->tx_cnt);531bcs->tx_cnt = 0;532}533}534535static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)536{537struct sk_buff *skb;538539skb = bcs->tx_skb;540if (!skb)541return;542543if (skb->len) {544hdlc_fill_fifo(bcs);545return;546}547bcs->tx_cnt = 0;548bcs->tx_skb = NULL;549B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize);550dev_kfree_skb_irq(skb);551}552553static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)554{555DBG(0x10, "ch%d stat %#x", bcs->channel, stat);556if (stat & HDLC_INT_RPR) {557DBG(0x10, "RPR");558hdlc_rpr_irq(bcs, stat);559}560if (stat & HDLC_INT_XDU) {561DBG(0x10, "XDU");562hdlc_xdu_irq(bcs);563hdlc_xpr_irq(bcs);564return;565}566if (stat & HDLC_INT_XPR) {567DBG(0x10, "XPR");568hdlc_xpr_irq(bcs);569}570}571572static inline void hdlc_irq(struct fritz_adapter *adapter)573{574int nr;575u32 stat;576577for (nr = 0; nr < 2; nr++) {578stat = adapter->read_hdlc_status(adapter, nr);579DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);580if (stat & HDLC_INT_MASK)581hdlc_irq_one(&adapter->bcs[nr], stat);582}583}584585static void modehdlc(struct fritz_bcs *bcs, int mode)586{587struct fritz_adapter *adapter = bcs->adapter;588589DBG(0x40, "hdlc %c mode %d --> %d",590'A' + bcs->channel, bcs->mode, mode);591592if (bcs->mode == mode)593return;594595bcs->fifo_size = 32;596bcs->ctrl.ctrl = 0;597bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;598switch (mode) {599case L1_MODE_NULL:600bcs->ctrl.sr.mode = HDLC_MODE_TRANS;601adapter->write_ctrl(bcs, 5);602break;603case L1_MODE_TRANS:604case L1_MODE_HDLC:605bcs->rcvidx = 0;606bcs->tx_cnt = 0;607bcs->tx_skb = NULL;608if (mode == L1_MODE_TRANS) {609bcs->ctrl.sr.mode = HDLC_MODE_TRANS;610} else {611bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;612}613adapter->write_ctrl(bcs, 5);614bcs->ctrl.sr.cmd = HDLC_CMD_XRS;615adapter->write_ctrl(bcs, 1);616bcs->ctrl.sr.cmd = 0;617break;618}619bcs->mode = mode;620}621622static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)623{624struct fritz_bcs *bcs = ifc->priv;625struct sk_buff *skb = arg;626int mode;627628DBG(0x10, "pr %#x", pr);629630switch (pr) {631case PH_DATA | REQUEST:632BUG_ON(bcs->tx_skb);633bcs->tx_skb = skb;634DBG_SKB(1, skb);635hdlc_fill_fifo(bcs);636break;637case PH_ACTIVATE | REQUEST:638mode = (long) arg;639DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);640modehdlc(bcs, mode);641B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);642break;643case PH_DEACTIVATE | REQUEST:644DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);645modehdlc(bcs, L1_MODE_NULL);646B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);647break;648}649}650651// ----------------------------------------------------------------------652653static irqreturn_t654fcpci2_irq(int intno, void *dev)655{656struct fritz_adapter *adapter = dev;657unsigned char val;658659val = inb(adapter->io + AVM_STATUS0);660if (!(val & AVM_STATUS0_IRQ_MASK))661/* hopefully a shared IRQ reqest */662return IRQ_NONE;663DBG(2, "STATUS0 %#x", val);664if (val & AVM_STATUS0_IRQ_ISAC)665isacsx_irq(&adapter->isac);666if (val & AVM_STATUS0_IRQ_HDLC)667hdlc_irq(adapter);668if (val & AVM_STATUS0_IRQ_ISAC)669isacsx_irq(&adapter->isac);670return IRQ_HANDLED;671}672673static irqreturn_t674fcpci_irq(int intno, void *dev)675{676struct fritz_adapter *adapter = dev;677unsigned char sval;678679sval = inb(adapter->io + 2);680if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)681/* possibly a shared IRQ reqest */682return IRQ_NONE;683DBG(2, "sval %#x", sval);684if (!(sval & AVM_STATUS0_IRQ_ISAC))685isac_irq(&adapter->isac);686687if (!(sval & AVM_STATUS0_IRQ_HDLC))688hdlc_irq(adapter);689return IRQ_HANDLED;690}691692// ----------------------------------------------------------------------693694static inline void fcpci2_init(struct fritz_adapter *adapter)695{696outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0);697outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);698699}700701static inline void fcpci_init(struct fritz_adapter *adapter)702{703outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |704AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);705706outb(AVM_STATUS1_ENA_IOM | adapter->irq,707adapter->io + AVM_STATUS1);708mdelay(10);709}710711// ----------------------------------------------------------------------712713static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)714{715u32 val = 0;716int retval;717718DBG(1,"");719720isac_init(&adapter->isac); // FIXME is this okay now721722retval = -EBUSY;723if (!request_region(adapter->io, 32, "fcpcipnp"))724goto err;725726switch (adapter->type) {727case AVM_FRITZ_PCIV2:728case AVM_FRITZ_PCI:729val = inl(adapter->io);730break;731case AVM_FRITZ_PNP:732val = inb(adapter->io);733val |= inb(adapter->io + 1) << 8;734break;735}736737DBG(1, "stat %#x Class %X Rev %d",738val, val & 0xff, (val>>8) & 0xff);739740spin_lock_init(&adapter->hw_lock);741adapter->isac.priv = adapter;742switch (adapter->type) {743case AVM_FRITZ_PCIV2:744adapter->isac.read_isac = &fcpci2_read_isac;745adapter->isac.write_isac = &fcpci2_write_isac;746adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo;747adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;748749adapter->read_hdlc_status = &fcpci2_read_hdlc_status;750adapter->write_ctrl = &fcpci2_write_ctrl;751break;752case AVM_FRITZ_PCI:753adapter->isac.read_isac = &fcpci_read_isac;754adapter->isac.write_isac = &fcpci_write_isac;755adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;756adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;757758adapter->read_hdlc_status = &fcpci_read_hdlc_status;759adapter->write_ctrl = &fcpci_write_ctrl;760break;761case AVM_FRITZ_PNP:762adapter->isac.read_isac = &fcpci_read_isac;763adapter->isac.write_isac = &fcpci_write_isac;764adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;765adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;766767adapter->read_hdlc_status = &fcpnp_read_hdlc_status;768adapter->write_ctrl = &fcpnp_write_ctrl;769break;770}771772// Reset773outb(0, adapter->io + AVM_STATUS0);774mdelay(10);775outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);776mdelay(10);777outb(0, adapter->io + AVM_STATUS0);778mdelay(10);779780switch (adapter->type) {781case AVM_FRITZ_PCIV2:782retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED,783"fcpcipnp", adapter);784break;785case AVM_FRITZ_PCI:786retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED,787"fcpcipnp", adapter);788break;789case AVM_FRITZ_PNP:790retval = request_irq(adapter->irq, fcpci_irq, 0,791"fcpcipnp", adapter);792break;793}794if (retval)795goto err_region;796797switch (adapter->type) {798case AVM_FRITZ_PCIV2:799fcpci2_init(adapter);800isacsx_setup(&adapter->isac);801break;802case AVM_FRITZ_PCI:803case AVM_FRITZ_PNP:804fcpci_init(adapter);805isac_setup(&adapter->isac);806break;807}808val = adapter->read_hdlc_status(adapter, 0);809DBG(0x20, "HDLC A STA %x", val);810val = adapter->read_hdlc_status(adapter, 1);811DBG(0x20, "HDLC B STA %x", val);812813adapter->bcs[0].mode = -1;814adapter->bcs[1].mode = -1;815modehdlc(&adapter->bcs[0], L1_MODE_NULL);816modehdlc(&adapter->bcs[1], L1_MODE_NULL);817818return 0;819820err_region:821release_region(adapter->io, 32);822err:823return retval;824}825826static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)827{828DBG(1,"");829830outb(0, adapter->io + AVM_STATUS0);831free_irq(adapter->irq, adapter);832release_region(adapter->io, 32);833}834835// ----------------------------------------------------------------------836837static struct fritz_adapter * __devinit838new_adapter(void)839{840struct fritz_adapter *adapter;841struct hisax_b_if *b_if[2];842int i;843844adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL);845if (!adapter)846return NULL;847848adapter->isac.hisax_d_if.owner = THIS_MODULE;849adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;850adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;851852for (i = 0; i < 2; i++) {853adapter->bcs[i].adapter = adapter;854adapter->bcs[i].channel = i;855adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];856adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;857}858859for (i = 0; i < 2; i++)860b_if[i] = &adapter->bcs[i].b_if;861862if (hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp",863protocol) != 0) {864kfree(adapter);865adapter = NULL;866}867868return adapter;869}870871static void delete_adapter(struct fritz_adapter *adapter)872{873hisax_unregister(&adapter->isac.hisax_d_if);874kfree(adapter);875}876877static int __devinit fcpci_probe(struct pci_dev *pdev,878const struct pci_device_id *ent)879{880struct fritz_adapter *adapter;881int retval;882883retval = -ENOMEM;884adapter = new_adapter();885if (!adapter)886goto err;887888pci_set_drvdata(pdev, adapter);889890if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)891adapter->type = AVM_FRITZ_PCIV2;892else893adapter->type = AVM_FRITZ_PCI;894895retval = pci_enable_device(pdev);896if (retval)897goto err_free;898899adapter->io = pci_resource_start(pdev, 1);900adapter->irq = pdev->irq;901902printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",903(char *) ent->driver_data, pci_name(pdev));904905retval = fcpcipnp_setup(adapter);906if (retval)907goto err_free;908909return 0;910911err_free:912delete_adapter(adapter);913err:914return retval;915}916917#ifdef CONFIG_PNP918static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)919{920struct fritz_adapter *adapter;921int retval;922923if (!pdev)924return(-ENODEV);925926retval = -ENOMEM;927adapter = new_adapter();928if (!adapter)929goto err;930931pnp_set_drvdata(pdev, adapter);932933adapter->type = AVM_FRITZ_PNP;934935pnp_disable_dev(pdev);936retval = pnp_activate_dev(pdev);937if (retval < 0) {938printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__,939(char *)dev_id->driver_data, retval);940goto err_free;941}942adapter->io = pnp_port_start(pdev, 0);943adapter->irq = pnp_irq(pdev, 0);944945printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",946(char *) dev_id->driver_data, adapter->io, adapter->irq);947948retval = fcpcipnp_setup(adapter);949if (retval)950goto err_free;951952return 0;953954err_free:955delete_adapter(adapter);956err:957return retval;958}959960static void __devexit fcpnp_remove(struct pnp_dev *pdev)961{962struct fritz_adapter *adapter = pnp_get_drvdata(pdev);963964if (adapter) {965fcpcipnp_release(adapter);966delete_adapter(adapter);967}968pnp_disable_dev(pdev);969}970971static struct pnp_driver fcpnp_driver = {972.name = "fcpnp",973.probe = fcpnp_probe,974.remove = __devexit_p(fcpnp_remove),975.id_table = fcpnp_ids,976};977#endif978979static void __devexit fcpci_remove(struct pci_dev *pdev)980{981struct fritz_adapter *adapter = pci_get_drvdata(pdev);982983fcpcipnp_release(adapter);984pci_disable_device(pdev);985delete_adapter(adapter);986}987988static struct pci_driver fcpci_driver = {989.name = "fcpci",990.probe = fcpci_probe,991.remove = __devexit_p(fcpci_remove),992.id_table = fcpci_ids,993};994995static int __init hisax_fcpcipnp_init(void)996{997int retval;998999printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");10001001retval = pci_register_driver(&fcpci_driver);1002if (retval)1003return retval;1004#ifdef CONFIG_PNP1005retval = pnp_register_driver(&fcpnp_driver);1006if (retval < 0) {1007pci_unregister_driver(&fcpci_driver);1008return retval;1009}1010#endif1011return 0;1012}10131014static void __exit hisax_fcpcipnp_exit(void)1015{1016#ifdef CONFIG_PNP1017pnp_unregister_driver(&fcpnp_driver);1018#endif1019pci_unregister_driver(&fcpci_driver);1020}10211022module_init(hisax_fcpcipnp_init);1023module_exit(hisax_fcpcipnp_exit);102410251026