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