1 /* $Id: bkm_a4t.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
2  *
3  * low level stuff for T-Berkom A4T
4  *
5  * Author       Roland Klabunde
6  * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.de>
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  */
12 
13 #define __NO_VERSION__
14 
15 #include <linux/config.h>
16 #include <linux/init.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "jade.h"
21 #include "isdnl1.h"
22 #include <linux/pci.h>
23 #include "bkm_ax.h"
24 
25 extern const char *CardType[];
26 
27 const char *bkm_a4t_revision = "$Revision: 1.1.4.1 $";
28 
29 
30 static inline u_char
readreg(unsigned int ale,unsigned long adr,u_char off)31 readreg(unsigned int ale, unsigned long adr, u_char off)
32 {
33 	register u_int ret;
34 	long flags;
35 	unsigned int *po = (unsigned int *) adr;	/* Postoffice */
36 	save_flags(flags);
37 	cli();
38 	*po = (GCS_2 | PO_WRITE | off);
39 	__WAITI20__(po);
40 	*po = (ale | PO_READ);
41 	__WAITI20__(po);
42 	ret = *po;
43 	restore_flags(flags);
44 	return ((unsigned char) ret);
45 }
46 
47 
48 static inline void
readfifo(unsigned int ale,unsigned long adr,u_char off,u_char * data,int size)49 readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
50 {
51 	/* fifo read without cli because it's allready done  */
52 	int i;
53 	for (i = 0; i < size; i++)
54 		*data++ = readreg(ale, adr, off);
55 }
56 
57 
58 static inline void
writereg(unsigned int ale,unsigned long adr,u_char off,u_char data)59 writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
60 {
61 	long flags;
62 	unsigned int *po = (unsigned int *) adr;	/* Postoffice */
63 	save_flags(flags);
64 	cli();
65 	*po = (GCS_2 | PO_WRITE | off);
66 	__WAITI20__(po);
67 	*po = (ale | PO_WRITE | data);
68 	__WAITI20__(po);
69 	restore_flags(flags);
70 }
71 
72 
73 static inline void
writefifo(unsigned int ale,unsigned long adr,u_char off,u_char * data,int size)74 writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
75 {
76 	/* fifo write without cli because it's allready done  */
77 	int i;
78 
79 	for (i = 0; i < size; i++)
80 		writereg(ale, adr, off, *data++);
81 }
82 
83 
84 /* Interface functions */
85 
86 static u_char
ReadISAC(struct IsdnCardState * cs,u_char offset)87 ReadISAC(struct IsdnCardState *cs, u_char offset)
88 {
89 	return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
90 }
91 
92 static void
WriteISAC(struct IsdnCardState * cs,u_char offset,u_char value)93 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
94 {
95 	writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
96 }
97 
98 static void
ReadISACfifo(struct IsdnCardState * cs,u_char * data,int size)99 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
100 {
101 	readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
102 }
103 
104 static void
WriteISACfifo(struct IsdnCardState * cs,u_char * data,int size)105 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
106 {
107 	writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
108 }
109 
110 static u_char
ReadJADE(struct IsdnCardState * cs,int jade,u_char offset)111 ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
112 {
113 	return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
114 }
115 
116 static void
WriteJADE(struct IsdnCardState * cs,int jade,u_char offset,u_char value)117 WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
118 {
119 	writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
120 }
121 
122 /*
123  * fast interrupt JADE stuff goes here
124  */
125 
126 #define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
127  		cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
128 #define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
129  		cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
130 
131 #define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
132 		cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
133 #define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
134 		cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
135 
136 #include "jade_irq.c"
137 
138 static void
bkm_interrupt(int intno,void * dev_id,struct pt_regs * regs)139 bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
140 {
141 	struct IsdnCardState *cs = dev_id;
142 	u_char val = 0;
143 	I20_REGISTER_FILE *pI20_Regs;
144 
145 	if (!cs) {
146 		printk(KERN_WARNING "HiSax: Telekom A4T: Spurious interrupt!\n");
147 		return;
148 	}
149 	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
150 
151 	/* ISDN interrupt pending? */
152 	if (pI20_Regs->i20IntStatus & intISDN) {
153 		/* Reset the ISDN interrupt     */
154 		pI20_Regs->i20IntStatus = intISDN;
155 		/* Disable ISDN interrupt */
156 		pI20_Regs->i20IntCtrl &= ~intISDN;
157 		/* Channel A first */
158 		val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
159 		if (val) {
160 			jade_int_main(cs, val, 0);
161 		}
162 		/* Channel B  */
163 		val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
164 		if (val) {
165 			jade_int_main(cs, val, 1);
166 		}
167 		/* D-Channel */
168 		val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
169 		if (val) {
170 			isac_interrupt(cs, val);
171 		}
172 		/* Reenable ISDN interrupt */
173 		pI20_Regs->i20IntCtrl |= intISDN;
174 	}
175 }
176 
177 void
release_io_bkm(struct IsdnCardState * cs)178 release_io_bkm(struct IsdnCardState *cs)
179 {
180 	if (cs->hw.ax.base) {
181 		iounmap((void *) cs->hw.ax.base);
182 		cs->hw.ax.base = 0;
183 	}
184 }
185 
186 static void
enable_bkm_int(struct IsdnCardState * cs,unsigned bEnable)187 enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
188 {
189 	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
190 		I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
191 		if (bEnable)
192 			pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
193 		else
194 			/* CAUTION: This disables the video capture driver too */
195 			pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
196 	}
197 }
198 
199 static void
reset_bkm(struct IsdnCardState * cs)200 reset_bkm(struct IsdnCardState *cs)
201 {
202 	long flags;
203 
204 	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
205 		I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
206 		save_flags(flags);
207 		sti();
208 		/* Issue the I20 soft reset     */
209 		pI20_Regs->i20SysControl = 0xFF;	/* all in */
210 		set_current_state(TASK_UNINTERRUPTIBLE);
211 		schedule_timeout((10 * HZ) / 1000);
212 		/* Remove the soft reset */
213 		pI20_Regs->i20SysControl = sysRESET | 0xFF;
214 		set_current_state(TASK_UNINTERRUPTIBLE);
215 		schedule_timeout((10 * HZ) / 1000);
216 		/* Set our configuration */
217 		pI20_Regs->i20SysControl = sysRESET | sysCFG;
218 		/* Issue ISDN reset     */
219 		pI20_Regs->i20GuestControl = guestWAIT_CFG |
220 		    g_A4T_JADE_RES |
221 		    g_A4T_ISAR_RES |
222 		    g_A4T_ISAC_RES |
223 		    g_A4T_JADE_BOOTR |
224 		    g_A4T_ISAR_BOOTR;
225 		set_current_state(TASK_UNINTERRUPTIBLE);
226 		schedule_timeout((10 * HZ) / 1000);
227 
228 		/* Remove RESET state from ISDN */
229 		pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
230 						g_A4T_JADE_RES |
231 						g_A4T_ISAR_RES);
232 		set_current_state(TASK_UNINTERRUPTIBLE);
233 		schedule_timeout((10 * HZ) / 1000);
234 		restore_flags(flags);
235 	}
236 }
237 
238 static int
BKM_card_msg(struct IsdnCardState * cs,int mt,void * arg)239 BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
240 {
241 	switch (mt) {
242 		case CARD_RESET:
243 			/* Disable ints */
244 			enable_bkm_int(cs, 0);
245 			reset_bkm(cs);
246 			return (0);
247 		case CARD_RELEASE:
248 			/* Sanity */
249 			enable_bkm_int(cs, 0);
250 			reset_bkm(cs);
251 			release_io_bkm(cs);
252 			return (0);
253 		case CARD_INIT:
254 			clear_pending_isac_ints(cs);
255 			clear_pending_jade_ints(cs);
256 			initisac(cs);
257 			initjade(cs);
258 			/* Enable ints */
259 			enable_bkm_int(cs, 1);
260 			return (0);
261 		case CARD_TEST:
262 			return (0);
263 	}
264 	return (0);
265 }
266 
267 static struct pci_dev *dev_a4t __initdata = NULL;
268 
269 int __init
setup_bkm_a4t(struct IsdnCard * card)270 setup_bkm_a4t(struct IsdnCard *card)
271 {
272 	struct IsdnCardState *cs = card->cs;
273 	char tmp[64];
274 	u_int pci_memaddr = 0, found = 0;
275 	I20_REGISTER_FILE *pI20_Regs;
276 #if CONFIG_PCI
277 #endif
278 
279 	strcpy(tmp, bkm_a4t_revision);
280 	printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
281 	if (cs->typ == ISDN_CTYPE_BKM_A4T) {
282 		cs->subtyp = BKM_A4T;
283 	} else
284 		return (0);
285 
286 #if CONFIG_PCI
287 	if (!pci_present()) {
288 		printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
289 		return (0);
290 	}
291 	while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
292 		PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
293 		u16 sub_sys;
294 		u16 sub_vendor;
295 
296 		sub_vendor = dev_a4t->subsystem_vendor;
297 		sub_sys = dev_a4t->subsystem_device;
298 		if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
299 			if (pci_enable_device(dev_a4t))
300 				return(0);
301 			found = 1;
302 			pci_memaddr = pci_resource_start(dev_a4t, 0);
303 			cs->irq = dev_a4t->irq;
304 			break;
305 		}
306 	}
307 	if (!found) {
308 		printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
309 		return (0);
310 	}
311 	if (!cs->irq) {		/* IRQ range check ?? */
312 		printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
313 		return (0);
314 	}
315 	if (!pci_memaddr) {
316 		printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
317 		return (0);
318 	}
319 	cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
320 	/* Check suspecious address */
321 	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
322 	if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
323 		printk(KERN_WARNING "HiSax: %s address %lx-%lx suspecious\n",
324 		       CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096);
325 		iounmap((void *) cs->hw.ax.base);
326 		cs->hw.ax.base = 0;
327 		return (0);
328 	}
329 	cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
330 	cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
331 	cs->hw.ax.isac_ale = GCS_1;
332 	cs->hw.ax.jade_ale = GCS_3;
333 #else
334 	printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
335 	printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
336 	return (0);
337 #endif				/* CONFIG_PCI */
338 	printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n",
339 	       CardType[card->typ], cs->hw.ax.base, cs->irq);
340 
341 	reset_bkm(cs);
342 	cs->readisac = &ReadISAC;
343 	cs->writeisac = &WriteISAC;
344 	cs->readisacfifo = &ReadISACfifo;
345 	cs->writeisacfifo = &WriteISACfifo;
346 	cs->BC_Read_Reg = &ReadJADE;
347 	cs->BC_Write_Reg = &WriteJADE;
348 	cs->BC_Send_Data = &jade_fill_fifo;
349 	cs->cardmsg = &BKM_card_msg;
350 	cs->irq_func = &bkm_interrupt;
351 	cs->irq_flags |= SA_SHIRQ;
352 	ISACVersion(cs, "Telekom A4T:");
353 	/* Jade version */
354 	JadeVersion(cs, "Telekom A4T:");
355 	return (1);
356 }
357