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