void initW6692(struct w6692_hw *card) { u8 val; card->dch.timer.function = (void *)dbusy_timer_handler; card->dch.timer.data = (u_long)&card->dch; init_timer(&card->dch.timer); w6692_mode(&card->bc[0], ISDN_P_NONE); w6692_mode(&card->bc[1], ISDN_P_NONE); WriteW6692(card, W_D_CTL, 0x00); disable_hwirq(card); WriteW6692(card, W_D_SAM, 0xff); WriteW6692(card, W_D_TAM, 0xff); WriteW6692(card, W_D_MODE, W_D_MODE_RACT); card->state = W_L1CMD_RST; ph_command(card, W_L1CMD_RST); ph_command(card, W_L1CMD_ECK); /* enable all IRQ but extern */ card->imask = 0x18; WriteW6692(card, W_D_EXIM, 0x00); WriteW6692B(&card->bc[0], W_B_EXIM, 0); WriteW6692B(&card->bc[1], W_B_EXIM, 0); /* Reset D-chan receiver and transmitter */ WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); /* Reset B-chan receiver and transmitter */ WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); /* enable peripheral */ if (card->subtype == W6692_USR) { /* seems that USR implemented some power control features * Pin 79 is connected to the oscilator circuit so we * have to handle it here */ card->pctl = 0x80; card->xdata = 0; WriteW6692(card, W_PCTL, card->pctl); WriteW6692(card, W_XDATA, card->xdata); } else { card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | W_PCTL_OE1 | W_PCTL_OE0; card->xaddr = 0x00;/* all sw off */ if (card->fmask & pots) card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */ if (card->fmask & led) card->xdata |= 0x04; /* LED OFF */ if ((card->fmask & pots) || (card->fmask & led)) { WriteW6692(card, W_PCTL, card->pctl); WriteW6692(card, W_XADDR, card->xaddr); WriteW6692(card, W_XDATA, card->xdata); val = ReadW6692(card, W_XADDR); if (debug & DEBUG_HW) pr_notice("%s: W_XADDR=%02x\n", card->name, val); } } }
void initW6692(struct w6692_hw *card) { u8 val; card->dch.timer.function = (void *)dbusy_timer_handler; card->dch.timer.data = (u_long)&card->dch; init_timer(&card->dch.timer); w6692_mode(&card->bc[0], ISDN_P_NONE); w6692_mode(&card->bc[1], ISDN_P_NONE); WriteW6692(card, W_D_CTL, 0x00); disable_hwirq(card); WriteW6692(card, W_D_SAM, 0xff); WriteW6692(card, W_D_TAM, 0xff); WriteW6692(card, W_D_MODE, W_D_MODE_RACT); card->state = W_L1CMD_RST; ph_command(card, W_L1CMD_RST); ph_command(card, W_L1CMD_ECK); card->imask = 0x18; WriteW6692(card, W_D_EXIM, 0x00); WriteW6692B(&card->bc[0], W_B_EXIM, 0); WriteW6692B(&card->bc[1], W_B_EXIM, 0); WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); if (card->subtype == W6692_USR) { card->pctl = 0x80; card->xdata = 0; WriteW6692(card, W_PCTL, card->pctl); WriteW6692(card, W_XDATA, card->xdata); } else { card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 | W_PCTL_OE1 | W_PCTL_OE0; card->xaddr = 0x00; if (card->fmask & pots) card->xdata |= 0x06; if (card->fmask & led) card->xdata |= 0x04; if ((card->fmask & pots) || (card->fmask & led)) { WriteW6692(card, W_PCTL, card->pctl); WriteW6692(card, W_XADDR, card->xaddr); WriteW6692(card, W_XDATA, card->xdata); val = ReadW6692(card, W_XADDR); if (debug & DEBUG_HW) pr_notice("%s: W_XADDR=%02x\n", card->name, val); } } }
static int disable_pots(struct w6692_ch *wch) { struct w6692_hw *card = wch->bch.hw; if (!(card->fmask & pots)) return -ENODEV; wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0); WriteW6692B(wch, W_B_MODE, wch->b_mode); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); return 0; }
static int enable_pots(struct w6692_ch *wch) { struct w6692_hw *card = wch->bch.hw; if ((!(card->fmask & pots)) || !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) return -ENODEV; wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; WriteW6692B(wch, W_B_MODE, wch->b_mode); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0); WriteW6692(card, W_PCTL, card->pctl); return 0; }
static void W6692_fill_Bfifo(struct w6692_ch *wch) { struct w6692_hw *card = wch->bch.hw; int count; u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; pr_debug("%s: fill Bfifo\n", card->name); if (!wch->bch.tx_skb) return; count = wch->bch.tx_skb->len - wch->bch.tx_idx; if (count <= 0) return; ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; if (count > W_B_FIFO_THRESH) count = W_B_FIFO_THRESH; else if (test_bit(FLG_HDLC, &wch->bch.Flags)) cmd |= W_B_CMDR_XME; pr_debug("%s: fill Bfifo%d/%d\n", card->name, count, wch->bch.tx_idx); wch->bch.tx_idx += count; outsb(wch->addr + W_B_XFIFO, ptr, count); WriteW6692B(wch, W_B_CMDR, cmd); if (debug & DEBUG_HW_DFIFO) { snprintf(card->log, 63, "B%1d-send %s %d ", wch->bch.nr, card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); } }
static int w6692_mode(struct w6692_ch *wch, u32 pr) { struct w6692_hw *card; card = wch->bch.hw; pr_debug("%s: B%d protocol %x-->%x\n", card->name, wch->bch.nr, wch->bch.state, pr); switch (pr) { case ISDN_P_NONE: if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM)) disable_pots(wch); wch->b_mode = 0; mISDN_clear_bchannel(&wch->bch); WriteW6692B(wch, W_B_MODE, wch->b_mode); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); test_and_clear_bit(FLG_HDLC, &wch->bch.Flags); test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags); break; case ISDN_P_B_RAW: wch->b_mode = W_B_MODE_MMS; WriteW6692B(wch, W_B_MODE, wch->b_mode); WriteW6692B(wch, W_B_EXIM, 0); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags); break; case ISDN_P_B_HDLC: wch->b_mode = W_B_MODE_ITF; WriteW6692B(wch, W_B_MODE, wch->b_mode); WriteW6692B(wch, W_B_ADM1, 0xff); WriteW6692B(wch, W_B_ADM2, 0xff); WriteW6692B(wch, W_B_EXIM, 0); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); test_and_set_bit(FLG_HDLC, &wch->bch.Flags); break; default: pr_info("%s: protocol %x not known\n", card->name, pr); return -ENOPROTOOPT; } wch->bch.state = pr; return 0; }
static void W6692_empty_Bfifo(struct w6692_ch *wch, int count) { struct w6692_hw *card = wch->bch.hw; u8 *ptr; pr_debug("%s: empty_Bfifo %d\n", card->name, count); if (unlikely(wch->bch.state == ISDN_P_NONE)) { pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); if (wch->bch.rx_skb) skb_trim(wch->bch.rx_skb, 0); return; } if (!wch->bch.rx_skb) { wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); if (unlikely(!wch->bch.rx_skb)) { pr_info("%s: B receive out of memory\n", card->name); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); return; } } if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { pr_debug("%s: empty_Bfifo incoming packet too large\n", card->name); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); skb_trim(wch->bch.rx_skb, 0); return; } ptr = skb_put(wch->bch.rx_skb, count); insb(wch->addr + W_B_RFIFO, ptr, count); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); if (debug & DEBUG_HW_DFIFO) { snprintf(card->log, 63, "B%1d-recv %s %d ", wch->bch.nr, card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); } }
static void W6692B_interrupt(struct w6692_hw *card, int ch) { struct w6692_ch *wch = &card->bc[ch]; int count; u8 stat, star = 0; stat = ReadW6692B(wch, W_B_EXIR); pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); if (stat & W_B_EXI_RME) { star = ReadW6692B(wch, W_B_STAR); if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { if ((star & W_B_STAR_RDOV) && test_bit(FLG_ACTIVE, &wch->bch.Flags)) { pr_debug("%s: B%d RDOV proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif } if (test_bit(FLG_HDLC, &wch->bch.Flags)) { if (star & W_B_STAR_CRCE) { pr_debug("%s: B%d CRC error\n", card->name, wch->bch.nr); #ifdef ERROR_STATISTIC wch->bch.err_crc++; #endif } if (star & W_B_STAR_RMB) { pr_debug("%s: B%d message abort\n", card->name, wch->bch.nr); #ifdef ERROR_STATISTIC wch->bch.err_inv++; #endif } } WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); if (wch->bch.rx_skb) skb_trim(wch->bch.rx_skb, 0); } else { count = ReadW6692B(wch, W_B_RBCL) & (W_B_FIFO_THRESH - 1); if (count == 0) count = W_B_FIFO_THRESH; W6692_empty_Bfifo(wch, count); recv_Bchannel(&wch->bch, 0); } } if (stat & W_B_EXI_RMR) { if (!(stat & W_B_EXI_RME)) star = ReadW6692B(wch, W_B_STAR); if (star & W_B_STAR_RDOV) { pr_debug("%s: B%d RDOV proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } else { W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) recv_Bchannel(&wch->bch, 0); } } if (stat & W_B_EXI_RDOV) { if (!(star & W_B_STAR_RDOV)) { pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } } if (stat & W_B_EXI_XFR) { if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { star = ReadW6692B(wch, W_B_STAR); pr_debug("%s: B%d star %02x\n", card->name, wch->bch.nr, star); } if (star & W_B_STAR_XDOW) { pr_debug("%s: B%d XDOW proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; } } send_next(wch); if (stat & W_B_EXI_XDUN) return; } if (stat & W_B_EXI_XDUN) { pr_debug("%s: B%d XDUN proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; } send_next(wch); } }