1*6115d2f3SKarsten Keil /* 2*6115d2f3SKarsten Keil * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards 3*6115d2f3SKarsten Keil * Thanks to AVM, Berlin for informations 4*6115d2f3SKarsten Keil * 5*6115d2f3SKarsten Keil * Author Karsten Keil <keil@isdn4linux.de> 6*6115d2f3SKarsten Keil * 7*6115d2f3SKarsten Keil * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 8*6115d2f3SKarsten Keil * 9*6115d2f3SKarsten Keil * This program is free software; you can redistribute it and/or modify 10*6115d2f3SKarsten Keil * it under the terms of the GNU General Public License version 2 as 11*6115d2f3SKarsten Keil * published by the Free Software Foundation. 12*6115d2f3SKarsten Keil * 13*6115d2f3SKarsten Keil * This program is distributed in the hope that it will be useful, 14*6115d2f3SKarsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*6115d2f3SKarsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*6115d2f3SKarsten Keil * GNU General Public License for more details. 17*6115d2f3SKarsten Keil * 18*6115d2f3SKarsten Keil * You should have received a copy of the GNU General Public License 19*6115d2f3SKarsten Keil * along with this program; if not, write to the Free Software 20*6115d2f3SKarsten Keil * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*6115d2f3SKarsten Keil * 22*6115d2f3SKarsten Keil */ 23*6115d2f3SKarsten Keil #include <linux/module.h> 24*6115d2f3SKarsten Keil #include <linux/pci.h> 25*6115d2f3SKarsten Keil #include <linux/delay.h> 26*6115d2f3SKarsten Keil #include <linux/mISDNhw.h> 27*6115d2f3SKarsten Keil #include <asm/unaligned.h> 28*6115d2f3SKarsten Keil #include "ipac.h" 29*6115d2f3SKarsten Keil 30*6115d2f3SKarsten Keil 31*6115d2f3SKarsten Keil #define AVMFRITZ_REV "2.1" 32*6115d2f3SKarsten Keil 33*6115d2f3SKarsten Keil static int AVM_cnt; 34*6115d2f3SKarsten Keil static int debug; 35*6115d2f3SKarsten Keil 36*6115d2f3SKarsten Keil enum { 37*6115d2f3SKarsten Keil AVM_FRITZ_PCI, 38*6115d2f3SKarsten Keil AVM_FRITZ_PCIV2, 39*6115d2f3SKarsten Keil }; 40*6115d2f3SKarsten Keil 41*6115d2f3SKarsten Keil #define HDLC_FIFO 0x0 42*6115d2f3SKarsten Keil #define HDLC_STATUS 0x4 43*6115d2f3SKarsten Keil #define CHIP_WINDOW 0x10 44*6115d2f3SKarsten Keil 45*6115d2f3SKarsten Keil #define CHIP_INDEX 0x4 46*6115d2f3SKarsten Keil #define AVM_HDLC_1 0x00 47*6115d2f3SKarsten Keil #define AVM_HDLC_2 0x01 48*6115d2f3SKarsten Keil #define AVM_ISAC_FIFO 0x02 49*6115d2f3SKarsten Keil #define AVM_ISAC_REG_LOW 0x04 50*6115d2f3SKarsten Keil #define AVM_ISAC_REG_HIGH 0x06 51*6115d2f3SKarsten Keil 52*6115d2f3SKarsten Keil #define AVM_STATUS0_IRQ_ISAC 0x01 53*6115d2f3SKarsten Keil #define AVM_STATUS0_IRQ_HDLC 0x02 54*6115d2f3SKarsten Keil #define AVM_STATUS0_IRQ_TIMER 0x04 55*6115d2f3SKarsten Keil #define AVM_STATUS0_IRQ_MASK 0x07 56*6115d2f3SKarsten Keil 57*6115d2f3SKarsten Keil #define AVM_STATUS0_RESET 0x01 58*6115d2f3SKarsten Keil #define AVM_STATUS0_DIS_TIMER 0x02 59*6115d2f3SKarsten Keil #define AVM_STATUS0_RES_TIMER 0x04 60*6115d2f3SKarsten Keil #define AVM_STATUS0_ENA_IRQ 0x08 61*6115d2f3SKarsten Keil #define AVM_STATUS0_TESTBIT 0x10 62*6115d2f3SKarsten Keil 63*6115d2f3SKarsten Keil #define AVM_STATUS1_INT_SEL 0x0f 64*6115d2f3SKarsten Keil #define AVM_STATUS1_ENA_IOM 0x80 65*6115d2f3SKarsten Keil 66*6115d2f3SKarsten Keil #define HDLC_MODE_ITF_FLG 0x01 67*6115d2f3SKarsten Keil #define HDLC_MODE_TRANS 0x02 68*6115d2f3SKarsten Keil #define HDLC_MODE_CCR_7 0x04 69*6115d2f3SKarsten Keil #define HDLC_MODE_CCR_16 0x08 70*6115d2f3SKarsten Keil #define HDLC_MODE_TESTLOOP 0x80 71*6115d2f3SKarsten Keil 72*6115d2f3SKarsten Keil #define HDLC_INT_XPR 0x80 73*6115d2f3SKarsten Keil #define HDLC_INT_XDU 0x40 74*6115d2f3SKarsten Keil #define HDLC_INT_RPR 0x20 75*6115d2f3SKarsten Keil #define HDLC_INT_MASK 0xE0 76*6115d2f3SKarsten Keil 77*6115d2f3SKarsten Keil #define HDLC_STAT_RME 0x01 78*6115d2f3SKarsten Keil #define HDLC_STAT_RDO 0x10 79*6115d2f3SKarsten Keil #define HDLC_STAT_CRCVFRRAB 0x0E 80*6115d2f3SKarsten Keil #define HDLC_STAT_CRCVFR 0x06 81*6115d2f3SKarsten Keil #define HDLC_STAT_RML_MASK 0x3f00 82*6115d2f3SKarsten Keil 83*6115d2f3SKarsten Keil #define HDLC_CMD_XRS 0x80 84*6115d2f3SKarsten Keil #define HDLC_CMD_XME 0x01 85*6115d2f3SKarsten Keil #define HDLC_CMD_RRS 0x20 86*6115d2f3SKarsten Keil #define HDLC_CMD_XML_MASK 0x3f00 87*6115d2f3SKarsten Keil #define HDLC_FIFO_SIZE 32 88*6115d2f3SKarsten Keil 89*6115d2f3SKarsten Keil /* Fritz PCI v2.0 */ 90*6115d2f3SKarsten Keil 91*6115d2f3SKarsten Keil #define AVM_HDLC_FIFO_1 0x10 92*6115d2f3SKarsten Keil #define AVM_HDLC_FIFO_2 0x18 93*6115d2f3SKarsten Keil 94*6115d2f3SKarsten Keil #define AVM_HDLC_STATUS_1 0x14 95*6115d2f3SKarsten Keil #define AVM_HDLC_STATUS_2 0x1c 96*6115d2f3SKarsten Keil 97*6115d2f3SKarsten Keil #define AVM_ISACX_INDEX 0x04 98*6115d2f3SKarsten Keil #define AVM_ISACX_DATA 0x08 99*6115d2f3SKarsten Keil 100*6115d2f3SKarsten Keil /* data struct */ 101*6115d2f3SKarsten Keil #define LOG_SIZE 63 102*6115d2f3SKarsten Keil 103*6115d2f3SKarsten Keil struct hdlc_stat_reg { 104*6115d2f3SKarsten Keil #ifdef __BIG_ENDIAN 105*6115d2f3SKarsten Keil u8 fill; 106*6115d2f3SKarsten Keil u8 mode; 107*6115d2f3SKarsten Keil u8 xml; 108*6115d2f3SKarsten Keil u8 cmd; 109*6115d2f3SKarsten Keil #else 110*6115d2f3SKarsten Keil u8 cmd; 111*6115d2f3SKarsten Keil u8 xml; 112*6115d2f3SKarsten Keil u8 mode; 113*6115d2f3SKarsten Keil u8 fill; 114*6115d2f3SKarsten Keil #endif 115*6115d2f3SKarsten Keil } __attribute__((packed)); 116*6115d2f3SKarsten Keil 117*6115d2f3SKarsten Keil struct hdlc_hw { 118*6115d2f3SKarsten Keil union { 119*6115d2f3SKarsten Keil u32 ctrl; 120*6115d2f3SKarsten Keil struct hdlc_stat_reg sr; 121*6115d2f3SKarsten Keil } ctrl; 122*6115d2f3SKarsten Keil u32 stat; 123*6115d2f3SKarsten Keil }; 124*6115d2f3SKarsten Keil 125*6115d2f3SKarsten Keil struct fritzcard { 126*6115d2f3SKarsten Keil struct list_head list; 127*6115d2f3SKarsten Keil struct pci_dev *pdev; 128*6115d2f3SKarsten Keil char name[MISDN_MAX_IDLEN]; 129*6115d2f3SKarsten Keil u8 type; 130*6115d2f3SKarsten Keil u8 ctrlreg; 131*6115d2f3SKarsten Keil u16 irq; 132*6115d2f3SKarsten Keil u32 irqcnt; 133*6115d2f3SKarsten Keil u32 addr; 134*6115d2f3SKarsten Keil spinlock_t lock; /* hw lock */ 135*6115d2f3SKarsten Keil struct isac_hw isac; 136*6115d2f3SKarsten Keil struct hdlc_hw hdlc[2]; 137*6115d2f3SKarsten Keil struct bchannel bch[2]; 138*6115d2f3SKarsten Keil char log[LOG_SIZE + 1]; 139*6115d2f3SKarsten Keil }; 140*6115d2f3SKarsten Keil 141*6115d2f3SKarsten Keil static LIST_HEAD(Cards); 142*6115d2f3SKarsten Keil static DEFINE_RWLOCK(card_lock); /* protect Cards */ 143*6115d2f3SKarsten Keil 144*6115d2f3SKarsten Keil static void 145*6115d2f3SKarsten Keil _set_debug(struct fritzcard *card) 146*6115d2f3SKarsten Keil { 147*6115d2f3SKarsten Keil card->isac.dch.debug = debug; 148*6115d2f3SKarsten Keil card->bch[0].debug = debug; 149*6115d2f3SKarsten Keil card->bch[1].debug = debug; 150*6115d2f3SKarsten Keil } 151*6115d2f3SKarsten Keil 152*6115d2f3SKarsten Keil static int 153*6115d2f3SKarsten Keil set_debug(const char *val, struct kernel_param *kp) 154*6115d2f3SKarsten Keil { 155*6115d2f3SKarsten Keil int ret; 156*6115d2f3SKarsten Keil struct fritzcard *card; 157*6115d2f3SKarsten Keil 158*6115d2f3SKarsten Keil ret = param_set_uint(val, kp); 159*6115d2f3SKarsten Keil if (!ret) { 160*6115d2f3SKarsten Keil read_lock(&card_lock); 161*6115d2f3SKarsten Keil list_for_each_entry(card, &Cards, list) 162*6115d2f3SKarsten Keil _set_debug(card); 163*6115d2f3SKarsten Keil read_unlock(&card_lock); 164*6115d2f3SKarsten Keil } 165*6115d2f3SKarsten Keil return ret; 166*6115d2f3SKarsten Keil } 167*6115d2f3SKarsten Keil 168*6115d2f3SKarsten Keil MODULE_AUTHOR("Karsten Keil"); 169*6115d2f3SKarsten Keil MODULE_LICENSE("GPL v2"); 170*6115d2f3SKarsten Keil MODULE_VERSION(AVMFRITZ_REV); 171*6115d2f3SKarsten Keil module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); 172*6115d2f3SKarsten Keil MODULE_PARM_DESC(debug, "avmfritz debug mask"); 173*6115d2f3SKarsten Keil 174*6115d2f3SKarsten Keil /* Interface functions */ 175*6115d2f3SKarsten Keil 176*6115d2f3SKarsten Keil static u8 177*6115d2f3SKarsten Keil ReadISAC_V1(void *p, u8 offset) 178*6115d2f3SKarsten Keil { 179*6115d2f3SKarsten Keil struct fritzcard *fc = p; 180*6115d2f3SKarsten Keil u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; 181*6115d2f3SKarsten Keil 182*6115d2f3SKarsten Keil outb(idx, fc->addr + CHIP_INDEX); 183*6115d2f3SKarsten Keil return inb(fc->addr + CHIP_WINDOW + (offset & 0xf)); 184*6115d2f3SKarsten Keil } 185*6115d2f3SKarsten Keil 186*6115d2f3SKarsten Keil static void 187*6115d2f3SKarsten Keil WriteISAC_V1(void *p, u8 offset, u8 value) 188*6115d2f3SKarsten Keil { 189*6115d2f3SKarsten Keil struct fritzcard *fc = p; 190*6115d2f3SKarsten Keil u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; 191*6115d2f3SKarsten Keil 192*6115d2f3SKarsten Keil outb(idx, fc->addr + CHIP_INDEX); 193*6115d2f3SKarsten Keil outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf)); 194*6115d2f3SKarsten Keil } 195*6115d2f3SKarsten Keil 196*6115d2f3SKarsten Keil static void 197*6115d2f3SKarsten Keil ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size) 198*6115d2f3SKarsten Keil { 199*6115d2f3SKarsten Keil struct fritzcard *fc = p; 200*6115d2f3SKarsten Keil 201*6115d2f3SKarsten Keil outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); 202*6115d2f3SKarsten Keil insb(fc->addr + CHIP_WINDOW, data, size); 203*6115d2f3SKarsten Keil } 204*6115d2f3SKarsten Keil 205*6115d2f3SKarsten Keil static void 206*6115d2f3SKarsten Keil WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size) 207*6115d2f3SKarsten Keil { 208*6115d2f3SKarsten Keil struct fritzcard *fc = p; 209*6115d2f3SKarsten Keil 210*6115d2f3SKarsten Keil outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX); 211*6115d2f3SKarsten Keil outsb(fc->addr + CHIP_WINDOW, data, size); 212*6115d2f3SKarsten Keil } 213*6115d2f3SKarsten Keil 214*6115d2f3SKarsten Keil static u8 215*6115d2f3SKarsten Keil ReadISAC_V2(void *p, u8 offset) 216*6115d2f3SKarsten Keil { 217*6115d2f3SKarsten Keil struct fritzcard *fc = p; 218*6115d2f3SKarsten Keil 219*6115d2f3SKarsten Keil outl(offset, fc->addr + AVM_ISACX_INDEX); 220*6115d2f3SKarsten Keil return 0xff & inl(fc->addr + AVM_ISACX_DATA); 221*6115d2f3SKarsten Keil } 222*6115d2f3SKarsten Keil 223*6115d2f3SKarsten Keil static void 224*6115d2f3SKarsten Keil WriteISAC_V2(void *p, u8 offset, u8 value) 225*6115d2f3SKarsten Keil { 226*6115d2f3SKarsten Keil struct fritzcard *fc = p; 227*6115d2f3SKarsten Keil 228*6115d2f3SKarsten Keil outl(offset, fc->addr + AVM_ISACX_INDEX); 229*6115d2f3SKarsten Keil outl(value, fc->addr + AVM_ISACX_DATA); 230*6115d2f3SKarsten Keil } 231*6115d2f3SKarsten Keil 232*6115d2f3SKarsten Keil static void 233*6115d2f3SKarsten Keil ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size) 234*6115d2f3SKarsten Keil { 235*6115d2f3SKarsten Keil struct fritzcard *fc = p; 236*6115d2f3SKarsten Keil int i; 237*6115d2f3SKarsten Keil 238*6115d2f3SKarsten Keil outl(off, fc->addr + AVM_ISACX_INDEX); 239*6115d2f3SKarsten Keil for (i = 0; i < size; i++) 240*6115d2f3SKarsten Keil data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA); 241*6115d2f3SKarsten Keil } 242*6115d2f3SKarsten Keil 243*6115d2f3SKarsten Keil static void 244*6115d2f3SKarsten Keil WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size) 245*6115d2f3SKarsten Keil { 246*6115d2f3SKarsten Keil struct fritzcard *fc = p; 247*6115d2f3SKarsten Keil int i; 248*6115d2f3SKarsten Keil 249*6115d2f3SKarsten Keil outl(off, fc->addr + AVM_ISACX_INDEX); 250*6115d2f3SKarsten Keil for (i = 0; i < size; i++) 251*6115d2f3SKarsten Keil outl(data[i], fc->addr + AVM_ISACX_DATA); 252*6115d2f3SKarsten Keil } 253*6115d2f3SKarsten Keil 254*6115d2f3SKarsten Keil static struct bchannel * 255*6115d2f3SKarsten Keil Sel_BCS(struct fritzcard *fc, u32 channel) 256*6115d2f3SKarsten Keil { 257*6115d2f3SKarsten Keil if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && 258*6115d2f3SKarsten Keil (fc->bch[0].nr & channel)) 259*6115d2f3SKarsten Keil return &fc->bch[0]; 260*6115d2f3SKarsten Keil else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && 261*6115d2f3SKarsten Keil (fc->bch[1].nr & channel)) 262*6115d2f3SKarsten Keil return &fc->bch[1]; 263*6115d2f3SKarsten Keil else 264*6115d2f3SKarsten Keil return NULL; 265*6115d2f3SKarsten Keil } 266*6115d2f3SKarsten Keil 267*6115d2f3SKarsten Keil static inline void 268*6115d2f3SKarsten Keil __write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { 269*6115d2f3SKarsten Keil u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1; 270*6115d2f3SKarsten Keil 271*6115d2f3SKarsten Keil outl(idx, fc->addr + CHIP_INDEX); 272*6115d2f3SKarsten Keil outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS); 273*6115d2f3SKarsten Keil } 274*6115d2f3SKarsten Keil 275*6115d2f3SKarsten Keil static inline void 276*6115d2f3SKarsten Keil __write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) { 277*6115d2f3SKarsten Keil outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 : 278*6115d2f3SKarsten Keil AVM_HDLC_STATUS_1)); 279*6115d2f3SKarsten Keil } 280*6115d2f3SKarsten Keil 281*6115d2f3SKarsten Keil void 282*6115d2f3SKarsten Keil write_ctrl(struct bchannel *bch, int which) { 283*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 284*6115d2f3SKarsten Keil struct hdlc_hw *hdlc; 285*6115d2f3SKarsten Keil 286*6115d2f3SKarsten Keil hdlc = &fc->hdlc[(bch->nr - 1) & 1]; 287*6115d2f3SKarsten Keil pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr, 288*6115d2f3SKarsten Keil which, hdlc->ctrl.ctrl); 289*6115d2f3SKarsten Keil switch (fc->type) { 290*6115d2f3SKarsten Keil case AVM_FRITZ_PCIV2: 291*6115d2f3SKarsten Keil __write_ctrl_pciv2(fc, hdlc, bch->nr); 292*6115d2f3SKarsten Keil break; 293*6115d2f3SKarsten Keil case AVM_FRITZ_PCI: 294*6115d2f3SKarsten Keil __write_ctrl_pci(fc, hdlc, bch->nr); 295*6115d2f3SKarsten Keil break; 296*6115d2f3SKarsten Keil } 297*6115d2f3SKarsten Keil } 298*6115d2f3SKarsten Keil 299*6115d2f3SKarsten Keil 300*6115d2f3SKarsten Keil static inline u32 301*6115d2f3SKarsten Keil __read_status_pci(u_long addr, u32 channel) 302*6115d2f3SKarsten Keil { 303*6115d2f3SKarsten Keil outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX); 304*6115d2f3SKarsten Keil return inl(addr + CHIP_WINDOW + HDLC_STATUS); 305*6115d2f3SKarsten Keil } 306*6115d2f3SKarsten Keil 307*6115d2f3SKarsten Keil static inline u32 308*6115d2f3SKarsten Keil __read_status_pciv2(u_long addr, u32 channel) 309*6115d2f3SKarsten Keil { 310*6115d2f3SKarsten Keil return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 : 311*6115d2f3SKarsten Keil AVM_HDLC_STATUS_1)); 312*6115d2f3SKarsten Keil } 313*6115d2f3SKarsten Keil 314*6115d2f3SKarsten Keil 315*6115d2f3SKarsten Keil static u32 316*6115d2f3SKarsten Keil read_status(struct fritzcard *fc, u32 channel) 317*6115d2f3SKarsten Keil { 318*6115d2f3SKarsten Keil switch (fc->type) { 319*6115d2f3SKarsten Keil case AVM_FRITZ_PCIV2: 320*6115d2f3SKarsten Keil return __read_status_pciv2(fc->addr, channel); 321*6115d2f3SKarsten Keil case AVM_FRITZ_PCI: 322*6115d2f3SKarsten Keil return __read_status_pci(fc->addr, channel); 323*6115d2f3SKarsten Keil } 324*6115d2f3SKarsten Keil /* dummy */ 325*6115d2f3SKarsten Keil return 0; 326*6115d2f3SKarsten Keil } 327*6115d2f3SKarsten Keil 328*6115d2f3SKarsten Keil static void 329*6115d2f3SKarsten Keil enable_hwirq(struct fritzcard *fc) 330*6115d2f3SKarsten Keil { 331*6115d2f3SKarsten Keil fc->ctrlreg |= AVM_STATUS0_ENA_IRQ; 332*6115d2f3SKarsten Keil outb(fc->ctrlreg, fc->addr + 2); 333*6115d2f3SKarsten Keil } 334*6115d2f3SKarsten Keil 335*6115d2f3SKarsten Keil static void 336*6115d2f3SKarsten Keil disable_hwirq(struct fritzcard *fc) 337*6115d2f3SKarsten Keil { 338*6115d2f3SKarsten Keil fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ; 339*6115d2f3SKarsten Keil outb(fc->ctrlreg, fc->addr + 2); 340*6115d2f3SKarsten Keil } 341*6115d2f3SKarsten Keil 342*6115d2f3SKarsten Keil static int 343*6115d2f3SKarsten Keil modehdlc(struct bchannel *bch, int protocol) 344*6115d2f3SKarsten Keil { 345*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 346*6115d2f3SKarsten Keil struct hdlc_hw *hdlc; 347*6115d2f3SKarsten Keil 348*6115d2f3SKarsten Keil hdlc = &fc->hdlc[(bch->nr - 1) & 1]; 349*6115d2f3SKarsten Keil pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name, 350*6115d2f3SKarsten Keil '@' + bch->nr, bch->state, protocol, bch->nr); 351*6115d2f3SKarsten Keil hdlc->ctrl.ctrl = 0; 352*6115d2f3SKarsten Keil switch (protocol) { 353*6115d2f3SKarsten Keil case -1: /* used for init */ 354*6115d2f3SKarsten Keil bch->state = -1; 355*6115d2f3SKarsten Keil case ISDN_P_NONE: 356*6115d2f3SKarsten Keil if (bch->state == ISDN_P_NONE) 357*6115d2f3SKarsten Keil break; 358*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; 359*6115d2f3SKarsten Keil hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; 360*6115d2f3SKarsten Keil write_ctrl(bch, 5); 361*6115d2f3SKarsten Keil bch->state = ISDN_P_NONE; 362*6115d2f3SKarsten Keil test_and_clear_bit(FLG_HDLC, &bch->Flags); 363*6115d2f3SKarsten Keil test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags); 364*6115d2f3SKarsten Keil break; 365*6115d2f3SKarsten Keil case ISDN_P_B_RAW: 366*6115d2f3SKarsten Keil bch->state = protocol; 367*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; 368*6115d2f3SKarsten Keil hdlc->ctrl.sr.mode = HDLC_MODE_TRANS; 369*6115d2f3SKarsten Keil write_ctrl(bch, 5); 370*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; 371*6115d2f3SKarsten Keil write_ctrl(bch, 1); 372*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = 0; 373*6115d2f3SKarsten Keil test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); 374*6115d2f3SKarsten Keil break; 375*6115d2f3SKarsten Keil case ISDN_P_B_HDLC: 376*6115d2f3SKarsten Keil bch->state = protocol; 377*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; 378*6115d2f3SKarsten Keil hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG; 379*6115d2f3SKarsten Keil write_ctrl(bch, 5); 380*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = HDLC_CMD_XRS; 381*6115d2f3SKarsten Keil write_ctrl(bch, 1); 382*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd = 0; 383*6115d2f3SKarsten Keil test_and_set_bit(FLG_HDLC, &bch->Flags); 384*6115d2f3SKarsten Keil break; 385*6115d2f3SKarsten Keil default: 386*6115d2f3SKarsten Keil pr_info("%s: protocol not known %x\n", fc->name, protocol); 387*6115d2f3SKarsten Keil return -ENOPROTOOPT; 388*6115d2f3SKarsten Keil } 389*6115d2f3SKarsten Keil return 0; 390*6115d2f3SKarsten Keil } 391*6115d2f3SKarsten Keil 392*6115d2f3SKarsten Keil static void 393*6115d2f3SKarsten Keil hdlc_empty_fifo(struct bchannel *bch, int count) 394*6115d2f3SKarsten Keil { 395*6115d2f3SKarsten Keil u32 *ptr; 396*6115d2f3SKarsten Keil u8 *p; 397*6115d2f3SKarsten Keil u32 val, addr; 398*6115d2f3SKarsten Keil int cnt = 0; 399*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 400*6115d2f3SKarsten Keil 401*6115d2f3SKarsten Keil pr_debug("%s: %s %d\n", fc->name, __func__, count); 402*6115d2f3SKarsten Keil if (!bch->rx_skb) { 403*6115d2f3SKarsten Keil bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); 404*6115d2f3SKarsten Keil if (!bch->rx_skb) { 405*6115d2f3SKarsten Keil pr_info("%s: B receive out of memory\n", 406*6115d2f3SKarsten Keil fc->name); 407*6115d2f3SKarsten Keil return; 408*6115d2f3SKarsten Keil } 409*6115d2f3SKarsten Keil } 410*6115d2f3SKarsten Keil if ((bch->rx_skb->len + count) > bch->maxlen) { 411*6115d2f3SKarsten Keil pr_debug("%s: overrun %d\n", fc->name, 412*6115d2f3SKarsten Keil bch->rx_skb->len + count); 413*6115d2f3SKarsten Keil return; 414*6115d2f3SKarsten Keil } 415*6115d2f3SKarsten Keil p = skb_put(bch->rx_skb, count); 416*6115d2f3SKarsten Keil ptr = (u32 *)p; 417*6115d2f3SKarsten Keil if (AVM_FRITZ_PCIV2 == fc->type) 418*6115d2f3SKarsten Keil addr = fc->addr + (bch->nr == 2 ? 419*6115d2f3SKarsten Keil AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); 420*6115d2f3SKarsten Keil else { 421*6115d2f3SKarsten Keil addr = fc->addr + CHIP_WINDOW; 422*6115d2f3SKarsten Keil outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); 423*6115d2f3SKarsten Keil } 424*6115d2f3SKarsten Keil while (cnt < count) { 425*6115d2f3SKarsten Keil val = le32_to_cpu(inl(addr)); 426*6115d2f3SKarsten Keil put_unaligned(val, ptr); 427*6115d2f3SKarsten Keil ptr++; 428*6115d2f3SKarsten Keil cnt += 4; 429*6115d2f3SKarsten Keil } 430*6115d2f3SKarsten Keil if (debug & DEBUG_HW_BFIFO) { 431*6115d2f3SKarsten Keil snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", 432*6115d2f3SKarsten Keil bch->nr, fc->name, count); 433*6115d2f3SKarsten Keil print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); 434*6115d2f3SKarsten Keil } 435*6115d2f3SKarsten Keil } 436*6115d2f3SKarsten Keil 437*6115d2f3SKarsten Keil static void 438*6115d2f3SKarsten Keil hdlc_fill_fifo(struct bchannel *bch) 439*6115d2f3SKarsten Keil { 440*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 441*6115d2f3SKarsten Keil struct hdlc_hw *hdlc; 442*6115d2f3SKarsten Keil int count, cnt = 0; 443*6115d2f3SKarsten Keil u8 *p; 444*6115d2f3SKarsten Keil u32 *ptr, val, addr; 445*6115d2f3SKarsten Keil 446*6115d2f3SKarsten Keil hdlc = &fc->hdlc[(bch->nr - 1) & 1]; 447*6115d2f3SKarsten Keil if (!bch->tx_skb) 448*6115d2f3SKarsten Keil return; 449*6115d2f3SKarsten Keil count = bch->tx_skb->len - bch->tx_idx; 450*6115d2f3SKarsten Keil if (count <= 0) 451*6115d2f3SKarsten Keil return; 452*6115d2f3SKarsten Keil p = bch->tx_skb->data + bch->tx_idx; 453*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; 454*6115d2f3SKarsten Keil if (count > HDLC_FIFO_SIZE) { 455*6115d2f3SKarsten Keil count = HDLC_FIFO_SIZE; 456*6115d2f3SKarsten Keil } else { 457*6115d2f3SKarsten Keil if (test_bit(FLG_HDLC, &bch->Flags)) 458*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; 459*6115d2f3SKarsten Keil } 460*6115d2f3SKarsten Keil pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, 461*6115d2f3SKarsten Keil bch->tx_idx, bch->tx_skb->len); 462*6115d2f3SKarsten Keil ptr = (u32 *)p; 463*6115d2f3SKarsten Keil bch->tx_idx += count; 464*6115d2f3SKarsten Keil hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count); 465*6115d2f3SKarsten Keil if (AVM_FRITZ_PCIV2 == fc->type) { 466*6115d2f3SKarsten Keil __write_ctrl_pciv2(fc, hdlc, bch->nr); 467*6115d2f3SKarsten Keil addr = fc->addr + (bch->nr == 2 ? 468*6115d2f3SKarsten Keil AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1); 469*6115d2f3SKarsten Keil } else { 470*6115d2f3SKarsten Keil __write_ctrl_pci(fc, hdlc, bch->nr); 471*6115d2f3SKarsten Keil addr = fc->addr + CHIP_WINDOW; 472*6115d2f3SKarsten Keil } 473*6115d2f3SKarsten Keil while (cnt < count) { 474*6115d2f3SKarsten Keil val = get_unaligned(ptr); 475*6115d2f3SKarsten Keil outl(cpu_to_le32(val), addr); 476*6115d2f3SKarsten Keil ptr++; 477*6115d2f3SKarsten Keil cnt += 4; 478*6115d2f3SKarsten Keil } 479*6115d2f3SKarsten Keil if (debug & DEBUG_HW_BFIFO) { 480*6115d2f3SKarsten Keil snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", 481*6115d2f3SKarsten Keil bch->nr, fc->name, count); 482*6115d2f3SKarsten Keil print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); 483*6115d2f3SKarsten Keil } 484*6115d2f3SKarsten Keil } 485*6115d2f3SKarsten Keil 486*6115d2f3SKarsten Keil static void 487*6115d2f3SKarsten Keil HDLC_irq_xpr(struct bchannel *bch) 488*6115d2f3SKarsten Keil { 489*6115d2f3SKarsten Keil if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) 490*6115d2f3SKarsten Keil hdlc_fill_fifo(bch); 491*6115d2f3SKarsten Keil else { 492*6115d2f3SKarsten Keil if (bch->tx_skb) { 493*6115d2f3SKarsten Keil /* send confirm, on trans, free on hdlc. */ 494*6115d2f3SKarsten Keil if (test_bit(FLG_TRANSPARENT, &bch->Flags)) 495*6115d2f3SKarsten Keil confirm_Bsend(bch); 496*6115d2f3SKarsten Keil dev_kfree_skb(bch->tx_skb); 497*6115d2f3SKarsten Keil } 498*6115d2f3SKarsten Keil if (get_next_bframe(bch)) 499*6115d2f3SKarsten Keil hdlc_fill_fifo(bch); 500*6115d2f3SKarsten Keil } 501*6115d2f3SKarsten Keil } 502*6115d2f3SKarsten Keil 503*6115d2f3SKarsten Keil static void 504*6115d2f3SKarsten Keil HDLC_irq(struct bchannel *bch, u32 stat) 505*6115d2f3SKarsten Keil { 506*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 507*6115d2f3SKarsten Keil int len; 508*6115d2f3SKarsten Keil struct hdlc_hw *hdlc; 509*6115d2f3SKarsten Keil 510*6115d2f3SKarsten Keil hdlc = &fc->hdlc[(bch->nr - 1) & 1]; 511*6115d2f3SKarsten Keil pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat); 512*6115d2f3SKarsten Keil if (stat & HDLC_INT_RPR) { 513*6115d2f3SKarsten Keil if (stat & HDLC_STAT_RDO) { 514*6115d2f3SKarsten Keil hdlc->ctrl.sr.xml = 0; 515*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS; 516*6115d2f3SKarsten Keil write_ctrl(bch, 1); 517*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS; 518*6115d2f3SKarsten Keil write_ctrl(bch, 1); 519*6115d2f3SKarsten Keil if (bch->rx_skb) 520*6115d2f3SKarsten Keil skb_trim(bch->rx_skb, 0); 521*6115d2f3SKarsten Keil } else { 522*6115d2f3SKarsten Keil len = (stat & HDLC_STAT_RML_MASK) >> 8; 523*6115d2f3SKarsten Keil if (!len) 524*6115d2f3SKarsten Keil len = 32; 525*6115d2f3SKarsten Keil hdlc_empty_fifo(bch, len); 526*6115d2f3SKarsten Keil if (!bch->rx_skb) 527*6115d2f3SKarsten Keil goto handle_tx; 528*6115d2f3SKarsten Keil if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, 529*6115d2f3SKarsten Keil &bch->Flags)) { 530*6115d2f3SKarsten Keil if (((stat & HDLC_STAT_CRCVFRRAB) == 531*6115d2f3SKarsten Keil HDLC_STAT_CRCVFR) || 532*6115d2f3SKarsten Keil test_bit(FLG_TRANSPARENT, &bch->Flags)) { 533*6115d2f3SKarsten Keil recv_Bchannel(bch, 0); 534*6115d2f3SKarsten Keil } else { 535*6115d2f3SKarsten Keil pr_debug("%s: got invalid frame\n", 536*6115d2f3SKarsten Keil fc->name); 537*6115d2f3SKarsten Keil skb_trim(bch->rx_skb, 0); 538*6115d2f3SKarsten Keil } 539*6115d2f3SKarsten Keil } 540*6115d2f3SKarsten Keil } 541*6115d2f3SKarsten Keil } 542*6115d2f3SKarsten Keil handle_tx: 543*6115d2f3SKarsten Keil if (stat & HDLC_INT_XDU) { 544*6115d2f3SKarsten Keil /* Here we lost an TX interrupt, so 545*6115d2f3SKarsten Keil * restart transmitting the whole frame on HDLC 546*6115d2f3SKarsten Keil * in transparent mode we send the next data 547*6115d2f3SKarsten Keil */ 548*6115d2f3SKarsten Keil if (bch->tx_skb) 549*6115d2f3SKarsten Keil pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n", 550*6115d2f3SKarsten Keil fc->name, bch->nr, bch->tx_skb->len, 551*6115d2f3SKarsten Keil bch->tx_idx, bch->Flags); 552*6115d2f3SKarsten Keil else 553*6115d2f3SKarsten Keil pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n", 554*6115d2f3SKarsten Keil fc->name, bch->nr, bch->Flags); 555*6115d2f3SKarsten Keil if (bch->tx_skb && bch->tx_skb->len) { 556*6115d2f3SKarsten Keil if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) 557*6115d2f3SKarsten Keil bch->tx_idx = 0; 558*6115d2f3SKarsten Keil } 559*6115d2f3SKarsten Keil hdlc->ctrl.sr.xml = 0; 560*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; 561*6115d2f3SKarsten Keil write_ctrl(bch, 1); 562*6115d2f3SKarsten Keil hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS; 563*6115d2f3SKarsten Keil HDLC_irq_xpr(bch); 564*6115d2f3SKarsten Keil return; 565*6115d2f3SKarsten Keil } else if (stat & HDLC_INT_XPR) 566*6115d2f3SKarsten Keil HDLC_irq_xpr(bch); 567*6115d2f3SKarsten Keil } 568*6115d2f3SKarsten Keil 569*6115d2f3SKarsten Keil static inline void 570*6115d2f3SKarsten Keil HDLC_irq_main(struct fritzcard *fc) 571*6115d2f3SKarsten Keil { 572*6115d2f3SKarsten Keil u32 stat; 573*6115d2f3SKarsten Keil struct bchannel *bch; 574*6115d2f3SKarsten Keil 575*6115d2f3SKarsten Keil stat = read_status(fc, 1); 576*6115d2f3SKarsten Keil if (stat & HDLC_INT_MASK) { 577*6115d2f3SKarsten Keil bch = Sel_BCS(fc, 1); 578*6115d2f3SKarsten Keil if (bch) 579*6115d2f3SKarsten Keil HDLC_irq(bch, stat); 580*6115d2f3SKarsten Keil else 581*6115d2f3SKarsten Keil pr_debug("%s: spurious ch1 IRQ\n", fc->name); 582*6115d2f3SKarsten Keil } 583*6115d2f3SKarsten Keil stat = read_status(fc, 2); 584*6115d2f3SKarsten Keil if (stat & HDLC_INT_MASK) { 585*6115d2f3SKarsten Keil bch = Sel_BCS(fc, 2); 586*6115d2f3SKarsten Keil if (bch) 587*6115d2f3SKarsten Keil HDLC_irq(bch, stat); 588*6115d2f3SKarsten Keil else 589*6115d2f3SKarsten Keil pr_debug("%s: spurious ch2 IRQ\n", fc->name); 590*6115d2f3SKarsten Keil } 591*6115d2f3SKarsten Keil } 592*6115d2f3SKarsten Keil 593*6115d2f3SKarsten Keil static irqreturn_t 594*6115d2f3SKarsten Keil avm_fritz_interrupt(int intno, void *dev_id) 595*6115d2f3SKarsten Keil { 596*6115d2f3SKarsten Keil struct fritzcard *fc = dev_id; 597*6115d2f3SKarsten Keil u8 val; 598*6115d2f3SKarsten Keil u8 sval; 599*6115d2f3SKarsten Keil 600*6115d2f3SKarsten Keil spin_lock(&fc->lock); 601*6115d2f3SKarsten Keil sval = inb(fc->addr + 2); 602*6115d2f3SKarsten Keil pr_debug("%s: irq stat0 %x\n", fc->name, sval); 603*6115d2f3SKarsten Keil if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { 604*6115d2f3SKarsten Keil /* shared IRQ from other HW */ 605*6115d2f3SKarsten Keil spin_unlock(&fc->lock); 606*6115d2f3SKarsten Keil return IRQ_NONE; 607*6115d2f3SKarsten Keil } 608*6115d2f3SKarsten Keil fc->irqcnt++; 609*6115d2f3SKarsten Keil 610*6115d2f3SKarsten Keil if (!(sval & AVM_STATUS0_IRQ_ISAC)) { 611*6115d2f3SKarsten Keil val = ReadISAC_V1(fc, ISAC_ISTA); 612*6115d2f3SKarsten Keil mISDNisac_irq(&fc->isac, val); 613*6115d2f3SKarsten Keil } 614*6115d2f3SKarsten Keil if (!(sval & AVM_STATUS0_IRQ_HDLC)) 615*6115d2f3SKarsten Keil HDLC_irq_main(fc); 616*6115d2f3SKarsten Keil spin_unlock(&fc->lock); 617*6115d2f3SKarsten Keil return IRQ_HANDLED; 618*6115d2f3SKarsten Keil } 619*6115d2f3SKarsten Keil 620*6115d2f3SKarsten Keil static irqreturn_t 621*6115d2f3SKarsten Keil avm_fritzv2_interrupt(int intno, void *dev_id) 622*6115d2f3SKarsten Keil { 623*6115d2f3SKarsten Keil struct fritzcard *fc = dev_id; 624*6115d2f3SKarsten Keil u8 val; 625*6115d2f3SKarsten Keil u8 sval; 626*6115d2f3SKarsten Keil 627*6115d2f3SKarsten Keil spin_lock(&fc->lock); 628*6115d2f3SKarsten Keil sval = inb(fc->addr + 2); 629*6115d2f3SKarsten Keil pr_debug("%s: irq stat0 %x\n", fc->name, sval); 630*6115d2f3SKarsten Keil if (!(sval & AVM_STATUS0_IRQ_MASK)) { 631*6115d2f3SKarsten Keil /* shared IRQ from other HW */ 632*6115d2f3SKarsten Keil spin_unlock(&fc->lock); 633*6115d2f3SKarsten Keil return IRQ_NONE; 634*6115d2f3SKarsten Keil } 635*6115d2f3SKarsten Keil fc->irqcnt++; 636*6115d2f3SKarsten Keil 637*6115d2f3SKarsten Keil if (sval & AVM_STATUS0_IRQ_HDLC) 638*6115d2f3SKarsten Keil HDLC_irq_main(fc); 639*6115d2f3SKarsten Keil if (sval & AVM_STATUS0_IRQ_ISAC) { 640*6115d2f3SKarsten Keil val = ReadISAC_V2(fc, ISACX_ISTA); 641*6115d2f3SKarsten Keil mISDNisac_irq(&fc->isac, val); 642*6115d2f3SKarsten Keil } 643*6115d2f3SKarsten Keil if (sval & AVM_STATUS0_IRQ_TIMER) { 644*6115d2f3SKarsten Keil pr_debug("%s: timer irq\n", fc->name); 645*6115d2f3SKarsten Keil outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2); 646*6115d2f3SKarsten Keil udelay(1); 647*6115d2f3SKarsten Keil outb(fc->ctrlreg, fc->addr + 2); 648*6115d2f3SKarsten Keil } 649*6115d2f3SKarsten Keil spin_unlock(&fc->lock); 650*6115d2f3SKarsten Keil return IRQ_HANDLED; 651*6115d2f3SKarsten Keil } 652*6115d2f3SKarsten Keil 653*6115d2f3SKarsten Keil static int 654*6115d2f3SKarsten Keil avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) 655*6115d2f3SKarsten Keil { 656*6115d2f3SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 657*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 658*6115d2f3SKarsten Keil int ret = -EINVAL; 659*6115d2f3SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb); 660*6115d2f3SKarsten Keil u32 id; 661*6115d2f3SKarsten Keil u_long flags; 662*6115d2f3SKarsten Keil 663*6115d2f3SKarsten Keil switch (hh->prim) { 664*6115d2f3SKarsten Keil case PH_DATA_REQ: 665*6115d2f3SKarsten Keil spin_lock_irqsave(&fc->lock, flags); 666*6115d2f3SKarsten Keil ret = bchannel_senddata(bch, skb); 667*6115d2f3SKarsten Keil if (ret > 0) { /* direct TX */ 668*6115d2f3SKarsten Keil id = hh->id; /* skb can be freed */ 669*6115d2f3SKarsten Keil hdlc_fill_fifo(bch); 670*6115d2f3SKarsten Keil ret = 0; 671*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 672*6115d2f3SKarsten Keil if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) 673*6115d2f3SKarsten Keil queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 674*6115d2f3SKarsten Keil } else 675*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 676*6115d2f3SKarsten Keil return ret; 677*6115d2f3SKarsten Keil case PH_ACTIVATE_REQ: 678*6115d2f3SKarsten Keil spin_lock_irqsave(&fc->lock, flags); 679*6115d2f3SKarsten Keil if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 680*6115d2f3SKarsten Keil ret = modehdlc(bch, ch->protocol); 681*6115d2f3SKarsten Keil else 682*6115d2f3SKarsten Keil ret = 0; 683*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 684*6115d2f3SKarsten Keil if (!ret) 685*6115d2f3SKarsten Keil _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 686*6115d2f3SKarsten Keil NULL, GFP_KERNEL); 687*6115d2f3SKarsten Keil break; 688*6115d2f3SKarsten Keil case PH_DEACTIVATE_REQ: 689*6115d2f3SKarsten Keil spin_lock_irqsave(&fc->lock, flags); 690*6115d2f3SKarsten Keil mISDN_clear_bchannel(bch); 691*6115d2f3SKarsten Keil modehdlc(bch, ISDN_P_NONE); 692*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 693*6115d2f3SKarsten Keil _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 694*6115d2f3SKarsten Keil NULL, GFP_KERNEL); 695*6115d2f3SKarsten Keil ret = 0; 696*6115d2f3SKarsten Keil break; 697*6115d2f3SKarsten Keil } 698*6115d2f3SKarsten Keil if (!ret) 699*6115d2f3SKarsten Keil dev_kfree_skb(skb); 700*6115d2f3SKarsten Keil return ret; 701*6115d2f3SKarsten Keil } 702*6115d2f3SKarsten Keil 703*6115d2f3SKarsten Keil static void 704*6115d2f3SKarsten Keil inithdlc(struct fritzcard *fc) 705*6115d2f3SKarsten Keil { 706*6115d2f3SKarsten Keil modehdlc(&fc->bch[0], -1); 707*6115d2f3SKarsten Keil modehdlc(&fc->bch[1], -1); 708*6115d2f3SKarsten Keil } 709*6115d2f3SKarsten Keil 710*6115d2f3SKarsten Keil void 711*6115d2f3SKarsten Keil clear_pending_hdlc_ints(struct fritzcard *fc) 712*6115d2f3SKarsten Keil { 713*6115d2f3SKarsten Keil u32 val; 714*6115d2f3SKarsten Keil 715*6115d2f3SKarsten Keil val = read_status(fc, 1); 716*6115d2f3SKarsten Keil pr_debug("%s: HDLC 1 STA %x\n", fc->name, val); 717*6115d2f3SKarsten Keil val = read_status(fc, 2); 718*6115d2f3SKarsten Keil pr_debug("%s: HDLC 2 STA %x\n", fc->name, val); 719*6115d2f3SKarsten Keil } 720*6115d2f3SKarsten Keil 721*6115d2f3SKarsten Keil static void 722*6115d2f3SKarsten Keil reset_avm(struct fritzcard *fc) 723*6115d2f3SKarsten Keil { 724*6115d2f3SKarsten Keil switch (fc->type) { 725*6115d2f3SKarsten Keil case AVM_FRITZ_PCI: 726*6115d2f3SKarsten Keil fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER; 727*6115d2f3SKarsten Keil break; 728*6115d2f3SKarsten Keil case AVM_FRITZ_PCIV2: 729*6115d2f3SKarsten Keil fc->ctrlreg = AVM_STATUS0_RESET; 730*6115d2f3SKarsten Keil break; 731*6115d2f3SKarsten Keil } 732*6115d2f3SKarsten Keil if (debug & DEBUG_HW) 733*6115d2f3SKarsten Keil pr_notice("%s: reset\n", fc->name); 734*6115d2f3SKarsten Keil disable_hwirq(fc); 735*6115d2f3SKarsten Keil mdelay(5); 736*6115d2f3SKarsten Keil switch (fc->type) { 737*6115d2f3SKarsten Keil case AVM_FRITZ_PCI: 738*6115d2f3SKarsten Keil fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER; 739*6115d2f3SKarsten Keil disable_hwirq(fc); 740*6115d2f3SKarsten Keil outb(AVM_STATUS1_ENA_IOM, fc->addr + 3); 741*6115d2f3SKarsten Keil break; 742*6115d2f3SKarsten Keil case AVM_FRITZ_PCIV2: 743*6115d2f3SKarsten Keil fc->ctrlreg = 0; 744*6115d2f3SKarsten Keil disable_hwirq(fc); 745*6115d2f3SKarsten Keil break; 746*6115d2f3SKarsten Keil } 747*6115d2f3SKarsten Keil mdelay(1); 748*6115d2f3SKarsten Keil if (debug & DEBUG_HW) 749*6115d2f3SKarsten Keil pr_notice("%s: S0/S1 %x/%x\n", fc->name, 750*6115d2f3SKarsten Keil inb(fc->addr + 2), inb(fc->addr + 3)); 751*6115d2f3SKarsten Keil } 752*6115d2f3SKarsten Keil 753*6115d2f3SKarsten Keil static int 754*6115d2f3SKarsten Keil init_card(struct fritzcard *fc) 755*6115d2f3SKarsten Keil { 756*6115d2f3SKarsten Keil int ret, cnt = 3; 757*6115d2f3SKarsten Keil u_long flags; 758*6115d2f3SKarsten Keil 759*6115d2f3SKarsten Keil reset_avm(fc); /* disable IRQ */ 760*6115d2f3SKarsten Keil if (fc->type == AVM_FRITZ_PCIV2) 761*6115d2f3SKarsten Keil ret = request_irq(fc->irq, avm_fritzv2_interrupt, 762*6115d2f3SKarsten Keil IRQF_SHARED, fc->name, fc); 763*6115d2f3SKarsten Keil else 764*6115d2f3SKarsten Keil ret = request_irq(fc->irq, avm_fritz_interrupt, 765*6115d2f3SKarsten Keil IRQF_SHARED, fc->name, fc); 766*6115d2f3SKarsten Keil if (ret) { 767*6115d2f3SKarsten Keil pr_info("%s: couldn't get interrupt %d\n", 768*6115d2f3SKarsten Keil fc->name, fc->irq); 769*6115d2f3SKarsten Keil return ret; 770*6115d2f3SKarsten Keil } 771*6115d2f3SKarsten Keil while (cnt--) { 772*6115d2f3SKarsten Keil spin_lock_irqsave(&fc->lock, flags); 773*6115d2f3SKarsten Keil ret = fc->isac.init(&fc->isac); 774*6115d2f3SKarsten Keil if (ret) { 775*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 776*6115d2f3SKarsten Keil pr_info("%s: ISAC init failed with %d\n", 777*6115d2f3SKarsten Keil fc->name, ret); 778*6115d2f3SKarsten Keil break; 779*6115d2f3SKarsten Keil } 780*6115d2f3SKarsten Keil clear_pending_hdlc_ints(fc); 781*6115d2f3SKarsten Keil inithdlc(fc); 782*6115d2f3SKarsten Keil enable_hwirq(fc); 783*6115d2f3SKarsten Keil /* RESET Receiver and Transmitter */ 784*6115d2f3SKarsten Keil if (AVM_FRITZ_PCIV2 == fc->type) { 785*6115d2f3SKarsten Keil WriteISAC_V2(fc, ISACX_MASK, 0); 786*6115d2f3SKarsten Keil WriteISAC_V2(fc, ISACX_CMDRD, 0x41); 787*6115d2f3SKarsten Keil } else { 788*6115d2f3SKarsten Keil WriteISAC_V1(fc, ISAC_MASK, 0); 789*6115d2f3SKarsten Keil WriteISAC_V1(fc, ISAC_CMDR, 0x41); 790*6115d2f3SKarsten Keil } 791*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 792*6115d2f3SKarsten Keil /* Timeout 10ms */ 793*6115d2f3SKarsten Keil msleep_interruptible(10); 794*6115d2f3SKarsten Keil if (debug & DEBUG_HW) 795*6115d2f3SKarsten Keil pr_notice("%s: IRQ %d count %d\n", fc->name, 796*6115d2f3SKarsten Keil fc->irq, fc->irqcnt); 797*6115d2f3SKarsten Keil if (!fc->irqcnt) { 798*6115d2f3SKarsten Keil pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", 799*6115d2f3SKarsten Keil fc->name, fc->irq, 3 - cnt); 800*6115d2f3SKarsten Keil reset_avm(fc); 801*6115d2f3SKarsten Keil } else 802*6115d2f3SKarsten Keil return 0; 803*6115d2f3SKarsten Keil } 804*6115d2f3SKarsten Keil free_irq(fc->irq, fc); 805*6115d2f3SKarsten Keil return -EIO; 806*6115d2f3SKarsten Keil } 807*6115d2f3SKarsten Keil 808*6115d2f3SKarsten Keil static int 809*6115d2f3SKarsten Keil channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 810*6115d2f3SKarsten Keil { 811*6115d2f3SKarsten Keil int ret = 0; 812*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 813*6115d2f3SKarsten Keil 814*6115d2f3SKarsten Keil switch (cq->op) { 815*6115d2f3SKarsten Keil case MISDN_CTRL_GETOP: 816*6115d2f3SKarsten Keil cq->op = 0; 817*6115d2f3SKarsten Keil break; 818*6115d2f3SKarsten Keil /* Nothing implemented yet */ 819*6115d2f3SKarsten Keil case MISDN_CTRL_FILL_EMPTY: 820*6115d2f3SKarsten Keil default: 821*6115d2f3SKarsten Keil pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); 822*6115d2f3SKarsten Keil ret = -EINVAL; 823*6115d2f3SKarsten Keil break; 824*6115d2f3SKarsten Keil } 825*6115d2f3SKarsten Keil return ret; 826*6115d2f3SKarsten Keil } 827*6115d2f3SKarsten Keil 828*6115d2f3SKarsten Keil static int 829*6115d2f3SKarsten Keil avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 830*6115d2f3SKarsten Keil { 831*6115d2f3SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 832*6115d2f3SKarsten Keil struct fritzcard *fc = bch->hw; 833*6115d2f3SKarsten Keil int ret = -EINVAL; 834*6115d2f3SKarsten Keil u_long flags; 835*6115d2f3SKarsten Keil 836*6115d2f3SKarsten Keil pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); 837*6115d2f3SKarsten Keil switch (cmd) { 838*6115d2f3SKarsten Keil case CLOSE_CHANNEL: 839*6115d2f3SKarsten Keil test_and_clear_bit(FLG_OPEN, &bch->Flags); 840*6115d2f3SKarsten Keil if (test_bit(FLG_ACTIVE, &bch->Flags)) { 841*6115d2f3SKarsten Keil spin_lock_irqsave(&fc->lock, flags); 842*6115d2f3SKarsten Keil mISDN_freebchannel(bch); 843*6115d2f3SKarsten Keil test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); 844*6115d2f3SKarsten Keil test_and_clear_bit(FLG_ACTIVE, &bch->Flags); 845*6115d2f3SKarsten Keil modehdlc(bch, ISDN_P_NONE); 846*6115d2f3SKarsten Keil spin_unlock_irqrestore(&fc->lock, flags); 847*6115d2f3SKarsten Keil } 848*6115d2f3SKarsten Keil ch->protocol = ISDN_P_NONE; 849*6115d2f3SKarsten Keil ch->peer = NULL; 850*6115d2f3SKarsten Keil module_put(THIS_MODULE); 851*6115d2f3SKarsten Keil ret = 0; 852*6115d2f3SKarsten Keil break; 853*6115d2f3SKarsten Keil case CONTROL_CHANNEL: 854*6115d2f3SKarsten Keil ret = channel_bctrl(bch, arg); 855*6115d2f3SKarsten Keil break; 856*6115d2f3SKarsten Keil default: 857*6115d2f3SKarsten Keil pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd); 858*6115d2f3SKarsten Keil } 859*6115d2f3SKarsten Keil return ret; 860*6115d2f3SKarsten Keil } 861*6115d2f3SKarsten Keil 862*6115d2f3SKarsten Keil static int 863*6115d2f3SKarsten Keil channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq) 864*6115d2f3SKarsten Keil { 865*6115d2f3SKarsten Keil int ret = 0; 866*6115d2f3SKarsten Keil 867*6115d2f3SKarsten Keil switch (cq->op) { 868*6115d2f3SKarsten Keil case MISDN_CTRL_GETOP: 869*6115d2f3SKarsten Keil cq->op = MISDN_CTRL_LOOP; 870*6115d2f3SKarsten Keil break; 871*6115d2f3SKarsten Keil case MISDN_CTRL_LOOP: 872*6115d2f3SKarsten Keil /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ 873*6115d2f3SKarsten Keil if (cq->channel < 0 || cq->channel > 3) { 874*6115d2f3SKarsten Keil ret = -EINVAL; 875*6115d2f3SKarsten Keil break; 876*6115d2f3SKarsten Keil } 877*6115d2f3SKarsten Keil ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel); 878*6115d2f3SKarsten Keil break; 879*6115d2f3SKarsten Keil default: 880*6115d2f3SKarsten Keil pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); 881*6115d2f3SKarsten Keil ret = -EINVAL; 882*6115d2f3SKarsten Keil break; 883*6115d2f3SKarsten Keil } 884*6115d2f3SKarsten Keil return ret; 885*6115d2f3SKarsten Keil } 886*6115d2f3SKarsten Keil 887*6115d2f3SKarsten Keil static int 888*6115d2f3SKarsten Keil open_bchannel(struct fritzcard *fc, struct channel_req *rq) 889*6115d2f3SKarsten Keil { 890*6115d2f3SKarsten Keil struct bchannel *bch; 891*6115d2f3SKarsten Keil 892*6115d2f3SKarsten Keil if (rq->adr.channel > 2) 893*6115d2f3SKarsten Keil return -EINVAL; 894*6115d2f3SKarsten Keil if (rq->protocol == ISDN_P_NONE) 895*6115d2f3SKarsten Keil return -EINVAL; 896*6115d2f3SKarsten Keil bch = &fc->bch[rq->adr.channel - 1]; 897*6115d2f3SKarsten Keil if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 898*6115d2f3SKarsten Keil return -EBUSY; /* b-channel can be only open once */ 899*6115d2f3SKarsten Keil test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); 900*6115d2f3SKarsten Keil bch->ch.protocol = rq->protocol; 901*6115d2f3SKarsten Keil rq->ch = &bch->ch; 902*6115d2f3SKarsten Keil return 0; 903*6115d2f3SKarsten Keil } 904*6115d2f3SKarsten Keil 905*6115d2f3SKarsten Keil /* 906*6115d2f3SKarsten Keil * device control function 907*6115d2f3SKarsten Keil */ 908*6115d2f3SKarsten Keil static int 909*6115d2f3SKarsten Keil avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 910*6115d2f3SKarsten Keil { 911*6115d2f3SKarsten Keil struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 912*6115d2f3SKarsten Keil struct dchannel *dch = container_of(dev, struct dchannel, dev); 913*6115d2f3SKarsten Keil struct fritzcard *fc = dch->hw; 914*6115d2f3SKarsten Keil struct channel_req *rq; 915*6115d2f3SKarsten Keil int err = 0; 916*6115d2f3SKarsten Keil 917*6115d2f3SKarsten Keil pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg); 918*6115d2f3SKarsten Keil switch (cmd) { 919*6115d2f3SKarsten Keil case OPEN_CHANNEL: 920*6115d2f3SKarsten Keil rq = arg; 921*6115d2f3SKarsten Keil if (rq->protocol == ISDN_P_TE_S0) 922*6115d2f3SKarsten Keil err = fc->isac.open(&fc->isac, rq); 923*6115d2f3SKarsten Keil else 924*6115d2f3SKarsten Keil err = open_bchannel(fc, rq); 925*6115d2f3SKarsten Keil if (err) 926*6115d2f3SKarsten Keil break; 927*6115d2f3SKarsten Keil if (!try_module_get(THIS_MODULE)) 928*6115d2f3SKarsten Keil pr_info("%s: cannot get module\n", fc->name); 929*6115d2f3SKarsten Keil break; 930*6115d2f3SKarsten Keil case CLOSE_CHANNEL: 931*6115d2f3SKarsten Keil pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id, 932*6115d2f3SKarsten Keil __builtin_return_address(0)); 933*6115d2f3SKarsten Keil module_put(THIS_MODULE); 934*6115d2f3SKarsten Keil break; 935*6115d2f3SKarsten Keil case CONTROL_CHANNEL: 936*6115d2f3SKarsten Keil err = channel_ctrl(fc, arg); 937*6115d2f3SKarsten Keil break; 938*6115d2f3SKarsten Keil default: 939*6115d2f3SKarsten Keil pr_debug("%s: %s unknown command %x\n", 940*6115d2f3SKarsten Keil fc->name, __func__, cmd); 941*6115d2f3SKarsten Keil return -EINVAL; 942*6115d2f3SKarsten Keil } 943*6115d2f3SKarsten Keil return err; 944*6115d2f3SKarsten Keil } 945*6115d2f3SKarsten Keil 946*6115d2f3SKarsten Keil int 947*6115d2f3SKarsten Keil setup_fritz(struct fritzcard *fc) 948*6115d2f3SKarsten Keil { 949*6115d2f3SKarsten Keil u32 val, ver; 950*6115d2f3SKarsten Keil 951*6115d2f3SKarsten Keil if (!request_region(fc->addr, 32, fc->name)) { 952*6115d2f3SKarsten Keil pr_info("%s: AVM config port %x-%x already in use\n", 953*6115d2f3SKarsten Keil fc->name, fc->addr, fc->addr + 31); 954*6115d2f3SKarsten Keil return -EIO; 955*6115d2f3SKarsten Keil } 956*6115d2f3SKarsten Keil switch (fc->type) { 957*6115d2f3SKarsten Keil case AVM_FRITZ_PCI: 958*6115d2f3SKarsten Keil val = inl(fc->addr); 959*6115d2f3SKarsten Keil outl(AVM_HDLC_1, fc->addr + CHIP_INDEX); 960*6115d2f3SKarsten Keil ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24; 961*6115d2f3SKarsten Keil if (debug & DEBUG_HW) { 962*6115d2f3SKarsten Keil pr_notice("%s: PCI stat %#x\n", fc->name, val); 963*6115d2f3SKarsten Keil pr_notice("%s: PCI Class %X Rev %d\n", fc->name, 964*6115d2f3SKarsten Keil val & 0xff, (val >> 8) & 0xff); 965*6115d2f3SKarsten Keil pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); 966*6115d2f3SKarsten Keil } 967*6115d2f3SKarsten Keil ASSIGN_FUNC(V1, ISAC, fc->isac); 968*6115d2f3SKarsten Keil fc->isac.type = IPAC_TYPE_ISAC; 969*6115d2f3SKarsten Keil break; 970*6115d2f3SKarsten Keil case AVM_FRITZ_PCIV2: 971*6115d2f3SKarsten Keil val = inl(fc->addr); 972*6115d2f3SKarsten Keil ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24; 973*6115d2f3SKarsten Keil if (debug & DEBUG_HW) { 974*6115d2f3SKarsten Keil pr_notice("%s: PCI V2 stat %#x\n", fc->name, val); 975*6115d2f3SKarsten Keil pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name, 976*6115d2f3SKarsten Keil val & 0xff, (val>>8) & 0xff); 977*6115d2f3SKarsten Keil pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf); 978*6115d2f3SKarsten Keil } 979*6115d2f3SKarsten Keil ASSIGN_FUNC(V2, ISAC, fc->isac); 980*6115d2f3SKarsten Keil fc->isac.type = IPAC_TYPE_ISACX; 981*6115d2f3SKarsten Keil break; 982*6115d2f3SKarsten Keil default: 983*6115d2f3SKarsten Keil release_region(fc->addr, 32); 984*6115d2f3SKarsten Keil pr_info("%s: AVM unknown type %d\n", fc->name, fc->type); 985*6115d2f3SKarsten Keil return -ENODEV; 986*6115d2f3SKarsten Keil } 987*6115d2f3SKarsten Keil pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name, 988*6115d2f3SKarsten Keil (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" : 989*6115d2f3SKarsten Keil "AVM Fritz!CARD PCIv2", fc->irq, fc->addr); 990*6115d2f3SKarsten Keil return 0; 991*6115d2f3SKarsten Keil } 992*6115d2f3SKarsten Keil 993*6115d2f3SKarsten Keil static void 994*6115d2f3SKarsten Keil release_card(struct fritzcard *card) 995*6115d2f3SKarsten Keil { 996*6115d2f3SKarsten Keil u_long flags; 997*6115d2f3SKarsten Keil 998*6115d2f3SKarsten Keil disable_hwirq(card); 999*6115d2f3SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1000*6115d2f3SKarsten Keil modehdlc(&card->bch[0], ISDN_P_NONE); 1001*6115d2f3SKarsten Keil modehdlc(&card->bch[1], ISDN_P_NONE); 1002*6115d2f3SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1003*6115d2f3SKarsten Keil card->isac.release(&card->isac); 1004*6115d2f3SKarsten Keil free_irq(card->irq, card); 1005*6115d2f3SKarsten Keil mISDN_freebchannel(&card->bch[1]); 1006*6115d2f3SKarsten Keil mISDN_freebchannel(&card->bch[0]); 1007*6115d2f3SKarsten Keil mISDN_unregister_device(&card->isac.dch.dev); 1008*6115d2f3SKarsten Keil release_region(card->addr, 32); 1009*6115d2f3SKarsten Keil pci_disable_device(card->pdev); 1010*6115d2f3SKarsten Keil pci_set_drvdata(card->pdev, NULL); 1011*6115d2f3SKarsten Keil write_lock_irqsave(&card_lock, flags); 1012*6115d2f3SKarsten Keil list_del(&card->list); 1013*6115d2f3SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1014*6115d2f3SKarsten Keil kfree(card); 1015*6115d2f3SKarsten Keil AVM_cnt--; 1016*6115d2f3SKarsten Keil } 1017*6115d2f3SKarsten Keil 1018*6115d2f3SKarsten Keil static int __devinit 1019*6115d2f3SKarsten Keil setup_instance(struct fritzcard *card) 1020*6115d2f3SKarsten Keil { 1021*6115d2f3SKarsten Keil int i, err; 1022*6115d2f3SKarsten Keil u_long flags; 1023*6115d2f3SKarsten Keil 1024*6115d2f3SKarsten Keil snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); 1025*6115d2f3SKarsten Keil write_lock_irqsave(&card_lock, flags); 1026*6115d2f3SKarsten Keil list_add_tail(&card->list, &Cards); 1027*6115d2f3SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1028*6115d2f3SKarsten Keil 1029*6115d2f3SKarsten Keil _set_debug(card); 1030*6115d2f3SKarsten Keil card->isac.name = card->name; 1031*6115d2f3SKarsten Keil spin_lock_init(&card->lock); 1032*6115d2f3SKarsten Keil card->isac.hwlock = &card->lock; 1033*6115d2f3SKarsten Keil mISDNisac_init(&card->isac, card); 1034*6115d2f3SKarsten Keil 1035*6115d2f3SKarsten Keil card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 1036*6115d2f3SKarsten Keil (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 1037*6115d2f3SKarsten Keil card->isac.dch.dev.D.ctrl = avm_dctrl; 1038*6115d2f3SKarsten Keil for (i = 0; i < 2; i++) { 1039*6115d2f3SKarsten Keil card->bch[i].nr = i + 1; 1040*6115d2f3SKarsten Keil set_channelmap(i + 1, card->isac.dch.dev.channelmap); 1041*6115d2f3SKarsten Keil mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); 1042*6115d2f3SKarsten Keil card->bch[i].hw = card; 1043*6115d2f3SKarsten Keil card->bch[i].ch.send = avm_l2l1B; 1044*6115d2f3SKarsten Keil card->bch[i].ch.ctrl = avm_bctrl; 1045*6115d2f3SKarsten Keil card->bch[i].ch.nr = i + 1; 1046*6115d2f3SKarsten Keil list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels); 1047*6115d2f3SKarsten Keil } 1048*6115d2f3SKarsten Keil err = setup_fritz(card); 1049*6115d2f3SKarsten Keil if (err) 1050*6115d2f3SKarsten Keil goto error; 1051*6115d2f3SKarsten Keil err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev, 1052*6115d2f3SKarsten Keil card->name); 1053*6115d2f3SKarsten Keil if (err) 1054*6115d2f3SKarsten Keil goto error_reg; 1055*6115d2f3SKarsten Keil err = init_card(card); 1056*6115d2f3SKarsten Keil if (!err) { 1057*6115d2f3SKarsten Keil AVM_cnt++; 1058*6115d2f3SKarsten Keil pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt); 1059*6115d2f3SKarsten Keil return 0; 1060*6115d2f3SKarsten Keil } 1061*6115d2f3SKarsten Keil mISDN_unregister_device(&card->isac.dch.dev); 1062*6115d2f3SKarsten Keil error_reg: 1063*6115d2f3SKarsten Keil release_region(card->addr, 32); 1064*6115d2f3SKarsten Keil error: 1065*6115d2f3SKarsten Keil card->isac.release(&card->isac); 1066*6115d2f3SKarsten Keil mISDN_freebchannel(&card->bch[1]); 1067*6115d2f3SKarsten Keil mISDN_freebchannel(&card->bch[0]); 1068*6115d2f3SKarsten Keil write_lock_irqsave(&card_lock, flags); 1069*6115d2f3SKarsten Keil list_del(&card->list); 1070*6115d2f3SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1071*6115d2f3SKarsten Keil kfree(card); 1072*6115d2f3SKarsten Keil return err; 1073*6115d2f3SKarsten Keil } 1074*6115d2f3SKarsten Keil 1075*6115d2f3SKarsten Keil static int __devinit 1076*6115d2f3SKarsten Keil fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 1077*6115d2f3SKarsten Keil { 1078*6115d2f3SKarsten Keil int err = -ENOMEM; 1079*6115d2f3SKarsten Keil struct fritzcard *card; 1080*6115d2f3SKarsten Keil 1081*6115d2f3SKarsten Keil card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL); 1082*6115d2f3SKarsten Keil if (!card) { 1083*6115d2f3SKarsten Keil pr_info("No kmem for fritzcard\n"); 1084*6115d2f3SKarsten Keil return err; 1085*6115d2f3SKarsten Keil } 1086*6115d2f3SKarsten Keil if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) 1087*6115d2f3SKarsten Keil card->type = AVM_FRITZ_PCIV2; 1088*6115d2f3SKarsten Keil else 1089*6115d2f3SKarsten Keil card->type = AVM_FRITZ_PCI; 1090*6115d2f3SKarsten Keil card->pdev = pdev; 1091*6115d2f3SKarsten Keil err = pci_enable_device(pdev); 1092*6115d2f3SKarsten Keil if (err) { 1093*6115d2f3SKarsten Keil kfree(card); 1094*6115d2f3SKarsten Keil return err; 1095*6115d2f3SKarsten Keil } 1096*6115d2f3SKarsten Keil 1097*6115d2f3SKarsten Keil pr_notice("mISDN: found adapter %s at %s\n", 1098*6115d2f3SKarsten Keil (char *) ent->driver_data, pci_name(pdev)); 1099*6115d2f3SKarsten Keil 1100*6115d2f3SKarsten Keil card->addr = pci_resource_start(pdev, 1); 1101*6115d2f3SKarsten Keil card->irq = pdev->irq; 1102*6115d2f3SKarsten Keil pci_set_drvdata(pdev, card); 1103*6115d2f3SKarsten Keil err = setup_instance(card); 1104*6115d2f3SKarsten Keil if (err) 1105*6115d2f3SKarsten Keil pci_set_drvdata(pdev, NULL); 1106*6115d2f3SKarsten Keil return err; 1107*6115d2f3SKarsten Keil } 1108*6115d2f3SKarsten Keil 1109*6115d2f3SKarsten Keil static void __devexit 1110*6115d2f3SKarsten Keil fritz_remove_pci(struct pci_dev *pdev) 1111*6115d2f3SKarsten Keil { 1112*6115d2f3SKarsten Keil struct fritzcard *card = pci_get_drvdata(pdev); 1113*6115d2f3SKarsten Keil 1114*6115d2f3SKarsten Keil if (card) 1115*6115d2f3SKarsten Keil release_card(card); 1116*6115d2f3SKarsten Keil else 1117*6115d2f3SKarsten Keil if (debug) 1118*6115d2f3SKarsten Keil pr_info("%s: drvdata allready removed\n", __func__); 1119*6115d2f3SKarsten Keil } 1120*6115d2f3SKarsten Keil 1121*6115d2f3SKarsten Keil static struct pci_device_id fcpci_ids[] __devinitdata = { 1122*6115d2f3SKarsten Keil { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID, 1123*6115d2f3SKarsten Keil 0, 0, (unsigned long) "Fritz!Card PCI"}, 1124*6115d2f3SKarsten Keil { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID, 1125*6115d2f3SKarsten Keil 0, 0, (unsigned long) "Fritz!Card PCI v2" }, 1126*6115d2f3SKarsten Keil { } 1127*6115d2f3SKarsten Keil }; 1128*6115d2f3SKarsten Keil MODULE_DEVICE_TABLE(pci, fcpci_ids); 1129*6115d2f3SKarsten Keil 1130*6115d2f3SKarsten Keil static struct pci_driver fcpci_driver = { 1131*6115d2f3SKarsten Keil .name = "fcpci", 1132*6115d2f3SKarsten Keil .probe = fritzpci_probe, 1133*6115d2f3SKarsten Keil .remove = __devexit_p(fritz_remove_pci), 1134*6115d2f3SKarsten Keil .id_table = fcpci_ids, 1135*6115d2f3SKarsten Keil }; 1136*6115d2f3SKarsten Keil 1137*6115d2f3SKarsten Keil static int __init AVM_init(void) 1138*6115d2f3SKarsten Keil { 1139*6115d2f3SKarsten Keil int err; 1140*6115d2f3SKarsten Keil 1141*6115d2f3SKarsten Keil pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV); 1142*6115d2f3SKarsten Keil err = pci_register_driver(&fcpci_driver); 1143*6115d2f3SKarsten Keil return err; 1144*6115d2f3SKarsten Keil } 1145*6115d2f3SKarsten Keil 1146*6115d2f3SKarsten Keil static void __exit AVM_cleanup(void) 1147*6115d2f3SKarsten Keil { 1148*6115d2f3SKarsten Keil pci_unregister_driver(&fcpci_driver); 1149*6115d2f3SKarsten Keil } 1150*6115d2f3SKarsten Keil 1151*6115d2f3SKarsten Keil module_init(AVM_init); 1152*6115d2f3SKarsten Keil module_exit(AVM_cleanup); 1153