162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * mISDNisar.c ISAR (Siemens PSB 7110) specific functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author Karsten Keil (keil@isdn4linux.de) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* define this to enable static debug messages, if you kernel supports 1162306a36Sopenharmony_ci * dynamic debugging, you should use debugfs for this 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci/* #define DEBUG */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/gfp.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/vmalloc.h> 1862306a36Sopenharmony_ci#include <linux/mISDNhw.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include "isar.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define ISAR_REV "2.1" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 2562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2662306a36Sopenharmony_ciMODULE_VERSION(ISAR_REV); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define DEBUG_HW_FIRMWARE_FIFO 0x10000 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 3162306a36Sopenharmony_ci 122, 145, 146}; 3262306a36Sopenharmony_ci#define FAXMODCNT 13 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void isar_setup(struct isar_hw *); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic inline int 3762306a36Sopenharmony_ciwaitforHIA(struct isar_hw *isar, int timeout) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int t = timeout; 4062306a36Sopenharmony_ci u8 val = isar->read_reg(isar->hw, ISAR_HIA); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci while ((val & 1) && t) { 4362306a36Sopenharmony_ci udelay(1); 4462306a36Sopenharmony_ci t--; 4562306a36Sopenharmony_ci val = isar->read_reg(isar->hw, ISAR_HIA); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); 4862306a36Sopenharmony_ci return timeout; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * send msg to ISAR mailbox 5362306a36Sopenharmony_ci * if msg is NULL use isar->buf 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic int 5662306a36Sopenharmony_cisend_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci if (!waitforHIA(isar, 1000)) 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); 6162306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_CTRL_H, creg); 6262306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_CTRL_L, len); 6362306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_WADR, 0); 6462306a36Sopenharmony_ci if (!msg) 6562306a36Sopenharmony_ci msg = isar->buf; 6662306a36Sopenharmony_ci if (msg && len) { 6762306a36Sopenharmony_ci isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); 6862306a36Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 6962306a36Sopenharmony_ci int l = 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci while (l < (int)len) { 7262306a36Sopenharmony_ci hex_dump_to_buffer(msg + l, len - l, 32, 1, 7362306a36Sopenharmony_ci isar->log, 256, 1); 7462306a36Sopenharmony_ci pr_debug("%s: %s %02x: %s\n", isar->name, 7562306a36Sopenharmony_ci __func__, l, isar->log); 7662306a36Sopenharmony_ci l += 32; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_HIS, his); 8162306a36Sopenharmony_ci waitforHIA(isar, 1000); 8262306a36Sopenharmony_ci return 1; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * receive message from ISAR mailbox 8762306a36Sopenharmony_ci * if msg is NULL use isar->buf 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic void 9062306a36Sopenharmony_circv_mbox(struct isar_hw *isar, u8 *msg) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci if (!msg) 9362306a36Sopenharmony_ci msg = isar->buf; 9462306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_RADR, 0); 9562306a36Sopenharmony_ci if (msg && isar->clsb) { 9662306a36Sopenharmony_ci isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); 9762306a36Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 9862306a36Sopenharmony_ci int l = 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci while (l < (int)isar->clsb) { 10162306a36Sopenharmony_ci hex_dump_to_buffer(msg + l, isar->clsb - l, 32, 10262306a36Sopenharmony_ci 1, isar->log, 256, 1); 10362306a36Sopenharmony_ci pr_debug("%s: %s %02x: %s\n", isar->name, 10462306a36Sopenharmony_ci __func__, l, isar->log); 10562306a36Sopenharmony_ci l += 32; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic inline void 11362306a36Sopenharmony_ciget_irq_infos(struct isar_hw *isar) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci isar->iis = isar->read_reg(isar->hw, ISAR_IIS); 11662306a36Sopenharmony_ci isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); 11762306a36Sopenharmony_ci isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); 11862306a36Sopenharmony_ci pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, 11962306a36Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * poll answer message from ISAR mailbox 12462306a36Sopenharmony_ci * should be used only with ISAR IRQs disabled before DSP was started 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistatic int 12862306a36Sopenharmony_cipoll_mbox(struct isar_hw *isar, int maxdelay) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int t = maxdelay; 13162306a36Sopenharmony_ci u8 irq; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci irq = isar->read_reg(isar->hw, ISAR_IRQBIT); 13462306a36Sopenharmony_ci while (t && !(irq & ISAR_IRQSTA)) { 13562306a36Sopenharmony_ci udelay(1); 13662306a36Sopenharmony_ci t--; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci if (t) { 13962306a36Sopenharmony_ci get_irq_infos(isar); 14062306a36Sopenharmony_ci rcv_mbox(isar, NULL); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci pr_debug("%s: pulled %d bytes after %d us\n", 14362306a36Sopenharmony_ci isar->name, isar->clsb, maxdelay - t); 14462306a36Sopenharmony_ci return t; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int 14862306a36Sopenharmony_ciISARVersion(struct isar_hw *isar) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci int ver; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* disable ISAR IRQ */ 15362306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 15462306a36Sopenharmony_ci isar->buf[0] = ISAR_MSG_HWVER; 15562306a36Sopenharmony_ci isar->buf[1] = 0; 15662306a36Sopenharmony_ci isar->buf[2] = 1; 15762306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) 15862306a36Sopenharmony_ci return -1; 15962306a36Sopenharmony_ci if (!poll_mbox(isar, 1000)) 16062306a36Sopenharmony_ci return -2; 16162306a36Sopenharmony_ci if (isar->iis == ISAR_IIS_VNR) { 16262306a36Sopenharmony_ci if (isar->clsb == 1) { 16362306a36Sopenharmony_ci ver = isar->buf[0] & 0xf; 16462306a36Sopenharmony_ci return ver; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci return -3; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci return -4; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int 17262306a36Sopenharmony_ciload_firmware(struct isar_hw *isar, const u8 *buf, int size) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci u32 saved_debug = isar->ch[0].bch.debug; 17562306a36Sopenharmony_ci int ret, cnt; 17662306a36Sopenharmony_ci u8 nom, noc; 17762306a36Sopenharmony_ci u16 left, val, *sp = (u16 *)buf; 17862306a36Sopenharmony_ci u8 *mp; 17962306a36Sopenharmony_ci u_long flags; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci struct { 18262306a36Sopenharmony_ci u16 sadr; 18362306a36Sopenharmony_ci u16 len; 18462306a36Sopenharmony_ci u16 d_key; 18562306a36Sopenharmony_ci } blk_head; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (1 != isar->version) { 18862306a36Sopenharmony_ci pr_err("%s: ISAR wrong version %d firmware download aborted\n", 18962306a36Sopenharmony_ci isar->name, isar->version); 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) 19362306a36Sopenharmony_ci isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; 19462306a36Sopenharmony_ci pr_debug("%s: load firmware %d words (%d bytes)\n", 19562306a36Sopenharmony_ci isar->name, size / 2, size); 19662306a36Sopenharmony_ci cnt = 0; 19762306a36Sopenharmony_ci size /= 2; 19862306a36Sopenharmony_ci /* disable ISAR IRQ */ 19962306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 20062306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 20162306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 20262306a36Sopenharmony_ci while (cnt < size) { 20362306a36Sopenharmony_ci blk_head.sadr = le16_to_cpu(*sp++); 20462306a36Sopenharmony_ci blk_head.len = le16_to_cpu(*sp++); 20562306a36Sopenharmony_ci blk_head.d_key = le16_to_cpu(*sp++); 20662306a36Sopenharmony_ci cnt += 3; 20762306a36Sopenharmony_ci pr_debug("ISAR firmware block (%#x,%d,%#x)\n", 20862306a36Sopenharmony_ci blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); 20962306a36Sopenharmony_ci left = blk_head.len; 21062306a36Sopenharmony_ci if (cnt + left > size) { 21162306a36Sopenharmony_ci pr_info("%s: firmware error have %d need %d words\n", 21262306a36Sopenharmony_ci isar->name, size, cnt + left); 21362306a36Sopenharmony_ci ret = -EINVAL; 21462306a36Sopenharmony_ci goto reterrflg; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 21762306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 21862306a36Sopenharmony_ci 0, NULL)) { 21962306a36Sopenharmony_ci pr_info("ISAR send_mbox dkey failed\n"); 22062306a36Sopenharmony_ci ret = -ETIME; 22162306a36Sopenharmony_ci goto reterror; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 22462306a36Sopenharmony_ci pr_warn("ISAR poll_mbox dkey failed\n"); 22562306a36Sopenharmony_ci ret = -ETIME; 22662306a36Sopenharmony_ci goto reterror; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 22962306a36Sopenharmony_ci if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { 23062306a36Sopenharmony_ci pr_info("ISAR wrong dkey response (%x,%x,%x)\n", 23162306a36Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 23262306a36Sopenharmony_ci ret = 1; 23362306a36Sopenharmony_ci goto reterrflg; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci while (left > 0) { 23662306a36Sopenharmony_ci if (left > 126) 23762306a36Sopenharmony_ci noc = 126; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci noc = left; 24062306a36Sopenharmony_ci nom = (2 * noc) + 3; 24162306a36Sopenharmony_ci mp = isar->buf; 24262306a36Sopenharmony_ci /* the ISAR is big endian */ 24362306a36Sopenharmony_ci *mp++ = blk_head.sadr >> 8; 24462306a36Sopenharmony_ci *mp++ = blk_head.sadr & 0xFF; 24562306a36Sopenharmony_ci left -= noc; 24662306a36Sopenharmony_ci cnt += noc; 24762306a36Sopenharmony_ci *mp++ = noc; 24862306a36Sopenharmony_ci pr_debug("%s: load %3d words at %04x\n", isar->name, 24962306a36Sopenharmony_ci noc, blk_head.sadr); 25062306a36Sopenharmony_ci blk_head.sadr += noc; 25162306a36Sopenharmony_ci while (noc) { 25262306a36Sopenharmony_ci val = le16_to_cpu(*sp++); 25362306a36Sopenharmony_ci *mp++ = val >> 8; 25462306a36Sopenharmony_ci *mp++ = val & 0xFF; 25562306a36Sopenharmony_ci noc--; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 25862306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { 25962306a36Sopenharmony_ci pr_info("ISAR send_mbox prog failed\n"); 26062306a36Sopenharmony_ci ret = -ETIME; 26162306a36Sopenharmony_ci goto reterror; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 26462306a36Sopenharmony_ci pr_info("ISAR poll_mbox prog failed\n"); 26562306a36Sopenharmony_ci ret = -ETIME; 26662306a36Sopenharmony_ci goto reterror; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 26962306a36Sopenharmony_ci if ((isar->iis != ISAR_IIS_FIRM) || 27062306a36Sopenharmony_ci isar->cmsb || isar->clsb) { 27162306a36Sopenharmony_ci pr_info("ISAR wrong prog response (%x,%x,%x)\n", 27262306a36Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 27362306a36Sopenharmony_ci ret = -EIO; 27462306a36Sopenharmony_ci goto reterrflg; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci pr_debug("%s: ISAR firmware block %d words loaded\n", 27862306a36Sopenharmony_ci isar->name, blk_head.len); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci isar->ch[0].bch.debug = saved_debug; 28162306a36Sopenharmony_ci /* 10ms delay */ 28262306a36Sopenharmony_ci cnt = 10; 28362306a36Sopenharmony_ci while (cnt--) 28462306a36Sopenharmony_ci mdelay(1); 28562306a36Sopenharmony_ci isar->buf[0] = 0xff; 28662306a36Sopenharmony_ci isar->buf[1] = 0xfe; 28762306a36Sopenharmony_ci isar->bstat = 0; 28862306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 28962306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { 29062306a36Sopenharmony_ci pr_info("ISAR send_mbox start dsp failed\n"); 29162306a36Sopenharmony_ci ret = -ETIME; 29262306a36Sopenharmony_ci goto reterror; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 29562306a36Sopenharmony_ci pr_info("ISAR poll_mbox start dsp failed\n"); 29662306a36Sopenharmony_ci ret = -ETIME; 29762306a36Sopenharmony_ci goto reterror; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { 30062306a36Sopenharmony_ci pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", 30162306a36Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 30262306a36Sopenharmony_ci ret = -EIO; 30362306a36Sopenharmony_ci goto reterror; 30462306a36Sopenharmony_ci } else 30562306a36Sopenharmony_ci pr_debug("%s: ISAR start dsp success\n", isar->name); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* NORMAL mode entered */ 30862306a36Sopenharmony_ci /* Enable IRQs of ISAR */ 30962306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); 31062306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 31162306a36Sopenharmony_ci cnt = 1000; /* max 1s */ 31262306a36Sopenharmony_ci while ((!isar->bstat) && cnt) { 31362306a36Sopenharmony_ci mdelay(1); 31462306a36Sopenharmony_ci cnt--; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci if (!cnt) { 31762306a36Sopenharmony_ci pr_info("ISAR no general status event received\n"); 31862306a36Sopenharmony_ci ret = -ETIME; 31962306a36Sopenharmony_ci goto reterrflg; 32062306a36Sopenharmony_ci } else 32162306a36Sopenharmony_ci pr_debug("%s: ISAR general status event %x\n", 32262306a36Sopenharmony_ci isar->name, isar->bstat); 32362306a36Sopenharmony_ci /* 10ms delay */ 32462306a36Sopenharmony_ci cnt = 10; 32562306a36Sopenharmony_ci while (cnt--) 32662306a36Sopenharmony_ci mdelay(1); 32762306a36Sopenharmony_ci isar->iis = 0; 32862306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 32962306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { 33062306a36Sopenharmony_ci pr_info("ISAR send_mbox self tst failed\n"); 33162306a36Sopenharmony_ci ret = -ETIME; 33262306a36Sopenharmony_ci goto reterror; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 33562306a36Sopenharmony_ci cnt = 10000; /* max 100 ms */ 33662306a36Sopenharmony_ci while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 33762306a36Sopenharmony_ci udelay(10); 33862306a36Sopenharmony_ci cnt--; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci mdelay(1); 34162306a36Sopenharmony_ci if (!cnt) { 34262306a36Sopenharmony_ci pr_info("ISAR no self tst response\n"); 34362306a36Sopenharmony_ci ret = -ETIME; 34462306a36Sopenharmony_ci goto reterrflg; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) 34762306a36Sopenharmony_ci && (isar->buf[0] == 0)) 34862306a36Sopenharmony_ci pr_debug("%s: ISAR selftest OK\n", isar->name); 34962306a36Sopenharmony_ci else { 35062306a36Sopenharmony_ci pr_info("ISAR selftest not OK %x/%x/%x\n", 35162306a36Sopenharmony_ci isar->cmsb, isar->clsb, isar->buf[0]); 35262306a36Sopenharmony_ci ret = -EIO; 35362306a36Sopenharmony_ci goto reterrflg; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 35662306a36Sopenharmony_ci isar->iis = 0; 35762306a36Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { 35862306a36Sopenharmony_ci pr_info("ISAR RQST SVN failed\n"); 35962306a36Sopenharmony_ci ret = -ETIME; 36062306a36Sopenharmony_ci goto reterror; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 36362306a36Sopenharmony_ci cnt = 30000; /* max 300 ms */ 36462306a36Sopenharmony_ci while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 36562306a36Sopenharmony_ci udelay(10); 36662306a36Sopenharmony_ci cnt--; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci mdelay(1); 36962306a36Sopenharmony_ci if (!cnt) { 37062306a36Sopenharmony_ci pr_info("ISAR no SVN response\n"); 37162306a36Sopenharmony_ci ret = -ETIME; 37262306a36Sopenharmony_ci goto reterrflg; 37362306a36Sopenharmony_ci } else { 37462306a36Sopenharmony_ci if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { 37562306a36Sopenharmony_ci pr_notice("%s: ISAR software version %#x\n", 37662306a36Sopenharmony_ci isar->name, isar->buf[0]); 37762306a36Sopenharmony_ci } else { 37862306a36Sopenharmony_ci pr_info("%s: ISAR wrong swver response (%x,%x)" 37962306a36Sopenharmony_ci " cnt(%d)\n", isar->name, isar->cmsb, 38062306a36Sopenharmony_ci isar->clsb, cnt); 38162306a36Sopenharmony_ci ret = -EIO; 38262306a36Sopenharmony_ci goto reterrflg; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 38662306a36Sopenharmony_ci isar_setup(isar); 38762306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 38862306a36Sopenharmony_ci ret = 0; 38962306a36Sopenharmony_cireterrflg: 39062306a36Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 39162306a36Sopenharmony_cireterror: 39262306a36Sopenharmony_ci isar->ch[0].bch.debug = saved_debug; 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci /* disable ISAR IRQ */ 39562306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 39662306a36Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 39762306a36Sopenharmony_ci return ret; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic inline void 40162306a36Sopenharmony_cideliver_status(struct isar_ch *ch, int status) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); 40462306a36Sopenharmony_ci _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic inline void 40862306a36Sopenharmony_ciisar_rcv_frame(struct isar_ch *ch) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci u8 *ptr; 41162306a36Sopenharmony_ci int maxlen; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (!ch->is->clsb) { 41462306a36Sopenharmony_ci pr_debug("%s; ISAR zero len frame\n", ch->is->name); 41562306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { 41962306a36Sopenharmony_ci ch->bch.dropcnt += ch->is->clsb; 42062306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 42162306a36Sopenharmony_ci return; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci switch (ch->bch.state) { 42462306a36Sopenharmony_ci case ISDN_P_NONE: 42562306a36Sopenharmony_ci pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", 42662306a36Sopenharmony_ci ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); 42762306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci case ISDN_P_B_RAW: 43062306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 43162306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 43262306a36Sopenharmony_ci maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 43362306a36Sopenharmony_ci if (maxlen < 0) { 43462306a36Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 43562306a36Sopenharmony_ci ch->is->name, ch->bch.nr, ch->is->clsb); 43662306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 44062306a36Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci case ISDN_P_B_HDLC: 44362306a36Sopenharmony_ci maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 44462306a36Sopenharmony_ci if (maxlen < 0) { 44562306a36Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 44662306a36Sopenharmony_ci ch->is->name, ch->bch.nr, ch->is->clsb); 44762306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_ERROR) { 45162306a36Sopenharmony_ci pr_debug("%s: ISAR frame error %x len %d\n", 45262306a36Sopenharmony_ci ch->is->name, ch->is->cmsb, ch->is->clsb); 45362306a36Sopenharmony_ci#ifdef ERROR_STATISTIC 45462306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_ERR_RER) 45562306a36Sopenharmony_ci ch->bch.err_inv++; 45662306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_ERR_CER) 45762306a36Sopenharmony_ci ch->bch.err_crc++; 45862306a36Sopenharmony_ci#endif 45962306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 46062306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_FSD) 46462306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 46562306a36Sopenharmony_ci ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 46662306a36Sopenharmony_ci rcv_mbox(ch->is, ptr); 46762306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_FED) { 46862306a36Sopenharmony_ci if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 46962306a36Sopenharmony_ci pr_debug("%s: ISAR frame too short %d\n", 47062306a36Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 47162306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 47562306a36Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 47962306a36Sopenharmony_ci if (ch->state != STFAX_ACTIV) { 48062306a36Sopenharmony_ci pr_debug("%s: isar_rcv_frame: not ACTIV\n", 48162306a36Sopenharmony_ci ch->is->name); 48262306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 48362306a36Sopenharmony_ci if (ch->bch.rx_skb) 48462306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci if (!ch->bch.rx_skb) { 48862306a36Sopenharmony_ci ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, 48962306a36Sopenharmony_ci GFP_ATOMIC); 49062306a36Sopenharmony_ci if (unlikely(!ch->bch.rx_skb)) { 49162306a36Sopenharmony_ci pr_info("%s: B receive out of memory\n", 49262306a36Sopenharmony_ci __func__); 49362306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FRM) { 49862306a36Sopenharmony_ci rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 49962306a36Sopenharmony_ci pr_debug("%s: isar_rcv_frame: %d\n", 50062306a36Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 50162306a36Sopenharmony_ci if (ch->is->cmsb & SART_NMD) { /* ABORT */ 50262306a36Sopenharmony_ci pr_debug("%s: isar_rcv_frame: no more data\n", 50362306a36Sopenharmony_ci ch->is->name); 50462306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 50562306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 50662306a36Sopenharmony_ci ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 50762306a36Sopenharmony_ci 0, NULL); 50862306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 50962306a36Sopenharmony_ci /* set_skb_flag(skb, DF_NOMOREDATA); */ 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 51262306a36Sopenharmony_ci if (ch->is->cmsb & SART_NMD) 51362306a36Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci if (ch->cmd != PCTRL_CMD_FRH) { 51762306a36Sopenharmony_ci pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", 51862306a36Sopenharmony_ci ch->is->name, ch->cmd); 51962306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 52062306a36Sopenharmony_ci if (ch->bch.rx_skb) 52162306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci /* PCTRL_CMD_FRH */ 52562306a36Sopenharmony_ci if ((ch->bch.rx_skb->len + ch->is->clsb) > 52662306a36Sopenharmony_ci (ch->bch.maxlen + 2)) { 52762306a36Sopenharmony_ci pr_info("%s: %s incoming packet too large\n", 52862306a36Sopenharmony_ci ch->is->name, __func__); 52962306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 53062306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } else if (ch->is->cmsb & HDLC_ERROR) { 53362306a36Sopenharmony_ci pr_info("%s: ISAR frame error %x len %d\n", 53462306a36Sopenharmony_ci ch->is->name, ch->is->cmsb, ch->is->clsb); 53562306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 53662306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_FSD) 54062306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 54162306a36Sopenharmony_ci ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 54262306a36Sopenharmony_ci rcv_mbox(ch->is, ptr); 54362306a36Sopenharmony_ci if (ch->is->cmsb & HDLC_FED) { 54462306a36Sopenharmony_ci if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 54562306a36Sopenharmony_ci pr_info("%s: ISAR frame too short %d\n", 54662306a36Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 54762306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 55162306a36Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci if (ch->is->cmsb & SART_NMD) { /* ABORT */ 55462306a36Sopenharmony_ci pr_debug("%s: isar_rcv_frame: no more data\n", 55562306a36Sopenharmony_ci ch->is->name); 55662306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 55762306a36Sopenharmony_ci if (ch->bch.rx_skb) 55862306a36Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 55962306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 56062306a36Sopenharmony_ci ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); 56162306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 56262306a36Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci default: 56662306a36Sopenharmony_ci pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); 56762306a36Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic void 57362306a36Sopenharmony_ciisar_fill_fifo(struct isar_ch *ch) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci int count; 57662306a36Sopenharmony_ci u8 msb; 57762306a36Sopenharmony_ci u8 *ptr; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, 58062306a36Sopenharmony_ci ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); 58162306a36Sopenharmony_ci if (!(ch->is->bstat & 58262306a36Sopenharmony_ci (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) 58362306a36Sopenharmony_ci return; 58462306a36Sopenharmony_ci if (!ch->bch.tx_skb) { 58562306a36Sopenharmony_ci if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || 58662306a36Sopenharmony_ci (ch->bch.state != ISDN_P_B_RAW)) 58762306a36Sopenharmony_ci return; 58862306a36Sopenharmony_ci count = ch->mml; 58962306a36Sopenharmony_ci /* use the card buffer */ 59062306a36Sopenharmony_ci memset(ch->is->buf, ch->bch.fill[0], count); 59162306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 59262306a36Sopenharmony_ci 0, count, ch->is->buf); 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci count = ch->bch.tx_skb->len - ch->bch.tx_idx; 59662306a36Sopenharmony_ci if (count <= 0) 59762306a36Sopenharmony_ci return; 59862306a36Sopenharmony_ci if (count > ch->mml) { 59962306a36Sopenharmony_ci msb = 0; 60062306a36Sopenharmony_ci count = ch->mml; 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci msb = HDLC_FED; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; 60562306a36Sopenharmony_ci if (!ch->bch.tx_idx) { 60662306a36Sopenharmony_ci pr_debug("%s: frame start\n", ch->is->name); 60762306a36Sopenharmony_ci if ((ch->bch.state == ISDN_P_B_T30_FAX) && 60862306a36Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTH)) { 60962306a36Sopenharmony_ci if (count > 1) { 61062306a36Sopenharmony_ci if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { 61162306a36Sopenharmony_ci /* last frame */ 61262306a36Sopenharmony_ci test_and_set_bit(FLG_LASTDATA, 61362306a36Sopenharmony_ci &ch->bch.Flags); 61462306a36Sopenharmony_ci pr_debug("%s: set LASTDATA\n", 61562306a36Sopenharmony_ci ch->is->name); 61662306a36Sopenharmony_ci if (msb == HDLC_FED) 61762306a36Sopenharmony_ci test_and_set_bit(FLG_DLEETX, 61862306a36Sopenharmony_ci &ch->bch.Flags); 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci msb |= HDLC_FST; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci ch->bch.tx_idx += count; 62562306a36Sopenharmony_ci switch (ch->bch.state) { 62662306a36Sopenharmony_ci case ISDN_P_NONE: 62762306a36Sopenharmony_ci pr_info("%s: wrong protocol 0\n", __func__); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case ISDN_P_B_RAW: 63062306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 63162306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 63262306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 63362306a36Sopenharmony_ci 0, count, ptr); 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci case ISDN_P_B_HDLC: 63662306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 63762306a36Sopenharmony_ci msb, count, ptr); 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 64062306a36Sopenharmony_ci if (ch->state != STFAX_ACTIV) 64162306a36Sopenharmony_ci pr_debug("%s: not ACTIV\n", ch->is->name); 64262306a36Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FTH) 64362306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 64462306a36Sopenharmony_ci msb, count, ptr); 64562306a36Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FTM) 64662306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 64762306a36Sopenharmony_ci 0, count, ptr); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci pr_debug("%s: not FTH/FTM\n", ch->is->name); 65062306a36Sopenharmony_ci break; 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci pr_info("%s: protocol(%x) error\n", 65362306a36Sopenharmony_ci __func__, ch->bch.state); 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic inline struct isar_ch * 65962306a36Sopenharmony_cisel_bch_isar(struct isar_hw *isar, u8 dpath) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct isar_ch *base = &isar->ch[0]; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if ((!dpath) || (dpath > 2)) 66462306a36Sopenharmony_ci return NULL; 66562306a36Sopenharmony_ci if (base->dpath == dpath) 66662306a36Sopenharmony_ci return base; 66762306a36Sopenharmony_ci base++; 66862306a36Sopenharmony_ci if (base->dpath == dpath) 66962306a36Sopenharmony_ci return base; 67062306a36Sopenharmony_ci return NULL; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic void 67462306a36Sopenharmony_cisend_next(struct isar_ch *ch) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, 67762306a36Sopenharmony_ci ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, 67862306a36Sopenharmony_ci ch->bch.tx_idx); 67962306a36Sopenharmony_ci if (ch->bch.state == ISDN_P_B_T30_FAX) { 68062306a36Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FTH) { 68162306a36Sopenharmony_ci if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { 68262306a36Sopenharmony_ci pr_debug("set NMD_DATA\n"); 68362306a36Sopenharmony_ci test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci } else if (ch->cmd == PCTRL_CMD_FTM) { 68662306a36Sopenharmony_ci if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { 68762306a36Sopenharmony_ci test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); 68862306a36Sopenharmony_ci test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci dev_kfree_skb(ch->bch.tx_skb); 69362306a36Sopenharmony_ci if (get_next_bframe(&ch->bch)) { 69462306a36Sopenharmony_ci isar_fill_fifo(ch); 69562306a36Sopenharmony_ci test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); 69662306a36Sopenharmony_ci } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { 69762306a36Sopenharmony_ci isar_fill_fifo(ch); 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { 70062306a36Sopenharmony_ci if (test_and_clear_bit(FLG_LASTDATA, 70162306a36Sopenharmony_ci &ch->bch.Flags)) { 70262306a36Sopenharmony_ci if (test_and_clear_bit(FLG_NMD_DATA, 70362306a36Sopenharmony_ci &ch->bch.Flags)) { 70462306a36Sopenharmony_ci u8 zd = 0; 70562306a36Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 70662306a36Sopenharmony_ci ISAR_HIS_SDATA, 0x01, 1, &zd); 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); 70962306a36Sopenharmony_ci } else { 71062306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { 71362306a36Sopenharmony_ci test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic void 71962306a36Sopenharmony_cicheck_send(struct isar_hw *isar, u8 rdm) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct isar_ch *ch; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci pr_debug("%s: rdm %x\n", isar->name, rdm); 72462306a36Sopenharmony_ci if (rdm & BSTAT_RDM1) { 72562306a36Sopenharmony_ci ch = sel_bch_isar(isar, 1); 72662306a36Sopenharmony_ci if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 72762306a36Sopenharmony_ci if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 72862306a36Sopenharmony_ci ch->bch.tx_idx)) 72962306a36Sopenharmony_ci isar_fill_fifo(ch); 73062306a36Sopenharmony_ci else 73162306a36Sopenharmony_ci send_next(ch); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci if (rdm & BSTAT_RDM2) { 73562306a36Sopenharmony_ci ch = sel_bch_isar(isar, 2); 73662306a36Sopenharmony_ci if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 73762306a36Sopenharmony_ci if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 73862306a36Sopenharmony_ci ch->bch.tx_idx)) 73962306a36Sopenharmony_ci isar_fill_fifo(ch); 74062306a36Sopenharmony_ci else 74162306a36Sopenharmony_ci send_next(ch); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", 74762306a36Sopenharmony_ci "300", "600", "1200", "2400", "4800", "7200", 74862306a36Sopenharmony_ci "9600nt", "9600t", "12000", "14400", "WRONG"}; 74962306a36Sopenharmony_cistatic const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", 75062306a36Sopenharmony_ci "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic void 75362306a36Sopenharmony_ciisar_pump_status_rsp(struct isar_ch *ch) { 75462306a36Sopenharmony_ci u8 ril = ch->is->buf[0]; 75562306a36Sopenharmony_ci u8 rim; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) 75862306a36Sopenharmony_ci return; 75962306a36Sopenharmony_ci if (ril > 14) { 76062306a36Sopenharmony_ci pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); 76162306a36Sopenharmony_ci ril = 15; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci switch (ch->is->buf[1]) { 76462306a36Sopenharmony_ci case 0: 76562306a36Sopenharmony_ci rim = 0; 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci case 0x20: 76862306a36Sopenharmony_ci rim = 2; 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci case 0x40: 77162306a36Sopenharmony_ci rim = 3; 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci case 0x41: 77462306a36Sopenharmony_ci rim = 4; 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci case 0x51: 77762306a36Sopenharmony_ci rim = 5; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case 0x61: 78062306a36Sopenharmony_ci rim = 6; 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci case 0x71: 78362306a36Sopenharmony_ci rim = 7; 78462306a36Sopenharmony_ci break; 78562306a36Sopenharmony_ci case 0x82: 78662306a36Sopenharmony_ci rim = 8; 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci case 0x92: 78962306a36Sopenharmony_ci rim = 9; 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case 0xa2: 79262306a36Sopenharmony_ci rim = 10; 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci default: 79562306a36Sopenharmony_ci rim = 1; 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); 79962306a36Sopenharmony_ci pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void 80362306a36Sopenharmony_ciisar_pump_statev_modem(struct isar_ch *ch, u8 devt) { 80462306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci switch (devt) { 80762306a36Sopenharmony_ci case PSEV_10MS_TIMER: 80862306a36Sopenharmony_ci pr_debug("%s: pump stev TIMER\n", ch->is->name); 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci case PSEV_CON_ON: 81162306a36Sopenharmony_ci pr_debug("%s: pump stev CONNECT\n", ch->is->name); 81262306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci case PSEV_CON_OFF: 81562306a36Sopenharmony_ci pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); 81662306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 81762306a36Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci case PSEV_V24_OFF: 82062306a36Sopenharmony_ci pr_debug("%s: pump stev V24 OFF\n", ch->is->name); 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci case PSEV_CTS_ON: 82362306a36Sopenharmony_ci pr_debug("%s: pump stev CTS ON\n", ch->is->name); 82462306a36Sopenharmony_ci break; 82562306a36Sopenharmony_ci case PSEV_CTS_OFF: 82662306a36Sopenharmony_ci pr_debug("%s pump stev CTS OFF\n", ch->is->name); 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci case PSEV_DCD_ON: 82962306a36Sopenharmony_ci pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); 83062306a36Sopenharmony_ci test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 83162306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 83262306a36Sopenharmony_ci break; 83362306a36Sopenharmony_ci case PSEV_DCD_OFF: 83462306a36Sopenharmony_ci pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci case PSEV_DSR_ON: 83762306a36Sopenharmony_ci pr_debug("%s: pump stev DSR ON\n", ch->is->name); 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci case PSEV_DSR_OFF: 84062306a36Sopenharmony_ci pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case PSEV_REM_RET: 84362306a36Sopenharmony_ci pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci case PSEV_REM_REN: 84662306a36Sopenharmony_ci pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci case PSEV_GSTN_CLR: 84962306a36Sopenharmony_ci pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci default: 85262306a36Sopenharmony_ci pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt); 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic void 85862306a36Sopenharmony_ciisar_pump_statev_fax(struct isar_ch *ch, u8 devt) { 85962306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 86062306a36Sopenharmony_ci u8 p1; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci switch (devt) { 86362306a36Sopenharmony_ci case PSEV_10MS_TIMER: 86462306a36Sopenharmony_ci pr_debug("%s: pump stev TIMER\n", ch->is->name); 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci case PSEV_RSP_READY: 86762306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_READY\n", ch->is->name); 86862306a36Sopenharmony_ci ch->state = STFAX_READY; 86962306a36Sopenharmony_ci deliver_status(ch, HW_MOD_READY); 87062306a36Sopenharmony_ci#ifdef AUTOCON 87162306a36Sopenharmony_ci if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) 87262306a36Sopenharmony_ci isar_pump_cmd(bch, HW_MOD_FRH, 3); 87362306a36Sopenharmony_ci else 87462306a36Sopenharmony_ci isar_pump_cmd(bch, HW_MOD_FTH, 3); 87562306a36Sopenharmony_ci#endif 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci case PSEV_LINE_TX_H: 87862306a36Sopenharmony_ci if (ch->state == STFAX_LINE) { 87962306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); 88062306a36Sopenharmony_ci ch->state = STFAX_CONT; 88162306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 88262306a36Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 88362306a36Sopenharmony_ci } else { 88462306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", 88562306a36Sopenharmony_ci ch->is->name, ch->state); 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci break; 88862306a36Sopenharmony_ci case PSEV_LINE_RX_H: 88962306a36Sopenharmony_ci if (ch->state == STFAX_LINE) { 89062306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); 89162306a36Sopenharmony_ci ch->state = STFAX_CONT; 89262306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 89362306a36Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 89462306a36Sopenharmony_ci } else { 89562306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", 89662306a36Sopenharmony_ci ch->is->name, ch->state); 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci case PSEV_LINE_TX_B: 90062306a36Sopenharmony_ci if (ch->state == STFAX_LINE) { 90162306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); 90262306a36Sopenharmony_ci ch->state = STFAX_CONT; 90362306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 90462306a36Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 90562306a36Sopenharmony_ci } else { 90662306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", 90762306a36Sopenharmony_ci ch->is->name, ch->state); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci case PSEV_LINE_RX_B: 91162306a36Sopenharmony_ci if (ch->state == STFAX_LINE) { 91262306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); 91362306a36Sopenharmony_ci ch->state = STFAX_CONT; 91462306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 91562306a36Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", 91862306a36Sopenharmony_ci ch->is->name, ch->state); 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci case PSEV_RSP_CONN: 92262306a36Sopenharmony_ci if (ch->state == STFAX_CONT) { 92362306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); 92462306a36Sopenharmony_ci ch->state = STFAX_ACTIV; 92562306a36Sopenharmony_ci test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 92662306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 92762306a36Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FTH) { 92862306a36Sopenharmony_ci int delay = (ch->mod == 3) ? 1000 : 200; 92962306a36Sopenharmony_ci /* 1s (200 ms) Flags before data */ 93062306a36Sopenharmony_ci if (test_and_set_bit(FLG_FTI_RUN, 93162306a36Sopenharmony_ci &ch->bch.Flags)) 93262306a36Sopenharmony_ci del_timer(&ch->ftimer); 93362306a36Sopenharmony_ci ch->ftimer.expires = 93462306a36Sopenharmony_ci jiffies + ((delay * HZ) / 1000); 93562306a36Sopenharmony_ci test_and_set_bit(FLG_LL_CONN, 93662306a36Sopenharmony_ci &ch->bch.Flags); 93762306a36Sopenharmony_ci add_timer(&ch->ftimer); 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_CONN wrong st %x\n", 94362306a36Sopenharmony_ci ch->is->name, ch->state); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci case PSEV_FLAGS_DET: 94762306a36Sopenharmony_ci pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci case PSEV_RSP_DISC: 95062306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_DISC state(%d)\n", 95162306a36Sopenharmony_ci ch->is->name, ch->state); 95262306a36Sopenharmony_ci if (ch->state == STFAX_ESCAPE) { 95362306a36Sopenharmony_ci p1 = 5; 95462306a36Sopenharmony_ci switch (ch->newcmd) { 95562306a36Sopenharmony_ci case 0: 95662306a36Sopenharmony_ci ch->state = STFAX_READY; 95762306a36Sopenharmony_ci break; 95862306a36Sopenharmony_ci case PCTRL_CMD_FTM: 95962306a36Sopenharmony_ci p1 = 2; 96062306a36Sopenharmony_ci fallthrough; 96162306a36Sopenharmony_ci case PCTRL_CMD_FTH: 96262306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 96362306a36Sopenharmony_ci PCTRL_CMD_SILON, 1, &p1); 96462306a36Sopenharmony_ci ch->state = STFAX_SILDET; 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci case PCTRL_CMD_FRH: 96762306a36Sopenharmony_ci case PCTRL_CMD_FRM: 96862306a36Sopenharmony_ci ch->mod = ch->newmod; 96962306a36Sopenharmony_ci p1 = ch->newmod; 97062306a36Sopenharmony_ci ch->newmod = 0; 97162306a36Sopenharmony_ci ch->cmd = ch->newcmd; 97262306a36Sopenharmony_ci ch->newcmd = 0; 97362306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 97462306a36Sopenharmony_ci ch->cmd, 1, &p1); 97562306a36Sopenharmony_ci ch->state = STFAX_LINE; 97662306a36Sopenharmony_ci ch->try_mod = 3; 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci default: 97962306a36Sopenharmony_ci pr_debug("%s: RSP_DISC unknown newcmd %x\n", 98062306a36Sopenharmony_ci ch->is->name, ch->newcmd); 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci } else if (ch->state == STFAX_ACTIV) { 98462306a36Sopenharmony_ci if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) 98562306a36Sopenharmony_ci deliver_status(ch, HW_MOD_OK); 98662306a36Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FRM) 98762306a36Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 98862306a36Sopenharmony_ci else 98962306a36Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 99062306a36Sopenharmony_ci ch->state = STFAX_READY; 99162306a36Sopenharmony_ci } else if (ch->state != STFAX_SILDET) { 99262306a36Sopenharmony_ci /* ignore in STFAX_SILDET */ 99362306a36Sopenharmony_ci ch->state = STFAX_READY; 99462306a36Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci case PSEV_RSP_SILDET: 99862306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); 99962306a36Sopenharmony_ci if (ch->state == STFAX_SILDET) { 100062306a36Sopenharmony_ci ch->mod = ch->newmod; 100162306a36Sopenharmony_ci p1 = ch->newmod; 100262306a36Sopenharmony_ci ch->newmod = 0; 100362306a36Sopenharmony_ci ch->cmd = ch->newcmd; 100462306a36Sopenharmony_ci ch->newcmd = 0; 100562306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 100662306a36Sopenharmony_ci ch->cmd, 1, &p1); 100762306a36Sopenharmony_ci ch->state = STFAX_LINE; 100862306a36Sopenharmony_ci ch->try_mod = 3; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci case PSEV_RSP_SILOFF: 101262306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); 101362306a36Sopenharmony_ci break; 101462306a36Sopenharmony_ci case PSEV_RSP_FCERR: 101562306a36Sopenharmony_ci if (ch->state == STFAX_LINE) { 101662306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_FCERR try %d\n", 101762306a36Sopenharmony_ci ch->is->name, ch->try_mod); 101862306a36Sopenharmony_ci if (ch->try_mod--) { 101962306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 102062306a36Sopenharmony_ci ch->cmd, 1, &ch->mod); 102162306a36Sopenharmony_ci break; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); 102562306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 102662306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 102762306a36Sopenharmony_ci 0, NULL); 102862306a36Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci default: 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_civoid 103662306a36Sopenharmony_cimISDNisar_irq(struct isar_hw *isar) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct isar_ch *ch; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci get_irq_infos(isar); 104162306a36Sopenharmony_ci switch (isar->iis & ISAR_IIS_MSCMSD) { 104262306a36Sopenharmony_ci case ISAR_IIS_RDATA: 104362306a36Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 104462306a36Sopenharmony_ci if (ch) 104562306a36Sopenharmony_ci isar_rcv_frame(ch); 104662306a36Sopenharmony_ci else { 104762306a36Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", 104862306a36Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 104962306a36Sopenharmony_ci isar->clsb); 105062306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci break; 105362306a36Sopenharmony_ci case ISAR_IIS_GSTEV: 105462306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 105562306a36Sopenharmony_ci isar->bstat |= isar->cmsb; 105662306a36Sopenharmony_ci check_send(isar, isar->cmsb); 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci case ISAR_IIS_BSTEV: 105962306a36Sopenharmony_ci#ifdef ERROR_STATISTIC 106062306a36Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 106162306a36Sopenharmony_ci if (ch) { 106262306a36Sopenharmony_ci if (isar->cmsb == BSTEV_TBO) 106362306a36Sopenharmony_ci ch->bch.err_tx++; 106462306a36Sopenharmony_ci if (isar->cmsb == BSTEV_RBO) 106562306a36Sopenharmony_ci ch->bch.err_rdo++; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci#endif 106862306a36Sopenharmony_ci pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", 106962306a36Sopenharmony_ci isar->name, isar->iis >> 6, isar->cmsb); 107062306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci case ISAR_IIS_PSTEV: 107362306a36Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 107462306a36Sopenharmony_ci if (ch) { 107562306a36Sopenharmony_ci rcv_mbox(isar, NULL); 107662306a36Sopenharmony_ci if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) 107762306a36Sopenharmony_ci isar_pump_statev_modem(ch, isar->cmsb); 107862306a36Sopenharmony_ci else if (ch->bch.state == ISDN_P_B_T30_FAX) 107962306a36Sopenharmony_ci isar_pump_statev_fax(ch, isar->cmsb); 108062306a36Sopenharmony_ci else if (ch->bch.state == ISDN_P_B_RAW) { 108162306a36Sopenharmony_ci int tt; 108262306a36Sopenharmony_ci tt = isar->cmsb | 0x30; 108362306a36Sopenharmony_ci if (tt == 0x3e) 108462306a36Sopenharmony_ci tt = '*'; 108562306a36Sopenharmony_ci else if (tt == 0x3f) 108662306a36Sopenharmony_ci tt = '#'; 108762306a36Sopenharmony_ci else if (tt > '9') 108862306a36Sopenharmony_ci tt += 7; 108962306a36Sopenharmony_ci tt |= DTMF_TONE_VAL; 109062306a36Sopenharmony_ci _queue_data(&ch->bch.ch, PH_CONTROL_IND, 109162306a36Sopenharmony_ci MISDN_ID_ANY, sizeof(tt), &tt, 109262306a36Sopenharmony_ci GFP_ATOMIC); 109362306a36Sopenharmony_ci } else 109462306a36Sopenharmony_ci pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", 109562306a36Sopenharmony_ci isar->name, ch->bch.state, 109662306a36Sopenharmony_ci isar->cmsb); 109762306a36Sopenharmony_ci } else { 109862306a36Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", 109962306a36Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 110062306a36Sopenharmony_ci isar->clsb); 110162306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case ISAR_IIS_PSTRSP: 110562306a36Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 110662306a36Sopenharmony_ci if (ch) { 110762306a36Sopenharmony_ci rcv_mbox(isar, NULL); 110862306a36Sopenharmony_ci isar_pump_status_rsp(ch); 110962306a36Sopenharmony_ci } else { 111062306a36Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", 111162306a36Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 111262306a36Sopenharmony_ci isar->clsb); 111362306a36Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci case ISAR_IIS_DIAG: 111762306a36Sopenharmony_ci case ISAR_IIS_BSTRSP: 111862306a36Sopenharmony_ci case ISAR_IIS_IOM2RSP: 111962306a36Sopenharmony_ci rcv_mbox(isar, NULL); 112062306a36Sopenharmony_ci break; 112162306a36Sopenharmony_ci case ISAR_IIS_INVMSG: 112262306a36Sopenharmony_ci rcv_mbox(isar, NULL); 112362306a36Sopenharmony_ci pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); 112462306a36Sopenharmony_ci break; 112562306a36Sopenharmony_ci default: 112662306a36Sopenharmony_ci rcv_mbox(isar, NULL); 112762306a36Sopenharmony_ci pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", 112862306a36Sopenharmony_ci isar->name, isar->iis, isar->cmsb, isar->clsb); 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ciEXPORT_SYMBOL(mISDNisar_irq); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void 113562306a36Sopenharmony_ciftimer_handler(struct timer_list *t) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci struct isar_ch *ch = from_timer(ch, t, ftimer); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); 114062306a36Sopenharmony_ci test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); 114162306a36Sopenharmony_ci if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) 114262306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic void 114662306a36Sopenharmony_cisetup_pump(struct isar_ch *ch) { 114762306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 114862306a36Sopenharmony_ci u8 ctrl, param[6]; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci switch (ch->bch.state) { 115162306a36Sopenharmony_ci case ISDN_P_NONE: 115262306a36Sopenharmony_ci case ISDN_P_B_RAW: 115362306a36Sopenharmony_ci case ISDN_P_B_HDLC: 115462306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 115762306a36Sopenharmony_ci if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { 115862306a36Sopenharmony_ci param[0] = 5; /* TOA 5 db */ 115962306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 116062306a36Sopenharmony_ci PMOD_DTMF_TRANS, 1, param); 116162306a36Sopenharmony_ci } else { 116262306a36Sopenharmony_ci param[0] = 40; /* REL -46 dbm */ 116362306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 116462306a36Sopenharmony_ci PMOD_DTMF, 1, param); 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci fallthrough; 116762306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 116862306a36Sopenharmony_ci ctrl = PMOD_DATAMODEM; 116962306a36Sopenharmony_ci if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 117062306a36Sopenharmony_ci ctrl |= PCTRL_ORIG; 117162306a36Sopenharmony_ci param[5] = PV32P6_CTN; 117262306a36Sopenharmony_ci } else { 117362306a36Sopenharmony_ci param[5] = PV32P6_ATN; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci param[0] = 6; /* 6 db */ 117662306a36Sopenharmony_ci param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | 117762306a36Sopenharmony_ci PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 117862306a36Sopenharmony_ci param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; 117962306a36Sopenharmony_ci param[3] = PV32P4_UT144; 118062306a36Sopenharmony_ci param[4] = PV32P5_UT144; 118162306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 118462306a36Sopenharmony_ci ctrl = PMOD_FAX; 118562306a36Sopenharmony_ci if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 118662306a36Sopenharmony_ci ctrl |= PCTRL_ORIG; 118762306a36Sopenharmony_ci param[1] = PFAXP2_CTN; 118862306a36Sopenharmony_ci } else { 118962306a36Sopenharmony_ci param[1] = PFAXP2_ATN; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci param[0] = 6; /* 6 db */ 119262306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); 119362306a36Sopenharmony_ci ch->state = STFAX_NULL; 119462306a36Sopenharmony_ci ch->newcmd = 0; 119562306a36Sopenharmony_ci ch->newmod = 0; 119662306a36Sopenharmony_ci test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci udelay(1000); 120062306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 120162306a36Sopenharmony_ci udelay(1000); 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistatic void 120562306a36Sopenharmony_cisetup_sart(struct isar_ch *ch) { 120662306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 120762306a36Sopenharmony_ci u8 ctrl, param[2] = {0, 0}; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci switch (ch->bch.state) { 121062306a36Sopenharmony_ci case ISDN_P_NONE: 121162306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 121262306a36Sopenharmony_ci 0, NULL); 121362306a36Sopenharmony_ci break; 121462306a36Sopenharmony_ci case ISDN_P_B_RAW: 121562306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 121662306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 121762306a36Sopenharmony_ci 2, param); 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci case ISDN_P_B_HDLC: 122062306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 122162306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 122262306a36Sopenharmony_ci 1, param); 122362306a36Sopenharmony_ci break; 122462306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 122562306a36Sopenharmony_ci ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; 122662306a36Sopenharmony_ci param[0] = S_P1_CHS_8; 122762306a36Sopenharmony_ci param[1] = S_P2_BFT_DEF; 122862306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci udelay(1000); 123262306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); 123362306a36Sopenharmony_ci udelay(1000); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic void 123762306a36Sopenharmony_cisetup_iom2(struct isar_ch *ch) { 123862306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 123962306a36Sopenharmony_ci u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci if (ch->bch.nr == 2) { 124262306a36Sopenharmony_ci msg[1] = 1; 124362306a36Sopenharmony_ci msg[3] = 1; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci switch (ch->bch.state) { 124662306a36Sopenharmony_ci case ISDN_P_NONE: 124762306a36Sopenharmony_ci cmsb = 0; 124862306a36Sopenharmony_ci /* dummy slot */ 124962306a36Sopenharmony_ci msg[1] = ch->dpath + 2; 125062306a36Sopenharmony_ci msg[3] = ch->dpath + 2; 125162306a36Sopenharmony_ci break; 125262306a36Sopenharmony_ci case ISDN_P_B_RAW: 125362306a36Sopenharmony_ci case ISDN_P_B_HDLC: 125462306a36Sopenharmony_ci break; 125562306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 125662306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 125762306a36Sopenharmony_ci cmsb |= IOM_CTRL_RCV; 125862306a36Sopenharmony_ci fallthrough; 125962306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 126062306a36Sopenharmony_ci if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) 126162306a36Sopenharmony_ci cmsb |= IOM_CTRL_RCV; 126262306a36Sopenharmony_ci cmsb |= IOM_CTRL_ALAW; 126362306a36Sopenharmony_ci break; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); 126662306a36Sopenharmony_ci udelay(1000); 126762306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); 126862306a36Sopenharmony_ci udelay(1000); 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic int 127262306a36Sopenharmony_cimodeisar(struct isar_ch *ch, u32 bprotocol) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci /* Here we are selecting the best datapath for requested protocol */ 127562306a36Sopenharmony_ci if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ 127662306a36Sopenharmony_ci switch (bprotocol) { 127762306a36Sopenharmony_ci case ISDN_P_NONE: /* init */ 127862306a36Sopenharmony_ci if (!ch->dpath) 127962306a36Sopenharmony_ci /* no init for dpath 0 */ 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); 128262306a36Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci case ISDN_P_B_RAW: 128562306a36Sopenharmony_ci case ISDN_P_B_HDLC: 128662306a36Sopenharmony_ci /* best is datapath 2 */ 128762306a36Sopenharmony_ci if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) 128862306a36Sopenharmony_ci ch->dpath = 2; 128962306a36Sopenharmony_ci else if (!test_and_set_bit(ISAR_DP1_USE, 129062306a36Sopenharmony_ci &ch->is->Flags)) 129162306a36Sopenharmony_ci ch->dpath = 1; 129262306a36Sopenharmony_ci else { 129362306a36Sopenharmony_ci pr_info("modeisar both paths in use\n"); 129462306a36Sopenharmony_ci return -EBUSY; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci if (bprotocol == ISDN_P_B_HDLC) 129762306a36Sopenharmony_ci test_and_set_bit(FLG_HDLC, &ch->bch.Flags); 129862306a36Sopenharmony_ci else 129962306a36Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, 130062306a36Sopenharmony_ci &ch->bch.Flags); 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 130362306a36Sopenharmony_ci case ISDN_P_B_T30_FAX: 130462306a36Sopenharmony_ci case ISDN_P_B_L2DTMF: 130562306a36Sopenharmony_ci /* only datapath 1 */ 130662306a36Sopenharmony_ci if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) 130762306a36Sopenharmony_ci ch->dpath = 1; 130862306a36Sopenharmony_ci else { 130962306a36Sopenharmony_ci pr_info("%s: ISAR modeisar analog functions" 131062306a36Sopenharmony_ci "only with DP1\n", ch->is->name); 131162306a36Sopenharmony_ci return -EBUSY; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci default: 131562306a36Sopenharmony_ci pr_info("%s: protocol not known %x\n", ch->is->name, 131662306a36Sopenharmony_ci bprotocol); 131762306a36Sopenharmony_ci return -ENOPROTOOPT; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, 132162306a36Sopenharmony_ci ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); 132262306a36Sopenharmony_ci ch->bch.state = bprotocol; 132362306a36Sopenharmony_ci setup_pump(ch); 132462306a36Sopenharmony_ci setup_iom2(ch); 132562306a36Sopenharmony_ci setup_sart(ch); 132662306a36Sopenharmony_ci if (ch->bch.state == ISDN_P_NONE) { 132762306a36Sopenharmony_ci /* Clear resources */ 132862306a36Sopenharmony_ci if (ch->dpath == 1) 132962306a36Sopenharmony_ci test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); 133062306a36Sopenharmony_ci else if (ch->dpath == 2) 133162306a36Sopenharmony_ci test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); 133262306a36Sopenharmony_ci ch->dpath = 0; 133362306a36Sopenharmony_ci ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); 133462306a36Sopenharmony_ci } else 133562306a36Sopenharmony_ci ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); 133662306a36Sopenharmony_ci return 0; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic void 134062306a36Sopenharmony_ciisar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 134362306a36Sopenharmony_ci u8 ctrl = 0, nom = 0, p1 = 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", 134662306a36Sopenharmony_ci ch->is->name, cmd, para, ch->bch.state); 134762306a36Sopenharmony_ci switch (cmd) { 134862306a36Sopenharmony_ci case HW_MOD_FTM: 134962306a36Sopenharmony_ci if (ch->state == STFAX_READY) { 135062306a36Sopenharmony_ci p1 = para; 135162306a36Sopenharmony_ci ctrl = PCTRL_CMD_FTM; 135262306a36Sopenharmony_ci nom = 1; 135362306a36Sopenharmony_ci ch->state = STFAX_LINE; 135462306a36Sopenharmony_ci ch->cmd = ctrl; 135562306a36Sopenharmony_ci ch->mod = para; 135662306a36Sopenharmony_ci ch->newmod = 0; 135762306a36Sopenharmony_ci ch->newcmd = 0; 135862306a36Sopenharmony_ci ch->try_mod = 3; 135962306a36Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 136062306a36Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) 136162306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 136262306a36Sopenharmony_ci else { 136362306a36Sopenharmony_ci ch->newmod = para; 136462306a36Sopenharmony_ci ch->newcmd = PCTRL_CMD_FTM; 136562306a36Sopenharmony_ci nom = 0; 136662306a36Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 136762306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci case HW_MOD_FTH: 137162306a36Sopenharmony_ci if (ch->state == STFAX_READY) { 137262306a36Sopenharmony_ci p1 = para; 137362306a36Sopenharmony_ci ctrl = PCTRL_CMD_FTH; 137462306a36Sopenharmony_ci nom = 1; 137562306a36Sopenharmony_ci ch->state = STFAX_LINE; 137662306a36Sopenharmony_ci ch->cmd = ctrl; 137762306a36Sopenharmony_ci ch->mod = para; 137862306a36Sopenharmony_ci ch->newmod = 0; 137962306a36Sopenharmony_ci ch->newcmd = 0; 138062306a36Sopenharmony_ci ch->try_mod = 3; 138162306a36Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 138262306a36Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) 138362306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 138462306a36Sopenharmony_ci else { 138562306a36Sopenharmony_ci ch->newmod = para; 138662306a36Sopenharmony_ci ch->newcmd = PCTRL_CMD_FTH; 138762306a36Sopenharmony_ci nom = 0; 138862306a36Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 138962306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci break; 139262306a36Sopenharmony_ci case HW_MOD_FRM: 139362306a36Sopenharmony_ci if (ch->state == STFAX_READY) { 139462306a36Sopenharmony_ci p1 = para; 139562306a36Sopenharmony_ci ctrl = PCTRL_CMD_FRM; 139662306a36Sopenharmony_ci nom = 1; 139762306a36Sopenharmony_ci ch->state = STFAX_LINE; 139862306a36Sopenharmony_ci ch->cmd = ctrl; 139962306a36Sopenharmony_ci ch->mod = para; 140062306a36Sopenharmony_ci ch->newmod = 0; 140162306a36Sopenharmony_ci ch->newcmd = 0; 140262306a36Sopenharmony_ci ch->try_mod = 3; 140362306a36Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 140462306a36Sopenharmony_ci (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) 140562306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 140662306a36Sopenharmony_ci else { 140762306a36Sopenharmony_ci ch->newmod = para; 140862306a36Sopenharmony_ci ch->newcmd = PCTRL_CMD_FRM; 140962306a36Sopenharmony_ci nom = 0; 141062306a36Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 141162306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci case HW_MOD_FRH: 141562306a36Sopenharmony_ci if (ch->state == STFAX_READY) { 141662306a36Sopenharmony_ci p1 = para; 141762306a36Sopenharmony_ci ctrl = PCTRL_CMD_FRH; 141862306a36Sopenharmony_ci nom = 1; 141962306a36Sopenharmony_ci ch->state = STFAX_LINE; 142062306a36Sopenharmony_ci ch->cmd = ctrl; 142162306a36Sopenharmony_ci ch->mod = para; 142262306a36Sopenharmony_ci ch->newmod = 0; 142362306a36Sopenharmony_ci ch->newcmd = 0; 142462306a36Sopenharmony_ci ch->try_mod = 3; 142562306a36Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 142662306a36Sopenharmony_ci (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) 142762306a36Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 142862306a36Sopenharmony_ci else { 142962306a36Sopenharmony_ci ch->newmod = para; 143062306a36Sopenharmony_ci ch->newcmd = PCTRL_CMD_FRH; 143162306a36Sopenharmony_ci nom = 0; 143262306a36Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 143362306a36Sopenharmony_ci ch->state = STFAX_ESCAPE; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci break; 143662306a36Sopenharmony_ci case PCTRL_CMD_TDTMF: 143762306a36Sopenharmony_ci p1 = para; 143862306a36Sopenharmony_ci nom = 1; 143962306a36Sopenharmony_ci ctrl = PCTRL_CMD_TDTMF; 144062306a36Sopenharmony_ci break; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci if (ctrl) 144362306a36Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); 144462306a36Sopenharmony_ci} 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cistatic void 144762306a36Sopenharmony_ciisar_setup(struct isar_hw *isar) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci u8 msg; 145062306a36Sopenharmony_ci int i; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* Dpath 1, 2 */ 145362306a36Sopenharmony_ci msg = 61; 145462306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 145562306a36Sopenharmony_ci /* Buffer Config */ 145662306a36Sopenharmony_ci send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | 145762306a36Sopenharmony_ci ISAR_HIS_P12CFG, 4, 1, &msg); 145862306a36Sopenharmony_ci isar->ch[i].mml = msg; 145962306a36Sopenharmony_ci isar->ch[i].bch.state = 0; 146062306a36Sopenharmony_ci isar->ch[i].dpath = i + 1; 146162306a36Sopenharmony_ci modeisar(&isar->ch[i], ISDN_P_NONE); 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic int 146662306a36Sopenharmony_ciisar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 146962306a36Sopenharmony_ci struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 147062306a36Sopenharmony_ci int ret = -EINVAL; 147162306a36Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 147262306a36Sopenharmony_ci u32 id, *val; 147362306a36Sopenharmony_ci u_long flags; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci switch (hh->prim) { 147662306a36Sopenharmony_ci case PH_DATA_REQ: 147762306a36Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 147862306a36Sopenharmony_ci ret = bchannel_senddata(bch, skb); 147962306a36Sopenharmony_ci if (ret > 0) { /* direct TX */ 148062306a36Sopenharmony_ci ret = 0; 148162306a36Sopenharmony_ci isar_fill_fifo(ich); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 148462306a36Sopenharmony_ci return ret; 148562306a36Sopenharmony_ci case PH_ACTIVATE_REQ: 148662306a36Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 148762306a36Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 148862306a36Sopenharmony_ci ret = modeisar(ich, ch->protocol); 148962306a36Sopenharmony_ci else 149062306a36Sopenharmony_ci ret = 0; 149162306a36Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 149262306a36Sopenharmony_ci if (!ret) 149362306a36Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 149462306a36Sopenharmony_ci NULL, GFP_KERNEL); 149562306a36Sopenharmony_ci break; 149662306a36Sopenharmony_ci case PH_DEACTIVATE_REQ: 149762306a36Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 149862306a36Sopenharmony_ci mISDN_clear_bchannel(bch); 149962306a36Sopenharmony_ci modeisar(ich, ISDN_P_NONE); 150062306a36Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 150162306a36Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 150262306a36Sopenharmony_ci NULL, GFP_KERNEL); 150362306a36Sopenharmony_ci ret = 0; 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci case PH_CONTROL_REQ: 150662306a36Sopenharmony_ci val = (u32 *)skb->data; 150762306a36Sopenharmony_ci pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, 150862306a36Sopenharmony_ci hh->id, *val); 150962306a36Sopenharmony_ci if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == 151062306a36Sopenharmony_ci DTMF_TONE_VAL)) { 151162306a36Sopenharmony_ci if (bch->state == ISDN_P_B_L2DTMF) { 151262306a36Sopenharmony_ci char tt = *val & DTMF_TONE_MASK; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (tt == '*') 151562306a36Sopenharmony_ci tt = 0x1e; 151662306a36Sopenharmony_ci else if (tt == '#') 151762306a36Sopenharmony_ci tt = 0x1f; 151862306a36Sopenharmony_ci else if (tt > '9') 151962306a36Sopenharmony_ci tt -= 7; 152062306a36Sopenharmony_ci tt &= 0x1f; 152162306a36Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 152262306a36Sopenharmony_ci isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); 152362306a36Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 152462306a36Sopenharmony_ci } else { 152562306a36Sopenharmony_ci pr_info("%s: DTMF send wrong protocol %x\n", 152662306a36Sopenharmony_ci __func__, bch->state); 152762306a36Sopenharmony_ci return -EINVAL; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || 153062306a36Sopenharmony_ci (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { 153162306a36Sopenharmony_ci for (id = 0; id < FAXMODCNT; id++) 153262306a36Sopenharmony_ci if (faxmodulation[id] == *val) 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci if ((FAXMODCNT > id) && 153562306a36Sopenharmony_ci test_bit(FLG_INITIALIZED, &bch->Flags)) { 153662306a36Sopenharmony_ci pr_debug("%s: isar: new mod\n", ich->is->name); 153762306a36Sopenharmony_ci isar_pump_cmd(ich, hh->id, *val); 153862306a36Sopenharmony_ci ret = 0; 153962306a36Sopenharmony_ci } else { 154062306a36Sopenharmony_ci pr_info("%s: wrong modulation\n", 154162306a36Sopenharmony_ci ich->is->name); 154262306a36Sopenharmony_ci ret = -EINVAL; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci } else if (hh->id == HW_MOD_LASTDATA) 154562306a36Sopenharmony_ci test_and_set_bit(FLG_DLEETX, &bch->Flags); 154662306a36Sopenharmony_ci else { 154762306a36Sopenharmony_ci pr_info("%s: unknown PH_CONTROL_REQ %x\n", 154862306a36Sopenharmony_ci ich->is->name, hh->id); 154962306a36Sopenharmony_ci ret = -EINVAL; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci fallthrough; 155262306a36Sopenharmony_ci default: 155362306a36Sopenharmony_ci pr_info("%s: %s unknown prim(%x,%x)\n", 155462306a36Sopenharmony_ci ich->is->name, __func__, hh->prim, hh->id); 155562306a36Sopenharmony_ci ret = -EINVAL; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci if (!ret) 155862306a36Sopenharmony_ci dev_kfree_skb(skb); 155962306a36Sopenharmony_ci return ret; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic int 156362306a36Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic int 156962306a36Sopenharmony_ciisar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 157262306a36Sopenharmony_ci struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 157362306a36Sopenharmony_ci int ret = -EINVAL; 157462306a36Sopenharmony_ci u_long flags; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); 157762306a36Sopenharmony_ci switch (cmd) { 157862306a36Sopenharmony_ci case CLOSE_CHANNEL: 157962306a36Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 158062306a36Sopenharmony_ci cancel_work_sync(&bch->workq); 158162306a36Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 158262306a36Sopenharmony_ci mISDN_clear_bchannel(bch); 158362306a36Sopenharmony_ci modeisar(ich, ISDN_P_NONE); 158462306a36Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 158562306a36Sopenharmony_ci ch->protocol = ISDN_P_NONE; 158662306a36Sopenharmony_ci ch->peer = NULL; 158762306a36Sopenharmony_ci module_put(ich->is->owner); 158862306a36Sopenharmony_ci ret = 0; 158962306a36Sopenharmony_ci break; 159062306a36Sopenharmony_ci case CONTROL_CHANNEL: 159162306a36Sopenharmony_ci ret = channel_bctrl(bch, arg); 159262306a36Sopenharmony_ci break; 159362306a36Sopenharmony_ci default: 159462306a36Sopenharmony_ci pr_info("%s: %s unknown prim(%x)\n", 159562306a36Sopenharmony_ci ich->is->name, __func__, cmd); 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci return ret; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic void 160162306a36Sopenharmony_cifree_isar(struct isar_hw *isar) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci modeisar(&isar->ch[0], ISDN_P_NONE); 160462306a36Sopenharmony_ci modeisar(&isar->ch[1], ISDN_P_NONE); 160562306a36Sopenharmony_ci del_timer(&isar->ch[0].ftimer); 160662306a36Sopenharmony_ci del_timer(&isar->ch[1].ftimer); 160762306a36Sopenharmony_ci test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 160862306a36Sopenharmony_ci test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic int 161262306a36Sopenharmony_ciinit_isar(struct isar_hw *isar) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci int cnt = 3; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci while (cnt--) { 161762306a36Sopenharmony_ci isar->version = ISARVersion(isar); 161862306a36Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW) 161962306a36Sopenharmony_ci pr_notice("%s: Testing version %d (%d time)\n", 162062306a36Sopenharmony_ci isar->name, isar->version, 3 - cnt); 162162306a36Sopenharmony_ci if (isar->version == 1) 162262306a36Sopenharmony_ci break; 162362306a36Sopenharmony_ci isar->ctrl(isar->hw, HW_RESET_REQ, 0); 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci if (isar->version != 1) 162662306a36Sopenharmony_ci return -EINVAL; 162762306a36Sopenharmony_ci timer_setup(&isar->ch[0].ftimer, ftimer_handler, 0); 162862306a36Sopenharmony_ci test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 162962306a36Sopenharmony_ci timer_setup(&isar->ch[1].ftimer, ftimer_handler, 0); 163062306a36Sopenharmony_ci test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 163162306a36Sopenharmony_ci return 0; 163262306a36Sopenharmony_ci} 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_cistatic int 163562306a36Sopenharmony_ciisar_open(struct isar_hw *isar, struct channel_req *rq) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci struct bchannel *bch; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 164062306a36Sopenharmony_ci return -EINVAL; 164162306a36Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 164262306a36Sopenharmony_ci return -EINVAL; 164362306a36Sopenharmony_ci bch = &isar->ch[rq->adr.channel - 1].bch; 164462306a36Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 164562306a36Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 164662306a36Sopenharmony_ci bch->ch.protocol = rq->protocol; 164762306a36Sopenharmony_ci rq->ch = &bch->ch; 164862306a36Sopenharmony_ci return 0; 164962306a36Sopenharmony_ci} 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ciu32 165262306a36Sopenharmony_cimISDNisar_init(struct isar_hw *isar, void *hw) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci u32 ret, i; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci isar->hw = hw; 165762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 165862306a36Sopenharmony_ci isar->ch[i].bch.nr = i + 1; 165962306a36Sopenharmony_ci mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); 166062306a36Sopenharmony_ci isar->ch[i].bch.ch.nr = i + 1; 166162306a36Sopenharmony_ci isar->ch[i].bch.ch.send = &isar_l2l1; 166262306a36Sopenharmony_ci isar->ch[i].bch.ch.ctrl = isar_bctrl; 166362306a36Sopenharmony_ci isar->ch[i].bch.hw = hw; 166462306a36Sopenharmony_ci isar->ch[i].is = isar; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci isar->init = &init_isar; 166862306a36Sopenharmony_ci isar->release = &free_isar; 166962306a36Sopenharmony_ci isar->firmware = &load_firmware; 167062306a36Sopenharmony_ci isar->open = &isar_open; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 167362306a36Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | 167462306a36Sopenharmony_ci (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | 167562306a36Sopenharmony_ci (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | 167662306a36Sopenharmony_ci (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci return ret; 167962306a36Sopenharmony_ci} 168062306a36Sopenharmony_ciEXPORT_SYMBOL(mISDNisar_init); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic int __init isar_mod_init(void) 168362306a36Sopenharmony_ci{ 168462306a36Sopenharmony_ci pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); 168562306a36Sopenharmony_ci return 0; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic void __exit isar_mod_cleanup(void) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci pr_notice("mISDN: ISAR module unloaded\n"); 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_cimodule_init(isar_mod_init); 169362306a36Sopenharmony_cimodule_exit(isar_mod_cleanup); 1694