static void W6692_empty_Dfifo(struct w6692_hw *card, int count) { struct dchannel *dch = &card->dch; u8 *ptr; pr_debug("%s: empty_Dfifo %d\n", card->name, count); if (!dch->rx_skb) { dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC); if (!dch->rx_skb) { pr_info("%s: D receive out of memory\n", card->name); WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); return; } } if ((dch->rx_skb->len + count) >= dch->maxlen) { pr_debug("%s: empty_Dfifo overrun %d\n", card->name, dch->rx_skb->len + count); WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); return; } ptr = skb_put(dch->rx_skb, count); insb(card->addr + W_D_RFIFO, ptr, count); WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); if (debug & DEBUG_HW_DFIFO) { snprintf(card->log, 63, "D-recv %s %d ", card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); } }
static void reset_w6692(struct w6692_hw *card) { WriteW6692(card, W_D_CTL, W_D_CTL_SRST); mdelay(10); WriteW6692(card, W_D_CTL, 0); }
static void w6692_led_handler(struct w6692_hw *card, int on) { if ((!(card->fmask & led)) || card->subtype == W6692_USR) return; if (on) { card->xdata &= 0xfb; WriteW6692(card, W_XDATA, card->xdata); } else { card->xdata |= 0x04; WriteW6692(card, W_XDATA, card->xdata); } }
static void dbusy_timer_handler(struct dchannel *dch) { struct w6692_hw *card = dch->hw; int rbch, star; u_long flags; if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { spin_lock_irqsave(&card->lock, flags); rbch = ReadW6692(card, W_D_RBCH); star = ReadW6692(card, W_D_STAR); pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n", card->name, rbch, star); if (star & W_D_STAR_XBZ) test_and_set_bit(FLG_L1_BUSY, &dch->Flags); else { test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags); if (dch->tx_idx) dch->tx_idx = 0; else pr_info("%s: W6692 D-Channel Busy no tx_idx\n", card->name); WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); } spin_unlock_irqrestore(&card->lock, flags); } }
static int setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb) { struct w6692_hw *card = wch->bch.hw; u16 *vol = (u16 *)skb->data; u8 val; if ((!(card->fmask & pots)) || !test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) return -ENODEV; if (skb->len < 2) return -EINVAL; if (*vol > 7) return -EINVAL; val = *vol & 7; val = 7 - val; if (mic) { val <<= 3; card->xaddr &= 0xc7; } else { card->xaddr &= 0xf8; } card->xaddr |= val; WriteW6692(card, W_XADDR, card->xaddr); return 0; }
static void W6692_fill_Dfifo(struct w6692_hw *card) { struct dchannel *dch = &card->dch; int count; u8 *ptr; u8 cmd = W_D_CMDR_XMS; pr_debug("%s: fill_Dfifo\n", card->name); if (!dch->tx_skb) return; count = dch->tx_skb->len - dch->tx_idx; if (count <= 0) return; if (count > W_D_FIFO_THRESH) count = W_D_FIFO_THRESH; else cmd |= W_D_CMDR_XME; ptr = dch->tx_skb->data + dch->tx_idx; dch->tx_idx += count; outsb(card->addr + W_D_XFIFO, ptr, count); WriteW6692(card, W_D_CMDR, cmd); if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name); del_timer(&dch->timer); } init_timer(&dch->timer); dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); add_timer(&dch->timer); if (debug & DEBUG_HW_DFIFO) { snprintf(card->log, 63, "D-send %s %d ", card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); } }
static void release_card(struct w6692_hw *card) { u_long flags; spin_lock_irqsave(&card->lock, flags); disable_hwirq(card); w6692_mode(&card->bc[0], ISDN_P_NONE); w6692_mode(&card->bc[1], ISDN_P_NONE); if ((card->fmask & led) || card->subtype == W6692_USR) { card->xdata |= 0x04; WriteW6692(card, W_XDATA, card->xdata); } spin_unlock_irqrestore(&card->lock, flags); free_irq(card->irq, card); l1_event(card->dch.l1, CLOSE_CHANNEL); mISDN_unregister_device(&card->dch.dev); release_region(card->addr, 256); mISDN_freebchannel(&card->bc[1].bch); mISDN_freebchannel(&card->bc[0].bch); mISDN_freedchannel(&card->dch); write_lock_irqsave(&card_lock, flags); list_del(&card->list); write_unlock_irqrestore(&card_lock, flags); pci_disable_device(card->pdev); pci_set_drvdata(card->pdev, NULL); kfree(card); }
static void handle_statusD(struct w6692_hw *card) { struct dchannel *dch = &card->dch; u8 exval, v1, cir; exval = ReadW6692(card, W_D_EXIR); pr_debug("%s: D_EXIR %02x\n", card->name, exval); if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { pr_debug("%s: D-channel underrun/collision\n", card->name); #ifdef ERROR_STATISTIC dch->err_tx++; #endif d_retransmit(card); } if (exval & W_D_EXI_RDOV) { pr_debug("%s: D-channel RDOV\n", card->name); WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST); } if (exval & W_D_EXI_TIN2) pr_debug("%s: spurious TIN2 interrupt\n", card->name); if (exval & W_D_EXI_MOC) { v1 = ReadW6692(card, W_MOSR); pr_debug("%s: spurious MOC interrupt MOSR %02x\n", card->name, v1); } if (exval & W_D_EXI_ISC) { cir = ReadW6692(card, W_CIR); pr_debug("%s: ISC CIR %02X\n", card->name, cir); if (cir & W_CIR_ICC) { v1 = cir & W_CIR_COD_MASK; pr_debug("%s: ph_state_change %x -> %x\n", card->name, dch->state, v1); card->state = v1; if (card->fmask & led) { switch (v1) { case W_L1IND_AI8: case W_L1IND_AI10: w6692_led_handler(card, 1); break; default: w6692_led_handler(card, 0); break; } } W6692_new_ph(card); } if (cir & W_CIR_SCC) { v1 = ReadW6692(card, W_SQR); pr_debug("%s: SCC SQR %02X\n", card->name, v1); } } if (exval & W_D_EXI_WEXP) pr_debug("%s: spurious WEXP interrupt!\n", card->name); if (exval & W_D_EXI_TEXP) pr_debug("%s: spurious TEXP interrupt!\n", card->name); }
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 handle_rxD(struct w6692_hw *card) { u8 stat; int count; stat = ReadW6692(card, W_D_RSTA); if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { if (stat & W_D_RSTA_RDOV) { pr_debug("%s: D-channel RDOV\n", card->name); #ifdef ERROR_STATISTIC card->dch.err_rx++; #endif } if (stat & W_D_RSTA_CRCE) { pr_debug("%s: D-channel CRC error\n", card->name); #ifdef ERROR_STATISTIC card->dch.err_crc++; #endif } if (stat & W_D_RSTA_RMB) { pr_debug("%s: D-channel ABORT\n", card->name); #ifdef ERROR_STATISTIC card->dch.err_rx++; #endif } if (card->dch.rx_skb) dev_kfree_skb(card->dch.rx_skb); card->dch.rx_skb = NULL; WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); } else { count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1); if (count == 0) count = W_D_FIFO_THRESH; W6692_empty_Dfifo(card, count); recv_Dchannel(&card->dch); } }
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 void ph_command(struct w6692_hw *card, u8 cmd) { pr_debug("%s: ph_command %x\n", card->name, cmd); WriteW6692(card, W_CIX, cmd); }
static void disable_hwirq(struct w6692_hw *card) { WriteW6692(card, W_IMASK, 0xff); }
static void enable_hwirq(struct w6692_hw *card) { WriteW6692(card, W_IMASK, card->imask); }
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); } } }