1*82c29810SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2da2272c9SKarsten Keil /* 3da2272c9SKarsten Keil * mISDNisar.c ISAR (Siemens PSB 7110) specific functions 4da2272c9SKarsten Keil * 5da2272c9SKarsten Keil * Author Karsten Keil (keil@isdn4linux.de) 6da2272c9SKarsten Keil * 7da2272c9SKarsten Keil * Copyright 2009 by Karsten Keil <keil@isdn4linux.de> 8da2272c9SKarsten Keil */ 9da2272c9SKarsten Keil 10da2272c9SKarsten Keil /* define this to enable static debug messages, if you kernel supports 11da2272c9SKarsten Keil * dynamic debugging, you should use debugfs for this 12da2272c9SKarsten Keil */ 13da2272c9SKarsten Keil /* #define DEBUG */ 14da2272c9SKarsten Keil 155a0e3ad6STejun Heo #include <linux/gfp.h> 16da2272c9SKarsten Keil #include <linux/delay.h> 17da2272c9SKarsten Keil #include <linux/vmalloc.h> 18da2272c9SKarsten Keil #include <linux/mISDNhw.h> 1907a97fe8SPaul Gortmaker #include <linux/module.h> 20da2272c9SKarsten Keil #include "isar.h" 21da2272c9SKarsten Keil 22da2272c9SKarsten Keil #define ISAR_REV "2.1" 23da2272c9SKarsten Keil 24da2272c9SKarsten Keil MODULE_AUTHOR("Karsten Keil"); 25da2272c9SKarsten Keil MODULE_LICENSE("GPL v2"); 26da2272c9SKarsten Keil MODULE_VERSION(ISAR_REV); 27da2272c9SKarsten Keil 28da2272c9SKarsten Keil #define DEBUG_HW_FIRMWARE_FIFO 0x10000 29da2272c9SKarsten Keil 30da2272c9SKarsten Keil static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; 31da2272c9SKarsten Keil static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 32da2272c9SKarsten Keil 122, 145, 146}; 33da2272c9SKarsten Keil #define FAXMODCNT 13 34da2272c9SKarsten Keil 35da2272c9SKarsten Keil static void isar_setup(struct isar_hw *); 36da2272c9SKarsten Keil 37da2272c9SKarsten Keil static inline int 38da2272c9SKarsten Keil waitforHIA(struct isar_hw *isar, int timeout) 39da2272c9SKarsten Keil { 40da2272c9SKarsten Keil int t = timeout; 41da2272c9SKarsten Keil u8 val = isar->read_reg(isar->hw, ISAR_HIA); 42da2272c9SKarsten Keil 43da2272c9SKarsten Keil while ((val & 1) && t) { 44da2272c9SKarsten Keil udelay(1); 45da2272c9SKarsten Keil t--; 46da2272c9SKarsten Keil val = isar->read_reg(isar->hw, ISAR_HIA); 47da2272c9SKarsten Keil } 48da2272c9SKarsten Keil pr_debug("%s: HIA after %dus\n", isar->name, timeout - t); 49da2272c9SKarsten Keil return timeout; 50da2272c9SKarsten Keil } 51da2272c9SKarsten Keil 52da2272c9SKarsten Keil /* 53da2272c9SKarsten Keil * send msg to ISAR mailbox 54da2272c9SKarsten Keil * if msg is NULL use isar->buf 55da2272c9SKarsten Keil */ 56da2272c9SKarsten Keil static int 57da2272c9SKarsten Keil send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg) 58da2272c9SKarsten Keil { 59da2272c9SKarsten Keil if (!waitforHIA(isar, 1000)) 60da2272c9SKarsten Keil return 0; 61da2272c9SKarsten Keil pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len); 62da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_CTRL_H, creg); 63da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_CTRL_L, len); 64da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_WADR, 0); 65da2272c9SKarsten Keil if (!msg) 66da2272c9SKarsten Keil msg = isar->buf; 67da2272c9SKarsten Keil if (msg && len) { 68da2272c9SKarsten Keil isar->write_fifo(isar->hw, ISAR_MBOX, msg, len); 69da2272c9SKarsten Keil if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 70da2272c9SKarsten Keil int l = 0; 71da2272c9SKarsten Keil 72da2272c9SKarsten Keil while (l < (int)len) { 73da2272c9SKarsten Keil hex_dump_to_buffer(msg + l, len - l, 32, 1, 74da2272c9SKarsten Keil isar->log, 256, 1); 75da2272c9SKarsten Keil pr_debug("%s: %s %02x: %s\n", isar->name, 76da2272c9SKarsten Keil __func__, l, isar->log); 77da2272c9SKarsten Keil l += 32; 78da2272c9SKarsten Keil } 79da2272c9SKarsten Keil } 80da2272c9SKarsten Keil } 81da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_HIS, his); 82da2272c9SKarsten Keil waitforHIA(isar, 1000); 83da2272c9SKarsten Keil return 1; 84da2272c9SKarsten Keil } 85da2272c9SKarsten Keil 86da2272c9SKarsten Keil /* 87da2272c9SKarsten Keil * receive message from ISAR mailbox 88da2272c9SKarsten Keil * if msg is NULL use isar->buf 89da2272c9SKarsten Keil */ 90da2272c9SKarsten Keil static void 91da2272c9SKarsten Keil rcv_mbox(struct isar_hw *isar, u8 *msg) 92da2272c9SKarsten Keil { 93da2272c9SKarsten Keil if (!msg) 94da2272c9SKarsten Keil msg = isar->buf; 95da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_RADR, 0); 96da2272c9SKarsten Keil if (msg && isar->clsb) { 97da2272c9SKarsten Keil isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb); 98da2272c9SKarsten Keil if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) { 99da2272c9SKarsten Keil int l = 0; 100da2272c9SKarsten Keil 101da2272c9SKarsten Keil while (l < (int)isar->clsb) { 102da2272c9SKarsten Keil hex_dump_to_buffer(msg + l, isar->clsb - l, 32, 103da2272c9SKarsten Keil 1, isar->log, 256, 1); 104da2272c9SKarsten Keil pr_debug("%s: %s %02x: %s\n", isar->name, 105da2272c9SKarsten Keil __func__, l, isar->log); 106da2272c9SKarsten Keil l += 32; 107da2272c9SKarsten Keil } 108da2272c9SKarsten Keil } 109da2272c9SKarsten Keil } 110da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 111da2272c9SKarsten Keil } 112da2272c9SKarsten Keil 113da2272c9SKarsten Keil static inline void 114da2272c9SKarsten Keil get_irq_infos(struct isar_hw *isar) 115da2272c9SKarsten Keil { 116da2272c9SKarsten Keil isar->iis = isar->read_reg(isar->hw, ISAR_IIS); 117da2272c9SKarsten Keil isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H); 118da2272c9SKarsten Keil isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L); 119da2272c9SKarsten Keil pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name, 120da2272c9SKarsten Keil isar->iis, isar->cmsb, isar->clsb); 121da2272c9SKarsten Keil } 122da2272c9SKarsten Keil 123da2272c9SKarsten Keil /* 124da2272c9SKarsten Keil * poll answer message from ISAR mailbox 125da2272c9SKarsten Keil * should be used only with ISAR IRQs disabled before DSP was started 126da2272c9SKarsten Keil * 127da2272c9SKarsten Keil */ 128da2272c9SKarsten Keil static int 129da2272c9SKarsten Keil poll_mbox(struct isar_hw *isar, int maxdelay) 130da2272c9SKarsten Keil { 131da2272c9SKarsten Keil int t = maxdelay; 132da2272c9SKarsten Keil u8 irq; 133da2272c9SKarsten Keil 134da2272c9SKarsten Keil irq = isar->read_reg(isar->hw, ISAR_IRQBIT); 135da2272c9SKarsten Keil while (t && !(irq & ISAR_IRQSTA)) { 136da2272c9SKarsten Keil udelay(1); 137da2272c9SKarsten Keil t--; 138da2272c9SKarsten Keil } 139da2272c9SKarsten Keil if (t) { 140da2272c9SKarsten Keil get_irq_infos(isar); 141da2272c9SKarsten Keil rcv_mbox(isar, NULL); 142da2272c9SKarsten Keil } 143da2272c9SKarsten Keil pr_debug("%s: pulled %d bytes after %d us\n", 144da2272c9SKarsten Keil isar->name, isar->clsb, maxdelay - t); 145da2272c9SKarsten Keil return t; 146da2272c9SKarsten Keil } 147da2272c9SKarsten Keil 148da2272c9SKarsten Keil static int 149da2272c9SKarsten Keil ISARVersion(struct isar_hw *isar) 150da2272c9SKarsten Keil { 151da2272c9SKarsten Keil int ver; 152da2272c9SKarsten Keil 153da2272c9SKarsten Keil /* disable ISAR IRQ */ 154da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 155da2272c9SKarsten Keil isar->buf[0] = ISAR_MSG_HWVER; 156da2272c9SKarsten Keil isar->buf[1] = 0; 157da2272c9SKarsten Keil isar->buf[2] = 1; 158da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL)) 159da2272c9SKarsten Keil return -1; 160da2272c9SKarsten Keil if (!poll_mbox(isar, 1000)) 161da2272c9SKarsten Keil return -2; 162da2272c9SKarsten Keil if (isar->iis == ISAR_IIS_VNR) { 163da2272c9SKarsten Keil if (isar->clsb == 1) { 164da2272c9SKarsten Keil ver = isar->buf[0] & 0xf; 165da2272c9SKarsten Keil return ver; 166da2272c9SKarsten Keil } 167da2272c9SKarsten Keil return -3; 168da2272c9SKarsten Keil } 169da2272c9SKarsten Keil return -4; 170da2272c9SKarsten Keil } 171da2272c9SKarsten Keil 172da2272c9SKarsten Keil static int 173da2272c9SKarsten Keil load_firmware(struct isar_hw *isar, const u8 *buf, int size) 174da2272c9SKarsten Keil { 175da2272c9SKarsten Keil u32 saved_debug = isar->ch[0].bch.debug; 176da2272c9SKarsten Keil int ret, cnt; 177da2272c9SKarsten Keil u8 nom, noc; 178da2272c9SKarsten Keil u16 left, val, *sp = (u16 *)buf; 179da2272c9SKarsten Keil u8 *mp; 180da2272c9SKarsten Keil u_long flags; 181da2272c9SKarsten Keil 182da2272c9SKarsten Keil struct { 183da2272c9SKarsten Keil u16 sadr; 184da2272c9SKarsten Keil u16 len; 185da2272c9SKarsten Keil u16 d_key; 186da2272c9SKarsten Keil } blk_head; 187da2272c9SKarsten Keil 188da2272c9SKarsten Keil if (1 != isar->version) { 189da2272c9SKarsten Keil pr_err("%s: ISAR wrong version %d firmware download aborted\n", 190da2272c9SKarsten Keil isar->name, isar->version); 191da2272c9SKarsten Keil return -EINVAL; 192da2272c9SKarsten Keil } 193da2272c9SKarsten Keil if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO)) 194da2272c9SKarsten Keil isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO; 195da2272c9SKarsten Keil pr_debug("%s: load firmware %d words (%d bytes)\n", 196da2272c9SKarsten Keil isar->name, size / 2, size); 197da2272c9SKarsten Keil cnt = 0; 198da2272c9SKarsten Keil size /= 2; 199da2272c9SKarsten Keil /* disable ISAR IRQ */ 200da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 201da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 202da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 203da2272c9SKarsten Keil while (cnt < size) { 204da2272c9SKarsten Keil blk_head.sadr = le16_to_cpu(*sp++); 205da2272c9SKarsten Keil blk_head.len = le16_to_cpu(*sp++); 206da2272c9SKarsten Keil blk_head.d_key = le16_to_cpu(*sp++); 207da2272c9SKarsten Keil cnt += 3; 208da2272c9SKarsten Keil pr_debug("ISAR firmware block (%#x,%d,%#x)\n", 209da2272c9SKarsten Keil blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); 210da2272c9SKarsten Keil left = blk_head.len; 211da2272c9SKarsten Keil if (cnt + left > size) { 212da2272c9SKarsten Keil pr_info("%s: firmware error have %d need %d words\n", 213da2272c9SKarsten Keil isar->name, size, cnt + left); 214da2272c9SKarsten Keil ret = -EINVAL; 215da2272c9SKarsten Keil goto reterrflg; 216da2272c9SKarsten Keil } 217da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 218da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 219da2272c9SKarsten Keil 0, NULL)) { 220da2272c9SKarsten Keil pr_info("ISAR send_mbox dkey failed\n"); 221da2272c9SKarsten Keil ret = -ETIME; 222da2272c9SKarsten Keil goto reterror; 223da2272c9SKarsten Keil } 224da2272c9SKarsten Keil if (!poll_mbox(isar, 1000)) { 225da2272c9SKarsten Keil pr_warning("ISAR poll_mbox dkey failed\n"); 226da2272c9SKarsten Keil ret = -ETIME; 227da2272c9SKarsten Keil goto reterror; 228da2272c9SKarsten Keil } 229da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 230da2272c9SKarsten Keil if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) { 231da2272c9SKarsten Keil pr_info("ISAR wrong dkey response (%x,%x,%x)\n", 232da2272c9SKarsten Keil isar->iis, isar->cmsb, isar->clsb); 233da2272c9SKarsten Keil ret = 1; 234da2272c9SKarsten Keil goto reterrflg; 235da2272c9SKarsten Keil } 236da2272c9SKarsten Keil while (left > 0) { 237da2272c9SKarsten Keil if (left > 126) 238da2272c9SKarsten Keil noc = 126; 239da2272c9SKarsten Keil else 240da2272c9SKarsten Keil noc = left; 241da2272c9SKarsten Keil nom = (2 * noc) + 3; 242da2272c9SKarsten Keil mp = isar->buf; 243da2272c9SKarsten Keil /* the ISAR is big endian */ 244da2272c9SKarsten Keil *mp++ = blk_head.sadr >> 8; 245da2272c9SKarsten Keil *mp++ = blk_head.sadr & 0xFF; 246da2272c9SKarsten Keil left -= noc; 247da2272c9SKarsten Keil cnt += noc; 248da2272c9SKarsten Keil *mp++ = noc; 249da2272c9SKarsten Keil pr_debug("%s: load %3d words at %04x\n", isar->name, 250da2272c9SKarsten Keil noc, blk_head.sadr); 251da2272c9SKarsten Keil blk_head.sadr += noc; 252da2272c9SKarsten Keil while (noc) { 253da2272c9SKarsten Keil val = le16_to_cpu(*sp++); 254da2272c9SKarsten Keil *mp++ = val >> 8; 255ad65ffd1SJoe Perches *mp++ = val & 0xFF; 256da2272c9SKarsten Keil noc--; 257da2272c9SKarsten Keil } 258da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 259da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) { 260da2272c9SKarsten Keil pr_info("ISAR send_mbox prog failed\n"); 261da2272c9SKarsten Keil ret = -ETIME; 262da2272c9SKarsten Keil goto reterror; 263da2272c9SKarsten Keil } 264da2272c9SKarsten Keil if (!poll_mbox(isar, 1000)) { 265da2272c9SKarsten Keil pr_info("ISAR poll_mbox prog failed\n"); 266da2272c9SKarsten Keil ret = -ETIME; 267da2272c9SKarsten Keil goto reterror; 268da2272c9SKarsten Keil } 269da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 270da2272c9SKarsten Keil if ((isar->iis != ISAR_IIS_FIRM) || 271da2272c9SKarsten Keil isar->cmsb || isar->clsb) { 272da2272c9SKarsten Keil pr_info("ISAR wrong prog response (%x,%x,%x)\n", 273da2272c9SKarsten Keil isar->iis, isar->cmsb, isar->clsb); 274da2272c9SKarsten Keil ret = -EIO; 275da2272c9SKarsten Keil goto reterrflg; 276da2272c9SKarsten Keil } 277da2272c9SKarsten Keil } 278da2272c9SKarsten Keil pr_debug("%s: ISAR firmware block %d words loaded\n", 279da2272c9SKarsten Keil isar->name, blk_head.len); 280da2272c9SKarsten Keil } 281da2272c9SKarsten Keil isar->ch[0].bch.debug = saved_debug; 282da2272c9SKarsten Keil /* 10ms delay */ 283da2272c9SKarsten Keil cnt = 10; 284da2272c9SKarsten Keil while (cnt--) 285da2272c9SKarsten Keil mdelay(1); 286da2272c9SKarsten Keil isar->buf[0] = 0xff; 287da2272c9SKarsten Keil isar->buf[1] = 0xfe; 288da2272c9SKarsten Keil isar->bstat = 0; 289da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 290da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) { 291da2272c9SKarsten Keil pr_info("ISAR send_mbox start dsp failed\n"); 292da2272c9SKarsten Keil ret = -ETIME; 293da2272c9SKarsten Keil goto reterror; 294da2272c9SKarsten Keil } 295da2272c9SKarsten Keil if (!poll_mbox(isar, 1000)) { 296da2272c9SKarsten Keil pr_info("ISAR poll_mbox start dsp failed\n"); 297da2272c9SKarsten Keil ret = -ETIME; 298da2272c9SKarsten Keil goto reterror; 299da2272c9SKarsten Keil } 300da2272c9SKarsten Keil if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) { 301da2272c9SKarsten Keil pr_info("ISAR wrong start dsp response (%x,%x,%x)\n", 302da2272c9SKarsten Keil isar->iis, isar->cmsb, isar->clsb); 303da2272c9SKarsten Keil ret = -EIO; 304da2272c9SKarsten Keil goto reterror; 305da2272c9SKarsten Keil } else 306da2272c9SKarsten Keil pr_debug("%s: ISAR start dsp success\n", isar->name); 307da2272c9SKarsten Keil 308da2272c9SKarsten Keil /* NORMAL mode entered */ 309da2272c9SKarsten Keil /* Enable IRQs of ISAR */ 310da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA); 311da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 312da2272c9SKarsten Keil cnt = 1000; /* max 1s */ 313da2272c9SKarsten Keil while ((!isar->bstat) && cnt) { 314da2272c9SKarsten Keil mdelay(1); 315da2272c9SKarsten Keil cnt--; 316da2272c9SKarsten Keil } 317da2272c9SKarsten Keil if (!cnt) { 318da2272c9SKarsten Keil pr_info("ISAR no general status event received\n"); 319da2272c9SKarsten Keil ret = -ETIME; 320da2272c9SKarsten Keil goto reterrflg; 321da2272c9SKarsten Keil } else 322da2272c9SKarsten Keil pr_debug("%s: ISAR general status event %x\n", 323da2272c9SKarsten Keil isar->name, isar->bstat); 324da2272c9SKarsten Keil /* 10ms delay */ 325da2272c9SKarsten Keil cnt = 10; 326da2272c9SKarsten Keil while (cnt--) 327da2272c9SKarsten Keil mdelay(1); 328da2272c9SKarsten Keil isar->iis = 0; 329da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 330da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { 331da2272c9SKarsten Keil pr_info("ISAR send_mbox self tst failed\n"); 332da2272c9SKarsten Keil ret = -ETIME; 333da2272c9SKarsten Keil goto reterror; 334da2272c9SKarsten Keil } 335da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 336da2272c9SKarsten Keil cnt = 10000; /* max 100 ms */ 337da2272c9SKarsten Keil while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 338da2272c9SKarsten Keil udelay(10); 339da2272c9SKarsten Keil cnt--; 340da2272c9SKarsten Keil } 341da2272c9SKarsten Keil mdelay(1); 342da2272c9SKarsten Keil if (!cnt) { 343da2272c9SKarsten Keil pr_info("ISAR no self tst response\n"); 344da2272c9SKarsten Keil ret = -ETIME; 345da2272c9SKarsten Keil goto reterrflg; 346da2272c9SKarsten Keil } 347da2272c9SKarsten Keil if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1) 348da2272c9SKarsten Keil && (isar->buf[0] == 0)) 349da2272c9SKarsten Keil pr_debug("%s: ISAR selftest OK\n", isar->name); 350da2272c9SKarsten Keil else { 351da2272c9SKarsten Keil pr_info("ISAR selftest not OK %x/%x/%x\n", 352da2272c9SKarsten Keil isar->cmsb, isar->clsb, isar->buf[0]); 353da2272c9SKarsten Keil ret = -EIO; 354da2272c9SKarsten Keil goto reterrflg; 355da2272c9SKarsten Keil } 356da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 357da2272c9SKarsten Keil isar->iis = 0; 358da2272c9SKarsten Keil if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { 359da2272c9SKarsten Keil pr_info("ISAR RQST SVN failed\n"); 360da2272c9SKarsten Keil ret = -ETIME; 361da2272c9SKarsten Keil goto reterror; 362da2272c9SKarsten Keil } 363da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 364da2272c9SKarsten Keil cnt = 30000; /* max 300 ms */ 365da2272c9SKarsten Keil while ((isar->iis != ISAR_IIS_DIAG) && cnt) { 366da2272c9SKarsten Keil udelay(10); 367da2272c9SKarsten Keil cnt--; 368da2272c9SKarsten Keil } 369da2272c9SKarsten Keil mdelay(1); 370da2272c9SKarsten Keil if (!cnt) { 371da2272c9SKarsten Keil pr_info("ISAR no SVN response\n"); 372da2272c9SKarsten Keil ret = -ETIME; 373da2272c9SKarsten Keil goto reterrflg; 374da2272c9SKarsten Keil } else { 375da2272c9SKarsten Keil if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) { 376da2272c9SKarsten Keil pr_notice("%s: ISAR software version %#x\n", 377da2272c9SKarsten Keil isar->name, isar->buf[0]); 378da2272c9SKarsten Keil } else { 379da2272c9SKarsten Keil pr_info("%s: ISAR wrong swver response (%x,%x)" 380da2272c9SKarsten Keil " cnt(%d)\n", isar->name, isar->cmsb, 381da2272c9SKarsten Keil isar->clsb, cnt); 382da2272c9SKarsten Keil ret = -EIO; 383da2272c9SKarsten Keil goto reterrflg; 384da2272c9SKarsten Keil } 385da2272c9SKarsten Keil } 386da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 387da2272c9SKarsten Keil isar_setup(isar); 388da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 389da2272c9SKarsten Keil ret = 0; 390da2272c9SKarsten Keil reterrflg: 391da2272c9SKarsten Keil spin_lock_irqsave(isar->hwlock, flags); 392da2272c9SKarsten Keil reterror: 393da2272c9SKarsten Keil isar->ch[0].bch.debug = saved_debug; 394da2272c9SKarsten Keil if (ret) 395da2272c9SKarsten Keil /* disable ISAR IRQ */ 396da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IRQBIT, 0); 397da2272c9SKarsten Keil spin_unlock_irqrestore(isar->hwlock, flags); 398da2272c9SKarsten Keil return ret; 399da2272c9SKarsten Keil } 400da2272c9SKarsten Keil 401da2272c9SKarsten Keil static inline void 402da2272c9SKarsten Keil deliver_status(struct isar_ch *ch, int status) 403da2272c9SKarsten Keil { 404da2272c9SKarsten Keil pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status); 405da2272c9SKarsten Keil _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC); 406da2272c9SKarsten Keil } 407da2272c9SKarsten Keil 408da2272c9SKarsten Keil static inline void 409da2272c9SKarsten Keil isar_rcv_frame(struct isar_ch *ch) 410da2272c9SKarsten Keil { 411da2272c9SKarsten Keil u8 *ptr; 4127206e659SKarsten Keil int maxlen; 413da2272c9SKarsten Keil 414da2272c9SKarsten Keil if (!ch->is->clsb) { 415da2272c9SKarsten Keil pr_debug("%s; ISAR zero len frame\n", ch->is->name); 416da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 417da2272c9SKarsten Keil return; 418da2272c9SKarsten Keil } 419c27b46e7SKarsten Keil if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { 420c27b46e7SKarsten Keil ch->bch.dropcnt += ch->is->clsb; 421c27b46e7SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 422c27b46e7SKarsten Keil return; 423c27b46e7SKarsten Keil } 424da2272c9SKarsten Keil switch (ch->bch.state) { 425da2272c9SKarsten Keil case ISDN_P_NONE: 426da2272c9SKarsten Keil pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", 427da2272c9SKarsten Keil ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); 428da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 429da2272c9SKarsten Keil break; 430da2272c9SKarsten Keil case ISDN_P_B_RAW: 431da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 432da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 4337206e659SKarsten Keil maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 4347206e659SKarsten Keil if (maxlen < 0) { 4357206e659SKarsten Keil pr_warning("%s.B%d: No bufferspace for %d bytes\n", 4367206e659SKarsten Keil ch->is->name, ch->bch.nr, ch->is->clsb); 437da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 438da2272c9SKarsten Keil break; 439da2272c9SKarsten Keil } 440da2272c9SKarsten Keil rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 441034005a0SKarsten Keil recv_Bchannel(&ch->bch, 0, false); 442da2272c9SKarsten Keil break; 443da2272c9SKarsten Keil case ISDN_P_B_HDLC: 4447206e659SKarsten Keil maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); 4457206e659SKarsten Keil if (maxlen < 0) { 4467206e659SKarsten Keil pr_warning("%s.B%d: No bufferspace for %d bytes\n", 4477206e659SKarsten Keil ch->is->name, ch->bch.nr, ch->is->clsb); 448da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 449da2272c9SKarsten Keil break; 450da2272c9SKarsten Keil } 451da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_ERROR) { 452da2272c9SKarsten Keil pr_debug("%s: ISAR frame error %x len %d\n", 453da2272c9SKarsten Keil ch->is->name, ch->is->cmsb, ch->is->clsb); 454da2272c9SKarsten Keil #ifdef ERROR_STATISTIC 455da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_ERR_RER) 456da2272c9SKarsten Keil ch->bch.err_inv++; 457da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_ERR_CER) 458da2272c9SKarsten Keil ch->bch.err_crc++; 459da2272c9SKarsten Keil #endif 460da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 461da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 462da2272c9SKarsten Keil break; 463da2272c9SKarsten Keil } 464da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_FSD) 465da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 466da2272c9SKarsten Keil ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 467da2272c9SKarsten Keil rcv_mbox(ch->is, ptr); 468da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_FED) { 469da2272c9SKarsten Keil if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 470da2272c9SKarsten Keil pr_debug("%s: ISAR frame to short %d\n", 471da2272c9SKarsten Keil ch->is->name, ch->bch.rx_skb->len); 472da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 473da2272c9SKarsten Keil break; 474da2272c9SKarsten Keil } 475da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 476034005a0SKarsten Keil recv_Bchannel(&ch->bch, 0, false); 477da2272c9SKarsten Keil } 478da2272c9SKarsten Keil break; 479da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 480da2272c9SKarsten Keil if (ch->state != STFAX_ACTIV) { 481da2272c9SKarsten Keil pr_debug("%s: isar_rcv_frame: not ACTIV\n", 482da2272c9SKarsten Keil ch->is->name); 483da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 484da2272c9SKarsten Keil if (ch->bch.rx_skb) 485da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 486da2272c9SKarsten Keil break; 487da2272c9SKarsten Keil } 488da2272c9SKarsten Keil if (!ch->bch.rx_skb) { 489da2272c9SKarsten Keil ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, 490da2272c9SKarsten Keil GFP_ATOMIC); 491da2272c9SKarsten Keil if (unlikely(!ch->bch.rx_skb)) { 492da2272c9SKarsten Keil pr_info("%s: B receive out of memory\n", 493da2272c9SKarsten Keil __func__); 494da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 495da2272c9SKarsten Keil break; 496da2272c9SKarsten Keil } 497da2272c9SKarsten Keil } 498da2272c9SKarsten Keil if (ch->cmd == PCTRL_CMD_FRM) { 499da2272c9SKarsten Keil rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); 500da2272c9SKarsten Keil pr_debug("%s: isar_rcv_frame: %d\n", 501da2272c9SKarsten Keil ch->is->name, ch->bch.rx_skb->len); 502da2272c9SKarsten Keil if (ch->is->cmsb & SART_NMD) { /* ABORT */ 503da2272c9SKarsten Keil pr_debug("%s: isar_rcv_frame: no more data\n", 504da2272c9SKarsten Keil ch->is->name); 505da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 506da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | 507da2272c9SKarsten Keil ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 508da2272c9SKarsten Keil 0, NULL); 509da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 510da2272c9SKarsten Keil /* set_skb_flag(skb, DF_NOMOREDATA); */ 511da2272c9SKarsten Keil } 512034005a0SKarsten Keil recv_Bchannel(&ch->bch, 0, false); 513da2272c9SKarsten Keil if (ch->is->cmsb & SART_NMD) 514da2272c9SKarsten Keil deliver_status(ch, HW_MOD_NOCARR); 515da2272c9SKarsten Keil break; 516da2272c9SKarsten Keil } 517da2272c9SKarsten Keil if (ch->cmd != PCTRL_CMD_FRH) { 518da2272c9SKarsten Keil pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", 519da2272c9SKarsten Keil ch->is->name, ch->cmd); 520da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 521da2272c9SKarsten Keil if (ch->bch.rx_skb) 522da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 523da2272c9SKarsten Keil break; 524da2272c9SKarsten Keil } 525da2272c9SKarsten Keil /* PCTRL_CMD_FRH */ 526da2272c9SKarsten Keil if ((ch->bch.rx_skb->len + ch->is->clsb) > 527da2272c9SKarsten Keil (ch->bch.maxlen + 2)) { 528da2272c9SKarsten Keil pr_info("%s: %s incoming packet too large\n", 529da2272c9SKarsten Keil ch->is->name, __func__); 530da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 531da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 532da2272c9SKarsten Keil break; 533da2272c9SKarsten Keil } else if (ch->is->cmsb & HDLC_ERROR) { 534da2272c9SKarsten Keil pr_info("%s: ISAR frame error %x len %d\n", 535da2272c9SKarsten Keil ch->is->name, ch->is->cmsb, ch->is->clsb); 536da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 537da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 538da2272c9SKarsten Keil break; 539da2272c9SKarsten Keil } 540da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_FSD) 541da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 542da2272c9SKarsten Keil ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); 543da2272c9SKarsten Keil rcv_mbox(ch->is, ptr); 544da2272c9SKarsten Keil if (ch->is->cmsb & HDLC_FED) { 545da2272c9SKarsten Keil if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ 546da2272c9SKarsten Keil pr_info("%s: ISAR frame to short %d\n", 547da2272c9SKarsten Keil ch->is->name, ch->bch.rx_skb->len); 548da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 549da2272c9SKarsten Keil break; 550da2272c9SKarsten Keil } 551da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); 552034005a0SKarsten Keil recv_Bchannel(&ch->bch, 0, false); 553da2272c9SKarsten Keil } 554da2272c9SKarsten Keil if (ch->is->cmsb & SART_NMD) { /* ABORT */ 555da2272c9SKarsten Keil pr_debug("%s: isar_rcv_frame: no more data\n", 556da2272c9SKarsten Keil ch->is->name); 557da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 558da2272c9SKarsten Keil if (ch->bch.rx_skb) 559da2272c9SKarsten Keil skb_trim(ch->bch.rx_skb, 0); 560da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | 561da2272c9SKarsten Keil ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); 562da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 563da2272c9SKarsten Keil deliver_status(ch, HW_MOD_NOCARR); 564da2272c9SKarsten Keil } 565da2272c9SKarsten Keil break; 566da2272c9SKarsten Keil default: 567da2272c9SKarsten Keil pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); 568da2272c9SKarsten Keil ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); 569da2272c9SKarsten Keil break; 570da2272c9SKarsten Keil } 571da2272c9SKarsten Keil } 572da2272c9SKarsten Keil 573da2272c9SKarsten Keil static void 574da2272c9SKarsten Keil isar_fill_fifo(struct isar_ch *ch) 575da2272c9SKarsten Keil { 576da2272c9SKarsten Keil int count; 577da2272c9SKarsten Keil u8 msb; 578da2272c9SKarsten Keil u8 *ptr; 579da2272c9SKarsten Keil 5806d1ee48fSKarsten Keil pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, 5816d1ee48fSKarsten Keil ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); 582da2272c9SKarsten Keil if (!(ch->is->bstat & 583da2272c9SKarsten Keil (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) 584da2272c9SKarsten Keil return; 5856d1ee48fSKarsten Keil if (!ch->bch.tx_skb) { 5866d1ee48fSKarsten Keil if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || 5876d1ee48fSKarsten Keil (ch->bch.state != ISDN_P_B_RAW)) 5886d1ee48fSKarsten Keil return; 5896d1ee48fSKarsten Keil count = ch->mml; 5906d1ee48fSKarsten Keil /* use the card buffer */ 5916d1ee48fSKarsten Keil memset(ch->is->buf, ch->bch.fill[0], count); 5926d1ee48fSKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 5936d1ee48fSKarsten Keil 0, count, ch->is->buf); 5946d1ee48fSKarsten Keil return; 5956d1ee48fSKarsten Keil } 5966d1ee48fSKarsten Keil count = ch->bch.tx_skb->len - ch->bch.tx_idx; 5976d1ee48fSKarsten Keil if (count <= 0) 5986d1ee48fSKarsten Keil return; 599da2272c9SKarsten Keil if (count > ch->mml) { 600da2272c9SKarsten Keil msb = 0; 601da2272c9SKarsten Keil count = ch->mml; 602da2272c9SKarsten Keil } else { 603da2272c9SKarsten Keil msb = HDLC_FED; 604da2272c9SKarsten Keil } 605da2272c9SKarsten Keil ptr = ch->bch.tx_skb->data + ch->bch.tx_idx; 606da2272c9SKarsten Keil if (!ch->bch.tx_idx) { 607da2272c9SKarsten Keil pr_debug("%s: frame start\n", ch->is->name); 608da2272c9SKarsten Keil if ((ch->bch.state == ISDN_P_B_T30_FAX) && 609da2272c9SKarsten Keil (ch->cmd == PCTRL_CMD_FTH)) { 610da2272c9SKarsten Keil if (count > 1) { 611da2272c9SKarsten Keil if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) { 612da2272c9SKarsten Keil /* last frame */ 613da2272c9SKarsten Keil test_and_set_bit(FLG_LASTDATA, 614da2272c9SKarsten Keil &ch->bch.Flags); 615da2272c9SKarsten Keil pr_debug("%s: set LASTDATA\n", 616da2272c9SKarsten Keil ch->is->name); 617da2272c9SKarsten Keil if (msb == HDLC_FED) 618da2272c9SKarsten Keil test_and_set_bit(FLG_DLEETX, 619da2272c9SKarsten Keil &ch->bch.Flags); 620da2272c9SKarsten Keil } 621da2272c9SKarsten Keil } 622da2272c9SKarsten Keil } 623da2272c9SKarsten Keil msb |= HDLC_FST; 624da2272c9SKarsten Keil } 625da2272c9SKarsten Keil ch->bch.tx_idx += count; 626da2272c9SKarsten Keil switch (ch->bch.state) { 627da2272c9SKarsten Keil case ISDN_P_NONE: 628da2272c9SKarsten Keil pr_info("%s: wrong protocol 0\n", __func__); 629da2272c9SKarsten Keil break; 630da2272c9SKarsten Keil case ISDN_P_B_RAW: 631da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 632da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 633da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 634da2272c9SKarsten Keil 0, count, ptr); 635da2272c9SKarsten Keil break; 636da2272c9SKarsten Keil case ISDN_P_B_HDLC: 637da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 638da2272c9SKarsten Keil msb, count, ptr); 639da2272c9SKarsten Keil break; 640da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 641da2272c9SKarsten Keil if (ch->state != STFAX_ACTIV) 642da2272c9SKarsten Keil pr_debug("%s: not ACTIV\n", ch->is->name); 643da2272c9SKarsten Keil else if (ch->cmd == PCTRL_CMD_FTH) 644da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 645da2272c9SKarsten Keil msb, count, ptr); 646da2272c9SKarsten Keil else if (ch->cmd == PCTRL_CMD_FTM) 647da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, 648da2272c9SKarsten Keil 0, count, ptr); 649da2272c9SKarsten Keil else 650da2272c9SKarsten Keil pr_debug("%s: not FTH/FTM\n", ch->is->name); 651da2272c9SKarsten Keil break; 652da2272c9SKarsten Keil default: 653da2272c9SKarsten Keil pr_info("%s: protocol(%x) error\n", 654da2272c9SKarsten Keil __func__, ch->bch.state); 655da2272c9SKarsten Keil break; 656da2272c9SKarsten Keil } 657da2272c9SKarsten Keil } 658da2272c9SKarsten Keil 659da2272c9SKarsten Keil static inline struct isar_ch * 660da2272c9SKarsten Keil sel_bch_isar(struct isar_hw *isar, u8 dpath) 661da2272c9SKarsten Keil { 662da2272c9SKarsten Keil struct isar_ch *base = &isar->ch[0]; 663da2272c9SKarsten Keil 664da2272c9SKarsten Keil if ((!dpath) || (dpath > 2)) 665da2272c9SKarsten Keil return NULL; 666da2272c9SKarsten Keil if (base->dpath == dpath) 667da2272c9SKarsten Keil return base; 668da2272c9SKarsten Keil base++; 669da2272c9SKarsten Keil if (base->dpath == dpath) 670da2272c9SKarsten Keil return base; 671da2272c9SKarsten Keil return NULL; 672da2272c9SKarsten Keil } 673da2272c9SKarsten Keil 674da2272c9SKarsten Keil static void 675da2272c9SKarsten Keil send_next(struct isar_ch *ch) 676da2272c9SKarsten Keil { 6776d1ee48fSKarsten Keil pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, 6786d1ee48fSKarsten Keil ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, 6796d1ee48fSKarsten Keil ch->bch.tx_idx); 680da2272c9SKarsten Keil if (ch->bch.state == ISDN_P_B_T30_FAX) { 681da2272c9SKarsten Keil if (ch->cmd == PCTRL_CMD_FTH) { 682da2272c9SKarsten Keil if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { 683da2272c9SKarsten Keil pr_debug("set NMD_DATA\n"); 684da2272c9SKarsten Keil test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 685da2272c9SKarsten Keil } 686da2272c9SKarsten Keil } else if (ch->cmd == PCTRL_CMD_FTM) { 687da2272c9SKarsten Keil if (test_bit(FLG_DLEETX, &ch->bch.Flags)) { 688da2272c9SKarsten Keil test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags); 689da2272c9SKarsten Keil test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags); 690da2272c9SKarsten Keil } 691da2272c9SKarsten Keil } 692da2272c9SKarsten Keil } 6938bfddfbeSKarsten Keil if (ch->bch.tx_skb) 694da2272c9SKarsten Keil dev_kfree_skb(ch->bch.tx_skb); 6958bfddfbeSKarsten Keil if (get_next_bframe(&ch->bch)) { 696da2272c9SKarsten Keil isar_fill_fifo(ch); 6976d1ee48fSKarsten Keil test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); 6986d1ee48fSKarsten Keil } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { 6996d1ee48fSKarsten Keil isar_fill_fifo(ch); 7008bfddfbeSKarsten Keil } else { 701da2272c9SKarsten Keil if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { 702da2272c9SKarsten Keil if (test_and_clear_bit(FLG_LASTDATA, 703da2272c9SKarsten Keil &ch->bch.Flags)) { 704da2272c9SKarsten Keil if (test_and_clear_bit(FLG_NMD_DATA, 705da2272c9SKarsten Keil &ch->bch.Flags)) { 706da2272c9SKarsten Keil u8 zd = 0; 707da2272c9SKarsten Keil send_mbox(ch->is, SET_DPS(ch->dpath) | 708da2272c9SKarsten Keil ISAR_HIS_SDATA, 0x01, 1, &zd); 709da2272c9SKarsten Keil } 710da2272c9SKarsten Keil test_and_set_bit(FLG_LL_OK, &ch->bch.Flags); 711da2272c9SKarsten Keil } else { 712da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 713da2272c9SKarsten Keil } 7146d1ee48fSKarsten Keil } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { 7156d1ee48fSKarsten Keil test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); 716da2272c9SKarsten Keil } 717da2272c9SKarsten Keil } 718da2272c9SKarsten Keil } 719da2272c9SKarsten Keil 720da2272c9SKarsten Keil static void 721da2272c9SKarsten Keil check_send(struct isar_hw *isar, u8 rdm) 722da2272c9SKarsten Keil { 723da2272c9SKarsten Keil struct isar_ch *ch; 724da2272c9SKarsten Keil 725da2272c9SKarsten Keil pr_debug("%s: rdm %x\n", isar->name, rdm); 726da2272c9SKarsten Keil if (rdm & BSTAT_RDM1) { 727da2272c9SKarsten Keil ch = sel_bch_isar(isar, 1); 728da2272c9SKarsten Keil if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 729da2272c9SKarsten Keil if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 730da2272c9SKarsten Keil ch->bch.tx_idx)) 731da2272c9SKarsten Keil isar_fill_fifo(ch); 732da2272c9SKarsten Keil else 733da2272c9SKarsten Keil send_next(ch); 734da2272c9SKarsten Keil } 735da2272c9SKarsten Keil } 736da2272c9SKarsten Keil if (rdm & BSTAT_RDM2) { 737da2272c9SKarsten Keil ch = sel_bch_isar(isar, 2); 738da2272c9SKarsten Keil if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) { 739da2272c9SKarsten Keil if (ch->bch.tx_skb && (ch->bch.tx_skb->len > 740da2272c9SKarsten Keil ch->bch.tx_idx)) 741da2272c9SKarsten Keil isar_fill_fifo(ch); 742da2272c9SKarsten Keil else 743da2272c9SKarsten Keil send_next(ch); 744da2272c9SKarsten Keil } 745da2272c9SKarsten Keil } 746da2272c9SKarsten Keil } 747da2272c9SKarsten Keil 748da2272c9SKarsten Keil const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", 749da2272c9SKarsten Keil "300", "600", "1200", "2400", "4800", "7200", 750da2272c9SKarsten Keil "9600nt", "9600t", "12000", "14400", "WRONG"}; 751da2272c9SKarsten Keil const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", 752da2272c9SKarsten Keil "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; 753da2272c9SKarsten Keil 754da2272c9SKarsten Keil static void 755da2272c9SKarsten Keil isar_pump_status_rsp(struct isar_ch *ch) { 756da2272c9SKarsten Keil u8 ril = ch->is->buf[0]; 757da2272c9SKarsten Keil u8 rim; 758da2272c9SKarsten Keil 759da2272c9SKarsten Keil if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags)) 760da2272c9SKarsten Keil return; 761da2272c9SKarsten Keil if (ril > 14) { 762da2272c9SKarsten Keil pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril); 763da2272c9SKarsten Keil ril = 15; 764da2272c9SKarsten Keil } 765da2272c9SKarsten Keil switch (ch->is->buf[1]) { 766da2272c9SKarsten Keil case 0: 767da2272c9SKarsten Keil rim = 0; 768da2272c9SKarsten Keil break; 769da2272c9SKarsten Keil case 0x20: 770da2272c9SKarsten Keil rim = 2; 771da2272c9SKarsten Keil break; 772da2272c9SKarsten Keil case 0x40: 773da2272c9SKarsten Keil rim = 3; 774da2272c9SKarsten Keil break; 775da2272c9SKarsten Keil case 0x41: 776da2272c9SKarsten Keil rim = 4; 777da2272c9SKarsten Keil break; 778da2272c9SKarsten Keil case 0x51: 779da2272c9SKarsten Keil rim = 5; 780da2272c9SKarsten Keil break; 781da2272c9SKarsten Keil case 0x61: 782da2272c9SKarsten Keil rim = 6; 783da2272c9SKarsten Keil break; 784da2272c9SKarsten Keil case 0x71: 785da2272c9SKarsten Keil rim = 7; 786da2272c9SKarsten Keil break; 787da2272c9SKarsten Keil case 0x82: 788da2272c9SKarsten Keil rim = 8; 789da2272c9SKarsten Keil break; 790da2272c9SKarsten Keil case 0x92: 791da2272c9SKarsten Keil rim = 9; 792da2272c9SKarsten Keil break; 793da2272c9SKarsten Keil case 0xa2: 794da2272c9SKarsten Keil rim = 10; 795da2272c9SKarsten Keil break; 796da2272c9SKarsten Keil default: 797da2272c9SKarsten Keil rim = 1; 798da2272c9SKarsten Keil break; 799da2272c9SKarsten Keil } 800da2272c9SKarsten Keil sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]); 801da2272c9SKarsten Keil pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg); 802da2272c9SKarsten Keil } 803da2272c9SKarsten Keil 804da2272c9SKarsten Keil static void 805da2272c9SKarsten Keil isar_pump_statev_modem(struct isar_ch *ch, u8 devt) { 806da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 807da2272c9SKarsten Keil 808da2272c9SKarsten Keil switch (devt) { 809da2272c9SKarsten Keil case PSEV_10MS_TIMER: 810da2272c9SKarsten Keil pr_debug("%s: pump stev TIMER\n", ch->is->name); 811da2272c9SKarsten Keil break; 812da2272c9SKarsten Keil case PSEV_CON_ON: 813da2272c9SKarsten Keil pr_debug("%s: pump stev CONNECT\n", ch->is->name); 814da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 815da2272c9SKarsten Keil break; 816da2272c9SKarsten Keil case PSEV_CON_OFF: 817da2272c9SKarsten Keil pr_debug("%s: pump stev NO CONNECT\n", ch->is->name); 818da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 819da2272c9SKarsten Keil deliver_status(ch, HW_MOD_NOCARR); 820da2272c9SKarsten Keil break; 821da2272c9SKarsten Keil case PSEV_V24_OFF: 822da2272c9SKarsten Keil pr_debug("%s: pump stev V24 OFF\n", ch->is->name); 823da2272c9SKarsten Keil break; 824da2272c9SKarsten Keil case PSEV_CTS_ON: 825da2272c9SKarsten Keil pr_debug("%s: pump stev CTS ON\n", ch->is->name); 826da2272c9SKarsten Keil break; 827da2272c9SKarsten Keil case PSEV_CTS_OFF: 828da2272c9SKarsten Keil pr_debug("%s pump stev CTS OFF\n", ch->is->name); 829da2272c9SKarsten Keil break; 830da2272c9SKarsten Keil case PSEV_DCD_ON: 831da2272c9SKarsten Keil pr_debug("%s: pump stev CARRIER ON\n", ch->is->name); 832da2272c9SKarsten Keil test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 833da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 834da2272c9SKarsten Keil break; 835da2272c9SKarsten Keil case PSEV_DCD_OFF: 836da2272c9SKarsten Keil pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name); 837da2272c9SKarsten Keil break; 838da2272c9SKarsten Keil case PSEV_DSR_ON: 839da2272c9SKarsten Keil pr_debug("%s: pump stev DSR ON\n", ch->is->name); 840da2272c9SKarsten Keil break; 841da2272c9SKarsten Keil case PSEV_DSR_OFF: 842da2272c9SKarsten Keil pr_debug("%s: pump stev DSR_OFF\n", ch->is->name); 843da2272c9SKarsten Keil break; 844da2272c9SKarsten Keil case PSEV_REM_RET: 845da2272c9SKarsten Keil pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name); 846da2272c9SKarsten Keil break; 847da2272c9SKarsten Keil case PSEV_REM_REN: 848da2272c9SKarsten Keil pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name); 849da2272c9SKarsten Keil break; 850da2272c9SKarsten Keil case PSEV_GSTN_CLR: 851da2272c9SKarsten Keil pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name); 852da2272c9SKarsten Keil break; 853da2272c9SKarsten Keil default: 854af901ca1SAndré Goddard Rosa pr_info("u%s: unknown pump stev %x\n", ch->is->name, devt); 855da2272c9SKarsten Keil break; 856da2272c9SKarsten Keil } 857da2272c9SKarsten Keil } 858da2272c9SKarsten Keil 859da2272c9SKarsten Keil static void 860da2272c9SKarsten Keil isar_pump_statev_fax(struct isar_ch *ch, u8 devt) { 861da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 862da2272c9SKarsten Keil u8 p1; 863da2272c9SKarsten Keil 864da2272c9SKarsten Keil switch (devt) { 865da2272c9SKarsten Keil case PSEV_10MS_TIMER: 866da2272c9SKarsten Keil pr_debug("%s: pump stev TIMER\n", ch->is->name); 867da2272c9SKarsten Keil break; 868da2272c9SKarsten Keil case PSEV_RSP_READY: 869da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_READY\n", ch->is->name); 870da2272c9SKarsten Keil ch->state = STFAX_READY; 871da2272c9SKarsten Keil deliver_status(ch, HW_MOD_READY); 872da2272c9SKarsten Keil #ifdef AUTOCON 873da2272c9SKarsten Keil if (test_bit(BC_FLG_ORIG, &ch->bch.Flags)) 874da2272c9SKarsten Keil isar_pump_cmd(bch, HW_MOD_FRH, 3); 875da2272c9SKarsten Keil else 876da2272c9SKarsten Keil isar_pump_cmd(bch, HW_MOD_FTH, 3); 877da2272c9SKarsten Keil #endif 878da2272c9SKarsten Keil break; 879da2272c9SKarsten Keil case PSEV_LINE_TX_H: 880da2272c9SKarsten Keil if (ch->state == STFAX_LINE) { 881da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name); 882da2272c9SKarsten Keil ch->state = STFAX_CONT; 883da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 884da2272c9SKarsten Keil PCTRL_CMD_CONT, 0, NULL); 885da2272c9SKarsten Keil } else { 886da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_TX_H wrong st %x\n", 887da2272c9SKarsten Keil ch->is->name, ch->state); 888da2272c9SKarsten Keil } 889da2272c9SKarsten Keil break; 890da2272c9SKarsten Keil case PSEV_LINE_RX_H: 891da2272c9SKarsten Keil if (ch->state == STFAX_LINE) { 892da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name); 893da2272c9SKarsten Keil ch->state = STFAX_CONT; 894da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 895da2272c9SKarsten Keil PCTRL_CMD_CONT, 0, NULL); 896da2272c9SKarsten Keil } else { 897da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_RX_H wrong st %x\n", 898da2272c9SKarsten Keil ch->is->name, ch->state); 899da2272c9SKarsten Keil } 900da2272c9SKarsten Keil break; 901da2272c9SKarsten Keil case PSEV_LINE_TX_B: 902da2272c9SKarsten Keil if (ch->state == STFAX_LINE) { 903da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name); 904da2272c9SKarsten Keil ch->state = STFAX_CONT; 905da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 906da2272c9SKarsten Keil PCTRL_CMD_CONT, 0, NULL); 907da2272c9SKarsten Keil } else { 908da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_TX_B wrong st %x\n", 909da2272c9SKarsten Keil ch->is->name, ch->state); 910da2272c9SKarsten Keil } 911da2272c9SKarsten Keil break; 912da2272c9SKarsten Keil case PSEV_LINE_RX_B: 913da2272c9SKarsten Keil if (ch->state == STFAX_LINE) { 914da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name); 915da2272c9SKarsten Keil ch->state = STFAX_CONT; 916da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 917da2272c9SKarsten Keil PCTRL_CMD_CONT, 0, NULL); 918da2272c9SKarsten Keil } else { 919da2272c9SKarsten Keil pr_debug("%s: pump stev LINE_RX_B wrong st %x\n", 920da2272c9SKarsten Keil ch->is->name, ch->state); 921da2272c9SKarsten Keil } 922da2272c9SKarsten Keil break; 923da2272c9SKarsten Keil case PSEV_RSP_CONN: 924da2272c9SKarsten Keil if (ch->state == STFAX_CONT) { 925da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_CONN\n", ch->is->name); 926da2272c9SKarsten Keil ch->state = STFAX_ACTIV; 927da2272c9SKarsten Keil test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags); 928da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 929da2272c9SKarsten Keil if (ch->cmd == PCTRL_CMD_FTH) { 930da2272c9SKarsten Keil int delay = (ch->mod == 3) ? 1000 : 200; 931da2272c9SKarsten Keil /* 1s (200 ms) Flags before data */ 932da2272c9SKarsten Keil if (test_and_set_bit(FLG_FTI_RUN, 933da2272c9SKarsten Keil &ch->bch.Flags)) 934da2272c9SKarsten Keil del_timer(&ch->ftimer); 935da2272c9SKarsten Keil ch->ftimer.expires = 936da2272c9SKarsten Keil jiffies + ((delay * HZ) / 1000); 937da2272c9SKarsten Keil test_and_set_bit(FLG_LL_CONN, 938da2272c9SKarsten Keil &ch->bch.Flags); 939da2272c9SKarsten Keil add_timer(&ch->ftimer); 940da2272c9SKarsten Keil } else { 941da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 942da2272c9SKarsten Keil } 943da2272c9SKarsten Keil } else { 944da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_CONN wrong st %x\n", 945da2272c9SKarsten Keil ch->is->name, ch->state); 946da2272c9SKarsten Keil } 947da2272c9SKarsten Keil break; 948da2272c9SKarsten Keil case PSEV_FLAGS_DET: 949da2272c9SKarsten Keil pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name); 950da2272c9SKarsten Keil break; 951da2272c9SKarsten Keil case PSEV_RSP_DISC: 952da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_DISC state(%d)\n", 953da2272c9SKarsten Keil ch->is->name, ch->state); 954da2272c9SKarsten Keil if (ch->state == STFAX_ESCAPE) { 955da2272c9SKarsten Keil p1 = 5; 956da2272c9SKarsten Keil switch (ch->newcmd) { 957da2272c9SKarsten Keil case 0: 958da2272c9SKarsten Keil ch->state = STFAX_READY; 959da2272c9SKarsten Keil break; 960da2272c9SKarsten Keil case PCTRL_CMD_FTM: 961da2272c9SKarsten Keil p1 = 2; 962d287c502SGustavo A. R. Silva /* fall through */ 963da2272c9SKarsten Keil case PCTRL_CMD_FTH: 964da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 965da2272c9SKarsten Keil PCTRL_CMD_SILON, 1, &p1); 966da2272c9SKarsten Keil ch->state = STFAX_SILDET; 967da2272c9SKarsten Keil break; 968da2272c9SKarsten Keil case PCTRL_CMD_FRH: 969da2272c9SKarsten Keil case PCTRL_CMD_FRM: 970da2272c9SKarsten Keil ch->mod = ch->newmod; 971da2272c9SKarsten Keil p1 = ch->newmod; 972da2272c9SKarsten Keil ch->newmod = 0; 973da2272c9SKarsten Keil ch->cmd = ch->newcmd; 974da2272c9SKarsten Keil ch->newcmd = 0; 975da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 976da2272c9SKarsten Keil ch->cmd, 1, &p1); 977da2272c9SKarsten Keil ch->state = STFAX_LINE; 978da2272c9SKarsten Keil ch->try_mod = 3; 979da2272c9SKarsten Keil break; 980da2272c9SKarsten Keil default: 981da2272c9SKarsten Keil pr_debug("%s: RSP_DISC unknown newcmd %x\n", 982da2272c9SKarsten Keil ch->is->name, ch->newcmd); 983da2272c9SKarsten Keil break; 984da2272c9SKarsten Keil } 985da2272c9SKarsten Keil } else if (ch->state == STFAX_ACTIV) { 986da2272c9SKarsten Keil if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags)) 987da2272c9SKarsten Keil deliver_status(ch, HW_MOD_OK); 988da2272c9SKarsten Keil else if (ch->cmd == PCTRL_CMD_FRM) 989da2272c9SKarsten Keil deliver_status(ch, HW_MOD_NOCARR); 990da2272c9SKarsten Keil else 991da2272c9SKarsten Keil deliver_status(ch, HW_MOD_FCERROR); 992da2272c9SKarsten Keil ch->state = STFAX_READY; 993da2272c9SKarsten Keil } else if (ch->state != STFAX_SILDET) { 994da2272c9SKarsten Keil /* ignore in STFAX_SILDET */ 995da2272c9SKarsten Keil ch->state = STFAX_READY; 996da2272c9SKarsten Keil deliver_status(ch, HW_MOD_FCERROR); 997da2272c9SKarsten Keil } 998da2272c9SKarsten Keil break; 999da2272c9SKarsten Keil case PSEV_RSP_SILDET: 1000da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name); 1001da2272c9SKarsten Keil if (ch->state == STFAX_SILDET) { 1002da2272c9SKarsten Keil ch->mod = ch->newmod; 1003da2272c9SKarsten Keil p1 = ch->newmod; 1004da2272c9SKarsten Keil ch->newmod = 0; 1005da2272c9SKarsten Keil ch->cmd = ch->newcmd; 1006da2272c9SKarsten Keil ch->newcmd = 0; 1007da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 1008da2272c9SKarsten Keil ch->cmd, 1, &p1); 1009da2272c9SKarsten Keil ch->state = STFAX_LINE; 1010da2272c9SKarsten Keil ch->try_mod = 3; 1011da2272c9SKarsten Keil } 1012da2272c9SKarsten Keil break; 1013da2272c9SKarsten Keil case PSEV_RSP_SILOFF: 1014da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name); 1015da2272c9SKarsten Keil break; 1016da2272c9SKarsten Keil case PSEV_RSP_FCERR: 1017da2272c9SKarsten Keil if (ch->state == STFAX_LINE) { 1018da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_FCERR try %d\n", 1019da2272c9SKarsten Keil ch->is->name, ch->try_mod); 1020da2272c9SKarsten Keil if (ch->try_mod--) { 1021da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, 1022da2272c9SKarsten Keil ch->cmd, 1, &ch->mod); 1023da2272c9SKarsten Keil break; 1024da2272c9SKarsten Keil } 1025da2272c9SKarsten Keil } 1026da2272c9SKarsten Keil pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name); 1027da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 1028da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 1029da2272c9SKarsten Keil 0, NULL); 1030da2272c9SKarsten Keil deliver_status(ch, HW_MOD_FCERROR); 1031da2272c9SKarsten Keil break; 1032da2272c9SKarsten Keil default: 1033da2272c9SKarsten Keil break; 1034da2272c9SKarsten Keil } 1035da2272c9SKarsten Keil } 1036da2272c9SKarsten Keil 1037da2272c9SKarsten Keil void 1038da2272c9SKarsten Keil mISDNisar_irq(struct isar_hw *isar) 1039da2272c9SKarsten Keil { 1040da2272c9SKarsten Keil struct isar_ch *ch; 1041da2272c9SKarsten Keil 1042da2272c9SKarsten Keil get_irq_infos(isar); 1043da2272c9SKarsten Keil switch (isar->iis & ISAR_IIS_MSCMSD) { 1044da2272c9SKarsten Keil case ISAR_IIS_RDATA: 1045da2272c9SKarsten Keil ch = sel_bch_isar(isar, isar->iis >> 6); 1046da2272c9SKarsten Keil if (ch) 1047da2272c9SKarsten Keil isar_rcv_frame(ch); 1048da2272c9SKarsten Keil else { 1049da2272c9SKarsten Keil pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n", 1050da2272c9SKarsten Keil isar->name, isar->iis, isar->cmsb, 1051da2272c9SKarsten Keil isar->clsb); 1052da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 1053da2272c9SKarsten Keil } 1054da2272c9SKarsten Keil break; 1055da2272c9SKarsten Keil case ISAR_IIS_GSTEV: 1056da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 1057da2272c9SKarsten Keil isar->bstat |= isar->cmsb; 1058da2272c9SKarsten Keil check_send(isar, isar->cmsb); 1059da2272c9SKarsten Keil break; 1060da2272c9SKarsten Keil case ISAR_IIS_BSTEV: 1061da2272c9SKarsten Keil #ifdef ERROR_STATISTIC 1062da2272c9SKarsten Keil ch = sel_bch_isar(isar, isar->iis >> 6); 1063da2272c9SKarsten Keil if (ch) { 1064da2272c9SKarsten Keil if (isar->cmsb == BSTEV_TBO) 1065da2272c9SKarsten Keil ch->bch.err_tx++; 1066da2272c9SKarsten Keil if (isar->cmsb == BSTEV_RBO) 1067da2272c9SKarsten Keil ch->bch.err_rdo++; 1068da2272c9SKarsten Keil } 1069da2272c9SKarsten Keil #endif 1070da2272c9SKarsten Keil pr_debug("%s: Buffer STEV dpath%d msb(%x)\n", 1071da2272c9SKarsten Keil isar->name, isar->iis >> 6, isar->cmsb); 1072da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 1073da2272c9SKarsten Keil break; 1074da2272c9SKarsten Keil case ISAR_IIS_PSTEV: 1075da2272c9SKarsten Keil ch = sel_bch_isar(isar, isar->iis >> 6); 1076da2272c9SKarsten Keil if (ch) { 1077da2272c9SKarsten Keil rcv_mbox(isar, NULL); 1078da2272c9SKarsten Keil if (ch->bch.state == ISDN_P_B_MODEM_ASYNC) 1079da2272c9SKarsten Keil isar_pump_statev_modem(ch, isar->cmsb); 1080da2272c9SKarsten Keil else if (ch->bch.state == ISDN_P_B_T30_FAX) 1081da2272c9SKarsten Keil isar_pump_statev_fax(ch, isar->cmsb); 1082da2272c9SKarsten Keil else if (ch->bch.state == ISDN_P_B_RAW) { 1083da2272c9SKarsten Keil int tt; 1084da2272c9SKarsten Keil tt = isar->cmsb | 0x30; 1085da2272c9SKarsten Keil if (tt == 0x3e) 1086da2272c9SKarsten Keil tt = '*'; 1087da2272c9SKarsten Keil else if (tt == 0x3f) 1088da2272c9SKarsten Keil tt = '#'; 1089da2272c9SKarsten Keil else if (tt > '9') 1090da2272c9SKarsten Keil tt += 7; 1091da2272c9SKarsten Keil tt |= DTMF_TONE_VAL; 1092da2272c9SKarsten Keil _queue_data(&ch->bch.ch, PH_CONTROL_IND, 1093da2272c9SKarsten Keil MISDN_ID_ANY, sizeof(tt), &tt, 1094da2272c9SKarsten Keil GFP_ATOMIC); 1095da2272c9SKarsten Keil } else 1096da2272c9SKarsten Keil pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n", 1097da2272c9SKarsten Keil isar->name, ch->bch.state, 1098da2272c9SKarsten Keil isar->cmsb); 1099da2272c9SKarsten Keil } else { 1100da2272c9SKarsten Keil pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n", 1101da2272c9SKarsten Keil isar->name, isar->iis, isar->cmsb, 1102da2272c9SKarsten Keil isar->clsb); 1103da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 1104da2272c9SKarsten Keil } 1105da2272c9SKarsten Keil break; 1106da2272c9SKarsten Keil case ISAR_IIS_PSTRSP: 1107da2272c9SKarsten Keil ch = sel_bch_isar(isar, isar->iis >> 6); 1108da2272c9SKarsten Keil if (ch) { 1109da2272c9SKarsten Keil rcv_mbox(isar, NULL); 1110da2272c9SKarsten Keil isar_pump_status_rsp(ch); 1111da2272c9SKarsten Keil } else { 1112da2272c9SKarsten Keil pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n", 1113da2272c9SKarsten Keil isar->name, isar->iis, isar->cmsb, 1114da2272c9SKarsten Keil isar->clsb); 1115da2272c9SKarsten Keil isar->write_reg(isar->hw, ISAR_IIA, 0); 1116da2272c9SKarsten Keil } 1117da2272c9SKarsten Keil break; 1118da2272c9SKarsten Keil case ISAR_IIS_DIAG: 1119da2272c9SKarsten Keil case ISAR_IIS_BSTRSP: 1120da2272c9SKarsten Keil case ISAR_IIS_IOM2RSP: 1121da2272c9SKarsten Keil rcv_mbox(isar, NULL); 1122da2272c9SKarsten Keil break; 1123da2272c9SKarsten Keil case ISAR_IIS_INVMSG: 1124da2272c9SKarsten Keil rcv_mbox(isar, NULL); 1125da2272c9SKarsten Keil pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb); 1126da2272c9SKarsten Keil break; 1127da2272c9SKarsten Keil default: 1128da2272c9SKarsten Keil rcv_mbox(isar, NULL); 1129da2272c9SKarsten Keil pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n", 1130da2272c9SKarsten Keil isar->name, isar->iis, isar->cmsb, isar->clsb); 1131da2272c9SKarsten Keil break; 1132da2272c9SKarsten Keil } 1133da2272c9SKarsten Keil } 1134da2272c9SKarsten Keil EXPORT_SYMBOL(mISDNisar_irq); 1135da2272c9SKarsten Keil 1136da2272c9SKarsten Keil static void 1137e99e88a9SKees Cook ftimer_handler(struct timer_list *t) 1138da2272c9SKarsten Keil { 1139e99e88a9SKees Cook struct isar_ch *ch = from_timer(ch, t, ftimer); 1140da2272c9SKarsten Keil 1141da2272c9SKarsten Keil pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags); 1142da2272c9SKarsten Keil test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags); 1143da2272c9SKarsten Keil if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags)) 1144da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 1145da2272c9SKarsten Keil } 1146da2272c9SKarsten Keil 1147da2272c9SKarsten Keil static void 1148da2272c9SKarsten Keil setup_pump(struct isar_ch *ch) { 1149da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 1150da2272c9SKarsten Keil u8 ctrl, param[6]; 1151da2272c9SKarsten Keil 1152da2272c9SKarsten Keil switch (ch->bch.state) { 1153da2272c9SKarsten Keil case ISDN_P_NONE: 1154da2272c9SKarsten Keil case ISDN_P_B_RAW: 1155da2272c9SKarsten Keil case ISDN_P_B_HDLC: 1156da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); 1157da2272c9SKarsten Keil break; 1158da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 1159da2272c9SKarsten Keil if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) { 1160da2272c9SKarsten Keil param[0] = 5; /* TOA 5 db */ 1161da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 1162da2272c9SKarsten Keil PMOD_DTMF_TRANS, 1, param); 1163da2272c9SKarsten Keil } else { 1164da2272c9SKarsten Keil param[0] = 40; /* REL -46 dbm */ 1165da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, 1166da2272c9SKarsten Keil PMOD_DTMF, 1, param); 1167da2272c9SKarsten Keil } 1168d287c502SGustavo A. R. Silva /* fall through */ 1169da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 1170da2272c9SKarsten Keil ctrl = PMOD_DATAMODEM; 1171da2272c9SKarsten Keil if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 1172da2272c9SKarsten Keil ctrl |= PCTRL_ORIG; 1173da2272c9SKarsten Keil param[5] = PV32P6_CTN; 1174da2272c9SKarsten Keil } else { 1175da2272c9SKarsten Keil param[5] = PV32P6_ATN; 1176da2272c9SKarsten Keil } 1177da2272c9SKarsten Keil param[0] = 6; /* 6 db */ 1178da2272c9SKarsten Keil param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | 1179da2272c9SKarsten Keil PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 1180da2272c9SKarsten Keil param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; 1181da2272c9SKarsten Keil param[3] = PV32P4_UT144; 1182da2272c9SKarsten Keil param[4] = PV32P5_UT144; 1183da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); 1184da2272c9SKarsten Keil break; 1185da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 1186da2272c9SKarsten Keil ctrl = PMOD_FAX; 1187da2272c9SKarsten Keil if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) { 1188da2272c9SKarsten Keil ctrl |= PCTRL_ORIG; 1189da2272c9SKarsten Keil param[1] = PFAXP2_CTN; 1190da2272c9SKarsten Keil } else { 1191da2272c9SKarsten Keil param[1] = PFAXP2_ATN; 1192da2272c9SKarsten Keil } 1193da2272c9SKarsten Keil param[0] = 6; /* 6 db */ 1194da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); 1195da2272c9SKarsten Keil ch->state = STFAX_NULL; 1196da2272c9SKarsten Keil ch->newcmd = 0; 1197da2272c9SKarsten Keil ch->newmod = 0; 1198da2272c9SKarsten Keil test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags); 1199da2272c9SKarsten Keil break; 1200da2272c9SKarsten Keil } 1201da2272c9SKarsten Keil udelay(1000); 1202da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); 1203da2272c9SKarsten Keil udelay(1000); 1204da2272c9SKarsten Keil } 1205da2272c9SKarsten Keil 1206da2272c9SKarsten Keil static void 1207da2272c9SKarsten Keil setup_sart(struct isar_ch *ch) { 1208da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 1209da2272c9SKarsten Keil u8 ctrl, param[2] = {0, 0}; 1210da2272c9SKarsten Keil 1211da2272c9SKarsten Keil switch (ch->bch.state) { 1212da2272c9SKarsten Keil case ISDN_P_NONE: 1213da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 1214da2272c9SKarsten Keil 0, NULL); 1215da2272c9SKarsten Keil break; 1216da2272c9SKarsten Keil case ISDN_P_B_RAW: 1217da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 1218da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 1219da2272c9SKarsten Keil 2, param); 1220da2272c9SKarsten Keil break; 1221da2272c9SKarsten Keil case ISDN_P_B_HDLC: 1222da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 1223da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1224da2272c9SKarsten Keil 1, param); 1225da2272c9SKarsten Keil break; 1226da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 1227da2272c9SKarsten Keil ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; 1228da2272c9SKarsten Keil param[0] = S_P1_CHS_8; 1229da2272c9SKarsten Keil param[1] = S_P2_BFT_DEF; 1230da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param); 1231da2272c9SKarsten Keil break; 1232da2272c9SKarsten Keil } 1233da2272c9SKarsten Keil udelay(1000); 1234da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); 1235da2272c9SKarsten Keil udelay(1000); 1236da2272c9SKarsten Keil } 1237da2272c9SKarsten Keil 1238da2272c9SKarsten Keil static void 1239da2272c9SKarsten Keil setup_iom2(struct isar_ch *ch) { 1240da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 1241da2272c9SKarsten Keil u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; 1242da2272c9SKarsten Keil 1243da2272c9SKarsten Keil if (ch->bch.nr == 2) { 1244da2272c9SKarsten Keil msg[1] = 1; 1245da2272c9SKarsten Keil msg[3] = 1; 1246da2272c9SKarsten Keil } 1247da2272c9SKarsten Keil switch (ch->bch.state) { 1248da2272c9SKarsten Keil case ISDN_P_NONE: 1249da2272c9SKarsten Keil cmsb = 0; 1250da2272c9SKarsten Keil /* dummy slot */ 1251da2272c9SKarsten Keil msg[1] = ch->dpath + 2; 1252da2272c9SKarsten Keil msg[3] = ch->dpath + 2; 1253da2272c9SKarsten Keil break; 1254da2272c9SKarsten Keil case ISDN_P_B_RAW: 1255da2272c9SKarsten Keil case ISDN_P_B_HDLC: 1256da2272c9SKarsten Keil break; 1257da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 1258da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 1259da2272c9SKarsten Keil cmsb |= IOM_CTRL_RCV; 1260d287c502SGustavo A. R. Silva /* fall through */ 1261da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 1262da2272c9SKarsten Keil if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) 1263da2272c9SKarsten Keil cmsb |= IOM_CTRL_RCV; 1264da2272c9SKarsten Keil cmsb |= IOM_CTRL_ALAW; 1265da2272c9SKarsten Keil break; 1266da2272c9SKarsten Keil } 1267da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); 1268da2272c9SKarsten Keil udelay(1000); 1269da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); 1270da2272c9SKarsten Keil udelay(1000); 1271da2272c9SKarsten Keil } 1272da2272c9SKarsten Keil 1273da2272c9SKarsten Keil static int 1274da2272c9SKarsten Keil modeisar(struct isar_ch *ch, u32 bprotocol) 1275da2272c9SKarsten Keil { 1276da2272c9SKarsten Keil /* Here we are selecting the best datapath for requested protocol */ 1277da2272c9SKarsten Keil if (ch->bch.state == ISDN_P_NONE) { /* New Setup */ 1278da2272c9SKarsten Keil switch (bprotocol) { 1279da2272c9SKarsten Keil case ISDN_P_NONE: /* init */ 1280da2272c9SKarsten Keil if (!ch->dpath) 1281da2272c9SKarsten Keil /* no init for dpath 0 */ 1282da2272c9SKarsten Keil return 0; 1283da2272c9SKarsten Keil test_and_clear_bit(FLG_HDLC, &ch->bch.Flags); 1284da2272c9SKarsten Keil test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags); 1285da2272c9SKarsten Keil break; 1286da2272c9SKarsten Keil case ISDN_P_B_RAW: 1287da2272c9SKarsten Keil case ISDN_P_B_HDLC: 1288da2272c9SKarsten Keil /* best is datapath 2 */ 1289da2272c9SKarsten Keil if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags)) 1290da2272c9SKarsten Keil ch->dpath = 2; 1291da2272c9SKarsten Keil else if (!test_and_set_bit(ISAR_DP1_USE, 1292da2272c9SKarsten Keil &ch->is->Flags)) 1293da2272c9SKarsten Keil ch->dpath = 1; 1294da2272c9SKarsten Keil else { 1295465b1678SMasanari Iida pr_info("modeisar both paths in use\n"); 1296da2272c9SKarsten Keil return -EBUSY; 1297da2272c9SKarsten Keil } 1298da2272c9SKarsten Keil if (bprotocol == ISDN_P_B_HDLC) 1299da2272c9SKarsten Keil test_and_set_bit(FLG_HDLC, &ch->bch.Flags); 1300da2272c9SKarsten Keil else 1301da2272c9SKarsten Keil test_and_set_bit(FLG_TRANSPARENT, 1302da2272c9SKarsten Keil &ch->bch.Flags); 1303da2272c9SKarsten Keil break; 1304da2272c9SKarsten Keil case ISDN_P_B_MODEM_ASYNC: 1305da2272c9SKarsten Keil case ISDN_P_B_T30_FAX: 1306da2272c9SKarsten Keil case ISDN_P_B_L2DTMF: 1307da2272c9SKarsten Keil /* only datapath 1 */ 1308da2272c9SKarsten Keil if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags)) 1309da2272c9SKarsten Keil ch->dpath = 1; 1310da2272c9SKarsten Keil else { 1311da2272c9SKarsten Keil pr_info("%s: ISAR modeisar analog functions" 1312da2272c9SKarsten Keil "only with DP1\n", ch->is->name); 1313da2272c9SKarsten Keil return -EBUSY; 1314da2272c9SKarsten Keil } 1315da2272c9SKarsten Keil break; 1316da2272c9SKarsten Keil default: 1317da2272c9SKarsten Keil pr_info("%s: protocol not known %x\n", ch->is->name, 1318da2272c9SKarsten Keil bprotocol); 1319da2272c9SKarsten Keil return -ENOPROTOOPT; 1320da2272c9SKarsten Keil } 1321da2272c9SKarsten Keil } 1322da2272c9SKarsten Keil pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name, 1323da2272c9SKarsten Keil ch->bch.nr, ch->dpath, ch->bch.state, bprotocol); 1324da2272c9SKarsten Keil ch->bch.state = bprotocol; 1325da2272c9SKarsten Keil setup_pump(ch); 1326da2272c9SKarsten Keil setup_iom2(ch); 1327da2272c9SKarsten Keil setup_sart(ch); 1328da2272c9SKarsten Keil if (ch->bch.state == ISDN_P_NONE) { 1329da2272c9SKarsten Keil /* Clear resources */ 1330da2272c9SKarsten Keil if (ch->dpath == 1) 1331da2272c9SKarsten Keil test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags); 1332da2272c9SKarsten Keil else if (ch->dpath == 2) 1333da2272c9SKarsten Keil test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags); 1334da2272c9SKarsten Keil ch->dpath = 0; 1335da2272c9SKarsten Keil ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr); 1336da2272c9SKarsten Keil } else 1337da2272c9SKarsten Keil ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr); 1338da2272c9SKarsten Keil return 0; 1339da2272c9SKarsten Keil } 1340da2272c9SKarsten Keil 1341da2272c9SKarsten Keil static void 1342da2272c9SKarsten Keil isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para) 1343da2272c9SKarsten Keil { 1344da2272c9SKarsten Keil u8 dps = SET_DPS(ch->dpath); 1345da2272c9SKarsten Keil u8 ctrl = 0, nom = 0, p1 = 0; 1346da2272c9SKarsten Keil 1347da2272c9SKarsten Keil pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n", 1348da2272c9SKarsten Keil ch->is->name, cmd, para, ch->bch.state); 1349da2272c9SKarsten Keil switch (cmd) { 1350da2272c9SKarsten Keil case HW_MOD_FTM: 1351da2272c9SKarsten Keil if (ch->state == STFAX_READY) { 1352da2272c9SKarsten Keil p1 = para; 1353da2272c9SKarsten Keil ctrl = PCTRL_CMD_FTM; 1354da2272c9SKarsten Keil nom = 1; 1355da2272c9SKarsten Keil ch->state = STFAX_LINE; 1356da2272c9SKarsten Keil ch->cmd = ctrl; 1357da2272c9SKarsten Keil ch->mod = para; 1358da2272c9SKarsten Keil ch->newmod = 0; 1359da2272c9SKarsten Keil ch->newcmd = 0; 1360da2272c9SKarsten Keil ch->try_mod = 3; 1361da2272c9SKarsten Keil } else if ((ch->state == STFAX_ACTIV) && 1362da2272c9SKarsten Keil (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para)) 1363da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 1364da2272c9SKarsten Keil else { 1365da2272c9SKarsten Keil ch->newmod = para; 1366da2272c9SKarsten Keil ch->newcmd = PCTRL_CMD_FTM; 1367da2272c9SKarsten Keil nom = 0; 1368da2272c9SKarsten Keil ctrl = PCTRL_CMD_ESC; 1369da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 1370da2272c9SKarsten Keil } 1371da2272c9SKarsten Keil break; 1372da2272c9SKarsten Keil case HW_MOD_FTH: 1373da2272c9SKarsten Keil if (ch->state == STFAX_READY) { 1374da2272c9SKarsten Keil p1 = para; 1375da2272c9SKarsten Keil ctrl = PCTRL_CMD_FTH; 1376da2272c9SKarsten Keil nom = 1; 1377da2272c9SKarsten Keil ch->state = STFAX_LINE; 1378da2272c9SKarsten Keil ch->cmd = ctrl; 1379da2272c9SKarsten Keil ch->mod = para; 1380da2272c9SKarsten Keil ch->newmod = 0; 1381da2272c9SKarsten Keil ch->newcmd = 0; 1382da2272c9SKarsten Keil ch->try_mod = 3; 1383da2272c9SKarsten Keil } else if ((ch->state == STFAX_ACTIV) && 1384da2272c9SKarsten Keil (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para)) 1385da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 1386da2272c9SKarsten Keil else { 1387da2272c9SKarsten Keil ch->newmod = para; 1388da2272c9SKarsten Keil ch->newcmd = PCTRL_CMD_FTH; 1389da2272c9SKarsten Keil nom = 0; 1390da2272c9SKarsten Keil ctrl = PCTRL_CMD_ESC; 1391da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 1392da2272c9SKarsten Keil } 1393da2272c9SKarsten Keil break; 1394da2272c9SKarsten Keil case HW_MOD_FRM: 1395da2272c9SKarsten Keil if (ch->state == STFAX_READY) { 1396da2272c9SKarsten Keil p1 = para; 1397da2272c9SKarsten Keil ctrl = PCTRL_CMD_FRM; 1398da2272c9SKarsten Keil nom = 1; 1399da2272c9SKarsten Keil ch->state = STFAX_LINE; 1400da2272c9SKarsten Keil ch->cmd = ctrl; 1401da2272c9SKarsten Keil ch->mod = para; 1402da2272c9SKarsten Keil ch->newmod = 0; 1403da2272c9SKarsten Keil ch->newcmd = 0; 1404da2272c9SKarsten Keil ch->try_mod = 3; 1405da2272c9SKarsten Keil } else if ((ch->state == STFAX_ACTIV) && 1406da2272c9SKarsten Keil (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para)) 1407da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 1408da2272c9SKarsten Keil else { 1409da2272c9SKarsten Keil ch->newmod = para; 1410da2272c9SKarsten Keil ch->newcmd = PCTRL_CMD_FRM; 1411da2272c9SKarsten Keil nom = 0; 1412da2272c9SKarsten Keil ctrl = PCTRL_CMD_ESC; 1413da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 1414da2272c9SKarsten Keil } 1415da2272c9SKarsten Keil break; 1416da2272c9SKarsten Keil case HW_MOD_FRH: 1417da2272c9SKarsten Keil if (ch->state == STFAX_READY) { 1418da2272c9SKarsten Keil p1 = para; 1419da2272c9SKarsten Keil ctrl = PCTRL_CMD_FRH; 1420da2272c9SKarsten Keil nom = 1; 1421da2272c9SKarsten Keil ch->state = STFAX_LINE; 1422da2272c9SKarsten Keil ch->cmd = ctrl; 1423da2272c9SKarsten Keil ch->mod = para; 1424da2272c9SKarsten Keil ch->newmod = 0; 1425da2272c9SKarsten Keil ch->newcmd = 0; 1426da2272c9SKarsten Keil ch->try_mod = 3; 1427da2272c9SKarsten Keil } else if ((ch->state == STFAX_ACTIV) && 1428da2272c9SKarsten Keil (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para)) 1429da2272c9SKarsten Keil deliver_status(ch, HW_MOD_CONNECT); 1430da2272c9SKarsten Keil else { 1431da2272c9SKarsten Keil ch->newmod = para; 1432da2272c9SKarsten Keil ch->newcmd = PCTRL_CMD_FRH; 1433da2272c9SKarsten Keil nom = 0; 1434da2272c9SKarsten Keil ctrl = PCTRL_CMD_ESC; 1435da2272c9SKarsten Keil ch->state = STFAX_ESCAPE; 1436da2272c9SKarsten Keil } 1437da2272c9SKarsten Keil break; 1438da2272c9SKarsten Keil case PCTRL_CMD_TDTMF: 1439da2272c9SKarsten Keil p1 = para; 1440da2272c9SKarsten Keil nom = 1; 1441da2272c9SKarsten Keil ctrl = PCTRL_CMD_TDTMF; 1442da2272c9SKarsten Keil break; 1443da2272c9SKarsten Keil } 1444da2272c9SKarsten Keil if (ctrl) 1445da2272c9SKarsten Keil send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); 1446da2272c9SKarsten Keil } 1447da2272c9SKarsten Keil 1448da2272c9SKarsten Keil static void 1449da2272c9SKarsten Keil isar_setup(struct isar_hw *isar) 1450da2272c9SKarsten Keil { 1451da2272c9SKarsten Keil u8 msg; 1452da2272c9SKarsten Keil int i; 1453da2272c9SKarsten Keil 1454da2272c9SKarsten Keil /* Dpath 1, 2 */ 1455da2272c9SKarsten Keil msg = 61; 1456da2272c9SKarsten Keil for (i = 0; i < 2; i++) { 1457da2272c9SKarsten Keil /* Buffer Config */ 1458da2272c9SKarsten Keil send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | 1459da2272c9SKarsten Keil ISAR_HIS_P12CFG, 4, 1, &msg); 1460da2272c9SKarsten Keil isar->ch[i].mml = msg; 1461da2272c9SKarsten Keil isar->ch[i].bch.state = 0; 1462da2272c9SKarsten Keil isar->ch[i].dpath = i + 1; 1463da2272c9SKarsten Keil modeisar(&isar->ch[i], ISDN_P_NONE); 1464da2272c9SKarsten Keil } 1465da2272c9SKarsten Keil } 1466da2272c9SKarsten Keil 1467da2272c9SKarsten Keil static int 1468da2272c9SKarsten Keil isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) 1469da2272c9SKarsten Keil { 1470da2272c9SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 1471da2272c9SKarsten Keil struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 1472da2272c9SKarsten Keil int ret = -EINVAL; 1473da2272c9SKarsten Keil struct mISDNhead *hh = mISDN_HEAD_P(skb); 1474da2272c9SKarsten Keil u32 id, *val; 1475da2272c9SKarsten Keil u_long flags; 1476da2272c9SKarsten Keil 1477da2272c9SKarsten Keil switch (hh->prim) { 1478da2272c9SKarsten Keil case PH_DATA_REQ: 1479da2272c9SKarsten Keil spin_lock_irqsave(ich->is->hwlock, flags); 1480da2272c9SKarsten Keil ret = bchannel_senddata(bch, skb); 1481da2272c9SKarsten Keil if (ret > 0) { /* direct TX */ 1482da2272c9SKarsten Keil ret = 0; 1483da2272c9SKarsten Keil isar_fill_fifo(ich); 14848bfddfbeSKarsten Keil } 1485da2272c9SKarsten Keil spin_unlock_irqrestore(ich->is->hwlock, flags); 1486da2272c9SKarsten Keil return ret; 1487da2272c9SKarsten Keil case PH_ACTIVATE_REQ: 1488da2272c9SKarsten Keil spin_lock_irqsave(ich->is->hwlock, flags); 1489da2272c9SKarsten Keil if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) 1490da2272c9SKarsten Keil ret = modeisar(ich, ch->protocol); 1491da2272c9SKarsten Keil else 1492da2272c9SKarsten Keil ret = 0; 1493da2272c9SKarsten Keil spin_unlock_irqrestore(ich->is->hwlock, flags); 1494da2272c9SKarsten Keil if (!ret) 1495da2272c9SKarsten Keil _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 1496da2272c9SKarsten Keil NULL, GFP_KERNEL); 1497da2272c9SKarsten Keil break; 1498da2272c9SKarsten Keil case PH_DEACTIVATE_REQ: 1499da2272c9SKarsten Keil spin_lock_irqsave(ich->is->hwlock, flags); 1500da2272c9SKarsten Keil mISDN_clear_bchannel(bch); 1501da2272c9SKarsten Keil modeisar(ich, ISDN_P_NONE); 1502da2272c9SKarsten Keil spin_unlock_irqrestore(ich->is->hwlock, flags); 1503da2272c9SKarsten Keil _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, 1504da2272c9SKarsten Keil NULL, GFP_KERNEL); 1505da2272c9SKarsten Keil ret = 0; 1506da2272c9SKarsten Keil break; 1507da2272c9SKarsten Keil case PH_CONTROL_REQ: 1508da2272c9SKarsten Keil val = (u32 *)skb->data; 1509da2272c9SKarsten Keil pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name, 1510da2272c9SKarsten Keil hh->id, *val); 1511da2272c9SKarsten Keil if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) == 1512da2272c9SKarsten Keil DTMF_TONE_VAL)) { 1513da2272c9SKarsten Keil if (bch->state == ISDN_P_B_L2DTMF) { 1514da2272c9SKarsten Keil char tt = *val & DTMF_TONE_MASK; 1515da2272c9SKarsten Keil 1516da2272c9SKarsten Keil if (tt == '*') 1517da2272c9SKarsten Keil tt = 0x1e; 1518da2272c9SKarsten Keil else if (tt == '#') 1519da2272c9SKarsten Keil tt = 0x1f; 1520da2272c9SKarsten Keil else if (tt > '9') 1521da2272c9SKarsten Keil tt -= 7; 1522da2272c9SKarsten Keil tt &= 0x1f; 1523da2272c9SKarsten Keil spin_lock_irqsave(ich->is->hwlock, flags); 1524da2272c9SKarsten Keil isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt); 1525da2272c9SKarsten Keil spin_unlock_irqrestore(ich->is->hwlock, flags); 1526da2272c9SKarsten Keil } else { 1527da2272c9SKarsten Keil pr_info("%s: DTMF send wrong protocol %x\n", 1528da2272c9SKarsten Keil __func__, bch->state); 1529da2272c9SKarsten Keil return -EINVAL; 1530da2272c9SKarsten Keil } 1531da2272c9SKarsten Keil } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) || 1532da2272c9SKarsten Keil (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) { 1533da2272c9SKarsten Keil for (id = 0; id < FAXMODCNT; id++) 1534da2272c9SKarsten Keil if (faxmodulation[id] == *val) 1535da2272c9SKarsten Keil break; 1536da2272c9SKarsten Keil if ((FAXMODCNT > id) && 1537da2272c9SKarsten Keil test_bit(FLG_INITIALIZED, &bch->Flags)) { 1538da2272c9SKarsten Keil pr_debug("%s: isar: new mod\n", ich->is->name); 1539da2272c9SKarsten Keil isar_pump_cmd(ich, hh->id, *val); 1540da2272c9SKarsten Keil ret = 0; 1541da2272c9SKarsten Keil } else { 1542da2272c9SKarsten Keil pr_info("%s: wrong modulation\n", 1543da2272c9SKarsten Keil ich->is->name); 1544da2272c9SKarsten Keil ret = -EINVAL; 1545da2272c9SKarsten Keil } 1546da2272c9SKarsten Keil } else if (hh->id == HW_MOD_LASTDATA) 1547da2272c9SKarsten Keil test_and_set_bit(FLG_DLEETX, &bch->Flags); 1548da2272c9SKarsten Keil else { 1549da2272c9SKarsten Keil pr_info("%s: unknown PH_CONTROL_REQ %x\n", 1550da2272c9SKarsten Keil ich->is->name, hh->id); 1551da2272c9SKarsten Keil ret = -EINVAL; 1552da2272c9SKarsten Keil } 1553d287c502SGustavo A. R. Silva /* fall through */ 1554da2272c9SKarsten Keil default: 1555da2272c9SKarsten Keil pr_info("%s: %s unknown prim(%x,%x)\n", 1556da2272c9SKarsten Keil ich->is->name, __func__, hh->prim, hh->id); 1557da2272c9SKarsten Keil ret = -EINVAL; 1558da2272c9SKarsten Keil } 1559da2272c9SKarsten Keil if (!ret) 1560da2272c9SKarsten Keil dev_kfree_skb(skb); 1561da2272c9SKarsten Keil return ret; 1562da2272c9SKarsten Keil } 1563da2272c9SKarsten Keil 1564da2272c9SKarsten Keil static int 1565da2272c9SKarsten Keil channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 1566da2272c9SKarsten Keil { 1567034005a0SKarsten Keil return mISDN_ctrl_bchannel(bch, cq); 1568da2272c9SKarsten Keil } 1569da2272c9SKarsten Keil 1570da2272c9SKarsten Keil static int 1571da2272c9SKarsten Keil isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) 1572da2272c9SKarsten Keil { 1573da2272c9SKarsten Keil struct bchannel *bch = container_of(ch, struct bchannel, ch); 1574da2272c9SKarsten Keil struct isar_ch *ich = container_of(bch, struct isar_ch, bch); 1575da2272c9SKarsten Keil int ret = -EINVAL; 1576da2272c9SKarsten Keil u_long flags; 1577da2272c9SKarsten Keil 1578da2272c9SKarsten Keil pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg); 1579da2272c9SKarsten Keil switch (cmd) { 1580da2272c9SKarsten Keil case CLOSE_CHANNEL: 1581da2272c9SKarsten Keil test_and_clear_bit(FLG_OPEN, &bch->Flags); 15824b921edaSKarsten Keil cancel_work_sync(&bch->workq); 1583da2272c9SKarsten Keil spin_lock_irqsave(ich->is->hwlock, flags); 15844b921edaSKarsten Keil mISDN_clear_bchannel(bch); 1585da2272c9SKarsten Keil modeisar(ich, ISDN_P_NONE); 1586da2272c9SKarsten Keil spin_unlock_irqrestore(ich->is->hwlock, flags); 1587da2272c9SKarsten Keil ch->protocol = ISDN_P_NONE; 1588da2272c9SKarsten Keil ch->peer = NULL; 1589da2272c9SKarsten Keil module_put(ich->is->owner); 1590da2272c9SKarsten Keil ret = 0; 1591da2272c9SKarsten Keil break; 1592da2272c9SKarsten Keil case CONTROL_CHANNEL: 1593da2272c9SKarsten Keil ret = channel_bctrl(bch, arg); 1594da2272c9SKarsten Keil break; 1595da2272c9SKarsten Keil default: 1596da2272c9SKarsten Keil pr_info("%s: %s unknown prim(%x)\n", 1597da2272c9SKarsten Keil ich->is->name, __func__, cmd); 1598da2272c9SKarsten Keil } 1599da2272c9SKarsten Keil return ret; 1600da2272c9SKarsten Keil } 1601da2272c9SKarsten Keil 1602da2272c9SKarsten Keil static void 1603da2272c9SKarsten Keil free_isar(struct isar_hw *isar) 1604da2272c9SKarsten Keil { 1605da2272c9SKarsten Keil modeisar(&isar->ch[0], ISDN_P_NONE); 1606da2272c9SKarsten Keil modeisar(&isar->ch[1], ISDN_P_NONE); 1607da2272c9SKarsten Keil del_timer(&isar->ch[0].ftimer); 1608da2272c9SKarsten Keil del_timer(&isar->ch[1].ftimer); 1609da2272c9SKarsten Keil test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 1610da2272c9SKarsten Keil test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 1611da2272c9SKarsten Keil } 1612da2272c9SKarsten Keil 1613da2272c9SKarsten Keil static int 1614da2272c9SKarsten Keil init_isar(struct isar_hw *isar) 1615da2272c9SKarsten Keil { 1616da2272c9SKarsten Keil int cnt = 3; 1617da2272c9SKarsten Keil 1618da2272c9SKarsten Keil while (cnt--) { 1619da2272c9SKarsten Keil isar->version = ISARVersion(isar); 1620da2272c9SKarsten Keil if (isar->ch[0].bch.debug & DEBUG_HW) 1621da2272c9SKarsten Keil pr_notice("%s: Testing version %d (%d time)\n", 1622da2272c9SKarsten Keil isar->name, isar->version, 3 - cnt); 1623da2272c9SKarsten Keil if (isar->version == 1) 1624da2272c9SKarsten Keil break; 1625da2272c9SKarsten Keil isar->ctrl(isar->hw, HW_RESET_REQ, 0); 1626da2272c9SKarsten Keil } 1627da2272c9SKarsten Keil if (isar->version != 1) 1628da2272c9SKarsten Keil return -EINVAL; 1629e99e88a9SKees Cook timer_setup(&isar->ch[0].ftimer, ftimer_handler, 0); 1630da2272c9SKarsten Keil test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags); 1631e99e88a9SKees Cook timer_setup(&isar->ch[1].ftimer, ftimer_handler, 0); 1632da2272c9SKarsten Keil test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags); 1633da2272c9SKarsten Keil return 0; 1634da2272c9SKarsten Keil } 1635da2272c9SKarsten Keil 1636da2272c9SKarsten Keil static int 1637da2272c9SKarsten Keil isar_open(struct isar_hw *isar, struct channel_req *rq) 1638da2272c9SKarsten Keil { 1639da2272c9SKarsten Keil struct bchannel *bch; 1640da2272c9SKarsten Keil 1641819a1008SDan Carpenter if (rq->adr.channel == 0 || rq->adr.channel > 2) 1642da2272c9SKarsten Keil return -EINVAL; 1643da2272c9SKarsten Keil if (rq->protocol == ISDN_P_NONE) 1644da2272c9SKarsten Keil return -EINVAL; 1645da2272c9SKarsten Keil bch = &isar->ch[rq->adr.channel - 1].bch; 1646da2272c9SKarsten Keil if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 1647da2272c9SKarsten Keil return -EBUSY; /* b-channel can be only open once */ 1648da2272c9SKarsten Keil bch->ch.protocol = rq->protocol; 1649da2272c9SKarsten Keil rq->ch = &bch->ch; 1650da2272c9SKarsten Keil return 0; 1651da2272c9SKarsten Keil } 1652da2272c9SKarsten Keil 1653da2272c9SKarsten Keil u32 1654da2272c9SKarsten Keil mISDNisar_init(struct isar_hw *isar, void *hw) 1655da2272c9SKarsten Keil { 1656da2272c9SKarsten Keil u32 ret, i; 1657da2272c9SKarsten Keil 1658da2272c9SKarsten Keil isar->hw = hw; 1659da2272c9SKarsten Keil for (i = 0; i < 2; i++) { 1660da2272c9SKarsten Keil isar->ch[i].bch.nr = i + 1; 1661034005a0SKarsten Keil mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); 1662da2272c9SKarsten Keil isar->ch[i].bch.ch.nr = i + 1; 1663da2272c9SKarsten Keil isar->ch[i].bch.ch.send = &isar_l2l1; 1664da2272c9SKarsten Keil isar->ch[i].bch.ch.ctrl = isar_bctrl; 1665da2272c9SKarsten Keil isar->ch[i].bch.hw = hw; 1666da2272c9SKarsten Keil isar->ch[i].is = isar; 1667da2272c9SKarsten Keil } 1668da2272c9SKarsten Keil 1669da2272c9SKarsten Keil isar->init = &init_isar; 1670da2272c9SKarsten Keil isar->release = &free_isar; 1671da2272c9SKarsten Keil isar->firmware = &load_firmware; 1672da2272c9SKarsten Keil isar->open = &isar_open; 1673da2272c9SKarsten Keil 1674da2272c9SKarsten Keil ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 1675da2272c9SKarsten Keil (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) | 1676da2272c9SKarsten Keil (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) | 1677da2272c9SKarsten Keil (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) | 1678da2272c9SKarsten Keil (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK)); 1679da2272c9SKarsten Keil 1680da2272c9SKarsten Keil return ret; 1681da2272c9SKarsten Keil } 1682da2272c9SKarsten Keil EXPORT_SYMBOL(mISDNisar_init); 1683da2272c9SKarsten Keil 168488850740SPeter Huewe static int __init isar_mod_init(void) 1685da2272c9SKarsten Keil { 1686da2272c9SKarsten Keil pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV); 1687da2272c9SKarsten Keil return 0; 1688da2272c9SKarsten Keil } 1689da2272c9SKarsten Keil 169088850740SPeter Huewe static void __exit isar_mod_cleanup(void) 1691da2272c9SKarsten Keil { 1692da2272c9SKarsten Keil pr_notice("mISDN: ISAR module unloaded\n"); 1693da2272c9SKarsten Keil } 1694da2272c9SKarsten Keil module_init(isar_mod_init); 1695da2272c9SKarsten Keil module_exit(isar_mod_cleanup); 1696