1*707b2ce6SKarsten Keil /* 2*707b2ce6SKarsten Keil * w6692.c mISDN driver for Winbond w6692 based cards 3*707b2ce6SKarsten Keil * 4*707b2ce6SKarsten Keil * Author Karsten Keil <kkeil@suse.de> 5*707b2ce6SKarsten Keil * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz> 6*707b2ce6SKarsten Keil * 7*707b2ce6SKarsten Keil * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 8*707b2ce6SKarsten Keil * 9*707b2ce6SKarsten Keil * This program is free software; you can redistribute it and/or modify 10*707b2ce6SKarsten Keil * it under the terms of the GNU General Public License version 2 as 11*707b2ce6SKarsten Keil * published by the Free Software Foundation. 12*707b2ce6SKarsten Keil * 13*707b2ce6SKarsten Keil * This program is distributed in the hope that it will be useful, 14*707b2ce6SKarsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*707b2ce6SKarsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*707b2ce6SKarsten Keil * GNU General Public License for more details. 17*707b2ce6SKarsten Keil * 18*707b2ce6SKarsten Keil * You should have received a copy of the GNU General Public License 19*707b2ce6SKarsten Keil * along with this program; if not, write to the Free Software 20*707b2ce6SKarsten Keil * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*707b2ce6SKarsten Keil * 22*707b2ce6SKarsten Keil */ 23*707b2ce6SKarsten Keil 24*707b2ce6SKarsten Keil #include <linux/module.h> 25*707b2ce6SKarsten Keil #include <linux/pci.h> 26*707b2ce6SKarsten Keil #include <linux/delay.h> 27*707b2ce6SKarsten Keil #include <linux/mISDNhw.h> 28*707b2ce6SKarsten Keil #include "w6692.h" 29*707b2ce6SKarsten Keil 30*707b2ce6SKarsten Keil #define W6692_REV "2.0" 31*707b2ce6SKarsten Keil 32*707b2ce6SKarsten Keil #define DBUSY_TIMER_VALUE 80 33*707b2ce6SKarsten Keil 34*707b2ce6SKarsten Keil enum { 35*707b2ce6SKarsten Keil W6692_ASUS, 36*707b2ce6SKarsten Keil W6692_WINBOND, 37*707b2ce6SKarsten Keil W6692_USR 38*707b2ce6SKarsten Keil }; 39*707b2ce6SKarsten Keil 40*707b2ce6SKarsten Keil /* private data in the PCI devices list */ 41*707b2ce6SKarsten Keil struct w6692map { 42*707b2ce6SKarsten Keil u_int subtype; 43*707b2ce6SKarsten Keil char *name; 44*707b2ce6SKarsten Keil }; 45*707b2ce6SKarsten Keil 46*707b2ce6SKarsten Keil static const struct w6692map w6692_map[] = 47*707b2ce6SKarsten Keil { 48*707b2ce6SKarsten Keil {W6692_ASUS, "Dynalink/AsusCom IS64PH"}, 49*707b2ce6SKarsten Keil {W6692_WINBOND, "Winbond W6692"}, 50*707b2ce6SKarsten Keil {W6692_USR, "USR W6692"} 51*707b2ce6SKarsten Keil }; 52*707b2ce6SKarsten Keil 53*707b2ce6SKarsten Keil #ifndef PCI_VENDOR_ID_USR 54*707b2ce6SKarsten Keil #define PCI_VENDOR_ID_USR 0x16ec 55*707b2ce6SKarsten Keil #define PCI_DEVICE_ID_USR_6692 0x3409 56*707b2ce6SKarsten Keil #endif 57*707b2ce6SKarsten Keil 58*707b2ce6SKarsten Keil struct w6692_ch { 59*707b2ce6SKarsten Keil struct bchannel bch; 60*707b2ce6SKarsten Keil u32 addr; 61*707b2ce6SKarsten Keil struct timer_list timer; 62*707b2ce6SKarsten Keil u8 b_mode; 63*707b2ce6SKarsten Keil }; 64*707b2ce6SKarsten Keil 65*707b2ce6SKarsten Keil struct w6692_hw { 66*707b2ce6SKarsten Keil struct list_head list; 67*707b2ce6SKarsten Keil struct pci_dev *pdev; 68*707b2ce6SKarsten Keil char name[MISDN_MAX_IDLEN]; 69*707b2ce6SKarsten Keil u32 irq; 70*707b2ce6SKarsten Keil u32 irqcnt; 71*707b2ce6SKarsten Keil u32 addr; 72*707b2ce6SKarsten Keil u32 fmask; /* feature mask - bit set per card nr */ 73*707b2ce6SKarsten Keil int subtype; 74*707b2ce6SKarsten Keil spinlock_t lock; /* hw lock */ 75*707b2ce6SKarsten Keil u8 imask; 76*707b2ce6SKarsten Keil u8 pctl; 77*707b2ce6SKarsten Keil u8 xaddr; 78*707b2ce6SKarsten Keil u8 xdata; 79*707b2ce6SKarsten Keil u8 state; 80*707b2ce6SKarsten Keil struct w6692_ch bc[2]; 81*707b2ce6SKarsten Keil struct dchannel dch; 82*707b2ce6SKarsten Keil char log[64]; 83*707b2ce6SKarsten Keil }; 84*707b2ce6SKarsten Keil 85*707b2ce6SKarsten Keil static LIST_HEAD(Cards); 86*707b2ce6SKarsten Keil static DEFINE_RWLOCK(card_lock); /* protect Cards */ 87*707b2ce6SKarsten Keil 88*707b2ce6SKarsten Keil static int w6692_cnt; 89*707b2ce6SKarsten Keil static int debug; 90*707b2ce6SKarsten Keil static u32 led; 91*707b2ce6SKarsten Keil static u32 pots; 92*707b2ce6SKarsten Keil 93*707b2ce6SKarsten Keil static void 94*707b2ce6SKarsten Keil _set_debug(struct w6692_hw *card) 95*707b2ce6SKarsten Keil { 96*707b2ce6SKarsten Keil card->dch.debug = debug; 97*707b2ce6SKarsten Keil card->bc[0].bch.debug = debug; 98*707b2ce6SKarsten Keil card->bc[1].bch.debug = debug; 99*707b2ce6SKarsten Keil } 100*707b2ce6SKarsten Keil 101*707b2ce6SKarsten Keil static int 102*707b2ce6SKarsten Keil set_debug(const char *val, struct kernel_param *kp) 103*707b2ce6SKarsten Keil { 104*707b2ce6SKarsten Keil int ret; 105*707b2ce6SKarsten Keil struct w6692_hw *card; 106*707b2ce6SKarsten Keil 107*707b2ce6SKarsten Keil ret = param_set_uint(val, kp); 108*707b2ce6SKarsten Keil if (!ret) { 109*707b2ce6SKarsten Keil read_lock(&card_lock); 110*707b2ce6SKarsten Keil list_for_each_entry(card, &Cards, list) 111*707b2ce6SKarsten Keil _set_debug(card); 112*707b2ce6SKarsten Keil read_unlock(&card_lock); 113*707b2ce6SKarsten Keil } 114*707b2ce6SKarsten Keil return ret; 115*707b2ce6SKarsten Keil } 116*707b2ce6SKarsten Keil 117*707b2ce6SKarsten Keil MODULE_AUTHOR("Karsten Keil"); 118*707b2ce6SKarsten Keil MODULE_LICENSE("GPL v2"); 119*707b2ce6SKarsten Keil MODULE_VERSION(W6692_REV); 120*707b2ce6SKarsten Keil module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); 121*707b2ce6SKarsten Keil MODULE_PARM_DESC(debug, "W6692 debug mask"); 122*707b2ce6SKarsten Keil module_param(led, uint, S_IRUGO | S_IWUSR); 123*707b2ce6SKarsten Keil MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)"); 124*707b2ce6SKarsten Keil module_param(pots, uint, S_IRUGO | S_IWUSR); 125*707b2ce6SKarsten Keil MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)"); 126*707b2ce6SKarsten Keil 127*707b2ce6SKarsten Keil static inline u8 128*707b2ce6SKarsten Keil ReadW6692(struct w6692_hw *card, u8 offset) 129*707b2ce6SKarsten Keil { 130*707b2ce6SKarsten Keil return inb(card->addr + offset); 131*707b2ce6SKarsten Keil } 132*707b2ce6SKarsten Keil 133*707b2ce6SKarsten Keil static inline void 134*707b2ce6SKarsten Keil WriteW6692(struct w6692_hw *card, u8 offset, u8 value) 135*707b2ce6SKarsten Keil { 136*707b2ce6SKarsten Keil outb(value, card->addr + offset); 137*707b2ce6SKarsten Keil } 138*707b2ce6SKarsten Keil 139*707b2ce6SKarsten Keil static inline u8 140*707b2ce6SKarsten Keil ReadW6692B(struct w6692_ch *bc, u8 offset) 141*707b2ce6SKarsten Keil { 142*707b2ce6SKarsten Keil return inb(bc->addr + offset); 143*707b2ce6SKarsten Keil } 144*707b2ce6SKarsten Keil 145*707b2ce6SKarsten Keil static inline void 146*707b2ce6SKarsten Keil WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value) 147*707b2ce6SKarsten Keil { 148*707b2ce6SKarsten Keil outb(value, bc->addr + offset); 149*707b2ce6SKarsten Keil } 150*707b2ce6SKarsten Keil 151*707b2ce6SKarsten Keil static void 152*707b2ce6SKarsten Keil enable_hwirq(struct w6692_hw *card) 153*707b2ce6SKarsten Keil { 154*707b2ce6SKarsten Keil WriteW6692(card, W_IMASK, card->imask); 155*707b2ce6SKarsten Keil } 156*707b2ce6SKarsten Keil 157*707b2ce6SKarsten Keil static void 158*707b2ce6SKarsten Keil disable_hwirq(struct w6692_hw *card) 159*707b2ce6SKarsten Keil { 160*707b2ce6SKarsten Keil WriteW6692(card, W_IMASK, 0xff); 161*707b2ce6SKarsten Keil } 162*707b2ce6SKarsten Keil 163*707b2ce6SKarsten Keil static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"}; 164*707b2ce6SKarsten Keil 165*707b2ce6SKarsten Keil static void 166*707b2ce6SKarsten Keil W6692Version(struct w6692_hw *card) 167*707b2ce6SKarsten Keil { 168*707b2ce6SKarsten Keil int val; 169*707b2ce6SKarsten Keil 170*707b2ce6SKarsten Keil val = ReadW6692(card, W_D_RBCH); 171*707b2ce6SKarsten Keil pr_notice("%s: Winbond W6692 version: %s\n", card->name, 172*707b2ce6SKarsten Keil W6692Ver[(val >> 6) & 3]); 173*707b2ce6SKarsten Keil } 174*707b2ce6SKarsten Keil 175*707b2ce6SKarsten Keil static void 176*707b2ce6SKarsten Keil w6692_led_handler(struct w6692_hw *card, int on) 177*707b2ce6SKarsten Keil { 178*707b2ce6SKarsten Keil if ((!(card->fmask & led)) || card->subtype == W6692_USR) 179*707b2ce6SKarsten Keil return; 180*707b2ce6SKarsten Keil if (on) { 181*707b2ce6SKarsten Keil card->xdata &= 0xfb; /* LED ON */ 182*707b2ce6SKarsten Keil WriteW6692(card, W_XDATA, card->xdata); 183*707b2ce6SKarsten Keil } else { 184*707b2ce6SKarsten Keil card->xdata |= 0x04; /* LED OFF */ 185*707b2ce6SKarsten Keil WriteW6692(card, W_XDATA, card->xdata); 186*707b2ce6SKarsten Keil } 187*707b2ce6SKarsten Keil } 188*707b2ce6SKarsten Keil 189*707b2ce6SKarsten Keil static void 190*707b2ce6SKarsten Keil ph_command(struct w6692_hw *card, u8 cmd) 191*707b2ce6SKarsten Keil { 192*707b2ce6SKarsten Keil pr_debug("%s: ph_command %x\n", card->name, cmd); 193*707b2ce6SKarsten Keil WriteW6692(card, W_CIX, cmd); 194*707b2ce6SKarsten Keil } 195*707b2ce6SKarsten Keil 196*707b2ce6SKarsten Keil static void 197*707b2ce6SKarsten Keil W6692_new_ph(struct w6692_hw *card) 198*707b2ce6SKarsten Keil { 199*707b2ce6SKarsten Keil if (card->state == W_L1CMD_RST) 200*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_DRC); 201*707b2ce6SKarsten Keil schedule_event(&card->dch, FLG_PHCHANGE); 202*707b2ce6SKarsten Keil } 203*707b2ce6SKarsten Keil 204*707b2ce6SKarsten Keil static void 205*707b2ce6SKarsten Keil W6692_ph_bh(struct dchannel *dch) 206*707b2ce6SKarsten Keil { 207*707b2ce6SKarsten Keil struct w6692_hw *card = dch->hw; 208*707b2ce6SKarsten Keil 209*707b2ce6SKarsten Keil switch (card->state) { 210*707b2ce6SKarsten Keil case W_L1CMD_RST: 211*707b2ce6SKarsten Keil dch->state = 0; 212*707b2ce6SKarsten Keil l1_event(dch->l1, HW_RESET_IND); 213*707b2ce6SKarsten Keil break; 214*707b2ce6SKarsten Keil case W_L1IND_CD: 215*707b2ce6SKarsten Keil dch->state = 3; 216*707b2ce6SKarsten Keil l1_event(dch->l1, HW_DEACT_CNF); 217*707b2ce6SKarsten Keil break; 218*707b2ce6SKarsten Keil case W_L1IND_DRD: 219*707b2ce6SKarsten Keil dch->state = 3; 220*707b2ce6SKarsten Keil l1_event(dch->l1, HW_DEACT_IND); 221*707b2ce6SKarsten Keil break; 222*707b2ce6SKarsten Keil case W_L1IND_CE: 223*707b2ce6SKarsten Keil dch->state = 4; 224*707b2ce6SKarsten Keil l1_event(dch->l1, HW_POWERUP_IND); 225*707b2ce6SKarsten Keil break; 226*707b2ce6SKarsten Keil case W_L1IND_LD: 227*707b2ce6SKarsten Keil if (dch->state <= 5) { 228*707b2ce6SKarsten Keil dch->state = 5; 229*707b2ce6SKarsten Keil l1_event(dch->l1, ANYSIGNAL); 230*707b2ce6SKarsten Keil } else { 231*707b2ce6SKarsten Keil dch->state = 8; 232*707b2ce6SKarsten Keil l1_event(dch->l1, LOSTFRAMING); 233*707b2ce6SKarsten Keil } 234*707b2ce6SKarsten Keil break; 235*707b2ce6SKarsten Keil case W_L1IND_ARD: 236*707b2ce6SKarsten Keil dch->state = 6; 237*707b2ce6SKarsten Keil l1_event(dch->l1, INFO2); 238*707b2ce6SKarsten Keil break; 239*707b2ce6SKarsten Keil case W_L1IND_AI8: 240*707b2ce6SKarsten Keil dch->state = 7; 241*707b2ce6SKarsten Keil l1_event(dch->l1, INFO4_P8); 242*707b2ce6SKarsten Keil break; 243*707b2ce6SKarsten Keil case W_L1IND_AI10: 244*707b2ce6SKarsten Keil dch->state = 7; 245*707b2ce6SKarsten Keil l1_event(dch->l1, INFO4_P10); 246*707b2ce6SKarsten Keil break; 247*707b2ce6SKarsten Keil default: 248*707b2ce6SKarsten Keil pr_debug("%s: TE unknown state %02x dch state %02x\n", 249*707b2ce6SKarsten Keil card->name, card->state, dch->state); 250*707b2ce6SKarsten Keil break; 251*707b2ce6SKarsten Keil } 252*707b2ce6SKarsten Keil pr_debug("%s: TE newstate %02x\n", card->name, dch->state); 253*707b2ce6SKarsten Keil } 254*707b2ce6SKarsten Keil 255*707b2ce6SKarsten Keil static void 256*707b2ce6SKarsten Keil W6692_empty_Dfifo(struct w6692_hw *card, int count) 257*707b2ce6SKarsten Keil { 258*707b2ce6SKarsten Keil struct dchannel *dch = &card->dch; 259*707b2ce6SKarsten Keil u8 *ptr; 260*707b2ce6SKarsten Keil 261*707b2ce6SKarsten Keil pr_debug("%s: empty_Dfifo %d\n", card->name, count); 262*707b2ce6SKarsten Keil if (!dch->rx_skb) { 263*707b2ce6SKarsten Keil dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); 264*707b2ce6SKarsten Keil if (!dch->rx_skb) { 265*707b2ce6SKarsten Keil pr_info("%s: D receive out of memory\n", card->name); 266*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); 267*707b2ce6SKarsten Keil return; 268*707b2ce6SKarsten Keil } 269*707b2ce6SKarsten Keil } 270*707b2ce6SKarsten Keil if ((dch->rx_skb->len + count) >= dch->maxlen) { 271*707b2ce6SKarsten Keil pr_debug("%s: empty_Dfifo overrun %d\n", card->name, 272*707b2ce6SKarsten Keil dch->rx_skb->len + count); 273*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); 274*707b2ce6SKarsten Keil return; 275*707b2ce6SKarsten Keil } 276*707b2ce6SKarsten Keil ptr = skb_put(dch->rx_skb, count); 277*707b2ce6SKarsten Keil insb(card->addr + W_D_RFIFO, ptr, count); 278*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); 279*707b2ce6SKarsten Keil if (debug & DEBUG_HW_DFIFO) { 280*707b2ce6SKarsten Keil snprintf(card->log, 63, "D-recv %s %d ", 281*707b2ce6SKarsten Keil card->name, count); 282*707b2ce6SKarsten Keil print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); 283*707b2ce6SKarsten Keil } 284*707b2ce6SKarsten Keil } 285*707b2ce6SKarsten Keil 286*707b2ce6SKarsten Keil static void 287*707b2ce6SKarsten Keil W6692_fill_Dfifo(struct w6692_hw *card) 288*707b2ce6SKarsten Keil { 289*707b2ce6SKarsten Keil struct dchannel *dch = &card->dch; 290*707b2ce6SKarsten Keil int count; 291*707b2ce6SKarsten Keil u8 *ptr; 292*707b2ce6SKarsten Keil u8 cmd = W_D_CMDR_XMS; 293*707b2ce6SKarsten Keil 294*707b2ce6SKarsten Keil pr_debug("%s: fill_Dfifo\n", card->name); 295*707b2ce6SKarsten Keil if (!dch->tx_skb) 296*707b2ce6SKarsten Keil return; 297*707b2ce6SKarsten Keil count = dch->tx_skb->len - dch->tx_idx; 298*707b2ce6SKarsten Keil if (count <= 0) 299*707b2ce6SKarsten Keil return; 300*707b2ce6SKarsten Keil if (count > W_D_FIFO_THRESH) 301*707b2ce6SKarsten Keil count = W_D_FIFO_THRESH; 302*707b2ce6SKarsten Keil else 303*707b2ce6SKarsten Keil cmd |= W_D_CMDR_XME; 304*707b2ce6SKarsten Keil ptr = dch->tx_skb->data + dch->tx_idx; 305*707b2ce6SKarsten Keil dch->tx_idx += count; 306*707b2ce6SKarsten Keil outsb(card->addr + W_D_XFIFO, ptr, count); 307*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, cmd); 308*707b2ce6SKarsten Keil if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { 309*707b2ce6SKarsten Keil pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); 310*707b2ce6SKarsten Keil del_timer(&dch->timer); 311*707b2ce6SKarsten Keil } 312*707b2ce6SKarsten Keil init_timer(&dch->timer); 313*707b2ce6SKarsten Keil dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); 314*707b2ce6SKarsten Keil add_timer(&dch->timer); 315*707b2ce6SKarsten Keil if (debug & DEBUG_HW_DFIFO) { 316*707b2ce6SKarsten Keil snprintf(card->log, 63, "D-send %s %d ", 317*707b2ce6SKarsten Keil card->name, count); 318*707b2ce6SKarsten Keil print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); 319*707b2ce6SKarsten Keil } 320*707b2ce6SKarsten Keil } 321*707b2ce6SKarsten Keil 322*707b2ce6SKarsten Keil static void 323*707b2ce6SKarsten Keil d_retransmit(struct w6692_hw *card) 324*707b2ce6SKarsten Keil { 325*707b2ce6SKarsten Keil struct dchannel *dch = &card->dch; 326*707b2ce6SKarsten Keil 327*707b2ce6SKarsten Keil if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 328*707b2ce6SKarsten Keil del_timer(&dch->timer); 329*707b2ce6SKarsten Keil #ifdef FIXME 330*707b2ce6SKarsten Keil if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 331*707b2ce6SKarsten Keil dchannel_sched_event(dch, D_CLEARBUSY); 332*707b2ce6SKarsten Keil #endif 333*707b2ce6SKarsten Keil if (test_bit(FLG_TX_BUSY, &dch->Flags)) { 334*707b2ce6SKarsten Keil /* Restart frame */ 335*707b2ce6SKarsten Keil dch->tx_idx = 0; 336*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 337*707b2ce6SKarsten Keil } else if (dch->tx_skb) { /* should not happen */ 338*707b2ce6SKarsten Keil pr_info("%s: %s without TX_BUSY\n", card->name, __func__); 339*707b2ce6SKarsten Keil test_and_set_bit(FLG_TX_BUSY, &dch->Flags); 340*707b2ce6SKarsten Keil dch->tx_idx = 0; 341*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 342*707b2ce6SKarsten Keil } else { 343*707b2ce6SKarsten Keil pr_info("%s: XDU no TX_BUSY\n", card->name); 344*707b2ce6SKarsten Keil if (get_next_dframe(dch)) 345*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 346*707b2ce6SKarsten Keil } 347*707b2ce6SKarsten Keil } 348*707b2ce6SKarsten Keil 349*707b2ce6SKarsten Keil static void 350*707b2ce6SKarsten Keil handle_rxD(struct w6692_hw *card) { 351*707b2ce6SKarsten Keil u8 stat; 352*707b2ce6SKarsten Keil int count; 353*707b2ce6SKarsten Keil 354*707b2ce6SKarsten Keil stat = ReadW6692(card, W_D_RSTA); 355*707b2ce6SKarsten Keil if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { 356*707b2ce6SKarsten Keil if (stat & W_D_RSTA_RDOV) { 357*707b2ce6SKarsten Keil pr_debug("%s: D-channel RDOV\n", card->name); 358*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 359*707b2ce6SKarsten Keil card->dch.err_rx++; 360*707b2ce6SKarsten Keil #endif 361*707b2ce6SKarsten Keil } 362*707b2ce6SKarsten Keil if (stat & W_D_RSTA_CRCE) { 363*707b2ce6SKarsten Keil pr_debug("%s: D-channel CRC error\n", card->name); 364*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 365*707b2ce6SKarsten Keil card->dch.err_crc++; 366*707b2ce6SKarsten Keil #endif 367*707b2ce6SKarsten Keil } 368*707b2ce6SKarsten Keil if (stat & W_D_RSTA_RMB) { 369*707b2ce6SKarsten Keil pr_debug("%s: D-channel ABORT\n", card->name); 370*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 371*707b2ce6SKarsten Keil card->dch.err_rx++; 372*707b2ce6SKarsten Keil #endif 373*707b2ce6SKarsten Keil } 374*707b2ce6SKarsten Keil if (card->dch.rx_skb) 375*707b2ce6SKarsten Keil dev_kfree_skb(card->dch.rx_skb); 376*707b2ce6SKarsten Keil card->dch.rx_skb = NULL; 377*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); 378*707b2ce6SKarsten Keil } else { 379*707b2ce6SKarsten Keil count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); 380*707b2ce6SKarsten Keil if (count == 0) 381*707b2ce6SKarsten Keil count = W_D_FIFO_THRESH; 382*707b2ce6SKarsten Keil W6692_empty_Dfifo(card, count); 383*707b2ce6SKarsten Keil recv_Dchannel(&card->dch); 384*707b2ce6SKarsten Keil } 385*707b2ce6SKarsten Keil } 386*707b2ce6SKarsten Keil 387*707b2ce6SKarsten Keil static void 388*707b2ce6SKarsten Keil handle_txD(struct w6692_hw *card) { 389*707b2ce6SKarsten Keil if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags)) 390*707b2ce6SKarsten Keil del_timer(&card->dch.timer); 391*707b2ce6SKarsten Keil if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) { 392*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 393*707b2ce6SKarsten Keil } else { 394*707b2ce6SKarsten Keil if (card->dch.tx_skb) 395*707b2ce6SKarsten Keil dev_kfree_skb(card->dch.tx_skb); 396*707b2ce6SKarsten Keil if (get_next_dframe(&card->dch)) 397*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 398*707b2ce6SKarsten Keil } 399*707b2ce6SKarsten Keil } 400*707b2ce6SKarsten Keil 401*707b2ce6SKarsten Keil static void 402*707b2ce6SKarsten Keil handle_statusD(struct w6692_hw *card) 403*707b2ce6SKarsten Keil { 404*707b2ce6SKarsten Keil struct dchannel *dch = &card->dch; 405*707b2ce6SKarsten Keil u8 exval, v1, cir; 406*707b2ce6SKarsten Keil 407*707b2ce6SKarsten Keil exval = ReadW6692(card, W_D_EXIR); 408*707b2ce6SKarsten Keil 409*707b2ce6SKarsten Keil pr_debug("%s: D_EXIR %02x\n", card->name, exval); 410*707b2ce6SKarsten Keil if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { 411*707b2ce6SKarsten Keil /* Transmit underrun/collision */ 412*707b2ce6SKarsten Keil pr_debug("%s: D-channel underrun/collision\n", card->name); 413*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 414*707b2ce6SKarsten Keil dch->err_tx++; 415*707b2ce6SKarsten Keil #endif 416*707b2ce6SKarsten Keil d_retransmit(card); 417*707b2ce6SKarsten Keil } 418*707b2ce6SKarsten Keil if (exval & W_D_EXI_RDOV) { /* RDOV */ 419*707b2ce6SKarsten Keil pr_debug("%s: D-channel RDOV\n", card->name); 420*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); 421*707b2ce6SKarsten Keil } 422*707b2ce6SKarsten Keil if (exval & W_D_EXI_TIN2) /* TIN2 - never */ 423*707b2ce6SKarsten Keil pr_debug("%s: spurious TIN2 interrupt\n", card->name); 424*707b2ce6SKarsten Keil if (exval & W_D_EXI_MOC) { /* MOC - not supported */ 425*707b2ce6SKarsten Keil v1 = ReadW6692(card, W_MOSR); 426*707b2ce6SKarsten Keil pr_debug("%s: spurious MOC interrupt MOSR %02x\n", 427*707b2ce6SKarsten Keil card->name, v1); 428*707b2ce6SKarsten Keil } 429*707b2ce6SKarsten Keil if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ 430*707b2ce6SKarsten Keil cir = ReadW6692(card, W_CIR); 431*707b2ce6SKarsten Keil pr_debug("%s: ISC CIR %02X\n", card->name, cir); 432*707b2ce6SKarsten Keil if (cir & W_CIR_ICC) { 433*707b2ce6SKarsten Keil v1 = cir & W_CIR_COD_MASK; 434*707b2ce6SKarsten Keil pr_debug("%s: ph_state_change %x -> %x\n", card->name, 435*707b2ce6SKarsten Keil dch->state, v1); 436*707b2ce6SKarsten Keil card->state = v1; 437*707b2ce6SKarsten Keil if (card->fmask & led) { 438*707b2ce6SKarsten Keil switch (v1) { 439*707b2ce6SKarsten Keil case W_L1IND_AI8: 440*707b2ce6SKarsten Keil case W_L1IND_AI10: 441*707b2ce6SKarsten Keil w6692_led_handler(card, 1); 442*707b2ce6SKarsten Keil break; 443*707b2ce6SKarsten Keil default: 444*707b2ce6SKarsten Keil w6692_led_handler(card, 0); 445*707b2ce6SKarsten Keil break; 446*707b2ce6SKarsten Keil } 447*707b2ce6SKarsten Keil } 448*707b2ce6SKarsten Keil W6692_new_ph(card); 449*707b2ce6SKarsten Keil } 450*707b2ce6SKarsten Keil if (cir & W_CIR_SCC) { 451*707b2ce6SKarsten Keil v1 = ReadW6692(card, W_SQR); 452*707b2ce6SKarsten Keil pr_debug("%s: SCC SQR %02X\n", card->name, v1); 453*707b2ce6SKarsten Keil } 454*707b2ce6SKarsten Keil } 455*707b2ce6SKarsten Keil if (exval & W_D_EXI_WEXP) 456*707b2ce6SKarsten Keil pr_debug("%s: spurious WEXP interrupt!\n", card->name); 457*707b2ce6SKarsten Keil if (exval & W_D_EXI_TEXP) 458*707b2ce6SKarsten Keil pr_debug("%s: spurious TEXP interrupt!\n", card->name); 459*707b2ce6SKarsten Keil } 460*707b2ce6SKarsten Keil 461*707b2ce6SKarsten Keil static void 462*707b2ce6SKarsten Keil W6692_empty_Bfifo(struct w6692_ch *wch, int count) 463*707b2ce6SKarsten Keil { 464*707b2ce6SKarsten Keil struct w6692_hw *card = wch->bch.hw; 465*707b2ce6SKarsten Keil u8 *ptr; 466*707b2ce6SKarsten Keil 467*707b2ce6SKarsten Keil pr_debug("%s: empty_Bfifo %d\n", card->name, count); 468*707b2ce6SKarsten Keil if (unlikely(wch->bch.state == ISDN_P_NONE)) { 469*707b2ce6SKarsten Keil pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); 470*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); 471*707b2ce6SKarsten Keil if (wch->bch.rx_skb) 472*707b2ce6SKarsten Keil skb_trim(wch->bch.rx_skb, 0); 473*707b2ce6SKarsten Keil return; 474*707b2ce6SKarsten Keil } 475*707b2ce6SKarsten Keil if (!wch->bch.rx_skb) { 476*707b2ce6SKarsten Keil wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); 477*707b2ce6SKarsten Keil if (unlikely(!wch->bch.rx_skb)) { 478*707b2ce6SKarsten Keil pr_info("%s: B receive out of memory\n", card->name); 479*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | 480*707b2ce6SKarsten Keil W_B_CMDR_RACT); 481*707b2ce6SKarsten Keil return; 482*707b2ce6SKarsten Keil } 483*707b2ce6SKarsten Keil } 484*707b2ce6SKarsten Keil if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { 485*707b2ce6SKarsten Keil pr_debug("%s: empty_Bfifo incoming packet too large\n", 486*707b2ce6SKarsten Keil card->name); 487*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); 488*707b2ce6SKarsten Keil skb_trim(wch->bch.rx_skb, 0); 489*707b2ce6SKarsten Keil return; 490*707b2ce6SKarsten Keil } 491*707b2ce6SKarsten Keil ptr = skb_put(wch->bch.rx_skb, count); 492*707b2ce6SKarsten Keil insb(wch->addr + W_B_RFIFO, ptr, count); 493*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); 494*707b2ce6SKarsten Keil if (debug & DEBUG_HW_DFIFO) { 495*707b2ce6SKarsten Keil snprintf(card->log, 63, "B%1d-recv %s %d ", 496*707b2ce6SKarsten Keil wch->bch.nr, card->name, count); 497*707b2ce6SKarsten Keil print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); 498*707b2ce6SKarsten Keil } 499*707b2ce6SKarsten Keil } 500*707b2ce6SKarsten Keil 501*707b2ce6SKarsten Keil static void 502*707b2ce6SKarsten Keil W6692_fill_Bfifo(struct w6692_ch *wch) 503*707b2ce6SKarsten Keil { 504*707b2ce6SKarsten Keil struct w6692_hw *card = wch->bch.hw; 505*707b2ce6SKarsten Keil int count; 506*707b2ce6SKarsten Keil u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; 507*707b2ce6SKarsten Keil 508*707b2ce6SKarsten Keil pr_debug("%s: fill Bfifo\n", card->name); 509*707b2ce6SKarsten Keil if (!wch->bch.tx_skb) 510*707b2ce6SKarsten Keil return; 511*707b2ce6SKarsten Keil count = wch->bch.tx_skb->len - wch->bch.tx_idx; 512*707b2ce6SKarsten Keil if (count <= 0) 513*707b2ce6SKarsten Keil return; 514*707b2ce6SKarsten Keil ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; 515*707b2ce6SKarsten Keil if (count > W_B_FIFO_THRESH) 516*707b2ce6SKarsten Keil count = W_B_FIFO_THRESH; 517*707b2ce6SKarsten Keil else if (test_bit(FLG_HDLC, &wch->bch.Flags)) 518*707b2ce6SKarsten Keil cmd |= W_B_CMDR_XME; 519*707b2ce6SKarsten Keil 520*707b2ce6SKarsten Keil pr_debug("%s: fill Bfifo%d/%d\n", card->name, 521*707b2ce6SKarsten Keil count, wch->bch.tx_idx); 522*707b2ce6SKarsten Keil wch->bch.tx_idx += count; 523*707b2ce6SKarsten Keil outsb(wch->addr + W_B_XFIFO, ptr, count); 524*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, cmd); 525*707b2ce6SKarsten Keil if (debug & DEBUG_HW_DFIFO) { 526*707b2ce6SKarsten Keil snprintf(card->log, 63, "B%1d-send %s %d ", 527*707b2ce6SKarsten Keil wch->bch.nr, card->name, count); 528*707b2ce6SKarsten Keil print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); 529*707b2ce6SKarsten Keil } 530*707b2ce6SKarsten Keil } 531*707b2ce6SKarsten Keil 532*707b2ce6SKarsten Keil static int 533*707b2ce6SKarsten Keil setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) 534*707b2ce6SKarsten Keil { 535*707b2ce6SKarsten Keil struct w6692_hw *card = wch->bch.hw; 536*707b2ce6SKarsten Keil u16 *vol = (u16 *)skb->data; 537*707b2ce6SKarsten Keil u8 val; 538*707b2ce6SKarsten Keil 539*707b2ce6SKarsten Keil if ((!(card->fmask & pots)) || 540*707b2ce6SKarsten Keil !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) 541*707b2ce6SKarsten Keil return -ENODEV; 542*707b2ce6SKarsten Keil if (skb->len < 2) 543*707b2ce6SKarsten Keil return -EINVAL; 544*707b2ce6SKarsten Keil if (*vol > 7) 545*707b2ce6SKarsten Keil return -EINVAL; 546*707b2ce6SKarsten Keil val = *vol & 7; 547*707b2ce6SKarsten Keil val = 7 - val; 548*707b2ce6SKarsten Keil if (mic) { 549*707b2ce6SKarsten Keil val <<= 3; 550*707b2ce6SKarsten Keil card->xaddr &= 0xc7; 551*707b2ce6SKarsten Keil } else { 552*707b2ce6SKarsten Keil card->xaddr &= 0xf8; 553*707b2ce6SKarsten Keil } 554*707b2ce6SKarsten Keil card->xaddr |= val; 555*707b2ce6SKarsten Keil WriteW6692(card, W_XADDR, card->xaddr); 556*707b2ce6SKarsten Keil return 0; 557*707b2ce6SKarsten Keil } 558*707b2ce6SKarsten Keil 559*707b2ce6SKarsten Keil static int 560*707b2ce6SKarsten Keil enable_pots(struct w6692_ch *wch) 561*707b2ce6SKarsten Keil { 562*707b2ce6SKarsten Keil struct w6692_hw *card = wch->bch.hw; 563*707b2ce6SKarsten Keil 564*707b2ce6SKarsten Keil if ((!(card->fmask & pots)) || 565*707b2ce6SKarsten Keil !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) 566*707b2ce6SKarsten Keil return -ENODEV; 567*707b2ce6SKarsten Keil wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; 568*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_MODE, wch->b_mode); 569*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); 570*707b2ce6SKarsten Keil card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); 571*707b2ce6SKarsten Keil WriteW6692(card, W_PCTL, card->pctl); 572*707b2ce6SKarsten Keil return 0; 573*707b2ce6SKarsten Keil } 574*707b2ce6SKarsten Keil 575*707b2ce6SKarsten Keil static int 576*707b2ce6SKarsten Keil disable_pots(struct w6692_ch *wch) 577*707b2ce6SKarsten Keil { 578*707b2ce6SKarsten Keil struct w6692_hw *card = wch->bch.hw; 579*707b2ce6SKarsten Keil 580*707b2ce6SKarsten Keil if (!(card->fmask & pots)) 581*707b2ce6SKarsten Keil return -ENODEV; 582*707b2ce6SKarsten Keil wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); 583*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_MODE, wch->b_mode); 584*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | 585*707b2ce6SKarsten Keil W_B_CMDR_XRST); 586*707b2ce6SKarsten Keil return 0; 587*707b2ce6SKarsten Keil } 588*707b2ce6SKarsten Keil 589*707b2ce6SKarsten Keil static int 590*707b2ce6SKarsten Keil w6692_mode(struct w6692_ch *wch, u32 pr) 591*707b2ce6SKarsten Keil { 592*707b2ce6SKarsten Keil struct w6692_hw *card; 593*707b2ce6SKarsten Keil 594*707b2ce6SKarsten Keil card = wch->bch.hw; 595*707b2ce6SKarsten Keil pr_debug("%s: B%d protocol %x-->%x\n", card->name, 596*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state, pr); 597*707b2ce6SKarsten Keil switch (pr) { 598*707b2ce6SKarsten Keil case ISDN_P_NONE: 599*707b2ce6SKarsten Keil if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) 600*707b2ce6SKarsten Keil disable_pots(wch); 601*707b2ce6SKarsten Keil wch->b_mode = 0; 602*707b2ce6SKarsten Keil mISDN_clear_bchannel(&wch->bch); 603*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_MODE, wch->b_mode); 604*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); 605*707b2ce6SKarsten Keil test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); 606*707b2ce6SKarsten Keil test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); 607*707b2ce6SKarsten Keil break; 608*707b2ce6SKarsten Keil case ISDN_P_B_RAW: 609*707b2ce6SKarsten Keil wch->b_mode = W_B_MODE_MMS; 610*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_MODE, wch->b_mode); 611*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_EXIM, 0); 612*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | 613*707b2ce6SKarsten Keil W_B_CMDR_XRST); 614*707b2ce6SKarsten Keil test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); 615*707b2ce6SKarsten Keil break; 616*707b2ce6SKarsten Keil case ISDN_P_B_HDLC: 617*707b2ce6SKarsten Keil wch->b_mode = W_B_MODE_ITF; 618*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_MODE, wch->b_mode); 619*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_ADM1, 0xff); 620*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_ADM2, 0xff); 621*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_EXIM, 0); 622*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | 623*707b2ce6SKarsten Keil W_B_CMDR_XRST); 624*707b2ce6SKarsten Keil test_and_set_bit(FLG_HDLC, &wch->bch.Flags); 625*707b2ce6SKarsten Keil break; 626*707b2ce6SKarsten Keil default: 627*707b2ce6SKarsten Keil pr_info("%s: protocol %x not known\n", card->name, pr); 628*707b2ce6SKarsten Keil return -ENOPROTOOPT; 629*707b2ce6SKarsten Keil } 630*707b2ce6SKarsten Keil wch->bch.state = pr; 631*707b2ce6SKarsten Keil return 0; 632*707b2ce6SKarsten Keil } 633*707b2ce6SKarsten Keil 634*707b2ce6SKarsten Keil static void 635*707b2ce6SKarsten Keil send_next(struct w6692_ch *wch) 636*707b2ce6SKarsten Keil { 637*707b2ce6SKarsten Keil if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) 638*707b2ce6SKarsten Keil W6692_fill_Bfifo(wch); 639*707b2ce6SKarsten Keil else { 640*707b2ce6SKarsten Keil if (wch->bch.tx_skb) { 641*707b2ce6SKarsten Keil /* send confirm, on trans, free on hdlc. */ 642*707b2ce6SKarsten Keil if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) 643*707b2ce6SKarsten Keil confirm_Bsend(&wch->bch); 644*707b2ce6SKarsten Keil dev_kfree_skb(wch->bch.tx_skb); 645*707b2ce6SKarsten Keil } 646*707b2ce6SKarsten Keil if (get_next_bframe(&wch->bch)) 647*707b2ce6SKarsten Keil W6692_fill_Bfifo(wch); 648*707b2ce6SKarsten Keil } 649*707b2ce6SKarsten Keil } 650*707b2ce6SKarsten Keil 651*707b2ce6SKarsten Keil static void 652*707b2ce6SKarsten Keil W6692B_interrupt(struct w6692_hw *card, int ch) 653*707b2ce6SKarsten Keil { 654*707b2ce6SKarsten Keil struct w6692_ch *wch = &card->bc[ch]; 655*707b2ce6SKarsten Keil int count; 656*707b2ce6SKarsten Keil u8 stat, star = 0; 657*707b2ce6SKarsten Keil 658*707b2ce6SKarsten Keil stat = ReadW6692B(wch, W_B_EXIR); 659*707b2ce6SKarsten Keil pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); 660*707b2ce6SKarsten Keil if (stat & W_B_EXI_RME) { 661*707b2ce6SKarsten Keil star = ReadW6692B(wch, W_B_STAR); 662*707b2ce6SKarsten Keil if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { 663*707b2ce6SKarsten Keil if ((star & W_B_STAR_RDOV) && 664*707b2ce6SKarsten Keil test_bit(FLG_ACTIVE, &wch->bch.Flags)) { 665*707b2ce6SKarsten Keil pr_debug("%s: B%d RDOV proto=%x\n", card->name, 666*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state); 667*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 668*707b2ce6SKarsten Keil wch->bch.err_rdo++; 669*707b2ce6SKarsten Keil #endif 670*707b2ce6SKarsten Keil } 671*707b2ce6SKarsten Keil if (test_bit(FLG_HDLC, &wch->bch.Flags)) { 672*707b2ce6SKarsten Keil if (star & W_B_STAR_CRCE) { 673*707b2ce6SKarsten Keil pr_debug("%s: B%d CRC error\n", 674*707b2ce6SKarsten Keil card->name, wch->bch.nr); 675*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 676*707b2ce6SKarsten Keil wch->bch.err_crc++; 677*707b2ce6SKarsten Keil #endif 678*707b2ce6SKarsten Keil } 679*707b2ce6SKarsten Keil if (star & W_B_STAR_RMB) { 680*707b2ce6SKarsten Keil pr_debug("%s: B%d message abort\n", 681*707b2ce6SKarsten Keil card->name, wch->bch.nr); 682*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 683*707b2ce6SKarsten Keil wch->bch.err_inv++; 684*707b2ce6SKarsten Keil #endif 685*707b2ce6SKarsten Keil } 686*707b2ce6SKarsten Keil } 687*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | 688*707b2ce6SKarsten Keil W_B_CMDR_RRST | W_B_CMDR_RACT); 689*707b2ce6SKarsten Keil if (wch->bch.rx_skb) 690*707b2ce6SKarsten Keil skb_trim(wch->bch.rx_skb, 0); 691*707b2ce6SKarsten Keil } else { 692*707b2ce6SKarsten Keil count = ReadW6692B(wch, W_B_RBCL) & 693*707b2ce6SKarsten Keil (W_B_FIFO_THRESH - 1); 694*707b2ce6SKarsten Keil if (count == 0) 695*707b2ce6SKarsten Keil count = W_B_FIFO_THRESH; 696*707b2ce6SKarsten Keil W6692_empty_Bfifo(wch, count); 697*707b2ce6SKarsten Keil recv_Bchannel(&wch->bch, 0); 698*707b2ce6SKarsten Keil } 699*707b2ce6SKarsten Keil } 700*707b2ce6SKarsten Keil if (stat & W_B_EXI_RMR) { 701*707b2ce6SKarsten Keil if (!(stat & W_B_EXI_RME)) 702*707b2ce6SKarsten Keil star = ReadW6692B(wch, W_B_STAR); 703*707b2ce6SKarsten Keil if (star & W_B_STAR_RDOV) { 704*707b2ce6SKarsten Keil pr_debug("%s: B%d RDOV proto=%x\n", card->name, 705*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state); 706*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 707*707b2ce6SKarsten Keil wch->bch.err_rdo++; 708*707b2ce6SKarsten Keil #endif 709*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | 710*707b2ce6SKarsten Keil W_B_CMDR_RRST | W_B_CMDR_RACT); 711*707b2ce6SKarsten Keil } else { 712*707b2ce6SKarsten Keil W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); 713*707b2ce6SKarsten Keil if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && 714*707b2ce6SKarsten Keil wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) 715*707b2ce6SKarsten Keil recv_Bchannel(&wch->bch, 0); 716*707b2ce6SKarsten Keil } 717*707b2ce6SKarsten Keil } 718*707b2ce6SKarsten Keil if (stat & W_B_EXI_RDOV) { 719*707b2ce6SKarsten Keil /* only if it is not handled yet */ 720*707b2ce6SKarsten Keil if (!(star & W_B_STAR_RDOV)) { 721*707b2ce6SKarsten Keil pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, 722*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state); 723*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 724*707b2ce6SKarsten Keil wch->bch.err_rdo++; 725*707b2ce6SKarsten Keil #endif 726*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | 727*707b2ce6SKarsten Keil W_B_CMDR_RRST | W_B_CMDR_RACT); 728*707b2ce6SKarsten Keil } 729*707b2ce6SKarsten Keil } 730*707b2ce6SKarsten Keil if (stat & W_B_EXI_XFR) { 731*707b2ce6SKarsten Keil if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { 732*707b2ce6SKarsten Keil star = ReadW6692B(wch, W_B_STAR); 733*707b2ce6SKarsten Keil pr_debug("%s: B%d star %02x\n", card->name, 734*707b2ce6SKarsten Keil wch->bch.nr, star); 735*707b2ce6SKarsten Keil } 736*707b2ce6SKarsten Keil if (star & W_B_STAR_XDOW) { 737*707b2ce6SKarsten Keil pr_debug("%s: B%d XDOW proto=%x\n", card->name, 738*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state); 739*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 740*707b2ce6SKarsten Keil wch->bch.err_xdu++; 741*707b2ce6SKarsten Keil #endif 742*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | 743*707b2ce6SKarsten Keil W_B_CMDR_RACT); 744*707b2ce6SKarsten Keil /* resend */ 745*707b2ce6SKarsten Keil if (wch->bch.tx_skb) { 746*707b2ce6SKarsten Keil if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) 747*707b2ce6SKarsten Keil wch->bch.tx_idx = 0; 748*707b2ce6SKarsten Keil } 749*707b2ce6SKarsten Keil } 750*707b2ce6SKarsten Keil send_next(wch); 751*707b2ce6SKarsten Keil if (stat & W_B_EXI_XDUN) 752*707b2ce6SKarsten Keil return; /* handle XDOW only once */ 753*707b2ce6SKarsten Keil } 754*707b2ce6SKarsten Keil if (stat & W_B_EXI_XDUN) { 755*707b2ce6SKarsten Keil pr_debug("%s: B%d XDUN proto=%x\n", card->name, 756*707b2ce6SKarsten Keil wch->bch.nr, wch->bch.state); 757*707b2ce6SKarsten Keil #ifdef ERROR_STATISTIC 758*707b2ce6SKarsten Keil wch->bch.err_xdu++; 759*707b2ce6SKarsten Keil #endif 760*707b2ce6SKarsten Keil WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); 761*707b2ce6SKarsten Keil /* resend */ 762*707b2ce6SKarsten Keil if (wch->bch.tx_skb) { 763*707b2ce6SKarsten Keil if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) 764*707b2ce6SKarsten Keil wch->bch.tx_idx = 0; 765*707b2ce6SKarsten Keil } 766*707b2ce6SKarsten Keil send_next(wch); 767*707b2ce6SKarsten Keil } 768*707b2ce6SKarsten Keil } 769*707b2ce6SKarsten Keil 770*707b2ce6SKarsten Keil static irqreturn_t 771*707b2ce6SKarsten Keil w6692_irq(int intno, void *dev_id) 772*707b2ce6SKarsten Keil { 773*707b2ce6SKarsten Keil struct w6692_hw *card = dev_id; 774*707b2ce6SKarsten Keil u8 ista; 775*707b2ce6SKarsten Keil 776*707b2ce6SKarsten Keil spin_lock(&card->lock); 777*707b2ce6SKarsten Keil ista = ReadW6692(card, W_ISTA); 778*707b2ce6SKarsten Keil if ((ista | card->imask) == card->imask) { 779*707b2ce6SKarsten Keil /* possible a shared IRQ reqest */ 780*707b2ce6SKarsten Keil spin_unlock(&card->lock); 781*707b2ce6SKarsten Keil return IRQ_NONE; 782*707b2ce6SKarsten Keil } 783*707b2ce6SKarsten Keil card->irqcnt++; 784*707b2ce6SKarsten Keil pr_debug("%s: ista %02x\n", card->name, ista); 785*707b2ce6SKarsten Keil ista &= ~card->imask; 786*707b2ce6SKarsten Keil if (ista & W_INT_B1_EXI) 787*707b2ce6SKarsten Keil W6692B_interrupt(card, 0); 788*707b2ce6SKarsten Keil if (ista & W_INT_B2_EXI) 789*707b2ce6SKarsten Keil W6692B_interrupt(card, 1); 790*707b2ce6SKarsten Keil if (ista & W_INT_D_RME) 791*707b2ce6SKarsten Keil handle_rxD(card); 792*707b2ce6SKarsten Keil if (ista & W_INT_D_RMR) 793*707b2ce6SKarsten Keil W6692_empty_Dfifo(card, W_D_FIFO_THRESH); 794*707b2ce6SKarsten Keil if (ista & W_INT_D_XFR) 795*707b2ce6SKarsten Keil handle_txD(card); 796*707b2ce6SKarsten Keil if (ista & W_INT_D_EXI) 797*707b2ce6SKarsten Keil handle_statusD(card); 798*707b2ce6SKarsten Keil if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ 799*707b2ce6SKarsten Keil pr_debug("%s: W6692 spurious XINT!\n", card->name); 800*707b2ce6SKarsten Keil /* End IRQ Handler */ 801*707b2ce6SKarsten Keil spin_unlock(&card->lock); 802*707b2ce6SKarsten Keil return IRQ_HANDLED; 803*707b2ce6SKarsten Keil } 804*707b2ce6SKarsten Keil 805*707b2ce6SKarsten Keil static void 806*707b2ce6SKarsten Keil dbusy_timer_handler(struct dchannel *dch) 807*707b2ce6SKarsten Keil { 808*707b2ce6SKarsten Keil struct w6692_hw *card = dch->hw; 809*707b2ce6SKarsten Keil int rbch, star; 810*707b2ce6SKarsten Keil u_long flags; 811*707b2ce6SKarsten Keil 812*707b2ce6SKarsten Keil if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { 813*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 814*707b2ce6SKarsten Keil rbch = ReadW6692(card, W_D_RBCH); 815*707b2ce6SKarsten Keil star = ReadW6692(card, W_D_STAR); 816*707b2ce6SKarsten Keil pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", 817*707b2ce6SKarsten Keil card->name, rbch, star); 818*707b2ce6SKarsten Keil if (star & W_D_STAR_XBZ) /* D-Channel Busy */ 819*707b2ce6SKarsten Keil test_and_set_bit(FLG_L1_BUSY, &dch->Flags); 820*707b2ce6SKarsten Keil else { 821*707b2ce6SKarsten Keil /* discard frame; reset transceiver */ 822*707b2ce6SKarsten Keil test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); 823*707b2ce6SKarsten Keil if (dch->tx_idx) 824*707b2ce6SKarsten Keil dch->tx_idx = 0; 825*707b2ce6SKarsten Keil else 826*707b2ce6SKarsten Keil pr_info("%s: W6692 D-Channel Busy no tx_idx\n", 827*707b2ce6SKarsten Keil card->name); 828*707b2ce6SKarsten Keil /* Transmitter reset */ 829*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); 830*707b2ce6SKarsten Keil } 831*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 832*707b2ce6SKarsten Keil } 833*707b2ce6SKarsten Keil } 834*707b2ce6SKarsten Keil 835*707b2ce6SKarsten Keil void initW6692(struct w6692_hw *card) 836*707b2ce6SKarsten Keil { 837*707b2ce6SKarsten Keil u8 val; 838*707b2ce6SKarsten Keil 839*707b2ce6SKarsten Keil card->dch.timer.function = (void *)dbusy_timer_handler; 840*707b2ce6SKarsten Keil card->dch.timer.data = (u_long)&card->dch; 841*707b2ce6SKarsten Keil init_timer(&card->dch.timer); 842*707b2ce6SKarsten Keil w6692_mode(&card->bc[0], ISDN_P_NONE); 843*707b2ce6SKarsten Keil w6692_mode(&card->bc[1], ISDN_P_NONE); 844*707b2ce6SKarsten Keil WriteW6692(card, W_D_CTL, 0x00); 845*707b2ce6SKarsten Keil disable_hwirq(card); 846*707b2ce6SKarsten Keil WriteW6692(card, W_D_SAM, 0xff); 847*707b2ce6SKarsten Keil WriteW6692(card, W_D_TAM, 0xff); 848*707b2ce6SKarsten Keil WriteW6692(card, W_D_MODE, W_D_MODE_RACT); 849*707b2ce6SKarsten Keil card->state = W_L1CMD_RST; 850*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_RST); 851*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_ECK); 852*707b2ce6SKarsten Keil /* enable all IRQ but extern */ 853*707b2ce6SKarsten Keil card->imask = 0x18; 854*707b2ce6SKarsten Keil WriteW6692(card, W_D_EXIM, 0x00); 855*707b2ce6SKarsten Keil WriteW6692B(&card->bc[0], W_B_EXIM, 0); 856*707b2ce6SKarsten Keil WriteW6692B(&card->bc[1], W_B_EXIM, 0); 857*707b2ce6SKarsten Keil /* Reset D-chan receiver and transmitter */ 858*707b2ce6SKarsten Keil WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); 859*707b2ce6SKarsten Keil /* Reset B-chan receiver and transmitter */ 860*707b2ce6SKarsten Keil WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); 861*707b2ce6SKarsten Keil WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); 862*707b2ce6SKarsten Keil /* enable peripheral */ 863*707b2ce6SKarsten Keil if (card->subtype == W6692_USR) { 864*707b2ce6SKarsten Keil /* seems that USR implemented some power control features 865*707b2ce6SKarsten Keil * Pin 79 is connected to the oscilator circuit so we 866*707b2ce6SKarsten Keil * have to handle it here 867*707b2ce6SKarsten Keil */ 868*707b2ce6SKarsten Keil card->pctl = 0x80; 869*707b2ce6SKarsten Keil card->xdata = 0; 870*707b2ce6SKarsten Keil WriteW6692(card, W_PCTL, card->pctl); 871*707b2ce6SKarsten Keil WriteW6692(card, W_XDATA, card->xdata); 872*707b2ce6SKarsten Keil } else { 873*707b2ce6SKarsten Keil card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | 874*707b2ce6SKarsten Keil W_PCTL_OE1 | W_PCTL_OE0; 875*707b2ce6SKarsten Keil card->xaddr = 0x00;/* all sw off */ 876*707b2ce6SKarsten Keil if (card->fmask & pots) 877*707b2ce6SKarsten Keil card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ 878*707b2ce6SKarsten Keil if (card->fmask & led) 879*707b2ce6SKarsten Keil card->xdata |= 0x04; /* LED OFF */ 880*707b2ce6SKarsten Keil if ((card->fmask & pots) || (card->fmask & led)) { 881*707b2ce6SKarsten Keil WriteW6692(card, W_PCTL, card->pctl); 882*707b2ce6SKarsten Keil WriteW6692(card, W_XADDR, card->xaddr); 883*707b2ce6SKarsten Keil WriteW6692(card, W_XDATA, card->xdata); 884*707b2ce6SKarsten Keil val = ReadW6692(card, W_XADDR); 885*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 886*707b2ce6SKarsten Keil pr_notice("%s: W_XADDR=%02x\n", 887*707b2ce6SKarsten Keil card->name, val); 888*707b2ce6SKarsten Keil } 889*707b2ce6SKarsten Keil } 890*707b2ce6SKarsten Keil } 891*707b2ce6SKarsten Keil 892*707b2ce6SKarsten Keil static void 893*707b2ce6SKarsten Keil reset_w6692(struct w6692_hw *card) 894*707b2ce6SKarsten Keil { 895*707b2ce6SKarsten Keil WriteW6692(card, W_D_CTL, W_D_CTL_SRST); 896*707b2ce6SKarsten Keil mdelay(10); 897*707b2ce6SKarsten Keil WriteW6692(card, W_D_CTL, 0); 898*707b2ce6SKarsten Keil } 899*707b2ce6SKarsten Keil 900*707b2ce6SKarsten Keil static int 901*707b2ce6SKarsten Keil init_card(struct w6692_hw *card) 902*707b2ce6SKarsten Keil { 903*707b2ce6SKarsten Keil int cnt = 3; 904*707b2ce6SKarsten Keil u_long flags; 905*707b2ce6SKarsten Keil 906*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 907*707b2ce6SKarsten Keil disable_hwirq(card); 908*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 909*707b2ce6SKarsten Keil if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) { 910*707b2ce6SKarsten Keil pr_info("%s: couldn't get interrupt %d\n", card->name, 911*707b2ce6SKarsten Keil card->irq); 912*707b2ce6SKarsten Keil return -EIO; 913*707b2ce6SKarsten Keil } 914*707b2ce6SKarsten Keil while (cnt--) { 915*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 916*707b2ce6SKarsten Keil initW6692(card); 917*707b2ce6SKarsten Keil enable_hwirq(card); 918*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 919*707b2ce6SKarsten Keil /* Timeout 10ms */ 920*707b2ce6SKarsten Keil msleep_interruptible(10); 921*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 922*707b2ce6SKarsten Keil pr_notice("%s: IRQ %d count %d\n", card->name, 923*707b2ce6SKarsten Keil card->irq, card->irqcnt); 924*707b2ce6SKarsten Keil if (!card->irqcnt) { 925*707b2ce6SKarsten Keil pr_info("%s: IRQ(%d) getting no IRQs during init %d\n", 926*707b2ce6SKarsten Keil card->name, card->irq, 3 - cnt); 927*707b2ce6SKarsten Keil reset_w6692(card); 928*707b2ce6SKarsten Keil } else 929*707b2ce6SKarsten Keil return 0; 930*707b2ce6SKarsten Keil } 931*707b2ce6SKarsten Keil free_irq(card->irq, card); 932*707b2ce6SKarsten Keil return -EIO; 933*707b2ce6SKarsten Keil } 934*707b2ce6SKarsten Keil 935*707b2ce6SKarsten Keil static int 936*707b2ce6SKarsten Keil w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) 937*707b2ce6SKarsten Keil { 938*707b2ce6SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 939*707b2ce6SKarsten Keil struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); 940*707b2ce6SKarsten Keil struct w6692_hw *card = bch->hw; 941*707b2ce6SKarsten Keil int ret = -EINVAL; 942*707b2ce6SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb); 943*707b2ce6SKarsten Keil u32 id; 944*707b2ce6SKarsten Keil u_long flags; 945*707b2ce6SKarsten Keil 946*707b2ce6SKarsten Keil switch (hh->prim) { 947*707b2ce6SKarsten Keil case PH_DATA_REQ: 948*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 949*707b2ce6SKarsten Keil ret = bchannel_senddata(bch, skb); 950*707b2ce6SKarsten Keil if (ret > 0) { /* direct TX */ 951*707b2ce6SKarsten Keil id = hh->id; /* skb can be freed */ 952*707b2ce6SKarsten Keil ret = 0; 953*707b2ce6SKarsten Keil W6692_fill_Bfifo(bc); 954*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 955*707b2ce6SKarsten Keil if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) 956*707b2ce6SKarsten Keil queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 957*707b2ce6SKarsten Keil } else 958*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 959*707b2ce6SKarsten Keil return ret; 960*707b2ce6SKarsten Keil case PH_ACTIVATE_REQ: 961*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 962*707b2ce6SKarsten Keil if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 963*707b2ce6SKarsten Keil ret = w6692_mode(bc, ch->protocol); 964*707b2ce6SKarsten Keil else 965*707b2ce6SKarsten Keil ret = 0; 966*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 967*707b2ce6SKarsten Keil if (!ret) 968*707b2ce6SKarsten Keil _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 969*707b2ce6SKarsten Keil NULL, GFP_KERNEL); 970*707b2ce6SKarsten Keil break; 971*707b2ce6SKarsten Keil case PH_DEACTIVATE_REQ: 972*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 973*707b2ce6SKarsten Keil mISDN_clear_bchannel(bch); 974*707b2ce6SKarsten Keil w6692_mode(bc, ISDN_P_NONE); 975*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 976*707b2ce6SKarsten Keil _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 977*707b2ce6SKarsten Keil NULL, GFP_KERNEL); 978*707b2ce6SKarsten Keil ret = 0; 979*707b2ce6SKarsten Keil break; 980*707b2ce6SKarsten Keil default: 981*707b2ce6SKarsten Keil pr_info("%s: %s unknown prim(%x,%x)\n", 982*707b2ce6SKarsten Keil card->name, __func__, hh->prim, hh->id); 983*707b2ce6SKarsten Keil ret = -EINVAL; 984*707b2ce6SKarsten Keil } 985*707b2ce6SKarsten Keil if (!ret) 986*707b2ce6SKarsten Keil dev_kfree_skb(skb); 987*707b2ce6SKarsten Keil return ret; 988*707b2ce6SKarsten Keil } 989*707b2ce6SKarsten Keil 990*707b2ce6SKarsten Keil static int 991*707b2ce6SKarsten Keil channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 992*707b2ce6SKarsten Keil { 993*707b2ce6SKarsten Keil int ret = 0; 994*707b2ce6SKarsten Keil 995*707b2ce6SKarsten Keil switch (cq->op) { 996*707b2ce6SKarsten Keil case MISDN_CTRL_GETOP: 997*707b2ce6SKarsten Keil cq->op = 0; 998*707b2ce6SKarsten Keil break; 999*707b2ce6SKarsten Keil /* Nothing implemented yet */ 1000*707b2ce6SKarsten Keil case MISDN_CTRL_FILL_EMPTY: 1001*707b2ce6SKarsten Keil default: 1002*707b2ce6SKarsten Keil pr_info("%s: unknown Op %x\n", __func__, cq->op); 1003*707b2ce6SKarsten Keil ret = -EINVAL; 1004*707b2ce6SKarsten Keil break; 1005*707b2ce6SKarsten Keil } 1006*707b2ce6SKarsten Keil return ret; 1007*707b2ce6SKarsten Keil } 1008*707b2ce6SKarsten Keil 1009*707b2ce6SKarsten Keil static int 1010*707b2ce6SKarsten Keil open_bchannel(struct w6692_hw *card, struct channel_req *rq) 1011*707b2ce6SKarsten Keil { 1012*707b2ce6SKarsten Keil struct bchannel *bch; 1013*707b2ce6SKarsten Keil 1014*707b2ce6SKarsten Keil if (rq->adr.channel > 2) 1015*707b2ce6SKarsten Keil return -EINVAL; 1016*707b2ce6SKarsten Keil if (rq->protocol == ISDN_P_NONE) 1017*707b2ce6SKarsten Keil return -EINVAL; 1018*707b2ce6SKarsten Keil bch = &card->bc[rq->adr.channel - 1].bch; 1019*707b2ce6SKarsten Keil if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 1020*707b2ce6SKarsten Keil return -EBUSY; /* b-channel can be only open once */ 1021*707b2ce6SKarsten Keil test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); 1022*707b2ce6SKarsten Keil bch->ch.protocol = rq->protocol; 1023*707b2ce6SKarsten Keil rq->ch = &bch->ch; 1024*707b2ce6SKarsten Keil return 0; 1025*707b2ce6SKarsten Keil } 1026*707b2ce6SKarsten Keil 1027*707b2ce6SKarsten Keil static int 1028*707b2ce6SKarsten Keil channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq) 1029*707b2ce6SKarsten Keil { 1030*707b2ce6SKarsten Keil int ret = 0; 1031*707b2ce6SKarsten Keil 1032*707b2ce6SKarsten Keil switch (cq->op) { 1033*707b2ce6SKarsten Keil case MISDN_CTRL_GETOP: 1034*707b2ce6SKarsten Keil cq->op = 0; 1035*707b2ce6SKarsten Keil break; 1036*707b2ce6SKarsten Keil default: 1037*707b2ce6SKarsten Keil pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op); 1038*707b2ce6SKarsten Keil ret = -EINVAL; 1039*707b2ce6SKarsten Keil break; 1040*707b2ce6SKarsten Keil } 1041*707b2ce6SKarsten Keil return ret; 1042*707b2ce6SKarsten Keil } 1043*707b2ce6SKarsten Keil 1044*707b2ce6SKarsten Keil static int 1045*707b2ce6SKarsten Keil w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 1046*707b2ce6SKarsten Keil { 1047*707b2ce6SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 1048*707b2ce6SKarsten Keil struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch); 1049*707b2ce6SKarsten Keil struct w6692_hw *card = bch->hw; 1050*707b2ce6SKarsten Keil int ret = -EINVAL; 1051*707b2ce6SKarsten Keil u_long flags; 1052*707b2ce6SKarsten Keil 1053*707b2ce6SKarsten Keil pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg); 1054*707b2ce6SKarsten Keil switch (cmd) { 1055*707b2ce6SKarsten Keil case CLOSE_CHANNEL: 1056*707b2ce6SKarsten Keil test_and_clear_bit(FLG_OPEN, &bch->Flags); 1057*707b2ce6SKarsten Keil if (test_bit(FLG_ACTIVE, &bch->Flags)) { 1058*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1059*707b2ce6SKarsten Keil mISDN_freebchannel(bch); 1060*707b2ce6SKarsten Keil w6692_mode(bc, ISDN_P_NONE); 1061*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1062*707b2ce6SKarsten Keil } else { 1063*707b2ce6SKarsten Keil skb_queue_purge(&bch->rqueue); 1064*707b2ce6SKarsten Keil bch->rcount = 0; 1065*707b2ce6SKarsten Keil } 1066*707b2ce6SKarsten Keil ch->protocol = ISDN_P_NONE; 1067*707b2ce6SKarsten Keil ch->peer = NULL; 1068*707b2ce6SKarsten Keil module_put(THIS_MODULE); 1069*707b2ce6SKarsten Keil ret = 0; 1070*707b2ce6SKarsten Keil break; 1071*707b2ce6SKarsten Keil case CONTROL_CHANNEL: 1072*707b2ce6SKarsten Keil ret = channel_bctrl(bch, arg); 1073*707b2ce6SKarsten Keil break; 1074*707b2ce6SKarsten Keil default: 1075*707b2ce6SKarsten Keil pr_info("%s: %s unknown prim(%x)\n", 1076*707b2ce6SKarsten Keil card->name, __func__, cmd); 1077*707b2ce6SKarsten Keil } 1078*707b2ce6SKarsten Keil return ret; 1079*707b2ce6SKarsten Keil } 1080*707b2ce6SKarsten Keil 1081*707b2ce6SKarsten Keil static int 1082*707b2ce6SKarsten Keil w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) 1083*707b2ce6SKarsten Keil { 1084*707b2ce6SKarsten Keil struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 1085*707b2ce6SKarsten Keil struct dchannel *dch = container_of(dev, struct dchannel, dev); 1086*707b2ce6SKarsten Keil struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); 1087*707b2ce6SKarsten Keil int ret = -EINVAL; 1088*707b2ce6SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb); 1089*707b2ce6SKarsten Keil u32 id; 1090*707b2ce6SKarsten Keil u_long flags; 1091*707b2ce6SKarsten Keil 1092*707b2ce6SKarsten Keil switch (hh->prim) { 1093*707b2ce6SKarsten Keil case PH_DATA_REQ: 1094*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1095*707b2ce6SKarsten Keil ret = dchannel_senddata(dch, skb); 1096*707b2ce6SKarsten Keil if (ret > 0) { /* direct TX */ 1097*707b2ce6SKarsten Keil id = hh->id; /* skb can be freed */ 1098*707b2ce6SKarsten Keil W6692_fill_Dfifo(card); 1099*707b2ce6SKarsten Keil ret = 0; 1100*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1101*707b2ce6SKarsten Keil queue_ch_frame(ch, PH_DATA_CNF, id, NULL); 1102*707b2ce6SKarsten Keil } else 1103*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1104*707b2ce6SKarsten Keil return ret; 1105*707b2ce6SKarsten Keil case PH_ACTIVATE_REQ: 1106*707b2ce6SKarsten Keil ret = l1_event(dch->l1, hh->prim); 1107*707b2ce6SKarsten Keil break; 1108*707b2ce6SKarsten Keil case PH_DEACTIVATE_REQ: 1109*707b2ce6SKarsten Keil test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 1110*707b2ce6SKarsten Keil ret = l1_event(dch->l1, hh->prim); 1111*707b2ce6SKarsten Keil break; 1112*707b2ce6SKarsten Keil } 1113*707b2ce6SKarsten Keil 1114*707b2ce6SKarsten Keil if (!ret) 1115*707b2ce6SKarsten Keil dev_kfree_skb(skb); 1116*707b2ce6SKarsten Keil return ret; 1117*707b2ce6SKarsten Keil } 1118*707b2ce6SKarsten Keil 1119*707b2ce6SKarsten Keil static int 1120*707b2ce6SKarsten Keil w6692_l1callback(struct dchannel *dch, u32 cmd) 1121*707b2ce6SKarsten Keil { 1122*707b2ce6SKarsten Keil struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); 1123*707b2ce6SKarsten Keil u_long flags; 1124*707b2ce6SKarsten Keil 1125*707b2ce6SKarsten Keil pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state); 1126*707b2ce6SKarsten Keil switch (cmd) { 1127*707b2ce6SKarsten Keil case INFO3_P8: 1128*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1129*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_AR8); 1130*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1131*707b2ce6SKarsten Keil break; 1132*707b2ce6SKarsten Keil case INFO3_P10: 1133*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1134*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_AR10); 1135*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1136*707b2ce6SKarsten Keil break; 1137*707b2ce6SKarsten Keil case HW_RESET_REQ: 1138*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1139*707b2ce6SKarsten Keil if (card->state != W_L1IND_DRD) 1140*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_RST); 1141*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_ECK); 1142*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1143*707b2ce6SKarsten Keil break; 1144*707b2ce6SKarsten Keil case HW_DEACT_REQ: 1145*707b2ce6SKarsten Keil skb_queue_purge(&dch->squeue); 1146*707b2ce6SKarsten Keil if (dch->tx_skb) { 1147*707b2ce6SKarsten Keil dev_kfree_skb(dch->tx_skb); 1148*707b2ce6SKarsten Keil dch->tx_skb = NULL; 1149*707b2ce6SKarsten Keil } 1150*707b2ce6SKarsten Keil dch->tx_idx = 0; 1151*707b2ce6SKarsten Keil if (dch->rx_skb) { 1152*707b2ce6SKarsten Keil dev_kfree_skb(dch->rx_skb); 1153*707b2ce6SKarsten Keil dch->rx_skb = NULL; 1154*707b2ce6SKarsten Keil } 1155*707b2ce6SKarsten Keil test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 1156*707b2ce6SKarsten Keil if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) 1157*707b2ce6SKarsten Keil del_timer(&dch->timer); 1158*707b2ce6SKarsten Keil break; 1159*707b2ce6SKarsten Keil case HW_POWERUP_REQ: 1160*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1161*707b2ce6SKarsten Keil ph_command(card, W_L1CMD_ECK); 1162*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1163*707b2ce6SKarsten Keil break; 1164*707b2ce6SKarsten Keil case PH_ACTIVATE_IND: 1165*707b2ce6SKarsten Keil test_and_set_bit(FLG_ACTIVE, &dch->Flags); 1166*707b2ce6SKarsten Keil _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 1167*707b2ce6SKarsten Keil GFP_ATOMIC); 1168*707b2ce6SKarsten Keil break; 1169*707b2ce6SKarsten Keil case PH_DEACTIVATE_IND: 1170*707b2ce6SKarsten Keil test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 1171*707b2ce6SKarsten Keil _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 1172*707b2ce6SKarsten Keil GFP_ATOMIC); 1173*707b2ce6SKarsten Keil break; 1174*707b2ce6SKarsten Keil default: 1175*707b2ce6SKarsten Keil pr_debug("%s: %s unknown command %x\n", card->name, 1176*707b2ce6SKarsten Keil __func__, cmd); 1177*707b2ce6SKarsten Keil return -1; 1178*707b2ce6SKarsten Keil } 1179*707b2ce6SKarsten Keil return 0; 1180*707b2ce6SKarsten Keil } 1181*707b2ce6SKarsten Keil 1182*707b2ce6SKarsten Keil static int 1183*707b2ce6SKarsten Keil open_dchannel(struct w6692_hw *card, struct channel_req *rq) 1184*707b2ce6SKarsten Keil { 1185*707b2ce6SKarsten Keil pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__, 1186*707b2ce6SKarsten Keil card->dch.dev.id, __builtin_return_address(1)); 1187*707b2ce6SKarsten Keil if (rq->protocol != ISDN_P_TE_S0) 1188*707b2ce6SKarsten Keil return -EINVAL; 1189*707b2ce6SKarsten Keil if (rq->adr.channel == 1) 1190*707b2ce6SKarsten Keil /* E-Channel not supported */ 1191*707b2ce6SKarsten Keil return -EINVAL; 1192*707b2ce6SKarsten Keil rq->ch = &card->dch.dev.D; 1193*707b2ce6SKarsten Keil rq->ch->protocol = rq->protocol; 1194*707b2ce6SKarsten Keil if (card->dch.state == 7) 1195*707b2ce6SKarsten Keil _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 1196*707b2ce6SKarsten Keil 0, NULL, GFP_KERNEL); 1197*707b2ce6SKarsten Keil return 0; 1198*707b2ce6SKarsten Keil } 1199*707b2ce6SKarsten Keil 1200*707b2ce6SKarsten Keil static int 1201*707b2ce6SKarsten Keil w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 1202*707b2ce6SKarsten Keil { 1203*707b2ce6SKarsten Keil struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 1204*707b2ce6SKarsten Keil struct dchannel *dch = container_of(dev, struct dchannel, dev); 1205*707b2ce6SKarsten Keil struct w6692_hw *card = container_of(dch, struct w6692_hw, dch); 1206*707b2ce6SKarsten Keil struct channel_req *rq; 1207*707b2ce6SKarsten Keil int err = 0; 1208*707b2ce6SKarsten Keil 1209*707b2ce6SKarsten Keil pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg); 1210*707b2ce6SKarsten Keil switch (cmd) { 1211*707b2ce6SKarsten Keil case OPEN_CHANNEL: 1212*707b2ce6SKarsten Keil rq = arg; 1213*707b2ce6SKarsten Keil if (rq->protocol == ISDN_P_TE_S0) 1214*707b2ce6SKarsten Keil err = open_dchannel(card, rq); 1215*707b2ce6SKarsten Keil else 1216*707b2ce6SKarsten Keil err = open_bchannel(card, rq); 1217*707b2ce6SKarsten Keil if (err) 1218*707b2ce6SKarsten Keil break; 1219*707b2ce6SKarsten Keil if (!try_module_get(THIS_MODULE)) 1220*707b2ce6SKarsten Keil pr_info("%s: cannot get module\n", card->name); 1221*707b2ce6SKarsten Keil break; 1222*707b2ce6SKarsten Keil case CLOSE_CHANNEL: 1223*707b2ce6SKarsten Keil pr_debug("%s: dev(%d) close from %p\n", card->name, 1224*707b2ce6SKarsten Keil dch->dev.id, __builtin_return_address(0)); 1225*707b2ce6SKarsten Keil module_put(THIS_MODULE); 1226*707b2ce6SKarsten Keil break; 1227*707b2ce6SKarsten Keil case CONTROL_CHANNEL: 1228*707b2ce6SKarsten Keil err = channel_ctrl(card, arg); 1229*707b2ce6SKarsten Keil break; 1230*707b2ce6SKarsten Keil default: 1231*707b2ce6SKarsten Keil pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd); 1232*707b2ce6SKarsten Keil return -EINVAL; 1233*707b2ce6SKarsten Keil } 1234*707b2ce6SKarsten Keil return err; 1235*707b2ce6SKarsten Keil } 1236*707b2ce6SKarsten Keil 1237*707b2ce6SKarsten Keil int 1238*707b2ce6SKarsten Keil setup_w6692(struct w6692_hw *card) 1239*707b2ce6SKarsten Keil { 1240*707b2ce6SKarsten Keil u32 val; 1241*707b2ce6SKarsten Keil 1242*707b2ce6SKarsten Keil if (!request_region(card->addr, 256, card->name)) { 1243*707b2ce6SKarsten Keil pr_info("%s: config port %x-%x already in use\n", card->name, 1244*707b2ce6SKarsten Keil card->addr, card->addr + 255); 1245*707b2ce6SKarsten Keil return -EIO; 1246*707b2ce6SKarsten Keil } 1247*707b2ce6SKarsten Keil W6692Version(card); 1248*707b2ce6SKarsten Keil card->bc[0].addr = card->addr; 1249*707b2ce6SKarsten Keil card->bc[1].addr = card->addr + 0x40; 1250*707b2ce6SKarsten Keil val = ReadW6692(card, W_ISTA); 1251*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 1252*707b2ce6SKarsten Keil pr_notice("%s ISTA=%02x\n", card->name, val); 1253*707b2ce6SKarsten Keil val = ReadW6692(card, W_IMASK); 1254*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 1255*707b2ce6SKarsten Keil pr_notice("%s IMASK=%02x\n", card->name, val); 1256*707b2ce6SKarsten Keil val = ReadW6692(card, W_D_EXIR); 1257*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 1258*707b2ce6SKarsten Keil pr_notice("%s D_EXIR=%02x\n", card->name, val); 1259*707b2ce6SKarsten Keil val = ReadW6692(card, W_D_EXIM); 1260*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 1261*707b2ce6SKarsten Keil pr_notice("%s D_EXIM=%02x\n", card->name, val); 1262*707b2ce6SKarsten Keil val = ReadW6692(card, W_D_RSTA); 1263*707b2ce6SKarsten Keil if (debug & DEBUG_HW) 1264*707b2ce6SKarsten Keil pr_notice("%s D_RSTA=%02x\n", card->name, val); 1265*707b2ce6SKarsten Keil return 0; 1266*707b2ce6SKarsten Keil } 1267*707b2ce6SKarsten Keil 1268*707b2ce6SKarsten Keil static void 1269*707b2ce6SKarsten Keil release_card(struct w6692_hw *card) 1270*707b2ce6SKarsten Keil { 1271*707b2ce6SKarsten Keil u_long flags; 1272*707b2ce6SKarsten Keil 1273*707b2ce6SKarsten Keil spin_lock_irqsave(&card->lock, flags); 1274*707b2ce6SKarsten Keil disable_hwirq(card); 1275*707b2ce6SKarsten Keil w6692_mode(&card->bc[0], ISDN_P_NONE); 1276*707b2ce6SKarsten Keil w6692_mode(&card->bc[1], ISDN_P_NONE); 1277*707b2ce6SKarsten Keil if ((card->fmask & led) || card->subtype == W6692_USR) { 1278*707b2ce6SKarsten Keil card->xdata |= 0x04; /* LED OFF */ 1279*707b2ce6SKarsten Keil WriteW6692(card, W_XDATA, card->xdata); 1280*707b2ce6SKarsten Keil } 1281*707b2ce6SKarsten Keil spin_unlock_irqrestore(&card->lock, flags); 1282*707b2ce6SKarsten Keil free_irq(card->irq, card); 1283*707b2ce6SKarsten Keil l1_event(card->dch.l1, CLOSE_CHANNEL); 1284*707b2ce6SKarsten Keil mISDN_unregister_device(&card->dch.dev); 1285*707b2ce6SKarsten Keil release_region(card->addr, 256); 1286*707b2ce6SKarsten Keil mISDN_freebchannel(&card->bc[1].bch); 1287*707b2ce6SKarsten Keil mISDN_freebchannel(&card->bc[0].bch); 1288*707b2ce6SKarsten Keil mISDN_freedchannel(&card->dch); 1289*707b2ce6SKarsten Keil write_lock_irqsave(&card_lock, flags); 1290*707b2ce6SKarsten Keil list_del(&card->list); 1291*707b2ce6SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1292*707b2ce6SKarsten Keil pci_disable_device(card->pdev); 1293*707b2ce6SKarsten Keil pci_set_drvdata(card->pdev, NULL); 1294*707b2ce6SKarsten Keil kfree(card); 1295*707b2ce6SKarsten Keil } 1296*707b2ce6SKarsten Keil 1297*707b2ce6SKarsten Keil static int 1298*707b2ce6SKarsten Keil setup_instance(struct w6692_hw *card) 1299*707b2ce6SKarsten Keil { 1300*707b2ce6SKarsten Keil int i, err; 1301*707b2ce6SKarsten Keil u_long flags; 1302*707b2ce6SKarsten Keil 1303*707b2ce6SKarsten Keil snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1); 1304*707b2ce6SKarsten Keil write_lock_irqsave(&card_lock, flags); 1305*707b2ce6SKarsten Keil list_add_tail(&card->list, &Cards); 1306*707b2ce6SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1307*707b2ce6SKarsten Keil card->fmask = (1 << w6692_cnt); 1308*707b2ce6SKarsten Keil _set_debug(card); 1309*707b2ce6SKarsten Keil spin_lock_init(&card->lock); 1310*707b2ce6SKarsten Keil mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh); 1311*707b2ce6SKarsten Keil card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0); 1312*707b2ce6SKarsten Keil card->dch.dev.D.send = w6692_l2l1D; 1313*707b2ce6SKarsten Keil card->dch.dev.D.ctrl = w6692_dctrl; 1314*707b2ce6SKarsten Keil card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 1315*707b2ce6SKarsten Keil (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 1316*707b2ce6SKarsten Keil card->dch.hw = card; 1317*707b2ce6SKarsten Keil card->dch.dev.nrbchan = 2; 1318*707b2ce6SKarsten Keil for (i = 0; i < 2; i++) { 1319*707b2ce6SKarsten Keil mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); 1320*707b2ce6SKarsten Keil card->bc[i].bch.hw = card; 1321*707b2ce6SKarsten Keil card->bc[i].bch.nr = i + 1; 1322*707b2ce6SKarsten Keil card->bc[i].bch.ch.nr = i + 1; 1323*707b2ce6SKarsten Keil card->bc[i].bch.ch.send = w6692_l2l1B; 1324*707b2ce6SKarsten Keil card->bc[i].bch.ch.ctrl = w6692_bctrl; 1325*707b2ce6SKarsten Keil set_channelmap(i + 1, card->dch.dev.channelmap); 1326*707b2ce6SKarsten Keil list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels); 1327*707b2ce6SKarsten Keil } 1328*707b2ce6SKarsten Keil err = setup_w6692(card); 1329*707b2ce6SKarsten Keil if (err) 1330*707b2ce6SKarsten Keil goto error_setup; 1331*707b2ce6SKarsten Keil err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, 1332*707b2ce6SKarsten Keil card->name); 1333*707b2ce6SKarsten Keil if (err) 1334*707b2ce6SKarsten Keil goto error_reg; 1335*707b2ce6SKarsten Keil err = init_card(card); 1336*707b2ce6SKarsten Keil if (err) 1337*707b2ce6SKarsten Keil goto error_init; 1338*707b2ce6SKarsten Keil err = create_l1(&card->dch, w6692_l1callback); 1339*707b2ce6SKarsten Keil if (!err) { 1340*707b2ce6SKarsten Keil w6692_cnt++; 1341*707b2ce6SKarsten Keil pr_notice("W6692 %d cards installed\n", w6692_cnt); 1342*707b2ce6SKarsten Keil return 0; 1343*707b2ce6SKarsten Keil } 1344*707b2ce6SKarsten Keil 1345*707b2ce6SKarsten Keil free_irq(card->irq, card); 1346*707b2ce6SKarsten Keil error_init: 1347*707b2ce6SKarsten Keil mISDN_unregister_device(&card->dch.dev); 1348*707b2ce6SKarsten Keil error_reg: 1349*707b2ce6SKarsten Keil release_region(card->addr, 256); 1350*707b2ce6SKarsten Keil error_setup: 1351*707b2ce6SKarsten Keil mISDN_freebchannel(&card->bc[1].bch); 1352*707b2ce6SKarsten Keil mISDN_freebchannel(&card->bc[0].bch); 1353*707b2ce6SKarsten Keil mISDN_freedchannel(&card->dch); 1354*707b2ce6SKarsten Keil write_lock_irqsave(&card_lock, flags); 1355*707b2ce6SKarsten Keil list_del(&card->list); 1356*707b2ce6SKarsten Keil write_unlock_irqrestore(&card_lock, flags); 1357*707b2ce6SKarsten Keil kfree(card); 1358*707b2ce6SKarsten Keil return err; 1359*707b2ce6SKarsten Keil } 1360*707b2ce6SKarsten Keil 1361*707b2ce6SKarsten Keil static int __devinit 1362*707b2ce6SKarsten Keil w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 1363*707b2ce6SKarsten Keil { 1364*707b2ce6SKarsten Keil int err = -ENOMEM; 1365*707b2ce6SKarsten Keil struct w6692_hw *card; 1366*707b2ce6SKarsten Keil struct w6692map *m = (struct w6692map *)ent->driver_data; 1367*707b2ce6SKarsten Keil 1368*707b2ce6SKarsten Keil card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL); 1369*707b2ce6SKarsten Keil if (!card) { 1370*707b2ce6SKarsten Keil pr_info("No kmem for w6692 card\n"); 1371*707b2ce6SKarsten Keil return err; 1372*707b2ce6SKarsten Keil } 1373*707b2ce6SKarsten Keil card->pdev = pdev; 1374*707b2ce6SKarsten Keil card->subtype = m->subtype; 1375*707b2ce6SKarsten Keil err = pci_enable_device(pdev); 1376*707b2ce6SKarsten Keil if (err) { 1377*707b2ce6SKarsten Keil kfree(card); 1378*707b2ce6SKarsten Keil return err; 1379*707b2ce6SKarsten Keil } 1380*707b2ce6SKarsten Keil 1381*707b2ce6SKarsten Keil printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n", 1382*707b2ce6SKarsten Keil m->name, pci_name(pdev)); 1383*707b2ce6SKarsten Keil 1384*707b2ce6SKarsten Keil card->addr = pci_resource_start(pdev, 1); 1385*707b2ce6SKarsten Keil card->irq = pdev->irq; 1386*707b2ce6SKarsten Keil pci_set_drvdata(pdev, card); 1387*707b2ce6SKarsten Keil err = setup_instance(card); 1388*707b2ce6SKarsten Keil if (err) 1389*707b2ce6SKarsten Keil pci_set_drvdata(pdev, NULL); 1390*707b2ce6SKarsten Keil return err; 1391*707b2ce6SKarsten Keil } 1392*707b2ce6SKarsten Keil 1393*707b2ce6SKarsten Keil static void __devexit 1394*707b2ce6SKarsten Keil w6692_remove_pci(struct pci_dev *pdev) 1395*707b2ce6SKarsten Keil { 1396*707b2ce6SKarsten Keil struct w6692_hw *card = pci_get_drvdata(pdev); 1397*707b2ce6SKarsten Keil 1398*707b2ce6SKarsten Keil if (card) 1399*707b2ce6SKarsten Keil release_card(card); 1400*707b2ce6SKarsten Keil else 1401*707b2ce6SKarsten Keil if (debug) 1402*707b2ce6SKarsten Keil pr_notice("%s: drvdata allready removed\n", __func__); 1403*707b2ce6SKarsten Keil } 1404*707b2ce6SKarsten Keil 1405*707b2ce6SKarsten Keil static struct pci_device_id w6692_ids[] = { 1406*707b2ce6SKarsten Keil { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, 1407*707b2ce6SKarsten Keil PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]}, 1408*707b2ce6SKarsten Keil { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, 1409*707b2ce6SKarsten Keil PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0, 1410*707b2ce6SKarsten Keil (ulong)&w6692_map[2]}, 1411*707b2ce6SKarsten Keil { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, 1412*707b2ce6SKarsten Keil PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]}, 1413*707b2ce6SKarsten Keil { } 1414*707b2ce6SKarsten Keil }; 1415*707b2ce6SKarsten Keil MODULE_DEVICE_TABLE(pci, w6692_ids); 1416*707b2ce6SKarsten Keil 1417*707b2ce6SKarsten Keil static struct pci_driver w6692_driver = { 1418*707b2ce6SKarsten Keil .name = "w6692", 1419*707b2ce6SKarsten Keil .probe = w6692_probe, 1420*707b2ce6SKarsten Keil .remove = __devexit_p(w6692_remove_pci), 1421*707b2ce6SKarsten Keil .id_table = w6692_ids, 1422*707b2ce6SKarsten Keil }; 1423*707b2ce6SKarsten Keil 1424*707b2ce6SKarsten Keil static int __init w6692_init(void) 1425*707b2ce6SKarsten Keil { 1426*707b2ce6SKarsten Keil int err; 1427*707b2ce6SKarsten Keil 1428*707b2ce6SKarsten Keil pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV); 1429*707b2ce6SKarsten Keil 1430*707b2ce6SKarsten Keil err = pci_register_driver(&w6692_driver); 1431*707b2ce6SKarsten Keil return err; 1432*707b2ce6SKarsten Keil } 1433*707b2ce6SKarsten Keil 1434*707b2ce6SKarsten Keil static void __exit w6692_cleanup(void) 1435*707b2ce6SKarsten Keil { 1436*707b2ce6SKarsten Keil pci_unregister_driver(&w6692_driver); 1437*707b2ce6SKarsten Keil } 1438*707b2ce6SKarsten Keil 1439*707b2ce6SKarsten Keil module_init(w6692_init); 1440*707b2ce6SKarsten Keil module_exit(w6692_cleanup); 1441