18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mISDNisar.c ISAR (Siemens PSB 7110) specific functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author Karsten Keil (keil@isdn4linux.de) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* define this to enable static debug messages, if you kernel supports 118c2ecf20Sopenharmony_ci * dynamic debugging, you should use debugfs for this 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci/* #define DEBUG */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/gfp.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 188c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include "isar.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define ISAR_REV "2.1" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Karsten Keil"); 258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 268c2ecf20Sopenharmony_ciMODULE_VERSION(ISAR_REV); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DEBUG_HW_FIRMWARE_FIFO 0x10000 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 318c2ecf20Sopenharmony_ci 122, 145, 146}; 328c2ecf20Sopenharmony_ci#define FAXMODCNT 13 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void isar_setup(struct isar_hw *); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic inline int 378c2ecf20Sopenharmony_ciwaitforHIA(struct isar_hw *isar, int timeout) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci int t = timeout; 408c2ecf20Sopenharmony_ci u8 val = isar->read_reg(isar->hw, ISAR_HIA); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci while ((val & 1) && t) { 438c2ecf20Sopenharmony_ci udelay(1); 448c2ecf20Sopenharmony_ci t--; 458c2ecf20Sopenharmony_ci val = isar->read_reg(isar->hw, ISAR_HIA); 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); 488c2ecf20Sopenharmony_ci return timeout; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * send msg to ISAR mailbox 538c2ecf20Sopenharmony_ci * if msg is NULL use isar->buf 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic int 568c2ecf20Sopenharmony_cisend_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci if (!waitforHIA(isar, 1000)) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); 618c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_CTRL_H, creg); 628c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_CTRL_L, len); 638c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_WADR, 0); 648c2ecf20Sopenharmony_ci if (!msg) 658c2ecf20Sopenharmony_ci msg = isar->buf; 668c2ecf20Sopenharmony_ci if (msg && len) { 678c2ecf20Sopenharmony_ci isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); 688c2ecf20Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 698c2ecf20Sopenharmony_ci int l = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci while (l < (int)len) { 728c2ecf20Sopenharmony_ci hex_dump_to_buffer(msg + l, len - l, 32, 1, 738c2ecf20Sopenharmony_ci isar->log, 256, 1); 748c2ecf20Sopenharmony_ci pr_debug("%s: %s %02x: %s\n", isar->name, 758c2ecf20Sopenharmony_ci __func__, l, isar->log); 768c2ecf20Sopenharmony_ci l += 32; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_HIS, his); 818c2ecf20Sopenharmony_ci waitforHIA(isar, 1000); 828c2ecf20Sopenharmony_ci return 1; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * receive message from ISAR mailbox 878c2ecf20Sopenharmony_ci * if msg is NULL use isar->buf 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistatic void 908c2ecf20Sopenharmony_circv_mbox(struct isar_hw *isar, u8 *msg) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci if (!msg) 938c2ecf20Sopenharmony_ci msg = isar->buf; 948c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_RADR, 0); 958c2ecf20Sopenharmony_ci if (msg && isar->clsb) { 968c2ecf20Sopenharmony_ci isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); 978c2ecf20Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 988c2ecf20Sopenharmony_ci int l = 0; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci while (l < (int)isar->clsb) { 1018c2ecf20Sopenharmony_ci hex_dump_to_buffer(msg + l, isar->clsb - l, 32, 1028c2ecf20Sopenharmony_ci 1, isar->log, 256, 1); 1038c2ecf20Sopenharmony_ci pr_debug("%s: %s %02x: %s\n", isar->name, 1048c2ecf20Sopenharmony_ci __func__, l, isar->log); 1058c2ecf20Sopenharmony_ci l += 32; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic inline void 1138c2ecf20Sopenharmony_ciget_irq_infos(struct isar_hw *isar) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci isar->iis = isar->read_reg(isar->hw, ISAR_IIS); 1168c2ecf20Sopenharmony_ci isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); 1178c2ecf20Sopenharmony_ci isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); 1188c2ecf20Sopenharmony_ci pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, 1198c2ecf20Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 1238c2ecf20Sopenharmony_ci * poll answer message from ISAR mailbox 1248c2ecf20Sopenharmony_ci * should be used only with ISAR IRQs disabled before DSP was started 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic int 1288c2ecf20Sopenharmony_cipoll_mbox(struct isar_hw *isar, int maxdelay) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci int t = maxdelay; 1318c2ecf20Sopenharmony_ci u8 irq; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci irq = isar->read_reg(isar->hw, ISAR_IRQBIT); 1348c2ecf20Sopenharmony_ci while (t && !(irq & ISAR_IRQSTA)) { 1358c2ecf20Sopenharmony_ci udelay(1); 1368c2ecf20Sopenharmony_ci t--; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci if (t) { 1398c2ecf20Sopenharmony_ci get_irq_infos(isar); 1408c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci pr_debug("%s: pulled %d bytes after %d us\n", 1438c2ecf20Sopenharmony_ci isar->name, isar->clsb, maxdelay - t); 1448c2ecf20Sopenharmony_ci return t; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int 1488c2ecf20Sopenharmony_ciISARVersion(struct isar_hw *isar) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int ver; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* disable ISAR IRQ */ 1538c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 1548c2ecf20Sopenharmony_ci isar->buf[0] = ISAR_MSG_HWVER; 1558c2ecf20Sopenharmony_ci isar->buf[1] = 0; 1568c2ecf20Sopenharmony_ci isar->buf[2] = 1; 1578c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) 1588c2ecf20Sopenharmony_ci return -1; 1598c2ecf20Sopenharmony_ci if (!poll_mbox(isar, 1000)) 1608c2ecf20Sopenharmony_ci return -2; 1618c2ecf20Sopenharmony_ci if (isar->iis == ISAR_IIS_VNR) { 1628c2ecf20Sopenharmony_ci if (isar->clsb == 1) { 1638c2ecf20Sopenharmony_ci ver = isar->buf[0] & 0xf; 1648c2ecf20Sopenharmony_ci return ver; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci return -3; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci return -4; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int 1728c2ecf20Sopenharmony_ciload_firmware(struct isar_hw *isar, const u8 *buf, int size) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 saved_debug = isar->ch[0].bch.debug; 1758c2ecf20Sopenharmony_ci int ret, cnt; 1768c2ecf20Sopenharmony_ci u8 nom, noc; 1778c2ecf20Sopenharmony_ci u16 left, val, *sp = (u16 *)buf; 1788c2ecf20Sopenharmony_ci u8 *mp; 1798c2ecf20Sopenharmony_ci u_long flags; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci struct { 1828c2ecf20Sopenharmony_ci u16 sadr; 1838c2ecf20Sopenharmony_ci u16 len; 1848c2ecf20Sopenharmony_ci u16 d_key; 1858c2ecf20Sopenharmony_ci } blk_head; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (1 != isar->version) { 1888c2ecf20Sopenharmony_ci pr_err("%s: ISAR wrong version %d firmware download aborted\n", 1898c2ecf20Sopenharmony_ci isar->name, isar->version); 1908c2ecf20Sopenharmony_ci return -EINVAL; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) 1938c2ecf20Sopenharmony_ci isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; 1948c2ecf20Sopenharmony_ci pr_debug("%s: load firmware %d words (%d bytes)\n", 1958c2ecf20Sopenharmony_ci isar->name, size / 2, size); 1968c2ecf20Sopenharmony_ci cnt = 0; 1978c2ecf20Sopenharmony_ci size /= 2; 1988c2ecf20Sopenharmony_ci /* disable ISAR IRQ */ 1998c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 2008c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 2018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 2028c2ecf20Sopenharmony_ci while (cnt < size) { 2038c2ecf20Sopenharmony_ci blk_head.sadr = le16_to_cpu(*sp++); 2048c2ecf20Sopenharmony_ci blk_head.len = le16_to_cpu(*sp++); 2058c2ecf20Sopenharmony_ci blk_head.d_key = le16_to_cpu(*sp++); 2068c2ecf20Sopenharmony_ci cnt += 3; 2078c2ecf20Sopenharmony_ci pr_debug("ISAR firmware block (%#x,%d,%#x)\n", 2088c2ecf20Sopenharmony_ci blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); 2098c2ecf20Sopenharmony_ci left = blk_head.len; 2108c2ecf20Sopenharmony_ci if (cnt + left > size) { 2118c2ecf20Sopenharmony_ci pr_info("%s: firmware error have %d need %d words\n", 2128c2ecf20Sopenharmony_ci isar->name, size, cnt + left); 2138c2ecf20Sopenharmony_ci ret = -EINVAL; 2148c2ecf20Sopenharmony_ci goto reterrflg; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 2178c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 2188c2ecf20Sopenharmony_ci 0, NULL)) { 2198c2ecf20Sopenharmony_ci pr_info("ISAR send_mbox dkey failed\n"); 2208c2ecf20Sopenharmony_ci ret = -ETIME; 2218c2ecf20Sopenharmony_ci goto reterror; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 2248c2ecf20Sopenharmony_ci pr_warn("ISAR poll_mbox dkey failed\n"); 2258c2ecf20Sopenharmony_ci ret = -ETIME; 2268c2ecf20Sopenharmony_ci goto reterror; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 2298c2ecf20Sopenharmony_ci if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { 2308c2ecf20Sopenharmony_ci pr_info("ISAR wrong dkey response (%x,%x,%x)\n", 2318c2ecf20Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 2328c2ecf20Sopenharmony_ci ret = 1; 2338c2ecf20Sopenharmony_ci goto reterrflg; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci while (left > 0) { 2368c2ecf20Sopenharmony_ci if (left > 126) 2378c2ecf20Sopenharmony_ci noc = 126; 2388c2ecf20Sopenharmony_ci else 2398c2ecf20Sopenharmony_ci noc = left; 2408c2ecf20Sopenharmony_ci nom = (2 * noc) + 3; 2418c2ecf20Sopenharmony_ci mp = isar->buf; 2428c2ecf20Sopenharmony_ci /* the ISAR is big endian */ 2438c2ecf20Sopenharmony_ci *mp++ = blk_head.sadr >> 8; 2448c2ecf20Sopenharmony_ci *mp++ = blk_head.sadr & 0xFF; 2458c2ecf20Sopenharmony_ci left -= noc; 2468c2ecf20Sopenharmony_ci cnt += noc; 2478c2ecf20Sopenharmony_ci *mp++ = noc; 2488c2ecf20Sopenharmony_ci pr_debug("%s: load %3d words at %04x\n", isar->name, 2498c2ecf20Sopenharmony_ci noc, blk_head.sadr); 2508c2ecf20Sopenharmony_ci blk_head.sadr += noc; 2518c2ecf20Sopenharmony_ci while (noc) { 2528c2ecf20Sopenharmony_ci val = le16_to_cpu(*sp++); 2538c2ecf20Sopenharmony_ci *mp++ = val >> 8; 2548c2ecf20Sopenharmony_ci *mp++ = val & 0xFF; 2558c2ecf20Sopenharmony_ci noc--; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 2588c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { 2598c2ecf20Sopenharmony_ci pr_info("ISAR send_mbox prog failed\n"); 2608c2ecf20Sopenharmony_ci ret = -ETIME; 2618c2ecf20Sopenharmony_ci goto reterror; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 2648c2ecf20Sopenharmony_ci pr_info("ISAR poll_mbox prog failed\n"); 2658c2ecf20Sopenharmony_ci ret = -ETIME; 2668c2ecf20Sopenharmony_ci goto reterror; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 2698c2ecf20Sopenharmony_ci if ((isar->iis != ISAR_IIS_FIRM) || 2708c2ecf20Sopenharmony_ci isar->cmsb || isar->clsb) { 2718c2ecf20Sopenharmony_ci pr_info("ISAR wrong prog response (%x,%x,%x)\n", 2728c2ecf20Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 2738c2ecf20Sopenharmony_ci ret = -EIO; 2748c2ecf20Sopenharmony_ci goto reterrflg; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci pr_debug("%s: ISAR firmware block %d words loaded\n", 2788c2ecf20Sopenharmony_ci isar->name, blk_head.len); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci isar->ch[0].bch.debug = saved_debug; 2818c2ecf20Sopenharmony_ci /* 10ms delay */ 2828c2ecf20Sopenharmony_ci cnt = 10; 2838c2ecf20Sopenharmony_ci while (cnt--) 2848c2ecf20Sopenharmony_ci mdelay(1); 2858c2ecf20Sopenharmony_ci isar->buf[0] = 0xff; 2868c2ecf20Sopenharmony_ci isar->buf[1] = 0xfe; 2878c2ecf20Sopenharmony_ci isar->bstat = 0; 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 2898c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { 2908c2ecf20Sopenharmony_ci pr_info("ISAR send_mbox start dsp failed\n"); 2918c2ecf20Sopenharmony_ci ret = -ETIME; 2928c2ecf20Sopenharmony_ci goto reterror; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci if (!poll_mbox(isar, 1000)) { 2958c2ecf20Sopenharmony_ci pr_info("ISAR poll_mbox start dsp failed\n"); 2968c2ecf20Sopenharmony_ci ret = -ETIME; 2978c2ecf20Sopenharmony_ci goto reterror; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { 3008c2ecf20Sopenharmony_ci pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", 3018c2ecf20Sopenharmony_ci isar->iis, isar->cmsb, isar->clsb); 3028c2ecf20Sopenharmony_ci ret = -EIO; 3038c2ecf20Sopenharmony_ci goto reterror; 3048c2ecf20Sopenharmony_ci } else 3058c2ecf20Sopenharmony_ci pr_debug("%s: ISAR start dsp success\n", isar->name); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* NORMAL mode entered */ 3088c2ecf20Sopenharmony_ci /* Enable IRQs of ISAR */ 3098c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); 3108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 3118c2ecf20Sopenharmony_ci cnt = 1000; /* max 1s */ 3128c2ecf20Sopenharmony_ci while ((!isar->bstat) && cnt) { 3138c2ecf20Sopenharmony_ci mdelay(1); 3148c2ecf20Sopenharmony_ci cnt--; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci if (!cnt) { 3178c2ecf20Sopenharmony_ci pr_info("ISAR no general status event received\n"); 3188c2ecf20Sopenharmony_ci ret = -ETIME; 3198c2ecf20Sopenharmony_ci goto reterrflg; 3208c2ecf20Sopenharmony_ci } else 3218c2ecf20Sopenharmony_ci pr_debug("%s: ISAR general status event %x\n", 3228c2ecf20Sopenharmony_ci isar->name, isar->bstat); 3238c2ecf20Sopenharmony_ci /* 10ms delay */ 3248c2ecf20Sopenharmony_ci cnt = 10; 3258c2ecf20Sopenharmony_ci while (cnt--) 3268c2ecf20Sopenharmony_ci mdelay(1); 3278c2ecf20Sopenharmony_ci isar->iis = 0; 3288c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 3298c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { 3308c2ecf20Sopenharmony_ci pr_info("ISAR send_mbox self tst failed\n"); 3318c2ecf20Sopenharmony_ci ret = -ETIME; 3328c2ecf20Sopenharmony_ci goto reterror; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 3358c2ecf20Sopenharmony_ci cnt = 10000; /* max 100 ms */ 3368c2ecf20Sopenharmony_ci while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 3378c2ecf20Sopenharmony_ci udelay(10); 3388c2ecf20Sopenharmony_ci cnt--; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci mdelay(1); 3418c2ecf20Sopenharmony_ci if (!cnt) { 3428c2ecf20Sopenharmony_ci pr_info("ISAR no self tst response\n"); 3438c2ecf20Sopenharmony_ci ret = -ETIME; 3448c2ecf20Sopenharmony_ci goto reterrflg; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) 3478c2ecf20Sopenharmony_ci && (isar->buf[0] == 0)) 3488c2ecf20Sopenharmony_ci pr_debug("%s: ISAR selftest OK\n", isar->name); 3498c2ecf20Sopenharmony_ci else { 3508c2ecf20Sopenharmony_ci pr_info("ISAR selftest not OK %x/%x/%x\n", 3518c2ecf20Sopenharmony_ci isar->cmsb, isar->clsb, isar->buf[0]); 3528c2ecf20Sopenharmony_ci ret = -EIO; 3538c2ecf20Sopenharmony_ci goto reterrflg; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 3568c2ecf20Sopenharmony_ci isar->iis = 0; 3578c2ecf20Sopenharmony_ci if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { 3588c2ecf20Sopenharmony_ci pr_info("ISAR RQST SVN failed\n"); 3598c2ecf20Sopenharmony_ci ret = -ETIME; 3608c2ecf20Sopenharmony_ci goto reterror; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 3638c2ecf20Sopenharmony_ci cnt = 30000; /* max 300 ms */ 3648c2ecf20Sopenharmony_ci while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 3658c2ecf20Sopenharmony_ci udelay(10); 3668c2ecf20Sopenharmony_ci cnt--; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci mdelay(1); 3698c2ecf20Sopenharmony_ci if (!cnt) { 3708c2ecf20Sopenharmony_ci pr_info("ISAR no SVN response\n"); 3718c2ecf20Sopenharmony_ci ret = -ETIME; 3728c2ecf20Sopenharmony_ci goto reterrflg; 3738c2ecf20Sopenharmony_ci } else { 3748c2ecf20Sopenharmony_ci if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { 3758c2ecf20Sopenharmony_ci pr_notice("%s: ISAR software version %#x\n", 3768c2ecf20Sopenharmony_ci isar->name, isar->buf[0]); 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci pr_info("%s: ISAR wrong swver response (%x,%x)" 3798c2ecf20Sopenharmony_ci " cnt(%d)\n", isar->name, isar->cmsb, 3808c2ecf20Sopenharmony_ci isar->clsb, cnt); 3818c2ecf20Sopenharmony_ci ret = -EIO; 3828c2ecf20Sopenharmony_ci goto reterrflg; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 3868c2ecf20Sopenharmony_ci isar_setup(isar); 3878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 3888c2ecf20Sopenharmony_ci ret = 0; 3898c2ecf20Sopenharmony_cireterrflg: 3908c2ecf20Sopenharmony_ci spin_lock_irqsave(isar->hwlock, flags); 3918c2ecf20Sopenharmony_cireterror: 3928c2ecf20Sopenharmony_ci isar->ch[0].bch.debug = saved_debug; 3938c2ecf20Sopenharmony_ci if (ret) 3948c2ecf20Sopenharmony_ci /* disable ISAR IRQ */ 3958c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 3968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(isar->hwlock, flags); 3978c2ecf20Sopenharmony_ci return ret; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic inline void 4018c2ecf20Sopenharmony_cideliver_status(struct isar_ch *ch, int status) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); 4048c2ecf20Sopenharmony_ci _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic inline void 4088c2ecf20Sopenharmony_ciisar_rcv_frame(struct isar_ch *ch) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci u8 *ptr; 4118c2ecf20Sopenharmony_ci int maxlen; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!ch->is->clsb) { 4148c2ecf20Sopenharmony_ci pr_debug("%s; ISAR zero len frame\n", ch->is->name); 4158c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4168c2ecf20Sopenharmony_ci return; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { 4198c2ecf20Sopenharmony_ci ch->bch.dropcnt += ch->is->clsb; 4208c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4218c2ecf20Sopenharmony_ci return; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci switch (ch->bch.state) { 4248c2ecf20Sopenharmony_ci case ISDN_P_NONE: 4258c2ecf20Sopenharmony_ci pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", 4268c2ecf20Sopenharmony_ci ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); 4278c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 4308c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 4318c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 4328c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 4338c2ecf20Sopenharmony_ci if (maxlen < 0) { 4348c2ecf20Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 4358c2ecf20Sopenharmony_ci ch->is->name, ch->bch.nr, ch->is->clsb); 4368c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 4408c2ecf20Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 4438c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 4448c2ecf20Sopenharmony_ci if (maxlen < 0) { 4458c2ecf20Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 4468c2ecf20Sopenharmony_ci ch->is->name, ch->bch.nr, ch->is->clsb); 4478c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_ERROR) { 4518c2ecf20Sopenharmony_ci pr_debug("%s: ISAR frame error %x len %d\n", 4528c2ecf20Sopenharmony_ci ch->is->name, ch->is->cmsb, ch->is->clsb); 4538c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 4548c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_ERR_RER) 4558c2ecf20Sopenharmony_ci ch->bch.err_inv++; 4568c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_ERR_CER) 4578c2ecf20Sopenharmony_ci ch->bch.err_crc++; 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 4608c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_FSD) 4648c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 4658c2ecf20Sopenharmony_ci ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 4668c2ecf20Sopenharmony_ci rcv_mbox(ch->is, ptr); 4678c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_FED) { 4688c2ecf20Sopenharmony_ci if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 4698c2ecf20Sopenharmony_ci pr_debug("%s: ISAR frame to short %d\n", 4708c2ecf20Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 4718c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 4758c2ecf20Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 4798c2ecf20Sopenharmony_ci if (ch->state != STFAX_ACTIV) { 4808c2ecf20Sopenharmony_ci pr_debug("%s: isar_rcv_frame: not ACTIV\n", 4818c2ecf20Sopenharmony_ci ch->is->name); 4828c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4838c2ecf20Sopenharmony_ci if (ch->bch.rx_skb) 4848c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if (!ch->bch.rx_skb) { 4888c2ecf20Sopenharmony_ci ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, 4898c2ecf20Sopenharmony_ci GFP_ATOMIC); 4908c2ecf20Sopenharmony_ci if (unlikely(!ch->bch.rx_skb)) { 4918c2ecf20Sopenharmony_ci pr_info("%s: B receive out of memory\n", 4928c2ecf20Sopenharmony_ci __func__); 4938c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FRM) { 4988c2ecf20Sopenharmony_ci rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 4998c2ecf20Sopenharmony_ci pr_debug("%s: isar_rcv_frame: %d\n", 5008c2ecf20Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 5018c2ecf20Sopenharmony_ci if (ch->is->cmsb & SART_NMD) { /* ABORT */ 5028c2ecf20Sopenharmony_ci pr_debug("%s: isar_rcv_frame: no more data\n", 5038c2ecf20Sopenharmony_ci ch->is->name); 5048c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5058c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 5068c2ecf20Sopenharmony_ci ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 5078c2ecf20Sopenharmony_ci 0, NULL); 5088c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 5098c2ecf20Sopenharmony_ci /* set_skb_flag(skb, DF_NOMOREDATA); */ 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 5128c2ecf20Sopenharmony_ci if (ch->is->cmsb & SART_NMD) 5138c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci if (ch->cmd != PCTRL_CMD_FRH) { 5178c2ecf20Sopenharmony_ci pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", 5188c2ecf20Sopenharmony_ci ch->is->name, ch->cmd); 5198c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5208c2ecf20Sopenharmony_ci if (ch->bch.rx_skb) 5218c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci /* PCTRL_CMD_FRH */ 5258c2ecf20Sopenharmony_ci if ((ch->bch.rx_skb->len + ch->is->clsb) > 5268c2ecf20Sopenharmony_ci (ch->bch.maxlen + 2)) { 5278c2ecf20Sopenharmony_ci pr_info("%s: %s incoming packet too large\n", 5288c2ecf20Sopenharmony_ci ch->is->name, __func__); 5298c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5308c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci } else if (ch->is->cmsb & HDLC_ERROR) { 5338c2ecf20Sopenharmony_ci pr_info("%s: ISAR frame error %x len %d\n", 5348c2ecf20Sopenharmony_ci ch->is->name, ch->is->cmsb, ch->is->clsb); 5358c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5368c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_FSD) 5408c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5418c2ecf20Sopenharmony_ci ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 5428c2ecf20Sopenharmony_ci rcv_mbox(ch->is, ptr); 5438c2ecf20Sopenharmony_ci if (ch->is->cmsb & HDLC_FED) { 5448c2ecf20Sopenharmony_ci if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 5458c2ecf20Sopenharmony_ci pr_info("%s: ISAR frame to short %d\n", 5468c2ecf20Sopenharmony_ci ch->is->name, ch->bch.rx_skb->len); 5478c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 5518c2ecf20Sopenharmony_ci recv_Bchannel(&ch->bch, 0, false); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci if (ch->is->cmsb & SART_NMD) { /* ABORT */ 5548c2ecf20Sopenharmony_ci pr_debug("%s: isar_rcv_frame: no more data\n", 5558c2ecf20Sopenharmony_ci ch->is->name); 5568c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5578c2ecf20Sopenharmony_ci if (ch->bch.rx_skb) 5588c2ecf20Sopenharmony_ci skb_trim(ch->bch.rx_skb, 0); 5598c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 5608c2ecf20Sopenharmony_ci ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); 5618c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 5628c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci default: 5668c2ecf20Sopenharmony_ci pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); 5678c2ecf20Sopenharmony_ci ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void 5738c2ecf20Sopenharmony_ciisar_fill_fifo(struct isar_ch *ch) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci int count; 5768c2ecf20Sopenharmony_ci u8 msb; 5778c2ecf20Sopenharmony_ci u8 *ptr; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, 5808c2ecf20Sopenharmony_ci ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); 5818c2ecf20Sopenharmony_ci if (!(ch->is->bstat & 5828c2ecf20Sopenharmony_ci (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) 5838c2ecf20Sopenharmony_ci return; 5848c2ecf20Sopenharmony_ci if (!ch->bch.tx_skb) { 5858c2ecf20Sopenharmony_ci if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || 5868c2ecf20Sopenharmony_ci (ch->bch.state != ISDN_P_B_RAW)) 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci count = ch->mml; 5898c2ecf20Sopenharmony_ci /* use the card buffer */ 5908c2ecf20Sopenharmony_ci memset(ch->is->buf, ch->bch.fill[0], count); 5918c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 5928c2ecf20Sopenharmony_ci 0, count, ch->is->buf); 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci count = ch->bch.tx_skb->len - ch->bch.tx_idx; 5968c2ecf20Sopenharmony_ci if (count <= 0) 5978c2ecf20Sopenharmony_ci return; 5988c2ecf20Sopenharmony_ci if (count > ch->mml) { 5998c2ecf20Sopenharmony_ci msb = 0; 6008c2ecf20Sopenharmony_ci count = ch->mml; 6018c2ecf20Sopenharmony_ci } else { 6028c2ecf20Sopenharmony_ci msb = HDLC_FED; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; 6058c2ecf20Sopenharmony_ci if (!ch->bch.tx_idx) { 6068c2ecf20Sopenharmony_ci pr_debug("%s: frame start\n", ch->is->name); 6078c2ecf20Sopenharmony_ci if ((ch->bch.state == ISDN_P_B_T30_FAX) && 6088c2ecf20Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTH)) { 6098c2ecf20Sopenharmony_ci if (count > 1) { 6108c2ecf20Sopenharmony_ci if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { 6118c2ecf20Sopenharmony_ci /* last frame */ 6128c2ecf20Sopenharmony_ci test_and_set_bit(FLG_LASTDATA, 6138c2ecf20Sopenharmony_ci &ch->bch.Flags); 6148c2ecf20Sopenharmony_ci pr_debug("%s: set LASTDATA\n", 6158c2ecf20Sopenharmony_ci ch->is->name); 6168c2ecf20Sopenharmony_ci if (msb == HDLC_FED) 6178c2ecf20Sopenharmony_ci test_and_set_bit(FLG_DLEETX, 6188c2ecf20Sopenharmony_ci &ch->bch.Flags); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci msb |= HDLC_FST; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci ch->bch.tx_idx += count; 6258c2ecf20Sopenharmony_ci switch (ch->bch.state) { 6268c2ecf20Sopenharmony_ci case ISDN_P_NONE: 6278c2ecf20Sopenharmony_ci pr_info("%s: wrong protocol 0\n", __func__); 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 6308c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 6318c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 6328c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 6338c2ecf20Sopenharmony_ci 0, count, ptr); 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 6368c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 6378c2ecf20Sopenharmony_ci msb, count, ptr); 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 6408c2ecf20Sopenharmony_ci if (ch->state != STFAX_ACTIV) 6418c2ecf20Sopenharmony_ci pr_debug("%s: not ACTIV\n", ch->is->name); 6428c2ecf20Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FTH) 6438c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 6448c2ecf20Sopenharmony_ci msb, count, ptr); 6458c2ecf20Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FTM) 6468c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 6478c2ecf20Sopenharmony_ci 0, count, ptr); 6488c2ecf20Sopenharmony_ci else 6498c2ecf20Sopenharmony_ci pr_debug("%s: not FTH/FTM\n", ch->is->name); 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci default: 6528c2ecf20Sopenharmony_ci pr_info("%s: protocol(%x) error\n", 6538c2ecf20Sopenharmony_ci __func__, ch->bch.state); 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic inline struct isar_ch * 6598c2ecf20Sopenharmony_cisel_bch_isar(struct isar_hw *isar, u8 dpath) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct isar_ch *base = &isar->ch[0]; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if ((!dpath) || (dpath > 2)) 6648c2ecf20Sopenharmony_ci return NULL; 6658c2ecf20Sopenharmony_ci if (base->dpath == dpath) 6668c2ecf20Sopenharmony_ci return base; 6678c2ecf20Sopenharmony_ci base++; 6688c2ecf20Sopenharmony_ci if (base->dpath == dpath) 6698c2ecf20Sopenharmony_ci return base; 6708c2ecf20Sopenharmony_ci return NULL; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void 6748c2ecf20Sopenharmony_cisend_next(struct isar_ch *ch) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, 6778c2ecf20Sopenharmony_ci ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, 6788c2ecf20Sopenharmony_ci ch->bch.tx_idx); 6798c2ecf20Sopenharmony_ci if (ch->bch.state == ISDN_P_B_T30_FAX) { 6808c2ecf20Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FTH) { 6818c2ecf20Sopenharmony_ci if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { 6828c2ecf20Sopenharmony_ci pr_debug("set NMD_DATA\n"); 6838c2ecf20Sopenharmony_ci test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci } else if (ch->cmd == PCTRL_CMD_FTM) { 6868c2ecf20Sopenharmony_ci if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { 6878c2ecf20Sopenharmony_ci test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); 6888c2ecf20Sopenharmony_ci test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci dev_kfree_skb(ch->bch.tx_skb); 6938c2ecf20Sopenharmony_ci if (get_next_bframe(&ch->bch)) { 6948c2ecf20Sopenharmony_ci isar_fill_fifo(ch); 6958c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); 6968c2ecf20Sopenharmony_ci } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { 6978c2ecf20Sopenharmony_ci isar_fill_fifo(ch); 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { 7008c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_LASTDATA, 7018c2ecf20Sopenharmony_ci &ch->bch.Flags)) { 7028c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_NMD_DATA, 7038c2ecf20Sopenharmony_ci &ch->bch.Flags)) { 7048c2ecf20Sopenharmony_ci u8 zd = 0; 7058c2ecf20Sopenharmony_ci send_mbox(ch->is, SET_DPS(ch->dpath) | 7068c2ecf20Sopenharmony_ci ISAR_HIS_SDATA, 0x01, 1, &zd); 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); 7098c2ecf20Sopenharmony_ci } else { 7108c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { 7138c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic void 7198c2ecf20Sopenharmony_cicheck_send(struct isar_hw *isar, u8 rdm) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct isar_ch *ch; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci pr_debug("%s: rdm %x\n", isar->name, rdm); 7248c2ecf20Sopenharmony_ci if (rdm & BSTAT_RDM1) { 7258c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, 1); 7268c2ecf20Sopenharmony_ci if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 7278c2ecf20Sopenharmony_ci if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 7288c2ecf20Sopenharmony_ci ch->bch.tx_idx)) 7298c2ecf20Sopenharmony_ci isar_fill_fifo(ch); 7308c2ecf20Sopenharmony_ci else 7318c2ecf20Sopenharmony_ci send_next(ch); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci if (rdm & BSTAT_RDM2) { 7358c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, 2); 7368c2ecf20Sopenharmony_ci if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 7378c2ecf20Sopenharmony_ci if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 7388c2ecf20Sopenharmony_ci ch->bch.tx_idx)) 7398c2ecf20Sopenharmony_ci isar_fill_fifo(ch); 7408c2ecf20Sopenharmony_ci else 7418c2ecf20Sopenharmony_ci send_next(ch); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", 7478c2ecf20Sopenharmony_ci "300", "600", "1200", "2400", "4800", "7200", 7488c2ecf20Sopenharmony_ci "9600nt", "9600t", "12000", "14400", "WRONG"}; 7498c2ecf20Sopenharmony_cistatic const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", 7508c2ecf20Sopenharmony_ci "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic void 7538c2ecf20Sopenharmony_ciisar_pump_status_rsp(struct isar_ch *ch) { 7548c2ecf20Sopenharmony_ci u8 ril = ch->is->buf[0]; 7558c2ecf20Sopenharmony_ci u8 rim; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) 7588c2ecf20Sopenharmony_ci return; 7598c2ecf20Sopenharmony_ci if (ril > 14) { 7608c2ecf20Sopenharmony_ci pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); 7618c2ecf20Sopenharmony_ci ril = 15; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci switch (ch->is->buf[1]) { 7648c2ecf20Sopenharmony_ci case 0: 7658c2ecf20Sopenharmony_ci rim = 0; 7668c2ecf20Sopenharmony_ci break; 7678c2ecf20Sopenharmony_ci case 0x20: 7688c2ecf20Sopenharmony_ci rim = 2; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci case 0x40: 7718c2ecf20Sopenharmony_ci rim = 3; 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci case 0x41: 7748c2ecf20Sopenharmony_ci rim = 4; 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci case 0x51: 7778c2ecf20Sopenharmony_ci rim = 5; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci case 0x61: 7808c2ecf20Sopenharmony_ci rim = 6; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case 0x71: 7838c2ecf20Sopenharmony_ci rim = 7; 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci case 0x82: 7868c2ecf20Sopenharmony_ci rim = 8; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case 0x92: 7898c2ecf20Sopenharmony_ci rim = 9; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case 0xa2: 7928c2ecf20Sopenharmony_ci rim = 10; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci default: 7958c2ecf20Sopenharmony_ci rim = 1; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); 7998c2ecf20Sopenharmony_ci pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void 8038c2ecf20Sopenharmony_ciisar_pump_statev_modem(struct isar_ch *ch, u8 devt) { 8048c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci switch (devt) { 8078c2ecf20Sopenharmony_ci case PSEV_10MS_TIMER: 8088c2ecf20Sopenharmony_ci pr_debug("%s: pump stev TIMER\n", ch->is->name); 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci case PSEV_CON_ON: 8118c2ecf20Sopenharmony_ci pr_debug("%s: pump stev CONNECT\n", ch->is->name); 8128c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case PSEV_CON_OFF: 8158c2ecf20Sopenharmony_ci pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); 8168c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 8178c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci case PSEV_V24_OFF: 8208c2ecf20Sopenharmony_ci pr_debug("%s: pump stev V24 OFF\n", ch->is->name); 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci case PSEV_CTS_ON: 8238c2ecf20Sopenharmony_ci pr_debug("%s: pump stev CTS ON\n", ch->is->name); 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case PSEV_CTS_OFF: 8268c2ecf20Sopenharmony_ci pr_debug("%s pump stev CTS OFF\n", ch->is->name); 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci case PSEV_DCD_ON: 8298c2ecf20Sopenharmony_ci pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); 8308c2ecf20Sopenharmony_ci test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 8318c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci case PSEV_DCD_OFF: 8348c2ecf20Sopenharmony_ci pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case PSEV_DSR_ON: 8378c2ecf20Sopenharmony_ci pr_debug("%s: pump stev DSR ON\n", ch->is->name); 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci case PSEV_DSR_OFF: 8408c2ecf20Sopenharmony_ci pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case PSEV_REM_RET: 8438c2ecf20Sopenharmony_ci pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci case PSEV_REM_REN: 8468c2ecf20Sopenharmony_ci pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci case PSEV_GSTN_CLR: 8498c2ecf20Sopenharmony_ci pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); 8508c2ecf20Sopenharmony_ci break; 8518c2ecf20Sopenharmony_ci default: 8528c2ecf20Sopenharmony_ci pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt); 8538c2ecf20Sopenharmony_ci break; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void 8588c2ecf20Sopenharmony_ciisar_pump_statev_fax(struct isar_ch *ch, u8 devt) { 8598c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 8608c2ecf20Sopenharmony_ci u8 p1; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci switch (devt) { 8638c2ecf20Sopenharmony_ci case PSEV_10MS_TIMER: 8648c2ecf20Sopenharmony_ci pr_debug("%s: pump stev TIMER\n", ch->is->name); 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci case PSEV_RSP_READY: 8678c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_READY\n", ch->is->name); 8688c2ecf20Sopenharmony_ci ch->state = STFAX_READY; 8698c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_READY); 8708c2ecf20Sopenharmony_ci#ifdef AUTOCON 8718c2ecf20Sopenharmony_ci if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) 8728c2ecf20Sopenharmony_ci isar_pump_cmd(bch, HW_MOD_FRH, 3); 8738c2ecf20Sopenharmony_ci else 8748c2ecf20Sopenharmony_ci isar_pump_cmd(bch, HW_MOD_FTH, 3); 8758c2ecf20Sopenharmony_ci#endif 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci case PSEV_LINE_TX_H: 8788c2ecf20Sopenharmony_ci if (ch->state == STFAX_LINE) { 8798c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); 8808c2ecf20Sopenharmony_ci ch->state = STFAX_CONT; 8818c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 8828c2ecf20Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 8838c2ecf20Sopenharmony_ci } else { 8848c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", 8858c2ecf20Sopenharmony_ci ch->is->name, ch->state); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci break; 8888c2ecf20Sopenharmony_ci case PSEV_LINE_RX_H: 8898c2ecf20Sopenharmony_ci if (ch->state == STFAX_LINE) { 8908c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); 8918c2ecf20Sopenharmony_ci ch->state = STFAX_CONT; 8928c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 8938c2ecf20Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 8948c2ecf20Sopenharmony_ci } else { 8958c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", 8968c2ecf20Sopenharmony_ci ch->is->name, ch->state); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci case PSEV_LINE_TX_B: 9008c2ecf20Sopenharmony_ci if (ch->state == STFAX_LINE) { 9018c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); 9028c2ecf20Sopenharmony_ci ch->state = STFAX_CONT; 9038c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 9048c2ecf20Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 9058c2ecf20Sopenharmony_ci } else { 9068c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", 9078c2ecf20Sopenharmony_ci ch->is->name, ch->state); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci case PSEV_LINE_RX_B: 9118c2ecf20Sopenharmony_ci if (ch->state == STFAX_LINE) { 9128c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); 9138c2ecf20Sopenharmony_ci ch->state = STFAX_CONT; 9148c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 9158c2ecf20Sopenharmony_ci PCTRL_CMD_CONT, 0, NULL); 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", 9188c2ecf20Sopenharmony_ci ch->is->name, ch->state); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci case PSEV_RSP_CONN: 9228c2ecf20Sopenharmony_ci if (ch->state == STFAX_CONT) { 9238c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); 9248c2ecf20Sopenharmony_ci ch->state = STFAX_ACTIV; 9258c2ecf20Sopenharmony_ci test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 9268c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 9278c2ecf20Sopenharmony_ci if (ch->cmd == PCTRL_CMD_FTH) { 9288c2ecf20Sopenharmony_ci int delay = (ch->mod == 3) ? 1000 : 200; 9298c2ecf20Sopenharmony_ci /* 1s (200 ms) Flags before data */ 9308c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_FTI_RUN, 9318c2ecf20Sopenharmony_ci &ch->bch.Flags)) 9328c2ecf20Sopenharmony_ci del_timer(&ch->ftimer); 9338c2ecf20Sopenharmony_ci ch->ftimer.expires = 9348c2ecf20Sopenharmony_ci jiffies + ((delay * HZ) / 1000); 9358c2ecf20Sopenharmony_ci test_and_set_bit(FLG_LL_CONN, 9368c2ecf20Sopenharmony_ci &ch->bch.Flags); 9378c2ecf20Sopenharmony_ci add_timer(&ch->ftimer); 9388c2ecf20Sopenharmony_ci } else { 9398c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_CONN wrong st %x\n", 9438c2ecf20Sopenharmony_ci ch->is->name, ch->state); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case PSEV_FLAGS_DET: 9478c2ecf20Sopenharmony_ci pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci case PSEV_RSP_DISC: 9508c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_DISC state(%d)\n", 9518c2ecf20Sopenharmony_ci ch->is->name, ch->state); 9528c2ecf20Sopenharmony_ci if (ch->state == STFAX_ESCAPE) { 9538c2ecf20Sopenharmony_ci p1 = 5; 9548c2ecf20Sopenharmony_ci switch (ch->newcmd) { 9558c2ecf20Sopenharmony_ci case 0: 9568c2ecf20Sopenharmony_ci ch->state = STFAX_READY; 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci case PCTRL_CMD_FTM: 9598c2ecf20Sopenharmony_ci p1 = 2; 9608c2ecf20Sopenharmony_ci fallthrough; 9618c2ecf20Sopenharmony_ci case PCTRL_CMD_FTH: 9628c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 9638c2ecf20Sopenharmony_ci PCTRL_CMD_SILON, 1, &p1); 9648c2ecf20Sopenharmony_ci ch->state = STFAX_SILDET; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case PCTRL_CMD_FRH: 9678c2ecf20Sopenharmony_ci case PCTRL_CMD_FRM: 9688c2ecf20Sopenharmony_ci ch->mod = ch->newmod; 9698c2ecf20Sopenharmony_ci p1 = ch->newmod; 9708c2ecf20Sopenharmony_ci ch->newmod = 0; 9718c2ecf20Sopenharmony_ci ch->cmd = ch->newcmd; 9728c2ecf20Sopenharmony_ci ch->newcmd = 0; 9738c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 9748c2ecf20Sopenharmony_ci ch->cmd, 1, &p1); 9758c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 9768c2ecf20Sopenharmony_ci ch->try_mod = 3; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci default: 9798c2ecf20Sopenharmony_ci pr_debug("%s: RSP_DISC unknown newcmd %x\n", 9808c2ecf20Sopenharmony_ci ch->is->name, ch->newcmd); 9818c2ecf20Sopenharmony_ci break; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci } else if (ch->state == STFAX_ACTIV) { 9848c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) 9858c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_OK); 9868c2ecf20Sopenharmony_ci else if (ch->cmd == PCTRL_CMD_FRM) 9878c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_NOCARR); 9888c2ecf20Sopenharmony_ci else 9898c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 9908c2ecf20Sopenharmony_ci ch->state = STFAX_READY; 9918c2ecf20Sopenharmony_ci } else if (ch->state != STFAX_SILDET) { 9928c2ecf20Sopenharmony_ci /* ignore in STFAX_SILDET */ 9938c2ecf20Sopenharmony_ci ch->state = STFAX_READY; 9948c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci case PSEV_RSP_SILDET: 9988c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); 9998c2ecf20Sopenharmony_ci if (ch->state == STFAX_SILDET) { 10008c2ecf20Sopenharmony_ci ch->mod = ch->newmod; 10018c2ecf20Sopenharmony_ci p1 = ch->newmod; 10028c2ecf20Sopenharmony_ci ch->newmod = 0; 10038c2ecf20Sopenharmony_ci ch->cmd = ch->newcmd; 10048c2ecf20Sopenharmony_ci ch->newcmd = 0; 10058c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 10068c2ecf20Sopenharmony_ci ch->cmd, 1, &p1); 10078c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 10088c2ecf20Sopenharmony_ci ch->try_mod = 3; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case PSEV_RSP_SILOFF: 10128c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case PSEV_RSP_FCERR: 10158c2ecf20Sopenharmony_ci if (ch->state == STFAX_LINE) { 10168c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_FCERR try %d\n", 10178c2ecf20Sopenharmony_ci ch->is->name, ch->try_mod); 10188c2ecf20Sopenharmony_ci if (ch->try_mod--) { 10198c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 10208c2ecf20Sopenharmony_ci ch->cmd, 1, &ch->mod); 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); 10258c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 10268c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 10278c2ecf20Sopenharmony_ci 0, NULL); 10288c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_FCERROR); 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci default: 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_civoid 10368c2ecf20Sopenharmony_cimISDNisar_irq(struct isar_hw *isar) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct isar_ch *ch; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci get_irq_infos(isar); 10418c2ecf20Sopenharmony_ci switch (isar->iis & ISAR_IIS_MSCMSD) { 10428c2ecf20Sopenharmony_ci case ISAR_IIS_RDATA: 10438c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 10448c2ecf20Sopenharmony_ci if (ch) 10458c2ecf20Sopenharmony_ci isar_rcv_frame(ch); 10468c2ecf20Sopenharmony_ci else { 10478c2ecf20Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", 10488c2ecf20Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 10498c2ecf20Sopenharmony_ci isar->clsb); 10508c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci case ISAR_IIS_GSTEV: 10548c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 10558c2ecf20Sopenharmony_ci isar->bstat |= isar->cmsb; 10568c2ecf20Sopenharmony_ci check_send(isar, isar->cmsb); 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci case ISAR_IIS_BSTEV: 10598c2ecf20Sopenharmony_ci#ifdef ERROR_STATISTIC 10608c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 10618c2ecf20Sopenharmony_ci if (ch) { 10628c2ecf20Sopenharmony_ci if (isar->cmsb == BSTEV_TBO) 10638c2ecf20Sopenharmony_ci ch->bch.err_tx++; 10648c2ecf20Sopenharmony_ci if (isar->cmsb == BSTEV_RBO) 10658c2ecf20Sopenharmony_ci ch->bch.err_rdo++; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci#endif 10688c2ecf20Sopenharmony_ci pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", 10698c2ecf20Sopenharmony_ci isar->name, isar->iis >> 6, isar->cmsb); 10708c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case ISAR_IIS_PSTEV: 10738c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 10748c2ecf20Sopenharmony_ci if (ch) { 10758c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 10768c2ecf20Sopenharmony_ci if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) 10778c2ecf20Sopenharmony_ci isar_pump_statev_modem(ch, isar->cmsb); 10788c2ecf20Sopenharmony_ci else if (ch->bch.state == ISDN_P_B_T30_FAX) 10798c2ecf20Sopenharmony_ci isar_pump_statev_fax(ch, isar->cmsb); 10808c2ecf20Sopenharmony_ci else if (ch->bch.state == ISDN_P_B_RAW) { 10818c2ecf20Sopenharmony_ci int tt; 10828c2ecf20Sopenharmony_ci tt = isar->cmsb | 0x30; 10838c2ecf20Sopenharmony_ci if (tt == 0x3e) 10848c2ecf20Sopenharmony_ci tt = '*'; 10858c2ecf20Sopenharmony_ci else if (tt == 0x3f) 10868c2ecf20Sopenharmony_ci tt = '#'; 10878c2ecf20Sopenharmony_ci else if (tt > '9') 10888c2ecf20Sopenharmony_ci tt += 7; 10898c2ecf20Sopenharmony_ci tt |= DTMF_TONE_VAL; 10908c2ecf20Sopenharmony_ci _queue_data(&ch->bch.ch, PH_CONTROL_IND, 10918c2ecf20Sopenharmony_ci MISDN_ID_ANY, sizeof(tt), &tt, 10928c2ecf20Sopenharmony_ci GFP_ATOMIC); 10938c2ecf20Sopenharmony_ci } else 10948c2ecf20Sopenharmony_ci pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", 10958c2ecf20Sopenharmony_ci isar->name, ch->bch.state, 10968c2ecf20Sopenharmony_ci isar->cmsb); 10978c2ecf20Sopenharmony_ci } else { 10988c2ecf20Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", 10998c2ecf20Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 11008c2ecf20Sopenharmony_ci isar->clsb); 11018c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case ISAR_IIS_PSTRSP: 11058c2ecf20Sopenharmony_ci ch = sel_bch_isar(isar, isar->iis >> 6); 11068c2ecf20Sopenharmony_ci if (ch) { 11078c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 11088c2ecf20Sopenharmony_ci isar_pump_status_rsp(ch); 11098c2ecf20Sopenharmony_ci } else { 11108c2ecf20Sopenharmony_ci pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", 11118c2ecf20Sopenharmony_ci isar->name, isar->iis, isar->cmsb, 11128c2ecf20Sopenharmony_ci isar->clsb); 11138c2ecf20Sopenharmony_ci isar->write_reg(isar->hw, ISAR_IIA, 0); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci case ISAR_IIS_DIAG: 11178c2ecf20Sopenharmony_ci case ISAR_IIS_BSTRSP: 11188c2ecf20Sopenharmony_ci case ISAR_IIS_IOM2RSP: 11198c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci case ISAR_IIS_INVMSG: 11228c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 11238c2ecf20Sopenharmony_ci pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci default: 11268c2ecf20Sopenharmony_ci rcv_mbox(isar, NULL); 11278c2ecf20Sopenharmony_ci pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", 11288c2ecf20Sopenharmony_ci isar->name, isar->iis, isar->cmsb, isar->clsb); 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNisar_irq); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic void 11358c2ecf20Sopenharmony_ciftimer_handler(struct timer_list *t) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct isar_ch *ch = from_timer(ch, t, ftimer); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); 11408c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); 11418c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) 11428c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic void 11468c2ecf20Sopenharmony_cisetup_pump(struct isar_ch *ch) { 11478c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 11488c2ecf20Sopenharmony_ci u8 ctrl, param[6]; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci switch (ch->bch.state) { 11518c2ecf20Sopenharmony_ci case ISDN_P_NONE: 11528c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 11538c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 11548c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 11578c2ecf20Sopenharmony_ci if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { 11588c2ecf20Sopenharmony_ci param[0] = 5; /* TOA 5 db */ 11598c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 11608c2ecf20Sopenharmony_ci PMOD_DTMF_TRANS, 1, param); 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci param[0] = 40; /* REL -46 dbm */ 11638c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 11648c2ecf20Sopenharmony_ci PMOD_DTMF, 1, param); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci fallthrough; 11678c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 11688c2ecf20Sopenharmony_ci ctrl = PMOD_DATAMODEM; 11698c2ecf20Sopenharmony_ci if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 11708c2ecf20Sopenharmony_ci ctrl |= PCTRL_ORIG; 11718c2ecf20Sopenharmony_ci param[5] = PV32P6_CTN; 11728c2ecf20Sopenharmony_ci } else { 11738c2ecf20Sopenharmony_ci param[5] = PV32P6_ATN; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci param[0] = 6; /* 6 db */ 11768c2ecf20Sopenharmony_ci param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | 11778c2ecf20Sopenharmony_ci PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 11788c2ecf20Sopenharmony_ci param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; 11798c2ecf20Sopenharmony_ci param[3] = PV32P4_UT144; 11808c2ecf20Sopenharmony_ci param[4] = PV32P5_UT144; 11818c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 11848c2ecf20Sopenharmony_ci ctrl = PMOD_FAX; 11858c2ecf20Sopenharmony_ci if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 11868c2ecf20Sopenharmony_ci ctrl |= PCTRL_ORIG; 11878c2ecf20Sopenharmony_ci param[1] = PFAXP2_CTN; 11888c2ecf20Sopenharmony_ci } else { 11898c2ecf20Sopenharmony_ci param[1] = PFAXP2_ATN; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci param[0] = 6; /* 6 db */ 11928c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); 11938c2ecf20Sopenharmony_ci ch->state = STFAX_NULL; 11948c2ecf20Sopenharmony_ci ch->newcmd = 0; 11958c2ecf20Sopenharmony_ci ch->newmod = 0; 11968c2ecf20Sopenharmony_ci test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); 11978c2ecf20Sopenharmony_ci break; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci udelay(1000); 12008c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 12018c2ecf20Sopenharmony_ci udelay(1000); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic void 12058c2ecf20Sopenharmony_cisetup_sart(struct isar_ch *ch) { 12068c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 12078c2ecf20Sopenharmony_ci u8 ctrl, param[2] = {0, 0}; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci switch (ch->bch.state) { 12108c2ecf20Sopenharmony_ci case ISDN_P_NONE: 12118c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 12128c2ecf20Sopenharmony_ci 0, NULL); 12138c2ecf20Sopenharmony_ci break; 12148c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 12158c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 12168c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 12178c2ecf20Sopenharmony_ci 2, param); 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 12208c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 12218c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 12228c2ecf20Sopenharmony_ci 1, param); 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 12258c2ecf20Sopenharmony_ci ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; 12268c2ecf20Sopenharmony_ci param[0] = S_P1_CHS_8; 12278c2ecf20Sopenharmony_ci param[1] = S_P2_BFT_DEF; 12288c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci udelay(1000); 12328c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); 12338c2ecf20Sopenharmony_ci udelay(1000); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic void 12378c2ecf20Sopenharmony_cisetup_iom2(struct isar_ch *ch) { 12388c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 12398c2ecf20Sopenharmony_ci u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (ch->bch.nr == 2) { 12428c2ecf20Sopenharmony_ci msg[1] = 1; 12438c2ecf20Sopenharmony_ci msg[3] = 1; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci switch (ch->bch.state) { 12468c2ecf20Sopenharmony_ci case ISDN_P_NONE: 12478c2ecf20Sopenharmony_ci cmsb = 0; 12488c2ecf20Sopenharmony_ci /* dummy slot */ 12498c2ecf20Sopenharmony_ci msg[1] = ch->dpath + 2; 12508c2ecf20Sopenharmony_ci msg[3] = ch->dpath + 2; 12518c2ecf20Sopenharmony_ci break; 12528c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 12538c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 12548c2ecf20Sopenharmony_ci break; 12558c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 12568c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 12578c2ecf20Sopenharmony_ci cmsb |= IOM_CTRL_RCV; 12588c2ecf20Sopenharmony_ci fallthrough; 12598c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 12608c2ecf20Sopenharmony_ci if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) 12618c2ecf20Sopenharmony_ci cmsb |= IOM_CTRL_RCV; 12628c2ecf20Sopenharmony_ci cmsb |= IOM_CTRL_ALAW; 12638c2ecf20Sopenharmony_ci break; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); 12668c2ecf20Sopenharmony_ci udelay(1000); 12678c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); 12688c2ecf20Sopenharmony_ci udelay(1000); 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic int 12728c2ecf20Sopenharmony_cimodeisar(struct isar_ch *ch, u32 bprotocol) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci /* Here we are selecting the best datapath for requested protocol */ 12758c2ecf20Sopenharmony_ci if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ 12768c2ecf20Sopenharmony_ci switch (bprotocol) { 12778c2ecf20Sopenharmony_ci case ISDN_P_NONE: /* init */ 12788c2ecf20Sopenharmony_ci if (!ch->dpath) 12798c2ecf20Sopenharmony_ci /* no init for dpath 0 */ 12808c2ecf20Sopenharmony_ci return 0; 12818c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); 12828c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); 12838c2ecf20Sopenharmony_ci break; 12848c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 12858c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 12868c2ecf20Sopenharmony_ci /* best is datapath 2 */ 12878c2ecf20Sopenharmony_ci if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) 12888c2ecf20Sopenharmony_ci ch->dpath = 2; 12898c2ecf20Sopenharmony_ci else if (!test_and_set_bit(ISAR_DP1_USE, 12908c2ecf20Sopenharmony_ci &ch->is->Flags)) 12918c2ecf20Sopenharmony_ci ch->dpath = 1; 12928c2ecf20Sopenharmony_ci else { 12938c2ecf20Sopenharmony_ci pr_info("modeisar both paths in use\n"); 12948c2ecf20Sopenharmony_ci return -EBUSY; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci if (bprotocol == ISDN_P_B_HDLC) 12978c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &ch->bch.Flags); 12988c2ecf20Sopenharmony_ci else 12998c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TRANSPARENT, 13008c2ecf20Sopenharmony_ci &ch->bch.Flags); 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci case ISDN_P_B_MODEM_ASYNC: 13038c2ecf20Sopenharmony_ci case ISDN_P_B_T30_FAX: 13048c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 13058c2ecf20Sopenharmony_ci /* only datapath 1 */ 13068c2ecf20Sopenharmony_ci if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) 13078c2ecf20Sopenharmony_ci ch->dpath = 1; 13088c2ecf20Sopenharmony_ci else { 13098c2ecf20Sopenharmony_ci pr_info("%s: ISAR modeisar analog functions" 13108c2ecf20Sopenharmony_ci "only with DP1\n", ch->is->name); 13118c2ecf20Sopenharmony_ci return -EBUSY; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci default: 13158c2ecf20Sopenharmony_ci pr_info("%s: protocol not known %x\n", ch->is->name, 13168c2ecf20Sopenharmony_ci bprotocol); 13178c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, 13218c2ecf20Sopenharmony_ci ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); 13228c2ecf20Sopenharmony_ci ch->bch.state = bprotocol; 13238c2ecf20Sopenharmony_ci setup_pump(ch); 13248c2ecf20Sopenharmony_ci setup_iom2(ch); 13258c2ecf20Sopenharmony_ci setup_sart(ch); 13268c2ecf20Sopenharmony_ci if (ch->bch.state == ISDN_P_NONE) { 13278c2ecf20Sopenharmony_ci /* Clear resources */ 13288c2ecf20Sopenharmony_ci if (ch->dpath == 1) 13298c2ecf20Sopenharmony_ci test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); 13308c2ecf20Sopenharmony_ci else if (ch->dpath == 2) 13318c2ecf20Sopenharmony_ci test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); 13328c2ecf20Sopenharmony_ci ch->dpath = 0; 13338c2ecf20Sopenharmony_ci ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); 13348c2ecf20Sopenharmony_ci } else 13358c2ecf20Sopenharmony_ci ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); 13368c2ecf20Sopenharmony_ci return 0; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic void 13408c2ecf20Sopenharmony_ciisar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci u8 dps = SET_DPS(ch->dpath); 13438c2ecf20Sopenharmony_ci u8 ctrl = 0, nom = 0, p1 = 0; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", 13468c2ecf20Sopenharmony_ci ch->is->name, cmd, para, ch->bch.state); 13478c2ecf20Sopenharmony_ci switch (cmd) { 13488c2ecf20Sopenharmony_ci case HW_MOD_FTM: 13498c2ecf20Sopenharmony_ci if (ch->state == STFAX_READY) { 13508c2ecf20Sopenharmony_ci p1 = para; 13518c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_FTM; 13528c2ecf20Sopenharmony_ci nom = 1; 13538c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 13548c2ecf20Sopenharmony_ci ch->cmd = ctrl; 13558c2ecf20Sopenharmony_ci ch->mod = para; 13568c2ecf20Sopenharmony_ci ch->newmod = 0; 13578c2ecf20Sopenharmony_ci ch->newcmd = 0; 13588c2ecf20Sopenharmony_ci ch->try_mod = 3; 13598c2ecf20Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 13608c2ecf20Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) 13618c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 13628c2ecf20Sopenharmony_ci else { 13638c2ecf20Sopenharmony_ci ch->newmod = para; 13648c2ecf20Sopenharmony_ci ch->newcmd = PCTRL_CMD_FTM; 13658c2ecf20Sopenharmony_ci nom = 0; 13668c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 13678c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci case HW_MOD_FTH: 13718c2ecf20Sopenharmony_ci if (ch->state == STFAX_READY) { 13728c2ecf20Sopenharmony_ci p1 = para; 13738c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_FTH; 13748c2ecf20Sopenharmony_ci nom = 1; 13758c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 13768c2ecf20Sopenharmony_ci ch->cmd = ctrl; 13778c2ecf20Sopenharmony_ci ch->mod = para; 13788c2ecf20Sopenharmony_ci ch->newmod = 0; 13798c2ecf20Sopenharmony_ci ch->newcmd = 0; 13808c2ecf20Sopenharmony_ci ch->try_mod = 3; 13818c2ecf20Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 13828c2ecf20Sopenharmony_ci (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) 13838c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 13848c2ecf20Sopenharmony_ci else { 13858c2ecf20Sopenharmony_ci ch->newmod = para; 13868c2ecf20Sopenharmony_ci ch->newcmd = PCTRL_CMD_FTH; 13878c2ecf20Sopenharmony_ci nom = 0; 13888c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 13898c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci case HW_MOD_FRM: 13938c2ecf20Sopenharmony_ci if (ch->state == STFAX_READY) { 13948c2ecf20Sopenharmony_ci p1 = para; 13958c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_FRM; 13968c2ecf20Sopenharmony_ci nom = 1; 13978c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 13988c2ecf20Sopenharmony_ci ch->cmd = ctrl; 13998c2ecf20Sopenharmony_ci ch->mod = para; 14008c2ecf20Sopenharmony_ci ch->newmod = 0; 14018c2ecf20Sopenharmony_ci ch->newcmd = 0; 14028c2ecf20Sopenharmony_ci ch->try_mod = 3; 14038c2ecf20Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 14048c2ecf20Sopenharmony_ci (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) 14058c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 14068c2ecf20Sopenharmony_ci else { 14078c2ecf20Sopenharmony_ci ch->newmod = para; 14088c2ecf20Sopenharmony_ci ch->newcmd = PCTRL_CMD_FRM; 14098c2ecf20Sopenharmony_ci nom = 0; 14108c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 14118c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci break; 14148c2ecf20Sopenharmony_ci case HW_MOD_FRH: 14158c2ecf20Sopenharmony_ci if (ch->state == STFAX_READY) { 14168c2ecf20Sopenharmony_ci p1 = para; 14178c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_FRH; 14188c2ecf20Sopenharmony_ci nom = 1; 14198c2ecf20Sopenharmony_ci ch->state = STFAX_LINE; 14208c2ecf20Sopenharmony_ci ch->cmd = ctrl; 14218c2ecf20Sopenharmony_ci ch->mod = para; 14228c2ecf20Sopenharmony_ci ch->newmod = 0; 14238c2ecf20Sopenharmony_ci ch->newcmd = 0; 14248c2ecf20Sopenharmony_ci ch->try_mod = 3; 14258c2ecf20Sopenharmony_ci } else if ((ch->state == STFAX_ACTIV) && 14268c2ecf20Sopenharmony_ci (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) 14278c2ecf20Sopenharmony_ci deliver_status(ch, HW_MOD_CONNECT); 14288c2ecf20Sopenharmony_ci else { 14298c2ecf20Sopenharmony_ci ch->newmod = para; 14308c2ecf20Sopenharmony_ci ch->newcmd = PCTRL_CMD_FRH; 14318c2ecf20Sopenharmony_ci nom = 0; 14328c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_ESC; 14338c2ecf20Sopenharmony_ci ch->state = STFAX_ESCAPE; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci break; 14368c2ecf20Sopenharmony_ci case PCTRL_CMD_TDTMF: 14378c2ecf20Sopenharmony_ci p1 = para; 14388c2ecf20Sopenharmony_ci nom = 1; 14398c2ecf20Sopenharmony_ci ctrl = PCTRL_CMD_TDTMF; 14408c2ecf20Sopenharmony_ci break; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci if (ctrl) 14438c2ecf20Sopenharmony_ci send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic void 14478c2ecf20Sopenharmony_ciisar_setup(struct isar_hw *isar) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci u8 msg; 14508c2ecf20Sopenharmony_ci int i; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* Dpath 1, 2 */ 14538c2ecf20Sopenharmony_ci msg = 61; 14548c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 14558c2ecf20Sopenharmony_ci /* Buffer Config */ 14568c2ecf20Sopenharmony_ci send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | 14578c2ecf20Sopenharmony_ci ISAR_HIS_P12CFG, 4, 1, &msg); 14588c2ecf20Sopenharmony_ci isar->ch[i].mml = msg; 14598c2ecf20Sopenharmony_ci isar->ch[i].bch.state = 0; 14608c2ecf20Sopenharmony_ci isar->ch[i].dpath = i + 1; 14618c2ecf20Sopenharmony_ci modeisar(&isar->ch[i], ISDN_P_NONE); 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic int 14668c2ecf20Sopenharmony_ciisar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 14698c2ecf20Sopenharmony_ci struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 14708c2ecf20Sopenharmony_ci int ret = -EINVAL; 14718c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 14728c2ecf20Sopenharmony_ci u32 id, *val; 14738c2ecf20Sopenharmony_ci u_long flags; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci switch (hh->prim) { 14768c2ecf20Sopenharmony_ci case PH_DATA_REQ: 14778c2ecf20Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 14788c2ecf20Sopenharmony_ci ret = bchannel_senddata(bch, skb); 14798c2ecf20Sopenharmony_ci if (ret > 0) { /* direct TX */ 14808c2ecf20Sopenharmony_ci ret = 0; 14818c2ecf20Sopenharmony_ci isar_fill_fifo(ich); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 14848c2ecf20Sopenharmony_ci return ret; 14858c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 14868c2ecf20Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 14878c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 14888c2ecf20Sopenharmony_ci ret = modeisar(ich, ch->protocol); 14898c2ecf20Sopenharmony_ci else 14908c2ecf20Sopenharmony_ci ret = 0; 14918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 14928c2ecf20Sopenharmony_ci if (!ret) 14938c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 14948c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 14958c2ecf20Sopenharmony_ci break; 14968c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 14978c2ecf20Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 14988c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 14998c2ecf20Sopenharmony_ci modeisar(ich, ISDN_P_NONE); 15008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 15018c2ecf20Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 15028c2ecf20Sopenharmony_ci NULL, GFP_KERNEL); 15038c2ecf20Sopenharmony_ci ret = 0; 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci case PH_CONTROL_REQ: 15068c2ecf20Sopenharmony_ci val = (u32 *)skb->data; 15078c2ecf20Sopenharmony_ci pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, 15088c2ecf20Sopenharmony_ci hh->id, *val); 15098c2ecf20Sopenharmony_ci if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == 15108c2ecf20Sopenharmony_ci DTMF_TONE_VAL)) { 15118c2ecf20Sopenharmony_ci if (bch->state == ISDN_P_B_L2DTMF) { 15128c2ecf20Sopenharmony_ci char tt = *val & DTMF_TONE_MASK; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (tt == '*') 15158c2ecf20Sopenharmony_ci tt = 0x1e; 15168c2ecf20Sopenharmony_ci else if (tt == '#') 15178c2ecf20Sopenharmony_ci tt = 0x1f; 15188c2ecf20Sopenharmony_ci else if (tt > '9') 15198c2ecf20Sopenharmony_ci tt -= 7; 15208c2ecf20Sopenharmony_ci tt &= 0x1f; 15218c2ecf20Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 15228c2ecf20Sopenharmony_ci isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); 15238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 15248c2ecf20Sopenharmony_ci } else { 15258c2ecf20Sopenharmony_ci pr_info("%s: DTMF send wrong protocol %x\n", 15268c2ecf20Sopenharmony_ci __func__, bch->state); 15278c2ecf20Sopenharmony_ci return -EINVAL; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || 15308c2ecf20Sopenharmony_ci (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { 15318c2ecf20Sopenharmony_ci for (id = 0; id < FAXMODCNT; id++) 15328c2ecf20Sopenharmony_ci if (faxmodulation[id] == *val) 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci if ((FAXMODCNT > id) && 15358c2ecf20Sopenharmony_ci test_bit(FLG_INITIALIZED, &bch->Flags)) { 15368c2ecf20Sopenharmony_ci pr_debug("%s: isar: new mod\n", ich->is->name); 15378c2ecf20Sopenharmony_ci isar_pump_cmd(ich, hh->id, *val); 15388c2ecf20Sopenharmony_ci ret = 0; 15398c2ecf20Sopenharmony_ci } else { 15408c2ecf20Sopenharmony_ci pr_info("%s: wrong modulation\n", 15418c2ecf20Sopenharmony_ci ich->is->name); 15428c2ecf20Sopenharmony_ci ret = -EINVAL; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci } else if (hh->id == HW_MOD_LASTDATA) 15458c2ecf20Sopenharmony_ci test_and_set_bit(FLG_DLEETX, &bch->Flags); 15468c2ecf20Sopenharmony_ci else { 15478c2ecf20Sopenharmony_ci pr_info("%s: unknown PH_CONTROL_REQ %x\n", 15488c2ecf20Sopenharmony_ci ich->is->name, hh->id); 15498c2ecf20Sopenharmony_ci ret = -EINVAL; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci fallthrough; 15528c2ecf20Sopenharmony_ci default: 15538c2ecf20Sopenharmony_ci pr_info("%s: %s unknown prim(%x,%x)\n", 15548c2ecf20Sopenharmony_ci ich->is->name, __func__, hh->prim, hh->id); 15558c2ecf20Sopenharmony_ci ret = -EINVAL; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci if (!ret) 15588c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 15598c2ecf20Sopenharmony_ci return ret; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic int 15638c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 15668c2ecf20Sopenharmony_ci} 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic int 15698c2ecf20Sopenharmony_ciisar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 15728c2ecf20Sopenharmony_ci struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 15738c2ecf20Sopenharmony_ci int ret = -EINVAL; 15748c2ecf20Sopenharmony_ci u_long flags; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); 15778c2ecf20Sopenharmony_ci switch (cmd) { 15788c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 15798c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 15808c2ecf20Sopenharmony_ci cancel_work_sync(&bch->workq); 15818c2ecf20Sopenharmony_ci spin_lock_irqsave(ich->is->hwlock, flags); 15828c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 15838c2ecf20Sopenharmony_ci modeisar(ich, ISDN_P_NONE); 15848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ich->is->hwlock, flags); 15858c2ecf20Sopenharmony_ci ch->protocol = ISDN_P_NONE; 15868c2ecf20Sopenharmony_ci ch->peer = NULL; 15878c2ecf20Sopenharmony_ci module_put(ich->is->owner); 15888c2ecf20Sopenharmony_ci ret = 0; 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 15918c2ecf20Sopenharmony_ci ret = channel_bctrl(bch, arg); 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci default: 15948c2ecf20Sopenharmony_ci pr_info("%s: %s unknown prim(%x)\n", 15958c2ecf20Sopenharmony_ci ich->is->name, __func__, cmd); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci return ret; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic void 16018c2ecf20Sopenharmony_cifree_isar(struct isar_hw *isar) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci modeisar(&isar->ch[0], ISDN_P_NONE); 16048c2ecf20Sopenharmony_ci modeisar(&isar->ch[1], ISDN_P_NONE); 16058c2ecf20Sopenharmony_ci del_timer(&isar->ch[0].ftimer); 16068c2ecf20Sopenharmony_ci del_timer(&isar->ch[1].ftimer); 16078c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 16088c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_cistatic int 16128c2ecf20Sopenharmony_ciinit_isar(struct isar_hw *isar) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci int cnt = 3; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci while (cnt--) { 16178c2ecf20Sopenharmony_ci isar->version = ISARVersion(isar); 16188c2ecf20Sopenharmony_ci if (isar->ch[0].bch.debug & DEBUG_HW) 16198c2ecf20Sopenharmony_ci pr_notice("%s: Testing version %d (%d time)\n", 16208c2ecf20Sopenharmony_ci isar->name, isar->version, 3 - cnt); 16218c2ecf20Sopenharmony_ci if (isar->version == 1) 16228c2ecf20Sopenharmony_ci break; 16238c2ecf20Sopenharmony_ci isar->ctrl(isar->hw, HW_RESET_REQ, 0); 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci if (isar->version != 1) 16268c2ecf20Sopenharmony_ci return -EINVAL; 16278c2ecf20Sopenharmony_ci timer_setup(&isar->ch[0].ftimer, ftimer_handler, 0); 16288c2ecf20Sopenharmony_ci test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 16298c2ecf20Sopenharmony_ci timer_setup(&isar->ch[1].ftimer, ftimer_handler, 0); 16308c2ecf20Sopenharmony_ci test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 16318c2ecf20Sopenharmony_ci return 0; 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_cistatic int 16358c2ecf20Sopenharmony_ciisar_open(struct isar_hw *isar, struct channel_req *rq) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci struct bchannel *bch; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 16408c2ecf20Sopenharmony_ci return -EINVAL; 16418c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 16428c2ecf20Sopenharmony_ci return -EINVAL; 16438c2ecf20Sopenharmony_ci bch = &isar->ch[rq->adr.channel - 1].bch; 16448c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 16458c2ecf20Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 16468c2ecf20Sopenharmony_ci bch->ch.protocol = rq->protocol; 16478c2ecf20Sopenharmony_ci rq->ch = &bch->ch; 16488c2ecf20Sopenharmony_ci return 0; 16498c2ecf20Sopenharmony_ci} 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ciu32 16528c2ecf20Sopenharmony_cimISDNisar_init(struct isar_hw *isar, void *hw) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci u32 ret, i; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci isar->hw = hw; 16578c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16588c2ecf20Sopenharmony_ci isar->ch[i].bch.nr = i + 1; 16598c2ecf20Sopenharmony_ci mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); 16608c2ecf20Sopenharmony_ci isar->ch[i].bch.ch.nr = i + 1; 16618c2ecf20Sopenharmony_ci isar->ch[i].bch.ch.send = &isar_l2l1; 16628c2ecf20Sopenharmony_ci isar->ch[i].bch.ch.ctrl = isar_bctrl; 16638c2ecf20Sopenharmony_ci isar->ch[i].bch.hw = hw; 16648c2ecf20Sopenharmony_ci isar->ch[i].is = isar; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci isar->init = &init_isar; 16688c2ecf20Sopenharmony_ci isar->release = &free_isar; 16698c2ecf20Sopenharmony_ci isar->firmware = &load_firmware; 16708c2ecf20Sopenharmony_ci isar->open = &isar_open; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 16738c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | 16748c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | 16758c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | 16768c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci return ret; 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDNisar_init); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic int __init isar_mod_init(void) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); 16858c2ecf20Sopenharmony_ci return 0; 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_cistatic void __exit isar_mod_cleanup(void) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci pr_notice("mISDN: ISAR module unloaded\n"); 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_cimodule_init(isar_mod_init); 16938c2ecf20Sopenharmony_cimodule_exit(isar_mod_cleanup); 1694