1637 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * isac.c ISAC specific routines4 *5 * Author Karsten Keil <keil@isdn4linux.de>6 *7 * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>8 */9 10#include <linux/irqreturn.h>11#include <linux/slab.h>12#include <linux/module.h>13#include <linux/mISDNhw.h>14#include "ipac.h"15 16 17#define DBUSY_TIMER_VALUE 8018#define ARCOFI_USE 119 20#define ISAC_REV "2.0"21 22MODULE_AUTHOR("Karsten Keil");23MODULE_VERSION(ISAC_REV);24MODULE_DESCRIPTION("mISDN driver for ISAC specific functions");25MODULE_LICENSE("GPL v2");26 27#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off))28#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v))29#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o))30#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v))31#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o))32#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v))33 34static inline void35ph_command(struct isac_hw *isac, u8 command)36{37 pr_debug("%s: ph_command %x\n", isac->name, command);38 if (isac->type & IPAC_TYPE_ISACX)39 WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);40 else41 WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);42}43 44static void45isac_ph_state_change(struct isac_hw *isac)46{47 switch (isac->state) {48 case (ISAC_IND_RS):49 case (ISAC_IND_EI):50 ph_command(isac, ISAC_CMD_DUI);51 }52 schedule_event(&isac->dch, FLG_PHCHANGE);53}54 55static void56isac_ph_state_bh(struct dchannel *dch)57{58 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);59 60 switch (isac->state) {61 case ISAC_IND_RS:62 case ISAC_IND_EI:63 dch->state = 0;64 l1_event(dch->l1, HW_RESET_IND);65 break;66 case ISAC_IND_DID:67 dch->state = 3;68 l1_event(dch->l1, HW_DEACT_CNF);69 break;70 case ISAC_IND_DR:71 case ISAC_IND_DR6:72 dch->state = 3;73 l1_event(dch->l1, HW_DEACT_IND);74 break;75 case ISAC_IND_PU:76 dch->state = 4;77 l1_event(dch->l1, HW_POWERUP_IND);78 break;79 case ISAC_IND_RSY:80 if (dch->state <= 5) {81 dch->state = 5;82 l1_event(dch->l1, ANYSIGNAL);83 } else {84 dch->state = 8;85 l1_event(dch->l1, LOSTFRAMING);86 }87 break;88 case ISAC_IND_ARD:89 dch->state = 6;90 l1_event(dch->l1, INFO2);91 break;92 case ISAC_IND_AI8:93 dch->state = 7;94 l1_event(dch->l1, INFO4_P8);95 break;96 case ISAC_IND_AI10:97 dch->state = 7;98 l1_event(dch->l1, INFO4_P10);99 break;100 }101 pr_debug("%s: TE newstate %x\n", isac->name, dch->state);102}103 104static void105isac_empty_fifo(struct isac_hw *isac, int count)106{107 u8 *ptr;108 109 pr_debug("%s: %s %d\n", isac->name, __func__, count);110 111 if (!isac->dch.rx_skb) {112 isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);113 if (!isac->dch.rx_skb) {114 pr_info("%s: D receive out of memory\n", isac->name);115 WriteISAC(isac, ISAC_CMDR, 0x80);116 return;117 }118 }119 if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {120 pr_debug("%s: %s overrun %d\n", isac->name, __func__,121 isac->dch.rx_skb->len + count);122 WriteISAC(isac, ISAC_CMDR, 0x80);123 return;124 }125 ptr = skb_put(isac->dch.rx_skb, count);126 isac->read_fifo(isac->dch.hw, isac->off, ptr, count);127 WriteISAC(isac, ISAC_CMDR, 0x80);128 if (isac->dch.debug & DEBUG_HW_DFIFO) {129 char pfx[MISDN_MAX_IDLEN + 16];130 131 snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",132 isac->name, count);133 print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);134 }135}136 137static void138isac_fill_fifo(struct isac_hw *isac)139{140 int count, more;141 u8 *ptr;142 143 if (!isac->dch.tx_skb)144 return;145 count = isac->dch.tx_skb->len - isac->dch.tx_idx;146 if (count <= 0)147 return;148 149 more = 0;150 if (count > 32) {151 more = !0;152 count = 32;153 }154 pr_debug("%s: %s %d\n", isac->name, __func__, count);155 ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;156 isac->dch.tx_idx += count;157 isac->write_fifo(isac->dch.hw, isac->off, ptr, count);158 WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);159 if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {160 pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);161 del_timer(&isac->dch.timer);162 }163 isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);164 add_timer(&isac->dch.timer);165 if (isac->dch.debug & DEBUG_HW_DFIFO) {166 char pfx[MISDN_MAX_IDLEN + 16];167 168 snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",169 isac->name, count);170 print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);171 }172}173 174static void175isac_rme_irq(struct isac_hw *isac)176{177 u8 val, count;178 179 val = ReadISAC(isac, ISAC_RSTA);180 if ((val & 0x70) != 0x20) {181 if (val & 0x40) {182 pr_debug("%s: ISAC RDO\n", isac->name);183#ifdef ERROR_STATISTIC184 isac->dch.err_rx++;185#endif186 }187 if (!(val & 0x20)) {188 pr_debug("%s: ISAC CRC error\n", isac->name);189#ifdef ERROR_STATISTIC190 isac->dch.err_crc++;191#endif192 }193 WriteISAC(isac, ISAC_CMDR, 0x80);194 dev_kfree_skb(isac->dch.rx_skb);195 isac->dch.rx_skb = NULL;196 } else {197 count = ReadISAC(isac, ISAC_RBCL) & 0x1f;198 if (count == 0)199 count = 32;200 isac_empty_fifo(isac, count);201 recv_Dchannel(&isac->dch);202 }203}204 205static void206isac_xpr_irq(struct isac_hw *isac)207{208 if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))209 del_timer(&isac->dch.timer);210 if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {211 isac_fill_fifo(isac);212 } else {213 dev_kfree_skb(isac->dch.tx_skb);214 if (get_next_dframe(&isac->dch))215 isac_fill_fifo(isac);216 }217}218 219static void220isac_retransmit(struct isac_hw *isac)221{222 if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))223 del_timer(&isac->dch.timer);224 if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {225 /* Restart frame */226 isac->dch.tx_idx = 0;227 isac_fill_fifo(isac);228 } else if (isac->dch.tx_skb) { /* should not happen */229 pr_info("%s: tx_skb exist but not busy\n", isac->name);230 test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);231 isac->dch.tx_idx = 0;232 isac_fill_fifo(isac);233 } else {234 pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);235 if (get_next_dframe(&isac->dch))236 isac_fill_fifo(isac);237 }238}239 240static void241isac_mos_irq(struct isac_hw *isac)242{243 u8 val;244 int ret;245 246 val = ReadISAC(isac, ISAC_MOSR);247 pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);248#if ARCOFI_USE249 if (val & 0x08) {250 if (!isac->mon_rx) {251 isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);252 if (!isac->mon_rx) {253 pr_info("%s: ISAC MON RX out of memory!\n",254 isac->name);255 isac->mocr &= 0xf0;256 isac->mocr |= 0x0a;257 WriteISAC(isac, ISAC_MOCR, isac->mocr);258 goto afterMONR0;259 } else260 isac->mon_rxp = 0;261 }262 if (isac->mon_rxp >= MAX_MON_FRAME) {263 isac->mocr &= 0xf0;264 isac->mocr |= 0x0a;265 WriteISAC(isac, ISAC_MOCR, isac->mocr);266 isac->mon_rxp = 0;267 pr_debug("%s: ISAC MON RX overflow!\n", isac->name);268 goto afterMONR0;269 }270 isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);271 pr_debug("%s: ISAC MOR0 %02x\n", isac->name,272 isac->mon_rx[isac->mon_rxp - 1]);273 if (isac->mon_rxp == 1) {274 isac->mocr |= 0x04;275 WriteISAC(isac, ISAC_MOCR, isac->mocr);276 }277 }278afterMONR0:279 if (val & 0x80) {280 if (!isac->mon_rx) {281 isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);282 if (!isac->mon_rx) {283 pr_info("%s: ISAC MON RX out of memory!\n",284 isac->name);285 isac->mocr &= 0x0f;286 isac->mocr |= 0xa0;287 WriteISAC(isac, ISAC_MOCR, isac->mocr);288 goto afterMONR1;289 } else290 isac->mon_rxp = 0;291 }292 if (isac->mon_rxp >= MAX_MON_FRAME) {293 isac->mocr &= 0x0f;294 isac->mocr |= 0xa0;295 WriteISAC(isac, ISAC_MOCR, isac->mocr);296 isac->mon_rxp = 0;297 pr_debug("%s: ISAC MON RX overflow!\n", isac->name);298 goto afterMONR1;299 }300 isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);301 pr_debug("%s: ISAC MOR1 %02x\n", isac->name,302 isac->mon_rx[isac->mon_rxp - 1]);303 isac->mocr |= 0x40;304 WriteISAC(isac, ISAC_MOCR, isac->mocr);305 }306afterMONR1:307 if (val & 0x04) {308 isac->mocr &= 0xf0;309 WriteISAC(isac, ISAC_MOCR, isac->mocr);310 isac->mocr |= 0x0a;311 WriteISAC(isac, ISAC_MOCR, isac->mocr);312 if (isac->monitor) {313 ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,314 isac->mon_rx, isac->mon_rxp);315 if (ret)316 kfree(isac->mon_rx);317 } else {318 pr_info("%s: MONITOR 0 received %d but no user\n",319 isac->name, isac->mon_rxp);320 kfree(isac->mon_rx);321 }322 isac->mon_rx = NULL;323 isac->mon_rxp = 0;324 }325 if (val & 0x40) {326 isac->mocr &= 0x0f;327 WriteISAC(isac, ISAC_MOCR, isac->mocr);328 isac->mocr |= 0xa0;329 WriteISAC(isac, ISAC_MOCR, isac->mocr);330 if (isac->monitor) {331 ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,332 isac->mon_rx, isac->mon_rxp);333 if (ret)334 kfree(isac->mon_rx);335 } else {336 pr_info("%s: MONITOR 1 received %d but no user\n",337 isac->name, isac->mon_rxp);338 kfree(isac->mon_rx);339 }340 isac->mon_rx = NULL;341 isac->mon_rxp = 0;342 }343 if (val & 0x02) {344 if ((!isac->mon_tx) || (isac->mon_txc &&345 (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {346 isac->mocr &= 0xf0;347 WriteISAC(isac, ISAC_MOCR, isac->mocr);348 isac->mocr |= 0x0a;349 WriteISAC(isac, ISAC_MOCR, isac->mocr);350 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {351 if (isac->monitor)352 isac->monitor(isac->dch.hw,353 MONITOR_TX_0, NULL, 0);354 }355 kfree(isac->mon_tx);356 isac->mon_tx = NULL;357 isac->mon_txc = 0;358 isac->mon_txp = 0;359 goto AfterMOX0;360 }361 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {362 if (isac->monitor)363 isac->monitor(isac->dch.hw,364 MONITOR_TX_0, NULL, 0);365 kfree(isac->mon_tx);366 isac->mon_tx = NULL;367 isac->mon_txc = 0;368 isac->mon_txp = 0;369 goto AfterMOX0;370 }371 WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);372 pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,373 isac->mon_tx[isac->mon_txp - 1]);374 }375AfterMOX0:376 if (val & 0x20) {377 if ((!isac->mon_tx) || (isac->mon_txc &&378 (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {379 isac->mocr &= 0x0f;380 WriteISAC(isac, ISAC_MOCR, isac->mocr);381 isac->mocr |= 0xa0;382 WriteISAC(isac, ISAC_MOCR, isac->mocr);383 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {384 if (isac->monitor)385 isac->monitor(isac->dch.hw,386 MONITOR_TX_1, NULL, 0);387 }388 kfree(isac->mon_tx);389 isac->mon_tx = NULL;390 isac->mon_txc = 0;391 isac->mon_txp = 0;392 goto AfterMOX1;393 }394 if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {395 if (isac->monitor)396 isac->monitor(isac->dch.hw,397 MONITOR_TX_1, NULL, 0);398 kfree(isac->mon_tx);399 isac->mon_tx = NULL;400 isac->mon_txc = 0;401 isac->mon_txp = 0;402 goto AfterMOX1;403 }404 WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);405 pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,406 isac->mon_tx[isac->mon_txp - 1]);407 }408AfterMOX1:409 val = 0; /* dummy to avoid warning */410#endif411}412 413static void414isac_cisq_irq(struct isac_hw *isac) {415 u8 val;416 417 val = ReadISAC(isac, ISAC_CIR0);418 pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);419 if (val & 2) {420 pr_debug("%s: ph_state change %x->%x\n", isac->name,421 isac->state, (val >> 2) & 0xf);422 isac->state = (val >> 2) & 0xf;423 isac_ph_state_change(isac);424 }425 if (val & 1) {426 val = ReadISAC(isac, ISAC_CIR1);427 pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);428 }429}430 431static void432isacsx_cic_irq(struct isac_hw *isac)433{434 u8 val;435 436 val = ReadISAC(isac, ISACX_CIR0);437 pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);438 if (val & ISACX_CIR0_CIC0) {439 pr_debug("%s: ph_state change %x->%x\n", isac->name,440 isac->state, val >> 4);441 isac->state = val >> 4;442 isac_ph_state_change(isac);443 }444}445 446static void447isacsx_rme_irq(struct isac_hw *isac)448{449 int count;450 u8 val;451 452 val = ReadISAC(isac, ISACX_RSTAD);453 if ((val & (ISACX_RSTAD_VFR |454 ISACX_RSTAD_RDO |455 ISACX_RSTAD_CRC |456 ISACX_RSTAD_RAB))457 != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {458 pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);459#ifdef ERROR_STATISTIC460 if (val & ISACX_RSTAD_CRC)461 isac->dch.err_rx++;462 else463 isac->dch.err_crc++;464#endif465 WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);466 dev_kfree_skb(isac->dch.rx_skb);467 isac->dch.rx_skb = NULL;468 } else {469 count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;470 if (count == 0)471 count = 32;472 isac_empty_fifo(isac, count);473 if (isac->dch.rx_skb) {474 skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);475 pr_debug("%s: dchannel received %d\n", isac->name,476 isac->dch.rx_skb->len);477 recv_Dchannel(&isac->dch);478 }479 }480}481 482irqreturn_t483mISDNisac_irq(struct isac_hw *isac, u8 val)484{485 if (unlikely(!val))486 return IRQ_NONE;487 pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);488 if (isac->type & IPAC_TYPE_ISACX) {489 if (val & ISACX__CIC)490 isacsx_cic_irq(isac);491 if (val & ISACX__ICD) {492 val = ReadISAC(isac, ISACX_ISTAD);493 pr_debug("%s: ISTAD %02x\n", isac->name, val);494 if (val & ISACX_D_XDU) {495 pr_debug("%s: ISAC XDU\n", isac->name);496#ifdef ERROR_STATISTIC497 isac->dch.err_tx++;498#endif499 isac_retransmit(isac);500 }501 if (val & ISACX_D_XMR) {502 pr_debug("%s: ISAC XMR\n", isac->name);503#ifdef ERROR_STATISTIC504 isac->dch.err_tx++;505#endif506 isac_retransmit(isac);507 }508 if (val & ISACX_D_XPR)509 isac_xpr_irq(isac);510 if (val & ISACX_D_RFO) {511 pr_debug("%s: ISAC RFO\n", isac->name);512 WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);513 }514 if (val & ISACX_D_RME)515 isacsx_rme_irq(isac);516 if (val & ISACX_D_RPF)517 isac_empty_fifo(isac, 0x20);518 }519 } else {520 if (val & 0x80) /* RME */521 isac_rme_irq(isac);522 if (val & 0x40) /* RPF */523 isac_empty_fifo(isac, 32);524 if (val & 0x10) /* XPR */525 isac_xpr_irq(isac);526 if (val & 0x04) /* CISQ */527 isac_cisq_irq(isac);528 if (val & 0x20) /* RSC - never */529 pr_debug("%s: ISAC RSC interrupt\n", isac->name);530 if (val & 0x02) /* SIN - never */531 pr_debug("%s: ISAC SIN interrupt\n", isac->name);532 if (val & 0x01) { /* EXI */533 val = ReadISAC(isac, ISAC_EXIR);534 pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);535 if (val & 0x80) /* XMR */536 pr_debug("%s: ISAC XMR\n", isac->name);537 if (val & 0x40) { /* XDU */538 pr_debug("%s: ISAC XDU\n", isac->name);539#ifdef ERROR_STATISTIC540 isac->dch.err_tx++;541#endif542 isac_retransmit(isac);543 }544 if (val & 0x04) /* MOS */545 isac_mos_irq(isac);546 }547 }548 return IRQ_HANDLED;549}550EXPORT_SYMBOL(mISDNisac_irq);551 552static int553isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)554{555 struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);556 struct dchannel *dch = container_of(dev, struct dchannel, dev);557 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);558 int ret = -EINVAL;559 struct mISDNhead *hh = mISDN_HEAD_P(skb);560 u32 id;561 u_long flags;562 563 switch (hh->prim) {564 case PH_DATA_REQ:565 spin_lock_irqsave(isac->hwlock, flags);566 ret = dchannel_senddata(dch, skb);567 if (ret > 0) { /* direct TX */568 id = hh->id; /* skb can be freed */569 isac_fill_fifo(isac);570 ret = 0;571 spin_unlock_irqrestore(isac->hwlock, flags);572 queue_ch_frame(ch, PH_DATA_CNF, id, NULL);573 } else574 spin_unlock_irqrestore(isac->hwlock, flags);575 return ret;576 case PH_ACTIVATE_REQ:577 ret = l1_event(dch->l1, hh->prim);578 break;579 case PH_DEACTIVATE_REQ:580 test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);581 ret = l1_event(dch->l1, hh->prim);582 break;583 }584 585 if (!ret)586 dev_kfree_skb(skb);587 return ret;588}589 590static int591isac_ctrl(struct isac_hw *isac, u32 cmd, unsigned long para)592{593 u8 tl = 0;594 unsigned long flags;595 int ret = 0;596 597 switch (cmd) {598 case HW_TESTLOOP:599 spin_lock_irqsave(isac->hwlock, flags);600 if (!(isac->type & IPAC_TYPE_ISACX)) {601 /* TODO: implement for IPAC_TYPE_ISACX */602 if (para & 1) /* B1 */603 tl |= 0x0c;604 else if (para & 2) /* B2 */605 tl |= 0x3;606 /* we only support IOM2 mode */607 WriteISAC(isac, ISAC_SPCR, tl);608 if (tl)609 WriteISAC(isac, ISAC_ADF1, 0x8);610 else611 WriteISAC(isac, ISAC_ADF1, 0x0);612 }613 spin_unlock_irqrestore(isac->hwlock, flags);614 break;615 case HW_TIMER3_VALUE:616 ret = l1_event(isac->dch.l1, HW_TIMER3_VALUE | (para & 0xff));617 break;618 default:619 pr_debug("%s: %s unknown command %x %lx\n", isac->name,620 __func__, cmd, para);621 ret = -1;622 }623 return ret;624}625 626static int627isac_l1cmd(struct dchannel *dch, u32 cmd)628{629 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);630 u_long flags;631 632 pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);633 switch (cmd) {634 case INFO3_P8:635 spin_lock_irqsave(isac->hwlock, flags);636 ph_command(isac, ISAC_CMD_AR8);637 spin_unlock_irqrestore(isac->hwlock, flags);638 break;639 case INFO3_P10:640 spin_lock_irqsave(isac->hwlock, flags);641 ph_command(isac, ISAC_CMD_AR10);642 spin_unlock_irqrestore(isac->hwlock, flags);643 break;644 case HW_RESET_REQ:645 spin_lock_irqsave(isac->hwlock, flags);646 if ((isac->state == ISAC_IND_EI) ||647 (isac->state == ISAC_IND_DR) ||648 (isac->state == ISAC_IND_DR6) ||649 (isac->state == ISAC_IND_RS))650 ph_command(isac, ISAC_CMD_TIM);651 else652 ph_command(isac, ISAC_CMD_RS);653 spin_unlock_irqrestore(isac->hwlock, flags);654 break;655 case HW_DEACT_REQ:656 skb_queue_purge(&dch->squeue);657 if (dch->tx_skb) {658 dev_kfree_skb(dch->tx_skb);659 dch->tx_skb = NULL;660 }661 dch->tx_idx = 0;662 if (dch->rx_skb) {663 dev_kfree_skb(dch->rx_skb);664 dch->rx_skb = NULL;665 }666 test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);667 if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))668 del_timer(&dch->timer);669 break;670 case HW_POWERUP_REQ:671 spin_lock_irqsave(isac->hwlock, flags);672 ph_command(isac, ISAC_CMD_TIM);673 spin_unlock_irqrestore(isac->hwlock, flags);674 break;675 case PH_ACTIVATE_IND:676 test_and_set_bit(FLG_ACTIVE, &dch->Flags);677 _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,678 GFP_ATOMIC);679 break;680 case PH_DEACTIVATE_IND:681 test_and_clear_bit(FLG_ACTIVE, &dch->Flags);682 _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,683 GFP_ATOMIC);684 break;685 default:686 pr_debug("%s: %s unknown command %x\n", isac->name,687 __func__, cmd);688 return -1;689 }690 return 0;691}692 693static void694isac_release(struct isac_hw *isac)695{696 if (isac->type & IPAC_TYPE_ISACX)697 WriteISAC(isac, ISACX_MASK, 0xff);698 else if (isac->type != 0)699 WriteISAC(isac, ISAC_MASK, 0xff);700 if (isac->dch.timer.function != NULL) {701 del_timer(&isac->dch.timer);702 isac->dch.timer.function = NULL;703 }704 kfree(isac->mon_rx);705 isac->mon_rx = NULL;706 kfree(isac->mon_tx);707 isac->mon_tx = NULL;708 if (isac->dch.l1)709 l1_event(isac->dch.l1, CLOSE_CHANNEL);710 mISDN_freedchannel(&isac->dch);711}712 713static void714dbusy_timer_handler(struct timer_list *t)715{716 struct isac_hw *isac = from_timer(isac, t, dch.timer);717 int rbch, star;718 u_long flags;719 720 if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {721 spin_lock_irqsave(isac->hwlock, flags);722 rbch = ReadISAC(isac, ISAC_RBCH);723 star = ReadISAC(isac, ISAC_STAR);724 pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",725 isac->name, rbch, star);726 if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */727 test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);728 else {729 /* discard frame; reset transceiver */730 test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);731 if (isac->dch.tx_idx)732 isac->dch.tx_idx = 0;733 else734 pr_info("%s: ISAC D-Channel Busy no tx_idx\n",735 isac->name);736 /* Transmitter reset */737 WriteISAC(isac, ISAC_CMDR, 0x01);738 }739 spin_unlock_irqrestore(isac->hwlock, flags);740 }741}742 743static int744open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller)745{746 pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,747 isac->dch.dev.id, caller);748 if (rq->protocol != ISDN_P_TE_S0)749 return -EINVAL;750 if (rq->adr.channel == 1)751 /* E-Channel not supported */752 return -EINVAL;753 rq->ch = &isac->dch.dev.D;754 rq->ch->protocol = rq->protocol;755 if (isac->dch.state == 7)756 _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,757 0, NULL, GFP_KERNEL);758 return 0;759}760 761static int762open_dchannel(struct isac_hw *isac, struct channel_req *rq)763{764 return open_dchannel_caller(isac, rq, __builtin_return_address(0));765}766 767static const char *ISACVer[] =768{"2086/2186 V1.1", "2085 B1", "2085 B2",769 "2085 V2.3"};770 771static int772isac_init(struct isac_hw *isac)773{774 u8 val;775 int err = 0;776 777 if (!isac->dch.l1) {778 err = create_l1(&isac->dch, isac_l1cmd);779 if (err)780 return err;781 }782 isac->mon_tx = NULL;783 isac->mon_rx = NULL;784 timer_setup(&isac->dch.timer, dbusy_timer_handler, 0);785 isac->mocr = 0xaa;786 if (isac->type & IPAC_TYPE_ISACX) {787 /* Disable all IRQ */788 WriteISAC(isac, ISACX_MASK, 0xff);789 val = ReadISAC(isac, ISACX_STARD);790 pr_debug("%s: ISACX STARD %x\n", isac->name, val);791 val = ReadISAC(isac, ISACX_ISTAD);792 pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);793 val = ReadISAC(isac, ISACX_ISTA);794 pr_debug("%s: ISACX ISTA %x\n", isac->name, val);795 /* clear LDD */796 WriteISAC(isac, ISACX_TR_CONF0, 0x00);797 /* enable transmitter */798 WriteISAC(isac, ISACX_TR_CONF2, 0x00);799 /* transparent mode 0, RAC, stop/go */800 WriteISAC(isac, ISACX_MODED, 0xc9);801 /* all HDLC IRQ unmasked */802 val = ReadISAC(isac, ISACX_ID);803 if (isac->dch.debug & DEBUG_HW)804 pr_notice("%s: ISACX Design ID %x\n",805 isac->name, val & 0x3f);806 val = ReadISAC(isac, ISACX_CIR0);807 pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);808 isac->state = val >> 4;809 isac_ph_state_change(isac);810 ph_command(isac, ISAC_CMD_RS);811 WriteISAC(isac, ISACX_MASK, IPACX__ON);812 WriteISAC(isac, ISACX_MASKD, 0x00);813 } else { /* old isac */814 WriteISAC(isac, ISAC_MASK, 0xff);815 val = ReadISAC(isac, ISAC_STAR);816 pr_debug("%s: ISAC STAR %x\n", isac->name, val);817 val = ReadISAC(isac, ISAC_MODE);818 pr_debug("%s: ISAC MODE %x\n", isac->name, val);819 val = ReadISAC(isac, ISAC_ADF2);820 pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);821 val = ReadISAC(isac, ISAC_ISTA);822 pr_debug("%s: ISAC ISTA %x\n", isac->name, val);823 if (val & 0x01) {824 val = ReadISAC(isac, ISAC_EXIR);825 pr_debug("%s: ISAC EXIR %x\n", isac->name, val);826 }827 val = ReadISAC(isac, ISAC_RBCH);828 if (isac->dch.debug & DEBUG_HW)829 pr_notice("%s: ISAC version (%x): %s\n", isac->name,830 val, ISACVer[(val >> 5) & 3]);831 isac->type |= ((val >> 5) & 3);832 if (!isac->adf2)833 isac->adf2 = 0x80;834 if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */835 pr_info("%s: only support IOM2 mode but adf2=%02x\n",836 isac->name, isac->adf2);837 isac_release(isac);838 return -EINVAL;839 }840 WriteISAC(isac, ISAC_ADF2, isac->adf2);841 WriteISAC(isac, ISAC_SQXR, 0x2f);842 WriteISAC(isac, ISAC_SPCR, 0x00);843 WriteISAC(isac, ISAC_STCR, 0x70);844 WriteISAC(isac, ISAC_MODE, 0xc9);845 WriteISAC(isac, ISAC_TIMR, 0x00);846 WriteISAC(isac, ISAC_ADF1, 0x00);847 val = ReadISAC(isac, ISAC_CIR0);848 pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);849 isac->state = (val >> 2) & 0xf;850 isac_ph_state_change(isac);851 ph_command(isac, ISAC_CMD_RS);852 WriteISAC(isac, ISAC_MASK, 0);853 }854 return err;855}856 857int858mISDNisac_init(struct isac_hw *isac, void *hw)859{860 mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);861 isac->dch.hw = hw;862 isac->dch.dev.D.send = isac_l1hw;863 isac->init = isac_init;864 isac->release = isac_release;865 isac->ctrl = isac_ctrl;866 isac->open = open_dchannel;867 isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);868 isac->dch.dev.nrbchan = 2;869 return 0;870}871EXPORT_SYMBOL(mISDNisac_init);872 873static void874waitforCEC(struct hscx_hw *hx)875{876 u8 starb, to = 50;877 878 while (to) {879 starb = ReadHSCX(hx, IPAC_STARB);880 if (!(starb & 0x04))881 break;882 udelay(1);883 to--;884 }885 if (to < 50)886 pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,887 50 - to);888 if (!to)889 pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);890}891 892 893static void894waitforXFW(struct hscx_hw *hx)895{896 u8 starb, to = 50;897 898 while (to) {899 starb = ReadHSCX(hx, IPAC_STARB);900 if ((starb & 0x44) == 0x40)901 break;902 udelay(1);903 to--;904 }905 if (to < 50)906 pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,907 50 - to);908 if (!to)909 pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);910}911 912static void913hscx_cmdr(struct hscx_hw *hx, u8 cmd)914{915 if (hx->ip->type & IPAC_TYPE_IPACX)916 WriteHSCX(hx, IPACX_CMDRB, cmd);917 else {918 waitforCEC(hx);919 WriteHSCX(hx, IPAC_CMDRB, cmd);920 }921}922 923static void924hscx_empty_fifo(struct hscx_hw *hscx, u8 count)925{926 u8 *p;927 int maxlen;928 929 pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);930 if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) {931 hscx->bch.dropcnt += count;932 hscx_cmdr(hscx, 0x80); /* RMC */933 return;934 }935 maxlen = bchannel_get_rxbuf(&hscx->bch, count);936 if (maxlen < 0) {937 hscx_cmdr(hscx, 0x80); /* RMC */938 if (hscx->bch.rx_skb)939 skb_trim(hscx->bch.rx_skb, 0);940 pr_warn("%s.B%d: No bufferspace for %d bytes\n",941 hscx->ip->name, hscx->bch.nr, count);942 return;943 }944 p = skb_put(hscx->bch.rx_skb, count);945 946 if (hscx->ip->type & IPAC_TYPE_IPACX)947 hscx->ip->read_fifo(hscx->ip->hw,948 hscx->off + IPACX_RFIFOB, p, count);949 else950 hscx->ip->read_fifo(hscx->ip->hw,951 hscx->off, p, count);952 953 hscx_cmdr(hscx, 0x80); /* RMC */954 955 if (hscx->bch.debug & DEBUG_HW_BFIFO) {956 snprintf(hscx->log, 64, "B%1d-recv %s %d ",957 hscx->bch.nr, hscx->ip->name, count);958 print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);959 }960}961 962static void963hscx_fill_fifo(struct hscx_hw *hscx)964{965 int count, more;966 u8 *p;967 968 if (!hscx->bch.tx_skb) {969 if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags))970 return;971 count = hscx->fifo_size;972 more = 1;973 p = hscx->log;974 memset(p, hscx->bch.fill[0], count);975 } else {976 count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;977 if (count <= 0)978 return;979 p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;980 981 more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;982 if (count > hscx->fifo_size) {983 count = hscx->fifo_size;984 more = 1;985 }986 pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr,987 count, hscx->bch.tx_idx, hscx->bch.tx_skb->len);988 hscx->bch.tx_idx += count;989 }990 if (hscx->ip->type & IPAC_TYPE_IPACX)991 hscx->ip->write_fifo(hscx->ip->hw,992 hscx->off + IPACX_XFIFOB, p, count);993 else {994 waitforXFW(hscx);995 hscx->ip->write_fifo(hscx->ip->hw,996 hscx->off, p, count);997 }998 hscx_cmdr(hscx, more ? 0x08 : 0x0a);999 1000 if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) {1001 snprintf(hscx->log, 64, "B%1d-send %s %d ",1002 hscx->bch.nr, hscx->ip->name, count);1003 print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);1004 }1005}1006 1007static void1008hscx_xpr(struct hscx_hw *hx)1009{1010 if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) {1011 hscx_fill_fifo(hx);1012 } else {1013 dev_kfree_skb(hx->bch.tx_skb);1014 if (get_next_bframe(&hx->bch)) {1015 hscx_fill_fifo(hx);1016 test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags);1017 } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) {1018 hscx_fill_fifo(hx);1019 }1020 }1021}1022 1023static void1024ipac_rme(struct hscx_hw *hx)1025{1026 int count;1027 u8 rstab;1028 1029 if (hx->ip->type & IPAC_TYPE_IPACX)1030 rstab = ReadHSCX(hx, IPACX_RSTAB);1031 else1032 rstab = ReadHSCX(hx, IPAC_RSTAB);1033 pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);1034 if ((rstab & 0xf0) != 0xa0) {1035 /* !(VFR && !RDO && CRC && !RAB) */1036 if (!(rstab & 0x80)) {1037 if (hx->bch.debug & DEBUG_HW_BCHANNEL)1038 pr_notice("%s: B%1d invalid frame\n",1039 hx->ip->name, hx->bch.nr);1040 }1041 if (rstab & 0x40) {1042 if (hx->bch.debug & DEBUG_HW_BCHANNEL)1043 pr_notice("%s: B%1d RDO proto=%x\n",1044 hx->ip->name, hx->bch.nr,1045 hx->bch.state);1046 }1047 if (!(rstab & 0x20)) {1048 if (hx->bch.debug & DEBUG_HW_BCHANNEL)1049 pr_notice("%s: B%1d CRC error\n",1050 hx->ip->name, hx->bch.nr);1051 }1052 hscx_cmdr(hx, 0x80); /* Do RMC */1053 return;1054 }1055 if (hx->ip->type & IPAC_TYPE_IPACX)1056 count = ReadHSCX(hx, IPACX_RBCLB);1057 else1058 count = ReadHSCX(hx, IPAC_RBCLB);1059 count &= (hx->fifo_size - 1);1060 if (count == 0)1061 count = hx->fifo_size;1062 hscx_empty_fifo(hx, count);1063 if (!hx->bch.rx_skb)1064 return;1065 if (hx->bch.rx_skb->len < 2) {1066 pr_debug("%s: B%1d frame too short %d\n",1067 hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);1068 skb_trim(hx->bch.rx_skb, 0);1069 } else {1070 skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);1071 recv_Bchannel(&hx->bch, 0, false);1072 }1073}1074 1075static void1076ipac_irq(struct hscx_hw *hx, u8 ista)1077{1078 u8 istab, m, exirb = 0;1079 1080 if (hx->ip->type & IPAC_TYPE_IPACX)1081 istab = ReadHSCX(hx, IPACX_ISTAB);1082 else if (hx->ip->type & IPAC_TYPE_IPAC) {1083 istab = ReadHSCX(hx, IPAC_ISTAB);1084 m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;1085 if (m & ista) {1086 exirb = ReadHSCX(hx, IPAC_EXIRB);1087 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1088 hx->bch.nr, exirb);1089 }1090 } else if (hx->bch.nr & 2) { /* HSCX B */1091 if (ista & (HSCX__EXA | HSCX__ICA))1092 ipac_irq(&hx->ip->hscx[0], ista);1093 if (ista & HSCX__EXB) {1094 exirb = ReadHSCX(hx, IPAC_EXIRB);1095 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1096 hx->bch.nr, exirb);1097 }1098 istab = ista & 0xF8;1099 } else { /* HSCX A */1100 istab = ReadHSCX(hx, IPAC_ISTAB);1101 if (ista & HSCX__EXA) {1102 exirb = ReadHSCX(hx, IPAC_EXIRB);1103 pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,1104 hx->bch.nr, exirb);1105 }1106 istab = istab & 0xF8;1107 }1108 if (exirb & IPAC_B_XDU)1109 istab |= IPACX_B_XDU;1110 if (exirb & IPAC_B_RFO)1111 istab |= IPACX_B_RFO;1112 pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);1113 1114 if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))1115 return;1116 1117 if (istab & IPACX_B_RME)1118 ipac_rme(hx);1119 1120 if (istab & IPACX_B_RPF) {1121 hscx_empty_fifo(hx, hx->fifo_size);1122 if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))1123 recv_Bchannel(&hx->bch, 0, false);1124 }1125 1126 if (istab & IPACX_B_RFO) {1127 pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);1128 hscx_cmdr(hx, 0x40); /* RRES */1129 }1130 1131 if (istab & IPACX_B_XPR)1132 hscx_xpr(hx);1133 1134 if (istab & IPACX_B_XDU) {1135 if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {1136 if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags))1137 test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags);1138 hscx_xpr(hx);1139 return;1140 }1141 pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,1142 hx->bch.nr, hx->bch.tx_idx);1143 hx->bch.tx_idx = 0;1144 hscx_cmdr(hx, 0x01); /* XRES */1145 }1146}1147 1148irqreturn_t1149mISDNipac_irq(struct ipac_hw *ipac, int maxloop)1150{1151 int cnt = maxloop + 1;1152 u8 ista, istad;1153 struct isac_hw *isac = &ipac->isac;1154 1155 if (ipac->type & IPAC_TYPE_IPACX) {1156 ista = ReadIPAC(ipac, ISACX_ISTA);1157 while (ista && --cnt) {1158 pr_debug("%s: ISTA %02x\n", ipac->name, ista);1159 if (ista & IPACX__ICA)1160 ipac_irq(&ipac->hscx[0], ista);1161 if (ista & IPACX__ICB)1162 ipac_irq(&ipac->hscx[1], ista);1163 if (ista & (ISACX__ICD | ISACX__CIC))1164 mISDNisac_irq(&ipac->isac, ista);1165 ista = ReadIPAC(ipac, ISACX_ISTA);1166 }1167 } else if (ipac->type & IPAC_TYPE_IPAC) {1168 ista = ReadIPAC(ipac, IPAC_ISTA);1169 while (ista && --cnt) {1170 pr_debug("%s: ISTA %02x\n", ipac->name, ista);1171 if (ista & (IPAC__ICD | IPAC__EXD)) {1172 istad = ReadISAC(isac, ISAC_ISTA);1173 pr_debug("%s: ISTAD %02x\n", ipac->name, istad);1174 if (istad & IPAC_D_TIN2)1175 pr_debug("%s TIN2 irq\n", ipac->name);1176 if (ista & IPAC__EXD)1177 istad |= 1; /* ISAC EXI */1178 mISDNisac_irq(isac, istad);1179 }1180 if (ista & (IPAC__ICA | IPAC__EXA))1181 ipac_irq(&ipac->hscx[0], ista);1182 if (ista & (IPAC__ICB | IPAC__EXB))1183 ipac_irq(&ipac->hscx[1], ista);1184 ista = ReadIPAC(ipac, IPAC_ISTA);1185 }1186 } else if (ipac->type & IPAC_TYPE_HSCX) {1187 while (--cnt) {1188 ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);1189 pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);1190 if (ista)1191 ipac_irq(&ipac->hscx[1], ista);1192 istad = ReadISAC(isac, ISAC_ISTA);1193 pr_debug("%s: ISTAD %02x\n", ipac->name, istad);1194 if (istad)1195 mISDNisac_irq(isac, istad);1196 if (0 == (ista | istad))1197 break;1198 }1199 }1200 if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */1201 return IRQ_NONE;1202 if (cnt < maxloop)1203 pr_debug("%s: %d irqloops cpu%d\n", ipac->name,1204 maxloop - cnt, smp_processor_id());1205 if (maxloop && !cnt)1206 pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,1207 maxloop, smp_processor_id());1208 return IRQ_HANDLED;1209}1210EXPORT_SYMBOL(mISDNipac_irq);1211 1212static int1213hscx_mode(struct hscx_hw *hscx, u32 bprotocol)1214{1215 pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,1216 '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);1217 if (hscx->ip->type & IPAC_TYPE_IPACX) {1218 if (hscx->bch.nr & 1) { /* B1 and ICA */1219 WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);1220 WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);1221 } else { /* B2 and ICB */1222 WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);1223 WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);1224 }1225 switch (bprotocol) {1226 case ISDN_P_NONE: /* init */1227 WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */1228 WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */1229 WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */1230 hscx_cmdr(hscx, 0x41);1231 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1232 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1233 break;1234 case ISDN_P_B_RAW:1235 WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */1236 WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */1237 hscx_cmdr(hscx, 0x41);1238 WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);1239 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1240 break;1241 case ISDN_P_B_HDLC:1242 WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */1243 WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */1244 hscx_cmdr(hscx, 0x41);1245 WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);1246 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1247 break;1248 default:1249 pr_info("%s: protocol not known %x\n", hscx->ip->name,1250 bprotocol);1251 return -ENOPROTOOPT;1252 }1253 } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */1254 WriteHSCX(hscx, IPAC_CCR1, 0x82);1255 WriteHSCX(hscx, IPAC_CCR2, 0x30);1256 WriteHSCX(hscx, IPAC_XCCR, 0x07);1257 WriteHSCX(hscx, IPAC_RCCR, 0x07);1258 WriteHSCX(hscx, IPAC_TSAX, hscx->slot);1259 WriteHSCX(hscx, IPAC_TSAR, hscx->slot);1260 switch (bprotocol) {1261 case ISDN_P_NONE:1262 WriteHSCX(hscx, IPAC_TSAX, 0x1F);1263 WriteHSCX(hscx, IPAC_TSAR, 0x1F);1264 WriteHSCX(hscx, IPAC_MODEB, 0x84);1265 WriteHSCX(hscx, IPAC_CCR1, 0x82);1266 WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */1267 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1268 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1269 break;1270 case ISDN_P_B_RAW:1271 WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */1272 WriteHSCX(hscx, IPAC_CCR1, 0x82);1273 hscx_cmdr(hscx, 0x41);1274 WriteHSCX(hscx, IPAC_MASKB, 0);1275 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1276 break;1277 case ISDN_P_B_HDLC:1278 WriteHSCX(hscx, IPAC_MODEB, 0x8c);1279 WriteHSCX(hscx, IPAC_CCR1, 0x8a);1280 hscx_cmdr(hscx, 0x41);1281 WriteHSCX(hscx, IPAC_MASKB, 0);1282 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1283 break;1284 default:1285 pr_info("%s: protocol not known %x\n", hscx->ip->name,1286 bprotocol);1287 return -ENOPROTOOPT;1288 }1289 } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */1290 WriteHSCX(hscx, IPAC_CCR1, 0x85);1291 WriteHSCX(hscx, IPAC_CCR2, 0x30);1292 WriteHSCX(hscx, IPAC_XCCR, 0x07);1293 WriteHSCX(hscx, IPAC_RCCR, 0x07);1294 WriteHSCX(hscx, IPAC_TSAX, hscx->slot);1295 WriteHSCX(hscx, IPAC_TSAR, hscx->slot);1296 switch (bprotocol) {1297 case ISDN_P_NONE:1298 WriteHSCX(hscx, IPAC_TSAX, 0x1F);1299 WriteHSCX(hscx, IPAC_TSAR, 0x1F);1300 WriteHSCX(hscx, IPAC_MODEB, 0x84);1301 WriteHSCX(hscx, IPAC_CCR1, 0x85);1302 WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */1303 test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);1304 test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1305 break;1306 case ISDN_P_B_RAW:1307 WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */1308 WriteHSCX(hscx, IPAC_CCR1, 0x85);1309 hscx_cmdr(hscx, 0x41);1310 WriteHSCX(hscx, IPAC_MASKB, 0);1311 test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);1312 break;1313 case ISDN_P_B_HDLC:1314 WriteHSCX(hscx, IPAC_MODEB, 0x8c);1315 WriteHSCX(hscx, IPAC_CCR1, 0x8d);1316 hscx_cmdr(hscx, 0x41);1317 WriteHSCX(hscx, IPAC_MASKB, 0);1318 test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);1319 break;1320 default:1321 pr_info("%s: protocol not known %x\n", hscx->ip->name,1322 bprotocol);1323 return -ENOPROTOOPT;1324 }1325 } else1326 return -EINVAL;1327 hscx->bch.state = bprotocol;1328 return 0;1329}1330 1331static int1332hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)1333{1334 struct bchannel *bch = container_of(ch, struct bchannel, ch);1335 struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);1336 int ret = -EINVAL;1337 struct mISDNhead *hh = mISDN_HEAD_P(skb);1338 unsigned long flags;1339 1340 switch (hh->prim) {1341 case PH_DATA_REQ:1342 spin_lock_irqsave(hx->ip->hwlock, flags);1343 ret = bchannel_senddata(bch, skb);1344 if (ret > 0) { /* direct TX */1345 ret = 0;1346 hscx_fill_fifo(hx);1347 }1348 spin_unlock_irqrestore(hx->ip->hwlock, flags);1349 return ret;1350 case PH_ACTIVATE_REQ:1351 spin_lock_irqsave(hx->ip->hwlock, flags);1352 if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))1353 ret = hscx_mode(hx, ch->protocol);1354 else1355 ret = 0;1356 spin_unlock_irqrestore(hx->ip->hwlock, flags);1357 if (!ret)1358 _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,1359 NULL, GFP_KERNEL);1360 break;1361 case PH_DEACTIVATE_REQ:1362 spin_lock_irqsave(hx->ip->hwlock, flags);1363 mISDN_clear_bchannel(bch);1364 hscx_mode(hx, ISDN_P_NONE);1365 spin_unlock_irqrestore(hx->ip->hwlock, flags);1366 _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,1367 NULL, GFP_KERNEL);1368 ret = 0;1369 break;1370 default:1371 pr_info("%s: %s unknown prim(%x,%x)\n",1372 hx->ip->name, __func__, hh->prim, hh->id);1373 ret = -EINVAL;1374 }1375 if (!ret)1376 dev_kfree_skb(skb);1377 return ret;1378}1379 1380static int1381channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)1382{1383 return mISDN_ctrl_bchannel(bch, cq);1384}1385 1386static int1387hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)1388{1389 struct bchannel *bch = container_of(ch, struct bchannel, ch);1390 struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);1391 int ret = -EINVAL;1392 u_long flags;1393 1394 pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);1395 switch (cmd) {1396 case CLOSE_CHANNEL:1397 test_and_clear_bit(FLG_OPEN, &bch->Flags);1398 cancel_work_sync(&bch->workq);1399 spin_lock_irqsave(hx->ip->hwlock, flags);1400 mISDN_clear_bchannel(bch);1401 hscx_mode(hx, ISDN_P_NONE);1402 spin_unlock_irqrestore(hx->ip->hwlock, flags);1403 ch->protocol = ISDN_P_NONE;1404 ch->peer = NULL;1405 module_put(hx->ip->owner);1406 ret = 0;1407 break;1408 case CONTROL_CHANNEL:1409 ret = channel_bctrl(bch, arg);1410 break;1411 default:1412 pr_info("%s: %s unknown prim(%x)\n",1413 hx->ip->name, __func__, cmd);1414 }1415 return ret;1416}1417 1418static void1419free_ipac(struct ipac_hw *ipac)1420{1421 isac_release(&ipac->isac);1422}1423 1424static const char *HSCXVer[] =1425{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",1426 "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};1427 1428 1429 1430static void1431hscx_init(struct hscx_hw *hx)1432{1433 u8 val;1434 1435 WriteHSCX(hx, IPAC_RAH2, 0xFF);1436 WriteHSCX(hx, IPAC_XBCH, 0x00);1437 WriteHSCX(hx, IPAC_RLCR, 0x00);1438 1439 if (hx->ip->type & IPAC_TYPE_HSCX) {1440 WriteHSCX(hx, IPAC_CCR1, 0x85);1441 val = ReadHSCX(hx, HSCX_VSTR);1442 pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);1443 if (hx->bch.debug & DEBUG_HW)1444 pr_notice("%s: HSCX version %s\n", hx->ip->name,1445 HSCXVer[val & 0x0f]);1446 } else1447 WriteHSCX(hx, IPAC_CCR1, 0x82);1448 WriteHSCX(hx, IPAC_CCR2, 0x30);1449 WriteHSCX(hx, IPAC_XCCR, 0x07);1450 WriteHSCX(hx, IPAC_RCCR, 0x07);1451}1452 1453static int1454ipac_init(struct ipac_hw *ipac)1455{1456 u8 val;1457 1458 if (ipac->type & IPAC_TYPE_HSCX) {1459 hscx_init(&ipac->hscx[0]);1460 hscx_init(&ipac->hscx[1]);1461 val = ReadIPAC(ipac, IPAC_ID);1462 } else if (ipac->type & IPAC_TYPE_IPAC) {1463 hscx_init(&ipac->hscx[0]);1464 hscx_init(&ipac->hscx[1]);1465 WriteIPAC(ipac, IPAC_MASK, IPAC__ON);1466 val = ReadIPAC(ipac, IPAC_CONF);1467 /* conf is default 0, but can be overwritten by card setup */1468 pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,1469 val, ipac->conf);1470 WriteIPAC(ipac, IPAC_CONF, ipac->conf);1471 val = ReadIPAC(ipac, IPAC_ID);1472 if (ipac->hscx[0].bch.debug & DEBUG_HW)1473 pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);1474 }1475 /* nothing special for IPACX to do here */1476 return isac_init(&ipac->isac);1477}1478 1479static int1480open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)1481{1482 struct bchannel *bch;1483 1484 if (rq->adr.channel == 0 || rq->adr.channel > 2)1485 return -EINVAL;1486 if (rq->protocol == ISDN_P_NONE)1487 return -EINVAL;1488 bch = &ipac->hscx[rq->adr.channel - 1].bch;1489 if (test_and_set_bit(FLG_OPEN, &bch->Flags))1490 return -EBUSY; /* b-channel can be only open once */1491 test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);1492 bch->ch.protocol = rq->protocol;1493 rq->ch = &bch->ch;1494 return 0;1495}1496 1497static int1498channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)1499{1500 int ret = 0;1501 1502 switch (cq->op) {1503 case MISDN_CTRL_GETOP:1504 cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3;1505 break;1506 case MISDN_CTRL_LOOP:1507 /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */1508 if (cq->channel < 0 || cq->channel > 3) {1509 ret = -EINVAL;1510 break;1511 }1512 ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);1513 break;1514 case MISDN_CTRL_L1_TIMER3:1515 ret = ipac->isac.ctrl(&ipac->isac, HW_TIMER3_VALUE, cq->p1);1516 break;1517 default:1518 pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);1519 ret = -EINVAL;1520 break;1521 }1522 return ret;1523}1524 1525static int1526ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)1527{1528 struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);1529 struct dchannel *dch = container_of(dev, struct dchannel, dev);1530 struct isac_hw *isac = container_of(dch, struct isac_hw, dch);1531 struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);1532 struct channel_req *rq;1533 int err = 0;1534 1535 pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);1536 switch (cmd) {1537 case OPEN_CHANNEL:1538 rq = arg;1539 if (rq->protocol == ISDN_P_TE_S0)1540 err = open_dchannel_caller(isac, rq, __builtin_return_address(0));1541 else1542 err = open_bchannel(ipac, rq);1543 if (err)1544 break;1545 if (!try_module_get(ipac->owner))1546 pr_info("%s: cannot get module\n", ipac->name);1547 break;1548 case CLOSE_CHANNEL:1549 pr_debug("%s: dev(%d) close from %p\n", ipac->name,1550 dch->dev.id, __builtin_return_address(0));1551 module_put(ipac->owner);1552 break;1553 case CONTROL_CHANNEL:1554 err = channel_ctrl(ipac, arg);1555 break;1556 default:1557 pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);1558 return -EINVAL;1559 }1560 return err;1561}1562 1563u321564mISDNipac_init(struct ipac_hw *ipac, void *hw)1565{1566 u32 ret;1567 u8 i;1568 1569 ipac->hw = hw;1570 if (ipac->isac.dch.debug & DEBUG_HW)1571 pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);1572 if (ipac->type & IPAC_TYPE_HSCX) {1573 ipac->isac.type = IPAC_TYPE_ISAC;1574 ipac->hscx[0].off = 0;1575 ipac->hscx[1].off = 0x40;1576 ipac->hscx[0].fifo_size = 32;1577 ipac->hscx[1].fifo_size = 32;1578 } else if (ipac->type & IPAC_TYPE_IPAC) {1579 ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;1580 ipac->hscx[0].off = 0;1581 ipac->hscx[1].off = 0x40;1582 ipac->hscx[0].fifo_size = 64;1583 ipac->hscx[1].fifo_size = 64;1584 } else if (ipac->type & IPAC_TYPE_IPACX) {1585 ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;1586 ipac->hscx[0].off = IPACX_OFF_ICA;1587 ipac->hscx[1].off = IPACX_OFF_ICB;1588 ipac->hscx[0].fifo_size = 64;1589 ipac->hscx[1].fifo_size = 64;1590 } else1591 return 0;1592 1593 mISDNisac_init(&ipac->isac, hw);1594 1595 ipac->isac.dch.dev.D.ctrl = ipac_dctrl;1596 1597 for (i = 0; i < 2; i++) {1598 ipac->hscx[i].bch.nr = i + 1;1599 set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);1600 list_add(&ipac->hscx[i].bch.ch.list,1601 &ipac->isac.dch.dev.bchannels);1602 mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM,1603 ipac->hscx[i].fifo_size);1604 ipac->hscx[i].bch.ch.nr = i + 1;1605 ipac->hscx[i].bch.ch.send = &hscx_l2l1;1606 ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;1607 ipac->hscx[i].bch.hw = hw;1608 ipac->hscx[i].ip = ipac;1609 /* default values for IOM time slots1610 * can be overwritten by card */1611 ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;1612 }1613 1614 ipac->init = ipac_init;1615 ipac->release = free_ipac;1616 1617 ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |1618 (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));1619 return ret;1620}1621EXPORT_SYMBOL(mISDNipac_init);1622 1623static int __init1624isac_mod_init(void)1625{1626 pr_notice("mISDNipac module version %s\n", ISAC_REV);1627 return 0;1628}1629 1630static void __exit1631isac_mod_cleanup(void)1632{1633 pr_notice("mISDNipac module unloaded\n");1634}1635module_init(isac_mod_init);1636module_exit(isac_mod_cleanup);1637