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