1a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil/*
2a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * NETJet mISDN driver
3a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
4a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * Author       Karsten Keil <keil@isdn4linux.de>
5a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
6a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * Copyright 2009  by Karsten Keil <keil@isdn4linux.de>
7a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
8a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * This program is free software; you can redistribute it and/or modify
9a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * it under the terms of the GNU General Public License version 2 as
10a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * published by the Free Software Foundation.
11a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
12a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * This program is distributed in the hope that it will be useful,
13a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of
14a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * GNU General Public License for more details.
16a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
17a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * You should have received a copy of the GNU General Public License
18a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * along with this program; if not, write to the Free Software
19a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil *
21a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil */
22a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
23a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
24a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include <linux/module.h>
25a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include <linux/pci.h>
26a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include <linux/delay.h>
27a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include <linux/mISDNhw.h>
285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
29a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include "ipac.h"
30a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include "iohelper.h"
31a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include "netjet.h"
32a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#include <linux/isdn/hdlc.h>
33a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
34a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define NETJET_REV	"2.0"
35a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
36a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilenum nj_types {
37a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	NETJET_S_TJ300,
38a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	NETJET_S_TJ320,
39a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ENTERNOW__TJ320,
40a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
41a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
42a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstruct tiger_dma {
43a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	size_t		size;
44a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32		*start;
45a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int		idx;
46a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32		dmastart;
47a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32		dmairq;
48a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32		dmaend;
49a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32		dmacur;
50a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
51a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
52a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstruct tiger_hw;
53a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
54a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstruct tiger_ch {
55a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct bchannel		bch;
56a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw		*nj;
57a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int			idx;
58a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int			free;
59a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int			lastrx;
60a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u16			rxstate;
61a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u16			txstate;
62a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct isdnhdlc_vars	hsend;
63a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct isdnhdlc_vars	hrecv;
64a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			*hsbuf;
65a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			*hrbuf;
66a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
67a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
68a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define TX_INIT		0x0001
69a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define TX_IDLE		0x0002
70a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define TX_RUN		0x0004
71a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define TX_UNDERRUN	0x0100
72a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define RX_OVERRUN	0x0100
73a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
74a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil#define LOG_SIZE	64
75a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
76a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstruct tiger_hw {
77a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct list_head	list;
78a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct pci_dev		*pdev;
79a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	char			name[MISDN_MAX_IDLEN];
80a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	enum nj_types		typ;
81a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int			irq;
82a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32			irqcnt;
83a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32			base;
84a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	size_t			base_s;
85a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	dma_addr_t		dma;
86a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	void			*dma_p;
87a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spinlock_t		lock;	/* lock HW */
88a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct isac_hw		isac;
89a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_dma	send;
90a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_dma	recv;
91a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_ch		bc[2];
92a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			ctrlreg;
93a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			dmactrl;
94a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			auxd;
95a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			last_is0;
96a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8			irqmask0;
97a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	char			log[LOG_SIZE];
98a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
99a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
100a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic LIST_HEAD(Cards);
101a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic DEFINE_RWLOCK(card_lock); /* protect Cards */
102a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic u32 debug;
103a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int nj_cnt;
104a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
105a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
106a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil_set_debug(struct tiger_hw *card)
107a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
108a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->isac.dch.debug = debug;
109a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->bc[0].bch.debug = debug;
110a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->bc[1].bch.debug = debug;
111a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
112a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
113a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
114a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilset_debug(const char *val, struct kernel_param *kp)
115a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
116a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret;
117a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card;
118a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
119a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ret = param_set_uint(val, kp);
120a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!ret) {
121a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		read_lock(&card_lock);
122a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		list_for_each_entry(card, &Cards, list)
123a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			_set_debug(card);
124a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		read_unlock(&card_lock);
125a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
126a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
127a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
128a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
129a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilMODULE_AUTHOR("Karsten Keil");
130a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilMODULE_LICENSE("GPL v2");
131a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilMODULE_VERSION(NETJET_REV);
132a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilmodule_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
133a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilMODULE_PARM_DESC(debug, "Netjet debug mask");
134a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
135a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
136a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_disable_hwirq(struct tiger_hw *card)
137a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
138a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(0, card->base + NJ_IRQMASK0);
139a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(0, card->base + NJ_IRQMASK1);
140a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
141a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
142a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
143a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic u8
144a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilReadISAC_nj(void *p, u8 offset)
145a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
146a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = p;
147a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8 ret;
148a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
149a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd &= 0xfc;
150a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd |= (offset >> 4) & 3;
151a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->auxd, card->base + NJ_AUXDATA);
152a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
153a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
154a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
155a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
156a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
157a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilWriteISAC_nj(void *p, u8 offset, u8 value)
158a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
159a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = p;
160a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
161a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd &= 0xfc;
162a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd |= (offset >> 4) & 3;
163a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->auxd, card->base + NJ_AUXDATA);
164a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
165a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
166a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
167a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
168a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
169a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
170a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = p;
171a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
172a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd &= 0xfc;
173a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->auxd, card->base + NJ_AUXDATA);
174a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	insb(card->base + NJ_ISAC_OFF, data, size);
175a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
176a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
177a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
178a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilWriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
179a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
180a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = p;
181a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
182a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd &= 0xfc;
183a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->auxd, card->base + NJ_AUXDATA);
184a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outsb(card->base + NJ_ISAC_OFF, data, size);
185a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
186a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
187a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
188a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilfill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)
189a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
190a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bc->bch.hw;
191a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 mask = 0xff, val;
192a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
193a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,
194475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 bc->bch.nr, fill, cnt, idx, card->send.idx);
195a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->bch.nr & 2) {
196a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		fill  <<= 8;
197a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mask <<= 8;
198a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
199a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mask ^= 0xffffffff;
200a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	while (cnt--) {
201a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		val = card->send.start[idx];
202a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		val &= mask;
203a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		val |= fill;
204a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->send.start[idx++] = val;
205a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (idx >= card->send.size)
206a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			idx = 0;
207a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
208a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
209a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
210a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
211a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilmode_tiger(struct tiger_ch *bc, u32 protocol)
212a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
213a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bc->bch.hw;
214a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
215a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: B%1d protocol %x-->%x\n", card->name,
216475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 bc->bch.nr, bc->bch.state, protocol);
217a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (protocol) {
218a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case ISDN_P_NONE:
219a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (bc->bch.state == ISDN_P_NONE)
220a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			break;
221a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		fill_mem(bc, 0, card->send.size, 0xff);
222a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.state = protocol;
223a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		/* only stop dma and interrupts if both channels NULL */
224a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if ((card->bc[0].bch.state == ISDN_P_NONE) &&
225a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		    (card->bc[1].bch.state == ISDN_P_NONE)) {
226a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->dmactrl = 0;
227a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(card->dmactrl, card->base + NJ_DMACTRL);
228a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(0, card->base + NJ_IRQMASK0);
229a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
230a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);
231a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);
232a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->txstate = 0;
233a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->rxstate = 0;
234a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->lastrx = -1;
235a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
236a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case ISDN_P_B_RAW:
237a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);
238a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.state = protocol;
239a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->idx = 0;
240475be4d85a274d0961593db41cf85689db1d583cJoe Perches		bc->free = card->send.size / 2;
241a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->rxstate = 0;
242a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->txstate = TX_INIT | TX_IDLE;
243a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->lastrx = -1;
244a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!card->dmactrl) {
245a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->dmactrl = 1;
246a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(card->dmactrl, card->base + NJ_DMACTRL);
247a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(0x0f, card->base + NJ_IRQMASK0);
248a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
249a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
250a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case ISDN_P_B_HDLC:
251a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		test_and_set_bit(FLG_HDLC, &bc->bch.Flags);
252a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.state = protocol;
253a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->idx = 0;
254475be4d85a274d0961593db41cf85689db1d583cJoe Perches		bc->free = card->send.size / 2;
255a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->rxstate = 0;
256a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->txstate = TX_INIT | TX_IDLE;
257a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		isdnhdlc_rcv_init(&bc->hrecv, 0);
258a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		isdnhdlc_out_init(&bc->hsend, 0);
259a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->lastrx = -1;
260a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!card->dmactrl) {
261a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->dmactrl = 1;
262a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(card->dmactrl, card->base + NJ_DMACTRL);
263a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			outb(0x0f, card->base + NJ_IRQMASK0);
264a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
265a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
266a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	default:
267a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: %s protocol %x not handled\n", card->name,
268a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			__func__, protocol);
269a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -ENOPROTOOPT;
270a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
271a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);
272a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);
273a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
274a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
275a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s ctrl %x irq  %02x/%02x idx %d/%d\n",
276475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 card->name, __func__,
277475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 inb(card->base + NJ_DMACTRL),
278475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 inb(card->base + NJ_IRQMASK0),
279475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 inb(card->base + NJ_IRQSTAT0),
280475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 card->send.idx,
281475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 card->recv.idx);
282a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return 0;
283a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
284a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
285a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
286a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_reset(struct tiger_hw *card)
287a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
288a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(0xff, card->base + NJ_CTRL); /* Reset On */
289a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mdelay(1);
290a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
291a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* now edge triggered for TJ320 GE 13/07/00 */
292a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* see comment in IRQ function */
293a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->typ == NETJET_S_TJ320) /* TJ320 */
294a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->ctrlreg = 0x40;  /* Reset Off and status read clear */
295a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
296a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->ctrlreg = 0x00;  /* Reset Off and status read clear */
297a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->ctrlreg, card->base + NJ_CTRL);
298a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mdelay(10);
299a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
300a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* configure AUX pins (all output except ISAC IRQ pin) */
301a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->auxd = 0;
302a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->dmactrl = 0;
303a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);
304a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(NJ_ISACIRQ,  card->base + NJ_IRQMASK1);
305a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outb(card->auxd, card->base + NJ_AUXDATA);
306a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
307a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
308a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
309a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilinittiger(struct tiger_hw *card)
310a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
311a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int i;
312a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
313a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE,
314475be4d85a274d0961593db41cf85689db1d583cJoe Perches					   &card->dma);
315a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!card->dma_p) {
316a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: No DMA memory\n", card->name);
317a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -ENOMEM;
318a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
319a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if ((u64)card->dma > 0xffffffff) {
320a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: DMA outside 32 bit\n", card->name);
321a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -ENOMEM;
322a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
323a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < 2; i++) {
324b42d9165e1e3d92e4e3318642463dbe592a12568Julia Lawall		card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC);
325a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!card->bc[i].hsbuf) {
326a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: no B%d send buffer\n", card->name, i + 1);
327a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return -ENOMEM;
328a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
329b42d9165e1e3d92e4e3318642463dbe592a12568Julia Lawall		card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC);
330a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!card->bc[i].hrbuf) {
331a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
332a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return -ENOMEM;
333a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
334a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
335a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	memset(card->dma_p, 0xff, NJ_DMA_SIZE);
336a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
337a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.start = card->dma_p;
338a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmastart = (u32)card->dma;
339a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmaend = card->send.dmastart +
340a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		(4 * (NJ_DMA_TXSIZE - 1));
341a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmairq = card->send.dmastart +
342a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		(4 * ((NJ_DMA_TXSIZE / 2) - 1));
343a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.size = NJ_DMA_TXSIZE;
344a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
345a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (debug & DEBUG_HW)
346a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_notice("%s: send buffer phy %#x - %#x - %#x  virt %p"
347475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  " size %zu u32\n", card->name,
348475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  card->send.dmastart, card->send.dmairq,
349475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  card->send.dmaend, card->send.start, card->send.size);
350a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
351a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->send.dmastart, card->base + NJ_DMA_READ_START);
352a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);
353a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->send.dmaend, card->base + NJ_DMA_READ_END);
354a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
355a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);
356a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.dmastart = (u32)card->dma  + (NJ_DMA_SIZE / 2);
357a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.dmaend = card->recv.dmastart +
358a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		(4 * (NJ_DMA_RXSIZE - 1));
359a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.dmairq = card->recv.dmastart +
360a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		(4 * ((NJ_DMA_RXSIZE / 2) - 1));
361a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.size = NJ_DMA_RXSIZE;
362a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
363a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (debug & DEBUG_HW)
364a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_notice("%s: recv buffer phy %#x - %#x - %#x  virt %p"
365475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  " size %zu u32\n", card->name,
366475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  card->recv.dmastart, card->recv.dmairq,
367475be4d85a274d0961593db41cf85689db1d583cJoe Perches			  card->recv.dmaend, card->recv.start, card->recv.size);
368a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
369a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);
370a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);
371a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);
372a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return 0;
373a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
374a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
375a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
376a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilread_dma(struct tiger_ch *bc, u32 idx, int cnt)
377a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
378a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bc->bch.hw;
379a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int i, stat;
380a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 val;
381a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8 *p, *pn;
382a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
383a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->lastrx == idx) {
384a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->rxstate |= RX_OVERRUN;
385a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: B%1d overrun at idx %d\n", card->name,
386a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			bc->bch.nr, idx);
387a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
388a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bc->lastrx = idx;
389a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!bc->bch.rx_skb) {
390a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);
391a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!bc->bch.rx_skb) {
392a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: B%1d receive out of memory\n",
393a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				card->name, bc->bch.nr);
394a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return;
395a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
396a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
397a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
398a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
399a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {
400a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_debug("%s: B%1d overrun %d\n", card->name,
401475be4d85a274d0961593db41cf85689db1d583cJoe Perches				 bc->bch.nr, bc->bch.rx_skb->len + cnt);
402a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			skb_trim(bc->bch.rx_skb, 0);
403a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return;
404a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
405a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		p = skb_put(bc->bch.rx_skb, cnt);
406a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	} else
407a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		p = bc->hrbuf;
408a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
409a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < cnt; i++) {
410a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		val = card->recv.start[idx++];
411a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (bc->bch.nr & 2)
412a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			val >>= 8;
413a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (idx >= card->recv.size)
414a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			idx = 0;
415a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		p[i] = val & 0xff;
416a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
417a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pn = bc->hrbuf;
418a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnext_frame:
419a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
420a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
421475be4d85a274d0961593db41cf85689db1d583cJoe Perches				       bc->bch.rx_skb->data, bc->bch.maxlen);
422475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (stat > 0) /* valid frame received */
423a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			p = skb_put(bc->bch.rx_skb, stat);
424a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else if (stat == -HDLC_CRC_ERROR)
425a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: B%1d receive frame CRC error\n",
426a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				card->name, bc->bch.nr);
427a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else if (stat == -HDLC_FRAMING_ERROR)
428a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: B%1d receive framing error\n",
429a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				card->name, bc->bch.nr);
430a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else if (stat == -HDLC_LENGTH_ERROR)
431a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: B%1d receive frame too long (> %d)\n",
432a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				card->name, bc->bch.nr, bc->bch.maxlen);
433a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	} else
434475be4d85a274d0961593db41cf85689db1d583cJoe Perches		stat = cnt;
435a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
436a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (stat > 0) {
437a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (debug & DEBUG_HW_BFIFO) {
438a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",
439475be4d85a274d0961593db41cf85689db1d583cJoe Perches				 bc->bch.nr, card->name, stat);
440a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,
441475be4d85a274d0961593db41cf85689db1d583cJoe Perches					     p, stat);
442a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
443a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		recv_Bchannel(&bc->bch, 0);
444a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
445a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
446a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pn += i;
447a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		cnt -= i;
448a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!bc->bch.rx_skb) {
449a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,
450475be4d85a274d0961593db41cf85689db1d583cJoe Perches						      GFP_ATOMIC);
451a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			if (!bc->bch.rx_skb) {
452a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				pr_info("%s: B%1d receive out of memory\n",
453a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil					card->name, bc->bch.nr);
454a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				return;
455a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			}
456a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
457a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (cnt > 0)
458a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			goto next_frame;
459a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
460a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
461a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
462a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
463a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilrecv_tiger(struct tiger_hw *card, u8 irq_stat)
464a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
465a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 idx;
466a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int cnt = card->recv.size / 2;
467a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
468a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* Note receive is via the WRITE DMA channel */
469a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->last_is0 &= ~NJ_IRQM0_WR_MASK;
470a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);
471a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
472a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (irq_stat & NJ_IRQM0_WR_END)
473a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		idx = cnt - 1;
474a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
475a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		idx = card->recv.size - 1;
476a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
477a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))
478a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		read_dma(&card->bc[0], idx, cnt);
479a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))
480a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		read_dma(&card->bc[1], idx, cnt);
481a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
482a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
483a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil/* sync with current DMA address at start or after exception */
484a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
485a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilresync(struct tiger_ch *bc, struct tiger_hw *card)
486a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
487a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
488a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
489a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->free > card->send.size / 2)
490a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->free = card->send.size / 2;
491a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* currently we simple sync to the next complete free area
492a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 * this hast the advantage that we have always maximum time to
493a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 * handle TX irq
494a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 */
495a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->send.idx < ((card->send.size / 2) - 1))
496a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->idx = (card->recv.size / 2) - 1;
497a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
498a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->idx = card->recv.size - 1;
499a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bc->txstate = TX_RUN;
500a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,
501475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);
502a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
503a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
504a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int bc_next_frame(struct tiger_ch *);
505a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
506a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
507a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilfill_hdlc_flag(struct tiger_ch *bc)
508a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
509a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bc->bch.hw;
510a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int count, i;
511a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 m, v;
512a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8  *p;
513a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
514a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->free == 0)
515a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return;
516a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,
517475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 __func__, bc->bch.nr, bc->free, bc->txstate,
518475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 bc->idx, card->send.idx);
519a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
520a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		resync(bc, card);
521a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,
522475be4d85a274d0961593db41cf85689db1d583cJoe Perches				bc->hsbuf, bc->free);
523a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,
524475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 bc->bch.nr, count);
525a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bc->free -= count;
526a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	p = bc->hsbuf;
527a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
528a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < count; i++) {
529a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (bc->idx >= card->send.size)
530a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			bc->idx = 0;
531a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v = card->send.start[bc->idx];
532a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v &= m;
533a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
534a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->send.start[bc->idx++] = v;
535a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
536a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (debug & DEBUG_HW_BFIFO) {
537a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
538475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 bc->bch.nr, card->name, count);
539a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
540a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
541a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
542a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
543a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
544a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilfill_dma(struct tiger_ch *bc)
545a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
546a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bc->bch.hw;
547a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int count, i;
548a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 m, v;
549a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8  *p;
550a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
551a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->free == 0)
552a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return;
553a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	count = bc->bch.tx_skb->len - bc->bch.tx_idx;
554a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (count <= 0)
555a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return;
556a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,
557475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,
558475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);
559a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
560a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		resync(bc, card);
561a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	p = bc->bch.tx_skb->data + bc->bch.tx_idx;
562a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
563a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		count = isdnhdlc_encode(&bc->hsend, p, count, &i,
564475be4d85a274d0961593db41cf85689db1d583cJoe Perches					bc->hsbuf, bc->free);
565a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
566475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 bc->bch.nr, i, count);
567a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.tx_idx += i;
568a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->free -= count;
569a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		p = bc->hsbuf;
570a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	} else {
571a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (count > bc->free)
572a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			count = bc->free;
573a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->bch.tx_idx += count;
574a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->free -= count;
575a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
576a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
577a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < count; i++) {
578a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (bc->idx >= card->send.size)
579a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			bc->idx = 0;
580a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v = card->send.start[bc->idx];
581a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v &= m;
582a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
583a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->send.start[bc->idx++] = v;
584a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
585a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (debug & DEBUG_HW_BFIFO) {
586a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
587475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 bc->bch.nr, card->name, count);
588a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
589a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
590a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->free)
591a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc_next_frame(bc);
592a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
593a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
594a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
595a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
596a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilbc_next_frame(struct tiger_ch *bc)
597a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
598a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)
599a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		fill_dma(bc);
600a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else {
601a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (bc->bch.tx_skb) {
602a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			/* send confirm, on trans, free on hdlc. */
603a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
604a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				confirm_Bsend(&bc->bch);
605a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			dev_kfree_skb(bc->bch.tx_skb);
606a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
607a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (get_next_bframe(&bc->bch))
608a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			fill_dma(bc);
609a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else
610a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return 0;
611a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
612a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return 1;
613a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
614a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
615a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
616a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilsend_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)
617a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
618a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret;
619a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
620a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bc->free += card->send.size / 2;
621a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (bc->free >= card->send.size) {
622a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {
623a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: B%1d TX underrun state %x\n", card->name,
624a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				bc->bch.nr, bc->txstate);
625a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			bc->txstate |= TX_UNDERRUN;
626a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
627a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		bc->free = card->send.size;
628a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
629a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ret = bc_next_frame(bc);
630a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!ret) {
631a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
632a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			fill_hdlc_flag(bc);
633a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			return;
634a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
635a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,
636475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 bc->bch.nr, bc->free, bc->idx, card->send.idx);
637a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!(bc->txstate & (TX_IDLE | TX_INIT))) {
638a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			fill_mem(bc, bc->idx, bc->free, 0xff);
639a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			if (bc->free == card->send.size)
640a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				bc->txstate |= TX_IDLE;
641a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
642a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
643a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
644a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
645a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
646a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilsend_tiger(struct tiger_hw *card, u8 irq_stat)
647a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
648a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int i;
649a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
650a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* Note send is via the READ DMA channel */
651a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {
652a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: tiger warn write double dma %x/%x\n",
653a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->name, irq_stat, card->last_is0);
654a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return;
655a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	} else {
656a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->last_is0 &= ~NJ_IRQM0_RD_MASK;
657a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);
658a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
659a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < 2; i++) {
660a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))
661a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			send_tiger_bc(card, &card->bc[i]);
662a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
663a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
664a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
665a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic irqreturn_t
666a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_irq(int intno, void *dev_id)
667a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
668a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = dev_id;
669a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u8 val, s1val, s0val;
670a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
671a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_lock(&card->lock);
672a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	s0val = inb(card->base | NJ_IRQSTAT0);
673a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	s1val = inb(card->base | NJ_IRQSTAT1);
674a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {
675a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		/* shared IRQ */
676a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_unlock(&card->lock);
677a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return IRQ_NONE;
678a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
679a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);
680a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->irqcnt++;
681a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!(s1val & NJ_ISACIRQ)) {
682a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		val = ReadISAC_nj(card, ISAC_ISTA);
683a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (val)
684a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			mISDNisac_irq(&card->isac, val);
685a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
686a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
687a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (s0val)
688a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		/* write to clear */
689a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		outb(s0val, card->base | NJ_IRQSTAT0);
690a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
691a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		goto end;
692a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	s1val = s0val;
693a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* set bits in sval to indicate which page is free */
694a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);
695a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
696a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->recv.dmacur < card->recv.dmairq)
697a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		s0val = 0x08;	/* the 2nd write area is free */
698a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
699a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		s0val = 0x04;	/* the 1st write area is free */
700a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
701a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
702a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
703a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->send.dmacur < card->send.dmairq)
704a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		s0val |= 0x02;	/* the 2nd read area is free */
705a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
706a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		s0val |= 0x01;	/* the 1st read area is free */
707a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
708a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,
709475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 s1val, s0val, card->last_is0,
710475be4d85a274d0961593db41cf85689db1d583cJoe Perches		 card->recv.idx, card->send.idx);
711a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* test if we have a DMA interrupt */
712a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (s0val != card->last_is0) {
713a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if ((s0val & NJ_IRQM0_RD_MASK) !=
714a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		    (card->last_is0 & NJ_IRQM0_RD_MASK))
715a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			/* got a write dma int */
716a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			send_tiger(card, s0val);
717a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if ((s0val & NJ_IRQM0_WR_MASK) !=
718a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		    (card->last_is0 & NJ_IRQM0_WR_MASK))
719a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			/* got a read dma int */
720a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			recv_tiger(card, s0val);
721a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
722a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilend:
723a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_unlock(&card->lock);
724a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return IRQ_HANDLED;
725a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
726a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
727a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
728a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
729a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
730a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret = -EINVAL;
731a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct bchannel *bch = container_of(ch, struct bchannel, ch);
732a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
733a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = bch->hw;
734a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct mISDNhead *hh = mISDN_HEAD_P(skb);
735a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u32 id;
736a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u_long flags;
737a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
738a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (hh->prim) {
739a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case PH_DATA_REQ:
740a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_lock_irqsave(&card->lock, flags);
741a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = bchannel_senddata(bch, skb);
742a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (ret > 0) { /* direct TX */
743a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			id = hh->id; /* skb can be freed */
744a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			fill_dma(bc);
745a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			ret = 0;
746a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			spin_unlock_irqrestore(&card->lock, flags);
747a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
748a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil				queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
749a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		} else
750a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			spin_unlock_irqrestore(&card->lock, flags);
751a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return ret;
752a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case PH_ACTIVATE_REQ:
753a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_lock_irqsave(&card->lock, flags);
754a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
755a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			ret = mode_tiger(bc, ch->protocol);
756a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else
757a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			ret = 0;
758a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_unlock_irqrestore(&card->lock, flags);
759a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!ret)
760a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
761475be4d85a274d0961593db41cf85689db1d583cJoe Perches				    NULL, GFP_KERNEL);
762a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
763a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case PH_DEACTIVATE_REQ:
764a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_lock_irqsave(&card->lock, flags);
765a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mISDN_clear_bchannel(bch);
766a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mode_tiger(bc, ISDN_P_NONE);
767a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_unlock_irqrestore(&card->lock, flags);
768a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
769475be4d85a274d0961593db41cf85689db1d583cJoe Perches			    NULL, GFP_KERNEL);
770a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = 0;
771a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
772a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
773a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!ret)
774a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		dev_kfree_skb(skb);
775a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
776a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
777a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
778a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
779a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilchannel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)
780a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
781a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret = 0;
782a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card  = bc->bch.hw;
783a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
784a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (cq->op) {
785a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case MISDN_CTRL_GETOP:
786a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		cq->op = 0;
787a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
788475be4d85a274d0961593db41cf85689db1d583cJoe Perches		/* Nothing implemented yet */
789a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case MISDN_CTRL_FILL_EMPTY:
790a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	default:
791a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
792a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = -EINVAL;
793a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
794a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
795a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
796a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
797a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
798a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
799a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
800a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
801a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct bchannel *bch = container_of(ch, struct bchannel, ch);
802a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
803a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card  = bch->hw;
804a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret = -EINVAL;
805a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u_long flags;
806a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
807a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
808a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (cmd) {
809a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case CLOSE_CHANNEL:
810a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		test_and_clear_bit(FLG_OPEN, &bch->Flags);
811a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (test_bit(FLG_ACTIVE, &bch->Flags)) {
812a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			spin_lock_irqsave(&card->lock, flags);
813a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			mISDN_freebchannel(bch);
814a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
815a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
816a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			mode_tiger(bc, ISDN_P_NONE);
817a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			spin_unlock_irqrestore(&card->lock, flags);
818a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
819a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ch->protocol = ISDN_P_NONE;
820a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ch->peer = NULL;
821a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		module_put(THIS_MODULE);
822a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = 0;
823a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
824a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case CONTROL_CHANNEL:
825a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = channel_bctrl(bc, arg);
826a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
827a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	default:
828a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);
829a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
830a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
831a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
832a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
833a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
834a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilchannel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)
835a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
836a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int	ret = 0;
837a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
838a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (cq->op) {
839a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case MISDN_CTRL_GETOP:
840a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		cq->op = MISDN_CTRL_LOOP;
841a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
842a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case MISDN_CTRL_LOOP:
843a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		/* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
844a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (cq->channel < 0 || cq->channel > 3) {
845a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			ret = -EINVAL;
846a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			break;
847a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		}
848a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);
849a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
850a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	default:
851a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
852a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		ret = -EINVAL;
853a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
854a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
855a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
856a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
857a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
858a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
859a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilopen_bchannel(struct tiger_hw *card, struct channel_req *rq)
860a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
861a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct bchannel *bch;
862a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
863819a100846295461bc0f1bfcb8e5ab11c1bc4cdbDan Carpenter	if (rq->adr.channel == 0 || rq->adr.channel > 2)
864a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EINVAL;
865a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (rq->protocol == ISDN_P_NONE)
866a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EINVAL;
867a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bch = &card->bc[rq->adr.channel - 1].bch;
868a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
869a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EBUSY; /* b-channel can be only open once */
870a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
871a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	bch->ch.protocol = rq->protocol;
872a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	rq->ch = &bch->ch;
873a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return 0;
874a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
875a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
876a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil/*
877a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * device control function
878a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil */
879a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
880a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
881a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
882a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct mISDNdevice	*dev = container_of(ch, struct mISDNdevice, D);
883a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct dchannel		*dch = container_of(dev, struct dchannel, dev);
884a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw	*card = dch->hw;
885a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct channel_req	*rq;
886a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int			err = 0;
887a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
888a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
889a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	switch (cmd) {
890a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case OPEN_CHANNEL:
891a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		rq = arg;
892a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (rq->protocol == ISDN_P_TE_S0)
893a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			err = card->isac.open(&card->isac, rq);
894a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		else
895a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			err = open_bchannel(card, rq);
896a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (err)
897a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			break;
898a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		if (!try_module_get(THIS_MODULE))
899a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			pr_info("%s: cannot get module\n", card->name);
900a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
901a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case CLOSE_CHANNEL:
902a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,
903475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 __builtin_return_address(0));
904a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		module_put(THIS_MODULE);
905a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
906a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	case CONTROL_CHANNEL:
907a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		err = channel_ctrl(card, arg);
908a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		break;
909a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	default:
910a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_debug("%s: %s unknown command %x\n",
911475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 card->name, __func__, cmd);
912a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EINVAL;
913a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
914a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return err;
915a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
916a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
917a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
918a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_init_card(struct tiger_hw *card)
919a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
920a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u_long flags;
921a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int ret;
922a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
923a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_lock_irqsave(&card->lock, flags);
924a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	nj_disable_hwirq(card);
925a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_unlock_irqrestore(&card->lock, flags);
926a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
927a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->irq = card->pdev->irq;
928a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {
929a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: couldn't get interrupt %d\n",
930a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->name, card->irq);
931a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->irq = -1;
932a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EIO;
933a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
934a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
935a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_lock_irqsave(&card->lock, flags);
936a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	nj_reset(card);
937a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ret = card->isac.init(&card->isac);
938a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (ret)
939a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		goto error;
940a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ret = inittiger(card);
941a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (ret)
942a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		goto error;
943a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mode_tiger(&card->bc[0], ISDN_P_NONE);
944a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mode_tiger(&card->bc[1], ISDN_P_NONE);
945a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilerror:
946a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_unlock_irqrestore(&card->lock, flags);
947a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return ret;
948a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
949a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
950a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
951a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void
952a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_release(struct tiger_hw *card)
953a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
954a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u_long flags;
955a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int i;
956a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
957a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->base_s) {
958a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_lock_irqsave(&card->lock, flags);
959a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		nj_disable_hwirq(card);
960a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mode_tiger(&card->bc[0], ISDN_P_NONE);
961a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mode_tiger(&card->bc[1], ISDN_P_NONE);
962a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->isac.release(&card->isac);
963a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		spin_unlock_irqrestore(&card->lock, flags);
964a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		release_region(card->base, card->base_s);
965a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->base_s = 0;
966a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
967a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->irq > 0)
968a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		free_irq(card->irq, card);
969a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->isac.dch.dev.dev.class)
970a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mISDN_unregister_device(&card->isac.dch.dev);
971475be4d85a274d0961593db41cf85689db1d583cJoe Perches
972a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < 2; i++) {
973a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mISDN_freebchannel(&card->bc[i].bch);
974a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		kfree(card->bc[i].hsbuf);
975a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		kfree(card->bc[i].hrbuf);
976a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
977a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card->dma_p)
978a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pci_free_consistent(card->pdev, NJ_DMA_SIZE,
979475be4d85a274d0961593db41cf85689db1d583cJoe Perches				    card->dma_p, card->dma);
980a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	write_lock_irqsave(&card_lock, flags);
981a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	list_del(&card->list);
982a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	write_unlock_irqrestore(&card_lock, flags);
983a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_clear_master(card->pdev);
984a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_disable_device(card->pdev);
985a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_set_drvdata(card->pdev, NULL);
986a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	kfree(card);
987a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
988a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
989a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
990a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int
991a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_setup(struct tiger_hw *card)
992a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
993a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->base = pci_resource_start(card->pdev, 0);
994a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->base_s = pci_resource_len(card->pdev, 0);
995a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!request_region(card->base, card->base_s, card->name)) {
996a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s: NETjet config port %#x-%#x already in use\n",
997a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			card->name, card->base,
998a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil			(u32)(card->base + card->base_s - 1));
999a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->base_s = 0;
1000a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -EIO;
1001a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1002a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	ASSIGN_FUNC(nj, ISAC, card->isac);
1003a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return 0;
1004a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1005a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1006a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1007a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int __devinit
1008a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilsetup_instance(struct tiger_hw *card)
1009a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
1010a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int i, err;
1011a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	u_long flags;
1012a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1013a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);
1014a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	write_lock_irqsave(&card_lock, flags);
1015a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	list_add_tail(&card->list, &Cards);
1016a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	write_unlock_irqrestore(&card_lock, flags);
1017a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1018a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	_set_debug(card);
1019a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->isac.name = card->name;
1020a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	spin_lock_init(&card->lock);
1021a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->isac.hwlock = &card->lock;
1022a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	mISDNisac_init(&card->isac, card);
1023a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1024a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
1025a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
1026a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->isac.dch.dev.D.ctrl = nj_dctrl;
1027a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	for (i = 0; i < 2; i++) {
1028a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.nr = i + 1;
1029a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		set_channelmap(i + 1, card->isac.dch.dev.channelmap);
1030a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
1031a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.hw = card;
1032a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.ch.send = nj_l2l1B;
1033a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.ch.ctrl = nj_bctrl;
1034a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.ch.nr = i + 1;
1035a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		list_add(&card->bc[i].bch.ch.list,
1036475be4d85a274d0961593db41cf85689db1d583cJoe Perches			 &card->isac.dch.dev.bchannels);
1037a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->bc[i].bch.hw = card;
1038a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1039a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = nj_setup(card);
1040a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (err)
1041a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		goto error;
1042a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
1043475be4d85a274d0961593db41cf85689db1d583cJoe Perches				    card->name);
1044a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (err)
1045a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		goto error;
1046a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = nj_init_card(card);
1047a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!err)  {
1048a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		nj_cnt++;
1049a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_notice("Netjet %d cards installed\n", nj_cnt);
1050a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return 0;
1051a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1052a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilerror:
1053a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	nj_release(card);
1054a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return err;
1055a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1056a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1057a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int __devinit
1058a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilnj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1059a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
1060a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int err = -ENOMEM;
1061a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int cfg;
1062a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card;
1063a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1064a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (pdev->subsystem_vendor == 0x8086 &&
1065a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	    pdev->subsystem_device == 0x0003) {
1066a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_notice("Netjet: Digium X100P/X101P not handled\n");
1067a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -ENODEV;
1068a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1069a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1070a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (pdev->subsystem_vendor == 0x55 &&
1071a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	    pdev->subsystem_device == 0x02) {
1072a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_notice("Netjet: Enter!Now not handled yet\n");
1073a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return -ENODEV;
1074a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1075a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1076367bbf2aa1654c12ab5d6dbf4428b043b425be29Prarit Bhargava	if (pdev->subsystem_vendor == 0xb100 &&
1077475be4d85a274d0961593db41cf85689db1d583cJoe Perches	    pdev->subsystem_device == 0x0003) {
1078367bbf2aa1654c12ab5d6dbf4428b043b425be29Prarit Bhargava		pr_notice("Netjet: Digium TDM400P not handled yet\n");
1079367bbf2aa1654c12ab5d6dbf4428b043b425be29Prarit Bhargava		return -ENODEV;
1080367bbf2aa1654c12ab5d6dbf4428b043b425be29Prarit Bhargava	}
1081367bbf2aa1654c12ab5d6dbf4428b043b425be29Prarit Bhargava
1082a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
1083a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (!card) {
1084a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("No kmem for Netjet\n");
1085a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return err;
1086a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1087a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1088a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->pdev = pdev;
1089a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1090a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = pci_enable_device(pdev);
1091a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (err) {
1092a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		kfree(card);
1093a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		return err;
1094a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	}
1095a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1096a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",
1097475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       pci_name(pdev));
1098a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1099a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_set_master(pdev);
1100a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1101a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	/* the TJ300 and TJ320 must be detected, the IRQ handling is different
1102a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 * unfortunately the chips use the same device ID, but the TJ320 has
1103a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 * the bit20 in status PCI cfg register set
1104a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	 */
1105a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_read_config_dword(pdev, 0x04, &cfg);
1106a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (cfg & 0x00100000)
1107a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->typ = NETJET_S_TJ320;
1108a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
1109a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		card->typ = NETJET_S_TJ300;
1110a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1111a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->base = pci_resource_start(pdev, 0);
1112a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	card->irq = pdev->irq;
1113a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_set_drvdata(pdev, card);
1114a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = setup_instance(card);
1115a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (err)
1116a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pci_set_drvdata(pdev, NULL);
1117a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1118a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return err;
1119a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1120a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1121a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1122a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void __devexit nj_remove(struct pci_dev *pdev)
1123a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
1124a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	struct tiger_hw *card = pci_get_drvdata(pdev);
1125a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1126a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	if (card)
1127a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		nj_release(card);
1128a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	else
1129a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil		pr_info("%s drvdata already removed\n", __func__);
1130a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1131a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1132a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil/* We cannot select cards with PCI_SUB... IDs, since here are cards with
1133a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
1134a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil * known other cards which not work with this driver - see probe function */
1135a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic struct pci_device_id nj_pci_ids[] __devinitdata = {
1136a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	{ PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
1137a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1138a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	{ }
1139a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
1140a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten KeilMODULE_DEVICE_TABLE(pci, nj_pci_ids);
1141a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1142a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic struct pci_driver nj_driver = {
1143a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	.name = "netjet",
1144a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	.probe = nj_probe,
1145a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	.remove = __devexit_p(nj_remove),
1146a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	.id_table = nj_pci_ids,
1147a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil};
1148a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1149a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic int __init nj_init(void)
1150a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
1151a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	int err;
1152a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1153a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);
1154a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	err = pci_register_driver(&nj_driver);
1155a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	return err;
1156a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1157a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1158a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilstatic void __exit nj_cleanup(void)
1159a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil{
1160a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil	pci_unregister_driver(&nj_driver);
1161a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil}
1162a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keil
1163a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilmodule_init(nj_init);
1164a900845e56617edc005fd8f35bfd5a407aaf96c8Karsten Keilmodule_exit(nj_cleanup);
1165