Path: blob/master/drivers/isdn/hardware/mISDN/avmfritz.c
15111 views
/*1* avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards2* Thanks to AVM, Berlin for informations3*4* Author Karsten Keil <[email protected]>5*6* Copyright 2009 by Karsten Keil <[email protected]>7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License version 2 as10* published by the Free Software Foundation.11*12* This program is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.20*21*/22#include <linux/module.h>23#include <linux/pci.h>24#include <linux/delay.h>25#include <linux/mISDNhw.h>26#include <linux/slab.h>27#include <asm/unaligned.h>28#include "ipac.h"293031#define AVMFRITZ_REV "2.1"3233static int AVM_cnt;34static int debug;3536enum {37AVM_FRITZ_PCI,38AVM_FRITZ_PCIV2,39};4041#define HDLC_FIFO 0x042#define HDLC_STATUS 0x443#define CHIP_WINDOW 0x104445#define CHIP_INDEX 0x446#define AVM_HDLC_1 0x0047#define AVM_HDLC_2 0x0148#define AVM_ISAC_FIFO 0x0249#define AVM_ISAC_REG_LOW 0x0450#define AVM_ISAC_REG_HIGH 0x065152#define AVM_STATUS0_IRQ_ISAC 0x0153#define AVM_STATUS0_IRQ_HDLC 0x0254#define AVM_STATUS0_IRQ_TIMER 0x0455#define AVM_STATUS0_IRQ_MASK 0x075657#define AVM_STATUS0_RESET 0x0158#define AVM_STATUS0_DIS_TIMER 0x0259#define AVM_STATUS0_RES_TIMER 0x0460#define AVM_STATUS0_ENA_IRQ 0x0861#define AVM_STATUS0_TESTBIT 0x106263#define AVM_STATUS1_INT_SEL 0x0f64#define AVM_STATUS1_ENA_IOM 0x806566#define HDLC_MODE_ITF_FLG 0x0167#define HDLC_MODE_TRANS 0x0268#define HDLC_MODE_CCR_7 0x0469#define HDLC_MODE_CCR_16 0x0870#define HDLC_MODE_TESTLOOP 0x807172#define HDLC_INT_XPR 0x8073#define HDLC_INT_XDU 0x4074#define HDLC_INT_RPR 0x2075#define HDLC_INT_MASK 0xE07677#define HDLC_STAT_RME 0x0178#define HDLC_STAT_RDO 0x1079#define HDLC_STAT_CRCVFRRAB 0x0E80#define HDLC_STAT_CRCVFR 0x0681#define HDLC_STAT_RML_MASK 0x3f008283#define HDLC_CMD_XRS 0x8084#define HDLC_CMD_XME 0x0185#define HDLC_CMD_RRS 0x2086#define HDLC_CMD_XML_MASK 0x3f0087#define HDLC_FIFO_SIZE 328889/* Fritz PCI v2.0 */9091#define AVM_HDLC_FIFO_1 0x1092#define AVM_HDLC_FIFO_2 0x189394#define AVM_HDLC_STATUS_1 0x1495#define AVM_HDLC_STATUS_2 0x1c9697#define AVM_ISACX_INDEX 0x0498#define AVM_ISACX_DATA 0x0899100/* data struct */101#define LOG_SIZE 63102103struct hdlc_stat_reg {104#ifdef __BIG_ENDIAN105u8 fill;106u8 mode;107u8 xml;108u8 cmd;109#else110u8 cmd;111u8 xml;112u8 mode;113u8 fill;114#endif115} __attribute__((packed));116117struct hdlc_hw {118union {119u32 ctrl;120struct hdlc_stat_reg sr;121} ctrl;122u32 stat;123};124125struct fritzcard {126struct list_head list;127struct pci_dev *pdev;128char name[MISDN_MAX_IDLEN];129u8 type;130u8 ctrlreg;131u16 irq;132u32 irqcnt;133u32 addr;134spinlock_t lock; /* hw lock */135struct isac_hw isac;136struct hdlc_hw hdlc[2];137struct bchannel bch[2];138char log[LOG_SIZE + 1];139};140141static LIST_HEAD(Cards);142static DEFINE_RWLOCK(card_lock); /* protect Cards */143144static void145_set_debug(struct fritzcard *card)146{147card->isac.dch.debug = debug;148card->bch[0].debug = debug;149card->bch[1].debug = debug;150}151152static int153set_debug(const char *val, struct kernel_param *kp)154{155int ret;156struct fritzcard *card;157158ret = param_set_uint(val, kp);159if (!ret) {160read_lock(&card_lock);161list_for_each_entry(card, &Cards, list)162_set_debug(card);163read_unlock(&card_lock);164}165return ret;166}167168MODULE_AUTHOR("Karsten Keil");169MODULE_LICENSE("GPL v2");170MODULE_VERSION(AVMFRITZ_REV);171module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);172MODULE_PARM_DESC(debug, "avmfritz debug mask");173174/* Interface functions */175176static u8177ReadISAC_V1(void *p, u8 offset)178{179struct fritzcard *fc = p;180u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;181182outb(idx, fc->addr + CHIP_INDEX);183return inb(fc->addr + CHIP_WINDOW + (offset & 0xf));184}185186static void187WriteISAC_V1(void *p, u8 offset, u8 value)188{189struct fritzcard *fc = p;190u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;191192outb(idx, fc->addr + CHIP_INDEX);193outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf));194}195196static void197ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size)198{199struct fritzcard *fc = p;200201outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);202insb(fc->addr + CHIP_WINDOW, data, size);203}204205static void206WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size)207{208struct fritzcard *fc = p;209210outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);211outsb(fc->addr + CHIP_WINDOW, data, size);212}213214static u8215ReadISAC_V2(void *p, u8 offset)216{217struct fritzcard *fc = p;218219outl(offset, fc->addr + AVM_ISACX_INDEX);220return 0xff & inl(fc->addr + AVM_ISACX_DATA);221}222223static void224WriteISAC_V2(void *p, u8 offset, u8 value)225{226struct fritzcard *fc = p;227228outl(offset, fc->addr + AVM_ISACX_INDEX);229outl(value, fc->addr + AVM_ISACX_DATA);230}231232static void233ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size)234{235struct fritzcard *fc = p;236int i;237238outl(off, fc->addr + AVM_ISACX_INDEX);239for (i = 0; i < size; i++)240data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA);241}242243static void244WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size)245{246struct fritzcard *fc = p;247int i;248249outl(off, fc->addr + AVM_ISACX_INDEX);250for (i = 0; i < size; i++)251outl(data[i], fc->addr + AVM_ISACX_DATA);252}253254static struct bchannel *255Sel_BCS(struct fritzcard *fc, u32 channel)256{257if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) &&258(fc->bch[0].nr & channel))259return &fc->bch[0];260else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) &&261(fc->bch[1].nr & channel))262return &fc->bch[1];263else264return NULL;265}266267static inline void268__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {269u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1;270271outl(idx, fc->addr + CHIP_INDEX);272outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);273}274275static inline void276__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {277outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 :278AVM_HDLC_STATUS_1));279}280281void282write_ctrl(struct bchannel *bch, int which) {283struct fritzcard *fc = bch->hw;284struct hdlc_hw *hdlc;285286hdlc = &fc->hdlc[(bch->nr - 1) & 1];287pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr,288which, hdlc->ctrl.ctrl);289switch (fc->type) {290case AVM_FRITZ_PCIV2:291__write_ctrl_pciv2(fc, hdlc, bch->nr);292break;293case AVM_FRITZ_PCI:294__write_ctrl_pci(fc, hdlc, bch->nr);295break;296}297}298299300static inline u32301__read_status_pci(u_long addr, u32 channel)302{303outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);304return inl(addr + CHIP_WINDOW + HDLC_STATUS);305}306307static inline u32308__read_status_pciv2(u_long addr, u32 channel)309{310return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 :311AVM_HDLC_STATUS_1));312}313314315static u32316read_status(struct fritzcard *fc, u32 channel)317{318switch (fc->type) {319case AVM_FRITZ_PCIV2:320return __read_status_pciv2(fc->addr, channel);321case AVM_FRITZ_PCI:322return __read_status_pci(fc->addr, channel);323}324/* dummy */325return 0;326}327328static void329enable_hwirq(struct fritzcard *fc)330{331fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;332outb(fc->ctrlreg, fc->addr + 2);333}334335static void336disable_hwirq(struct fritzcard *fc)337{338fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ;339outb(fc->ctrlreg, fc->addr + 2);340}341342static int343modehdlc(struct bchannel *bch, int protocol)344{345struct fritzcard *fc = bch->hw;346struct hdlc_hw *hdlc;347348hdlc = &fc->hdlc[(bch->nr - 1) & 1];349pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,350'@' + bch->nr, bch->state, protocol, bch->nr);351hdlc->ctrl.ctrl = 0;352switch (protocol) {353case -1: /* used for init */354bch->state = -1;355case ISDN_P_NONE:356if (bch->state == ISDN_P_NONE)357break;358hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;359hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;360write_ctrl(bch, 5);361bch->state = ISDN_P_NONE;362test_and_clear_bit(FLG_HDLC, &bch->Flags);363test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);364break;365case ISDN_P_B_RAW:366bch->state = protocol;367hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;368hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;369write_ctrl(bch, 5);370hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;371write_ctrl(bch, 1);372hdlc->ctrl.sr.cmd = 0;373test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);374break;375case ISDN_P_B_HDLC:376bch->state = protocol;377hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;378hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;379write_ctrl(bch, 5);380hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;381write_ctrl(bch, 1);382hdlc->ctrl.sr.cmd = 0;383test_and_set_bit(FLG_HDLC, &bch->Flags);384break;385default:386pr_info("%s: protocol not known %x\n", fc->name, protocol);387return -ENOPROTOOPT;388}389return 0;390}391392static void393hdlc_empty_fifo(struct bchannel *bch, int count)394{395u32 *ptr;396u8 *p;397u32 val, addr;398int cnt = 0;399struct fritzcard *fc = bch->hw;400401pr_debug("%s: %s %d\n", fc->name, __func__, count);402if (!bch->rx_skb) {403bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);404if (!bch->rx_skb) {405pr_info("%s: B receive out of memory\n",406fc->name);407return;408}409}410if ((bch->rx_skb->len + count) > bch->maxlen) {411pr_debug("%s: overrun %d\n", fc->name,412bch->rx_skb->len + count);413return;414}415p = skb_put(bch->rx_skb, count);416ptr = (u32 *)p;417if (AVM_FRITZ_PCIV2 == fc->type)418addr = fc->addr + (bch->nr == 2 ?419AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);420else {421addr = fc->addr + CHIP_WINDOW;422outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);423}424while (cnt < count) {425val = le32_to_cpu(inl(addr));426put_unaligned(val, ptr);427ptr++;428cnt += 4;429}430if (debug & DEBUG_HW_BFIFO) {431snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",432bch->nr, fc->name, count);433print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);434}435}436437static void438hdlc_fill_fifo(struct bchannel *bch)439{440struct fritzcard *fc = bch->hw;441struct hdlc_hw *hdlc;442int count, cnt = 0;443u8 *p;444u32 *ptr, val, addr;445446hdlc = &fc->hdlc[(bch->nr - 1) & 1];447if (!bch->tx_skb)448return;449count = bch->tx_skb->len - bch->tx_idx;450if (count <= 0)451return;452p = bch->tx_skb->data + bch->tx_idx;453hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;454if (count > HDLC_FIFO_SIZE) {455count = HDLC_FIFO_SIZE;456} else {457if (test_bit(FLG_HDLC, &bch->Flags))458hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;459}460pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,461bch->tx_idx, bch->tx_skb->len);462ptr = (u32 *)p;463bch->tx_idx += count;464hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);465if (AVM_FRITZ_PCIV2 == fc->type) {466__write_ctrl_pciv2(fc, hdlc, bch->nr);467addr = fc->addr + (bch->nr == 2 ?468AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);469} else {470__write_ctrl_pci(fc, hdlc, bch->nr);471addr = fc->addr + CHIP_WINDOW;472}473while (cnt < count) {474val = get_unaligned(ptr);475outl(cpu_to_le32(val), addr);476ptr++;477cnt += 4;478}479if (debug & DEBUG_HW_BFIFO) {480snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ",481bch->nr, fc->name, count);482print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);483}484}485486static void487HDLC_irq_xpr(struct bchannel *bch)488{489if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)490hdlc_fill_fifo(bch);491else {492if (bch->tx_skb) {493/* send confirm, on trans, free on hdlc. */494if (test_bit(FLG_TRANSPARENT, &bch->Flags))495confirm_Bsend(bch);496dev_kfree_skb(bch->tx_skb);497}498if (get_next_bframe(bch))499hdlc_fill_fifo(bch);500}501}502503static void504HDLC_irq(struct bchannel *bch, u32 stat)505{506struct fritzcard *fc = bch->hw;507int len;508struct hdlc_hw *hdlc;509510hdlc = &fc->hdlc[(bch->nr - 1) & 1];511pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);512if (stat & HDLC_INT_RPR) {513if (stat & HDLC_STAT_RDO) {514hdlc->ctrl.sr.xml = 0;515hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;516write_ctrl(bch, 1);517hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;518write_ctrl(bch, 1);519if (bch->rx_skb)520skb_trim(bch->rx_skb, 0);521} else {522len = (stat & HDLC_STAT_RML_MASK) >> 8;523if (!len)524len = 32;525hdlc_empty_fifo(bch, len);526if (!bch->rx_skb)527goto handle_tx;528if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,529&bch->Flags)) {530if (((stat & HDLC_STAT_CRCVFRRAB) ==531HDLC_STAT_CRCVFR) ||532test_bit(FLG_TRANSPARENT, &bch->Flags)) {533recv_Bchannel(bch, 0);534} else {535pr_debug("%s: got invalid frame\n",536fc->name);537skb_trim(bch->rx_skb, 0);538}539}540}541}542handle_tx:543if (stat & HDLC_INT_XDU) {544/* Here we lost an TX interrupt, so545* restart transmitting the whole frame on HDLC546* in transparent mode we send the next data547*/548if (bch->tx_skb)549pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",550fc->name, bch->nr, bch->tx_skb->len,551bch->tx_idx, bch->Flags);552else553pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",554fc->name, bch->nr, bch->Flags);555if (bch->tx_skb && bch->tx_skb->len) {556if (!test_bit(FLG_TRANSPARENT, &bch->Flags))557bch->tx_idx = 0;558}559hdlc->ctrl.sr.xml = 0;560hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;561write_ctrl(bch, 1);562hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;563HDLC_irq_xpr(bch);564return;565} else if (stat & HDLC_INT_XPR)566HDLC_irq_xpr(bch);567}568569static inline void570HDLC_irq_main(struct fritzcard *fc)571{572u32 stat;573struct bchannel *bch;574575stat = read_status(fc, 1);576if (stat & HDLC_INT_MASK) {577bch = Sel_BCS(fc, 1);578if (bch)579HDLC_irq(bch, stat);580else581pr_debug("%s: spurious ch1 IRQ\n", fc->name);582}583stat = read_status(fc, 2);584if (stat & HDLC_INT_MASK) {585bch = Sel_BCS(fc, 2);586if (bch)587HDLC_irq(bch, stat);588else589pr_debug("%s: spurious ch2 IRQ\n", fc->name);590}591}592593static irqreturn_t594avm_fritz_interrupt(int intno, void *dev_id)595{596struct fritzcard *fc = dev_id;597u8 val;598u8 sval;599600spin_lock(&fc->lock);601sval = inb(fc->addr + 2);602pr_debug("%s: irq stat0 %x\n", fc->name, sval);603if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {604/* shared IRQ from other HW */605spin_unlock(&fc->lock);606return IRQ_NONE;607}608fc->irqcnt++;609610if (!(sval & AVM_STATUS0_IRQ_ISAC)) {611val = ReadISAC_V1(fc, ISAC_ISTA);612mISDNisac_irq(&fc->isac, val);613}614if (!(sval & AVM_STATUS0_IRQ_HDLC))615HDLC_irq_main(fc);616spin_unlock(&fc->lock);617return IRQ_HANDLED;618}619620static irqreturn_t621avm_fritzv2_interrupt(int intno, void *dev_id)622{623struct fritzcard *fc = dev_id;624u8 val;625u8 sval;626627spin_lock(&fc->lock);628sval = inb(fc->addr + 2);629pr_debug("%s: irq stat0 %x\n", fc->name, sval);630if (!(sval & AVM_STATUS0_IRQ_MASK)) {631/* shared IRQ from other HW */632spin_unlock(&fc->lock);633return IRQ_NONE;634}635fc->irqcnt++;636637if (sval & AVM_STATUS0_IRQ_HDLC)638HDLC_irq_main(fc);639if (sval & AVM_STATUS0_IRQ_ISAC) {640val = ReadISAC_V2(fc, ISACX_ISTA);641mISDNisac_irq(&fc->isac, val);642}643if (sval & AVM_STATUS0_IRQ_TIMER) {644pr_debug("%s: timer irq\n", fc->name);645outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);646udelay(1);647outb(fc->ctrlreg, fc->addr + 2);648}649spin_unlock(&fc->lock);650return IRQ_HANDLED;651}652653static int654avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)655{656struct bchannel *bch = container_of(ch, struct bchannel, ch);657struct fritzcard *fc = bch->hw;658int ret = -EINVAL;659struct mISDNhead *hh = mISDN_HEAD_P(skb);660u32 id;661u_long flags;662663switch (hh->prim) {664case PH_DATA_REQ:665spin_lock_irqsave(&fc->lock, flags);666ret = bchannel_senddata(bch, skb);667if (ret > 0) { /* direct TX */668id = hh->id; /* skb can be freed */669hdlc_fill_fifo(bch);670ret = 0;671spin_unlock_irqrestore(&fc->lock, flags);672if (!test_bit(FLG_TRANSPARENT, &bch->Flags))673queue_ch_frame(ch, PH_DATA_CNF, id, NULL);674} else675spin_unlock_irqrestore(&fc->lock, flags);676return ret;677case PH_ACTIVATE_REQ:678spin_lock_irqsave(&fc->lock, flags);679if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))680ret = modehdlc(bch, ch->protocol);681else682ret = 0;683spin_unlock_irqrestore(&fc->lock, flags);684if (!ret)685_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,686NULL, GFP_KERNEL);687break;688case PH_DEACTIVATE_REQ:689spin_lock_irqsave(&fc->lock, flags);690mISDN_clear_bchannel(bch);691modehdlc(bch, ISDN_P_NONE);692spin_unlock_irqrestore(&fc->lock, flags);693_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,694NULL, GFP_KERNEL);695ret = 0;696break;697}698if (!ret)699dev_kfree_skb(skb);700return ret;701}702703static void704inithdlc(struct fritzcard *fc)705{706modehdlc(&fc->bch[0], -1);707modehdlc(&fc->bch[1], -1);708}709710void711clear_pending_hdlc_ints(struct fritzcard *fc)712{713u32 val;714715val = read_status(fc, 1);716pr_debug("%s: HDLC 1 STA %x\n", fc->name, val);717val = read_status(fc, 2);718pr_debug("%s: HDLC 2 STA %x\n", fc->name, val);719}720721static void722reset_avm(struct fritzcard *fc)723{724switch (fc->type) {725case AVM_FRITZ_PCI:726fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;727break;728case AVM_FRITZ_PCIV2:729fc->ctrlreg = AVM_STATUS0_RESET;730break;731}732if (debug & DEBUG_HW)733pr_notice("%s: reset\n", fc->name);734disable_hwirq(fc);735mdelay(5);736switch (fc->type) {737case AVM_FRITZ_PCI:738fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;739disable_hwirq(fc);740outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);741break;742case AVM_FRITZ_PCIV2:743fc->ctrlreg = 0;744disable_hwirq(fc);745break;746}747mdelay(1);748if (debug & DEBUG_HW)749pr_notice("%s: S0/S1 %x/%x\n", fc->name,750inb(fc->addr + 2), inb(fc->addr + 3));751}752753static int754init_card(struct fritzcard *fc)755{756int ret, cnt = 3;757u_long flags;758759reset_avm(fc); /* disable IRQ */760if (fc->type == AVM_FRITZ_PCIV2)761ret = request_irq(fc->irq, avm_fritzv2_interrupt,762IRQF_SHARED, fc->name, fc);763else764ret = request_irq(fc->irq, avm_fritz_interrupt,765IRQF_SHARED, fc->name, fc);766if (ret) {767pr_info("%s: couldn't get interrupt %d\n",768fc->name, fc->irq);769return ret;770}771while (cnt--) {772spin_lock_irqsave(&fc->lock, flags);773ret = fc->isac.init(&fc->isac);774if (ret) {775spin_unlock_irqrestore(&fc->lock, flags);776pr_info("%s: ISAC init failed with %d\n",777fc->name, ret);778break;779}780clear_pending_hdlc_ints(fc);781inithdlc(fc);782enable_hwirq(fc);783/* RESET Receiver and Transmitter */784if (AVM_FRITZ_PCIV2 == fc->type) {785WriteISAC_V2(fc, ISACX_MASK, 0);786WriteISAC_V2(fc, ISACX_CMDRD, 0x41);787} else {788WriteISAC_V1(fc, ISAC_MASK, 0);789WriteISAC_V1(fc, ISAC_CMDR, 0x41);790}791spin_unlock_irqrestore(&fc->lock, flags);792/* Timeout 10ms */793msleep_interruptible(10);794if (debug & DEBUG_HW)795pr_notice("%s: IRQ %d count %d\n", fc->name,796fc->irq, fc->irqcnt);797if (!fc->irqcnt) {798pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",799fc->name, fc->irq, 3 - cnt);800reset_avm(fc);801} else802return 0;803}804free_irq(fc->irq, fc);805return -EIO;806}807808static int809channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)810{811int ret = 0;812struct fritzcard *fc = bch->hw;813814switch (cq->op) {815case MISDN_CTRL_GETOP:816cq->op = 0;817break;818/* Nothing implemented yet */819case MISDN_CTRL_FILL_EMPTY:820default:821pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);822ret = -EINVAL;823break;824}825return ret;826}827828static int829avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)830{831struct bchannel *bch = container_of(ch, struct bchannel, ch);832struct fritzcard *fc = bch->hw;833int ret = -EINVAL;834u_long flags;835836pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);837switch (cmd) {838case CLOSE_CHANNEL:839test_and_clear_bit(FLG_OPEN, &bch->Flags);840if (test_bit(FLG_ACTIVE, &bch->Flags)) {841spin_lock_irqsave(&fc->lock, flags);842mISDN_freebchannel(bch);843test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);844test_and_clear_bit(FLG_ACTIVE, &bch->Flags);845modehdlc(bch, ISDN_P_NONE);846spin_unlock_irqrestore(&fc->lock, flags);847}848ch->protocol = ISDN_P_NONE;849ch->peer = NULL;850module_put(THIS_MODULE);851ret = 0;852break;853case CONTROL_CHANNEL:854ret = channel_bctrl(bch, arg);855break;856default:857pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd);858}859return ret;860}861862static int863channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq)864{865int ret = 0;866867switch (cq->op) {868case MISDN_CTRL_GETOP:869cq->op = MISDN_CTRL_LOOP;870break;871case MISDN_CTRL_LOOP:872/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */873if (cq->channel < 0 || cq->channel > 3) {874ret = -EINVAL;875break;876}877ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel);878break;879default:880pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);881ret = -EINVAL;882break;883}884return ret;885}886887static int888open_bchannel(struct fritzcard *fc, struct channel_req *rq)889{890struct bchannel *bch;891892if (rq->adr.channel > 2)893return -EINVAL;894if (rq->protocol == ISDN_P_NONE)895return -EINVAL;896bch = &fc->bch[rq->adr.channel - 1];897if (test_and_set_bit(FLG_OPEN, &bch->Flags))898return -EBUSY; /* b-channel can be only open once */899test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);900bch->ch.protocol = rq->protocol;901rq->ch = &bch->ch;902return 0;903}904905/*906* device control function907*/908static int909avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)910{911struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);912struct dchannel *dch = container_of(dev, struct dchannel, dev);913struct fritzcard *fc = dch->hw;914struct channel_req *rq;915int err = 0;916917pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);918switch (cmd) {919case OPEN_CHANNEL:920rq = arg;921if (rq->protocol == ISDN_P_TE_S0)922err = fc->isac.open(&fc->isac, rq);923else924err = open_bchannel(fc, rq);925if (err)926break;927if (!try_module_get(THIS_MODULE))928pr_info("%s: cannot get module\n", fc->name);929break;930case CLOSE_CHANNEL:931pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id,932__builtin_return_address(0));933module_put(THIS_MODULE);934break;935case CONTROL_CHANNEL:936err = channel_ctrl(fc, arg);937break;938default:939pr_debug("%s: %s unknown command %x\n",940fc->name, __func__, cmd);941return -EINVAL;942}943return err;944}945946int947setup_fritz(struct fritzcard *fc)948{949u32 val, ver;950951if (!request_region(fc->addr, 32, fc->name)) {952pr_info("%s: AVM config port %x-%x already in use\n",953fc->name, fc->addr, fc->addr + 31);954return -EIO;955}956switch (fc->type) {957case AVM_FRITZ_PCI:958val = inl(fc->addr);959outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);960ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;961if (debug & DEBUG_HW) {962pr_notice("%s: PCI stat %#x\n", fc->name, val);963pr_notice("%s: PCI Class %X Rev %d\n", fc->name,964val & 0xff, (val >> 8) & 0xff);965pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);966}967ASSIGN_FUNC(V1, ISAC, fc->isac);968fc->isac.type = IPAC_TYPE_ISAC;969break;970case AVM_FRITZ_PCIV2:971val = inl(fc->addr);972ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;973if (debug & DEBUG_HW) {974pr_notice("%s: PCI V2 stat %#x\n", fc->name, val);975pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name,976val & 0xff, (val>>8) & 0xff);977pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);978}979ASSIGN_FUNC(V2, ISAC, fc->isac);980fc->isac.type = IPAC_TYPE_ISACX;981break;982default:983release_region(fc->addr, 32);984pr_info("%s: AVM unknown type %d\n", fc->name, fc->type);985return -ENODEV;986}987pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name,988(fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" :989"AVM Fritz!CARD PCIv2", fc->irq, fc->addr);990return 0;991}992993static void994release_card(struct fritzcard *card)995{996u_long flags;997998disable_hwirq(card);999spin_lock_irqsave(&card->lock, flags);1000modehdlc(&card->bch[0], ISDN_P_NONE);1001modehdlc(&card->bch[1], ISDN_P_NONE);1002spin_unlock_irqrestore(&card->lock, flags);1003card->isac.release(&card->isac);1004free_irq(card->irq, card);1005mISDN_freebchannel(&card->bch[1]);1006mISDN_freebchannel(&card->bch[0]);1007mISDN_unregister_device(&card->isac.dch.dev);1008release_region(card->addr, 32);1009pci_disable_device(card->pdev);1010pci_set_drvdata(card->pdev, NULL);1011write_lock_irqsave(&card_lock, flags);1012list_del(&card->list);1013write_unlock_irqrestore(&card_lock, flags);1014kfree(card);1015AVM_cnt--;1016}10171018static int __devinit1019setup_instance(struct fritzcard *card)1020{1021int i, err;1022u_long flags;10231024snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);1025write_lock_irqsave(&card_lock, flags);1026list_add_tail(&card->list, &Cards);1027write_unlock_irqrestore(&card_lock, flags);10281029_set_debug(card);1030card->isac.name = card->name;1031spin_lock_init(&card->lock);1032card->isac.hwlock = &card->lock;1033mISDNisac_init(&card->isac, card);10341035card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |1036(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));1037card->isac.dch.dev.D.ctrl = avm_dctrl;1038for (i = 0; i < 2; i++) {1039card->bch[i].nr = i + 1;1040set_channelmap(i + 1, card->isac.dch.dev.channelmap);1041mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);1042card->bch[i].hw = card;1043card->bch[i].ch.send = avm_l2l1B;1044card->bch[i].ch.ctrl = avm_bctrl;1045card->bch[i].ch.nr = i + 1;1046list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels);1047}1048err = setup_fritz(card);1049if (err)1050goto error;1051err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,1052card->name);1053if (err)1054goto error_reg;1055err = init_card(card);1056if (!err) {1057AVM_cnt++;1058pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt);1059return 0;1060}1061mISDN_unregister_device(&card->isac.dch.dev);1062error_reg:1063release_region(card->addr, 32);1064error:1065card->isac.release(&card->isac);1066mISDN_freebchannel(&card->bch[1]);1067mISDN_freebchannel(&card->bch[0]);1068write_lock_irqsave(&card_lock, flags);1069list_del(&card->list);1070write_unlock_irqrestore(&card_lock, flags);1071kfree(card);1072return err;1073}10741075static int __devinit1076fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)1077{1078int err = -ENOMEM;1079struct fritzcard *card;10801081card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL);1082if (!card) {1083pr_info("No kmem for fritzcard\n");1084return err;1085}1086if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)1087card->type = AVM_FRITZ_PCIV2;1088else1089card->type = AVM_FRITZ_PCI;1090card->pdev = pdev;1091err = pci_enable_device(pdev);1092if (err) {1093kfree(card);1094return err;1095}10961097pr_notice("mISDN: found adapter %s at %s\n",1098(char *) ent->driver_data, pci_name(pdev));10991100card->addr = pci_resource_start(pdev, 1);1101card->irq = pdev->irq;1102pci_set_drvdata(pdev, card);1103err = setup_instance(card);1104if (err)1105pci_set_drvdata(pdev, NULL);1106return err;1107}11081109static void __devexit1110fritz_remove_pci(struct pci_dev *pdev)1111{1112struct fritzcard *card = pci_get_drvdata(pdev);11131114if (card)1115release_card(card);1116else1117if (debug)1118pr_info("%s: drvdata already removed\n", __func__);1119}11201121static struct pci_device_id fcpci_ids[] __devinitdata = {1122{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,11230, 0, (unsigned long) "Fritz!Card PCI"},1124{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,11250, 0, (unsigned long) "Fritz!Card PCI v2" },1126{ }1127};1128MODULE_DEVICE_TABLE(pci, fcpci_ids);11291130static struct pci_driver fcpci_driver = {1131.name = "fcpci",1132.probe = fritzpci_probe,1133.remove = __devexit_p(fritz_remove_pci),1134.id_table = fcpci_ids,1135};11361137static int __init AVM_init(void)1138{1139int err;11401141pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV);1142err = pci_register_driver(&fcpci_driver);1143return err;1144}11451146static void __exit AVM_cleanup(void)1147{1148pci_unregister_driver(&fcpci_driver);1149}11501151module_init(AVM_init);1152module_exit(AVM_cleanup);115311541155