1 /* $Id: eicon_isa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
2  *
3  * ISDN low-level module for Eicon active ISDN-Cards.
4  * Hardware-specific code for old ISA cards.
5  *
6  * Copyright 1998      by Fritz Elfert (fritz@isdn4linux.de)
7  * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
8  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
9  *
10  * This software may be used and distributed according to the terms
11  * of the GNU General Public License, incorporated herein by reference.
12  *
13  */
14 
15 #include <linux/config.h>
16 #include "eicon.h"
17 #include "eicon_isa.h"
18 
19 #define check_shmem   check_region
20 #define release_shmem release_region
21 #define request_shmem request_region
22 
23 char *eicon_isa_revision = "$Revision: 1.1.4.1 $";
24 
25 #undef EICON_MCA_DEBUG
26 
27 #ifdef CONFIG_ISDN_DRV_EICON_ISA
28 
29 /* Mask for detecting invalid IRQ parameter */
30 static int eicon_isa_valid_irq[] = {
31 	0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/
32 	0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */
33 	0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */
34 	0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */
35 	0x1cbc  /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */
36 };
37 
38 static void
eicon_isa_release_shmem(eicon_isa_card * card)39 eicon_isa_release_shmem(eicon_isa_card *card) {
40 	if (card->mvalid) {
41 		iounmap(card->shmem);
42 		release_mem_region(card->physmem, card->ramsize);
43 	}
44 	card->mvalid = 0;
45 }
46 
47 static void
eicon_isa_release_irq(eicon_isa_card * card)48 eicon_isa_release_irq(eicon_isa_card *card) {
49 	if (!card->master)
50 		return;
51 	if (card->ivalid)
52 		free_irq(card->irq, card);
53 	card->ivalid = 0;
54 }
55 
56 void
eicon_isa_release(eicon_isa_card * card)57 eicon_isa_release(eicon_isa_card *card) {
58 	eicon_isa_release_irq(card);
59 	eicon_isa_release_shmem(card);
60 }
61 
62 void
eicon_isa_printpar(eicon_isa_card * card)63 eicon_isa_printpar(eicon_isa_card *card) {
64 	switch (card->type) {
65 		case EICON_CTYPE_S:
66 		case EICON_CTYPE_SX:
67 		case EICON_CTYPE_SCOM:
68 		case EICON_CTYPE_QUADRO:
69 		case EICON_CTYPE_S2M:
70 			printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n",
71 			       eicon_ctype_name[card->type],
72 			       card->physmem,
73 			       card->irq);
74 	}
75 }
76 
77 int
eicon_isa_find_card(int Mem,int Irq,char * Id)78 eicon_isa_find_card(int Mem, int Irq, char * Id)
79 {
80 	int primary = 1;
81 	unsigned long amem;
82 
83 	if (!strlen(Id))
84 		return -1;
85 
86 	if (Mem == -1)
87 		return -1;
88 
89 	/* Check for valid membase address */
90 	if ((Mem < 0x0c0000) ||
91 	    (Mem > 0x0fc000) ||
92 	    (Mem & 0xfff)) {
93 		printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %s\n",
94 			 Mem, Id);
95 		return -1;
96 	}
97 	if (check_mem_region(Mem, RAMSIZE)) {
98 		printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
99 		return -1;
100 	}
101 
102 	amem = (unsigned long) ioremap(Mem, RAMSIZE);
103         writew(0x55aa, amem + 0x402);
104         if (readw(amem + 0x402) != 0x55aa) primary = 0;
105 	writew(0, amem + 0x402);
106 	if (readw(amem + 0x402) != 0) primary = 0;
107 
108 	printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);
109 	if (primary) {
110 		printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
111 		writeb(0, amem + 0x3ffe);
112 		iounmap((unsigned char *)amem);
113 		return EICON_CTYPE_ISAPRI;
114 	} else {
115 		printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
116 		writeb(0, amem + 0x400);
117 		iounmap((unsigned char *)amem);
118 		return EICON_CTYPE_ISABRI;
119 	}
120 	return -1;
121 }
122 
123 int
eicon_isa_bootload(eicon_isa_card * card,eicon_isa_codebuf * cb)124 eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
125 	int	tmp;
126 	int               timeout;
127 	eicon_isa_codebuf cbuf;
128 	unsigned char     *code;
129 	eicon_isa_boot    *boot;
130 
131 	if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
132 		return -EFAULT;
133 
134 	/* Allocate code-buffer and copy code from userspace */
135 	if (cbuf.bootstrap_len > 1024) {
136 		printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n",
137 		       cbuf.bootstrap_len);
138 		return -EINVAL;
139 	}
140 	if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) {
141 		printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n");
142 		return -ENOMEM;
143 	}
144 	if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) {
145 		kfree(code);
146 		return -EFAULT;
147 	}
148 
149 	if (card->type == EICON_CTYPE_ISAPRI)
150 		card->ramsize  = RAMSIZE_P;
151 	else
152 		card->ramsize  = RAMSIZE;
153 
154 	if (check_mem_region(card->physmem, card->ramsize)) {
155 		printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
156 			card->physmem);
157 		kfree(code);
158 		return -EBUSY;
159 	}
160 	request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
161 	card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
162 #ifdef EICON_MCA_DEBUG
163 	printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
164 #endif
165 	card->mvalid = 1;
166 
167 	switch(card->type) {
168 		case EICON_CTYPE_S:
169 		case EICON_CTYPE_SX:
170 		case EICON_CTYPE_SCOM:
171 		case EICON_CTYPE_QUADRO:
172 		case EICON_CTYPE_ISABRI:
173 			card->intack   = (__u8 *)card->shmem + INTACK;
174 			card->startcpu = (__u8 *)card->shmem + STARTCPU;
175 			card->stopcpu  = (__u8 *)card->shmem + STOPCPU;
176 			break;
177 		case EICON_CTYPE_S2M:
178 		case EICON_CTYPE_ISAPRI:
179 			card->intack   = (__u8 *)card->shmem + INTACK_P;
180 			card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
181 			card->stopcpu  = (__u8 *)card->shmem + STOPCPU_P;
182 			break;
183 		default:
184 			printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);
185 			eicon_isa_release_shmem(card);
186 			kfree(code);
187 			return -EINVAL;
188 	}
189 
190 	/* clear any pending irq's */
191 	readb(card->intack);
192 #ifdef CONFIG_MCA
193 	if (MCA_bus) {
194 		if (card->type == EICON_CTYPE_SCOM) {
195 			outb_p(0,card->io+1);
196 		}
197 		else {
198 			printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n");
199 			eicon_isa_release_shmem(card);
200 			return -EINVAL;
201 		};
202 
203 #ifdef EICON_MCA_DEBUG
204 	printk(KERN_INFO "eicon_isa_boot: card->io      = %x.\n", card->io);
205 	printk(KERN_INFO "eicon_isa_boot: card->irq     = %d.\n", (int)card->irq);
206 #endif
207 	}
208 #else
209 	/* set reset-line active */
210 	writeb(0, card->stopcpu);
211 #endif  /* CONFIG_MCA */
212 	/* clear irq-requests */
213 	writeb(0, card->intack);
214 	readb(card->intack);
215 
216 	/* Copy code into card */
217 	memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len);
218 
219 	/* Check for properly loaded code */
220 	if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) {
221 		printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n");
222 		eicon_isa_release_shmem(card);
223 		kfree(code);
224 		return -EIO;
225 	}
226 	/* if 16k-ramsize, duplicate the reset-jump-code */
227 	if (card->ramsize == RAMSIZE_P)
228 		memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12);
229 
230 	kfree(code);
231 	boot = &card->shmem->boot;
232 
233 	/* Delay 0.2 sec. */
234 	SLEEP(HZ / 5);
235 
236 	/* Start CPU */
237 	writeb(cbuf.boot_opt, &boot->ctrl);
238 #ifdef CONFIG_MCA
239 	if (MCA_bus) {
240 		outb_p(0, card->io);
241 	}
242 #else
243 	writeb(0, card->startcpu);
244 #endif /* CONFIG_MCA */
245 
246 	/* Delay 0.2 sec. */
247 	SLEEP(HZ / 5);
248 
249 	timeout = jiffies + (HZ * 22);
250 	while (time_before(jiffies, timeout)) {
251 		if (readb(&boot->ctrl) == 0)
252 			break;
253 		SLEEP(10);
254 	}
255 	if (readb(&boot->ctrl) != 0) {
256 		printk(KERN_WARNING "eicon_isa_boot: CPU test failed.\n");
257 #ifdef EICON_MCA_DEBUG
258 		printk(KERN_INFO "eicon_isa_boot: &boot->ctrl = %d.\n",
259 			readb(&boot->ctrl));
260 #endif
261 		eicon_isa_release_shmem(card);
262 		return -EIO;
263 	}
264 
265 	/* Check for memory-test errors */
266 	if (readw(&boot->ebit)) {
267 		printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n",
268 		       readw(&boot->ebit), readl(&boot->eloc));
269 		eicon_isa_release_shmem(card);
270 		return -EIO;
271 	}
272 
273         /* Check card type and memory size */
274         tmp = readb(&boot->card);
275 	if ((tmp < 0) || (tmp > 4)) {
276 		printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n");
277 		eicon_isa_release_shmem(card);
278 		return -EIO;
279 	}
280 	card->type = tmp;
281 	((eicon_card *)card->card)->type = tmp;
282 
283         tmp = readb(&boot->msize);
284         if (tmp != 8 && tmp != 16 && tmp != 24 &&
285             tmp != 32 && tmp != 48 && tmp != 60) {
286                 printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n");
287 		eicon_isa_release_shmem(card);
288                 return -EIO;
289         }
290 	printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]);
291 	if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
292 		tmp = eicon_addcard(card->type, card->physmem, card->irq,
293 				((eicon_card *)card->card)->regname, 0);
294 		printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
295 	}
296 	return 0;
297 }
298 
299 int
eicon_isa_load(eicon_isa_card * card,eicon_isa_codebuf * cb)300 eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
301 	eicon_isa_boot    *boot;
302 	int               tmp;
303 	int               timeout;
304 	int 		  j;
305 	eicon_isa_codebuf cbuf;
306 	unsigned char     *code;
307 	unsigned char     *p;
308 
309 	if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
310 		return -EFAULT;
311 
312 	if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) {
313 		printk(KERN_WARNING "eicon_isa_load: Couldn't allocate code buffer\n");
314 		return -ENOMEM;
315 	}
316 
317 	if (copy_from_user(code, &cb->code, cbuf.firmware_len)) {
318 		kfree(code);
319 		return -EFAULT;
320 	}
321 
322 	boot = &card->shmem->boot;
323 
324 	if ((!card->ivalid) && card->master) {
325 		card->irqprobe = 1;
326 		/* Check for valid IRQ */
327 		if ((card->irq < 0) || (card->irq > 15) ||
328 		    (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) {
329 			printk(KERN_WARNING "eicon_isa_load: illegal irq: %d\n", card->irq);
330 			eicon_isa_release_shmem(card);
331 			kfree(code);
332 			return -EINVAL;
333 		}
334 		/* Register irq */
335 		if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card))
336 			card->ivalid = 1;
337 		else {
338 			printk(KERN_WARNING "eicon_isa_load: irq %d already in use.\n",
339 			       card->irq);
340 			eicon_isa_release_shmem(card);
341 			kfree(code);
342 			return -EBUSY;
343 		}
344 	}
345 
346         tmp = readb(&boot->msize);
347         if (tmp != 8 && tmp != 16 && tmp != 24 &&
348             tmp != 32 && tmp != 48 && tmp != 60) {
349                 printk(KERN_WARNING "eicon_isa_load: invalid memsize\n");
350 		eicon_isa_release_shmem(card);
351                 return -EIO;
352         }
353 
354 	eicon_isa_printpar(card);
355 
356 	/* Download firmware */
357 	printk(KERN_INFO "%s %dkB, loading firmware ...\n",
358 	       eicon_ctype_name[card->type],
359 	       tmp * 16);
360 	tmp = cbuf.firmware_len >> 8;
361 	p = code;
362 	while (tmp--) {
363 		memcpy_toio(&boot->b, p, 256);
364 		writeb(1, &boot->ctrl);
365 		timeout = jiffies + HZ / 10;
366 		while (time_before(jiffies, timeout)) {
367 			if (readb(&boot->ctrl) == 0)
368 				break;
369 			SLEEP(2);
370 		}
371 		if (readb(&boot->ctrl)) {
372 			printk(KERN_WARNING "eicon_isa_load: download timeout at 0x%x\n", p-code);
373 			eicon_isa_release(card);
374 			kfree(code);
375 			return -EIO;
376 		}
377 		p += 256;
378 	}
379 	kfree(code);
380 
381 	/* Initialize firmware parameters */
382 	memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14);
383 	memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96);
384 	memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96);
385 
386 	/* Start firmware, wait for signature */
387 	writeb(2, &boot->ctrl);
388 	timeout = jiffies + (5*HZ);
389 	while (time_before(jiffies, timeout)) {
390 		if (readw(&boot->signature) == 0x4447)
391 			break;
392 		SLEEP(2);
393 	}
394 	if (readw(&boot->signature) != 0x4447) {
395 		printk(KERN_WARNING "eicon_isa_load: firmware selftest failed %04x\n",
396 		       readw(&boot->signature));
397 		eicon_isa_release(card);
398 		return -EIO;
399 	}
400 
401 	card->channels = readb(&card->shmem->c[0x3f6]);
402 
403 	/* clear irq-requests, reset irq-count */
404 	readb(card->intack);
405 	writeb(0, card->intack);
406 
407 	if (card->master) {
408 		card->irqprobe = 1;
409 		/* Trigger an interrupt and check if it is delivered */
410 		tmp = readb(&card->shmem->com.ReadyInt);
411 		tmp ++;
412 		writeb(tmp, &card->shmem->com.ReadyInt);
413 		timeout = jiffies + HZ / 5;
414 		while (time_before(jiffies, timeout)) {
415 			if (card->irqprobe > 1)
416 				break;
417 			SLEEP(2);
418 		}
419 		if (card->irqprobe == 1) {
420 			printk(KERN_WARNING "eicon_isa_load: IRQ # %d test failed\n", card->irq);
421 			eicon_isa_release(card);
422 			return -EIO;
423 		}
424 	}
425 #ifdef EICON_MCA_DEBUG
426 	printk(KERN_INFO "eicon_isa_load: IRQ # %d test succeeded.\n", card->irq);
427 #endif
428 
429 	writeb(card->irq, &card->shmem->com.Int);
430 
431 	/* initializing some variables */
432 	((eicon_card *)card->card)->ReadyInt = 0;
433 	((eicon_card *)card->card)->ref_in  = 1;
434 	((eicon_card *)card->card)->ref_out = 1;
435 	for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
436 	for(j=0; j< (card->channels + 1); j++) {
437 		((eicon_card *)card->card)->bch[j].e.busy = 0;
438 		((eicon_card *)card->card)->bch[j].e.D3Id = 0;
439 		((eicon_card *)card->card)->bch[j].e.B2Id = 0;
440 		((eicon_card *)card->card)->bch[j].e.ref = 0;
441 		((eicon_card *)card->card)->bch[j].e.Req = 0;
442 		((eicon_card *)card->card)->bch[j].e.complete = 1;
443 		((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
444 	}
445 
446 	printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels);
447 	printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]);
448 
449 	/* Enable normal IRQ processing */
450 	card->irqprobe = 0;
451 	return 0;
452 }
453 
454 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
455