File: /usr/src/linux/drivers/isdn/act2000/act2000_isa.c
1 /* $Id: act2000_isa.c,v 1.11.6.2 2001/07/18 16:25:12 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
4 *
5 * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
6 * Thanks to Friedemann Baitinger and IBM Germany
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 #define __NO_VERSION__
25 #include "act2000.h"
26 #include "act2000_isa.h"
27 #include "capi.h"
28
29 static act2000_card *irq2card_map[16];
30
31 static void
32 act2000_isa_delay(long t)
33 {
34 sti();
35 set_current_state(TASK_INTERRUPTIBLE);
36 schedule_timeout(t);
37 sti();
38 }
39
40 /*
41 * Reset Controller, then try to read the Card's signature.
42 + Return:
43 * 1 = Signature found.
44 * 0 = Signature not found.
45 */
46 static int
47 act2000_isa_reset(unsigned short portbase)
48 {
49 unsigned char reg;
50 int i;
51 int found;
52 int serial = 0;
53
54 found = 0;
55 if ((reg = inb(portbase + ISA_COR)) != 0xff) {
56 outb(reg | ISA_COR_RESET, portbase + ISA_COR);
57 mdelay(10);
58 outb(reg, portbase + ISA_COR);
59 mdelay(10);
60
61 for (i = 0; i < 16; i++) {
62 if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
63 serial |= 0x10000;
64 serial >>= 1;
65 }
66 if (serial == ISA_SER_ID)
67 found++;
68 }
69 return found;
70 }
71
72 int
73 act2000_isa_detect(unsigned short portbase)
74 {
75 int ret = 0;
76
77 if (!check_region(portbase, ISA_REGION))
78 ret = act2000_isa_reset(portbase);
79 return ret;
80 }
81
82 static void
83 act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
84 {
85 act2000_card *card = irq2card_map[irq];
86 u_char istatus;
87
88 if (!card) {
89 printk(KERN_WARNING
90 "act2000: Spurious interrupt!\n");
91 return;
92 }
93 istatus = (inb(ISA_PORT_ISR) & 0x07);
94 if (istatus & ISA_ISR_OUT) {
95 /* RX fifo has data */
96 istatus &= ISA_ISR_OUT_MASK;
97 outb(0, ISA_PORT_SIS);
98 act2000_isa_receive(card);
99 outb(ISA_SIS_INT, ISA_PORT_SIS);
100 }
101 if (istatus & ISA_ISR_ERR) {
102 /* Error Interrupt */
103 istatus &= ISA_ISR_ERR_MASK;
104 printk(KERN_WARNING "act2000: errIRQ\n");
105 }
106 if (istatus)
107 printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
108 }
109
110 static void
111 act2000_isa_select_irq(act2000_card * card)
112 {
113 unsigned char reg;
114
115 reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
116 switch (card->irq) {
117 case 3:
118 reg = ISA_COR_IRQ03;
119 break;
120 case 5:
121 reg = ISA_COR_IRQ05;
122 break;
123 case 7:
124 reg = ISA_COR_IRQ07;
125 break;
126 case 10:
127 reg = ISA_COR_IRQ10;
128 break;
129 case 11:
130 reg = ISA_COR_IRQ11;
131 break;
132 case 12:
133 reg = ISA_COR_IRQ12;
134 break;
135 case 15:
136 reg = ISA_COR_IRQ15;
137 break;
138 }
139 outb(reg, ISA_PORT_COR);
140 }
141
142 static void
143 act2000_isa_enable_irq(act2000_card * card)
144 {
145 act2000_isa_select_irq(card);
146 /* Enable READ irq */
147 outb(ISA_SIS_INT, ISA_PORT_SIS);
148 }
149
150 /*
151 * Install interrupt handler, enable irq on card.
152 * If irq is -1, choose next free irq, else irq is given explicitely.
153 */
154 int
155 act2000_isa_config_irq(act2000_card * card, short irq)
156 {
157 if (card->flags & ACT2000_FLAGS_IVALID) {
158 free_irq(card->irq, NULL);
159 irq2card_map[card->irq] = NULL;
160 }
161 card->flags &= ~ACT2000_FLAGS_IVALID;
162 outb(ISA_COR_IRQOFF, ISA_PORT_COR);
163 if (!irq)
164 return 0;
165
166 if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
167 card->irq = irq;
168 irq2card_map[card->irq] = card;
169 card->flags |= ACT2000_FLAGS_IVALID;
170 printk(KERN_WARNING
171 "act2000: Could not request irq %d\n",irq);
172 return -EBUSY;
173 } else {
174 act2000_isa_select_irq(card);
175 /* Disable READ and WRITE irq */
176 outb(0, ISA_PORT_SIS);
177 outb(0, ISA_PORT_SOS);
178 }
179 return 0;
180 }
181
182 int
183 act2000_isa_config_port(act2000_card * card, unsigned short portbase)
184 {
185 if (card->flags & ACT2000_FLAGS_PVALID) {
186 release_region(card->port, ISA_REGION);
187 card->flags &= ~ACT2000_FLAGS_PVALID;
188 }
189 if (!check_region(portbase, ISA_REGION)) {
190 request_region(portbase, ACT2000_PORTLEN, card->regname);
191 card->port = portbase;
192 card->flags |= ACT2000_FLAGS_PVALID;
193 return 0;
194 }
195 return -EBUSY;
196 }
197
198 /*
199 * Release ressources, used by an adaptor.
200 */
201 void
202 act2000_isa_release(act2000_card * card)
203 {
204 unsigned long flags;
205
206 save_flags(flags);
207 cli();
208 if (card->flags & ACT2000_FLAGS_IVALID) {
209 free_irq(card->irq, NULL);
210 irq2card_map[card->irq] = NULL;
211 }
212 card->flags &= ~ACT2000_FLAGS_IVALID;
213 if (card->flags & ACT2000_FLAGS_PVALID)
214 release_region(card->port, ISA_REGION);
215 card->flags &= ~ACT2000_FLAGS_PVALID;
216 restore_flags(flags);
217 }
218
219 static int
220 act2000_isa_writeb(act2000_card * card, u_char data)
221 {
222 u_char timeout = 40;
223
224 while (timeout) {
225 if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
226 outb(data, ISA_PORT_SDO);
227 return 0;
228 } else {
229 timeout--;
230 udelay(10);
231 }
232 }
233 return 1;
234 }
235
236 static int
237 act2000_isa_readb(act2000_card * card, u_char * data)
238 {
239 u_char timeout = 40;
240
241 while (timeout) {
242 if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
243 *data = inb(ISA_PORT_SDI);
244 return 0;
245 } else {
246 timeout--;
247 udelay(10);
248 }
249 }
250 return 1;
251 }
252
253 void
254 act2000_isa_receive(act2000_card *card)
255 {
256 u_char c;
257
258 if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
259 return;
260 while (!act2000_isa_readb(card, &c)) {
261 if (card->idat.isa.rcvidx < 8) {
262 card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
263 if (card->idat.isa.rcvidx == 8) {
264 int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
265
266 if (valid) {
267 card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
268 card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
269 if (card->idat.isa.rcvskb == NULL) {
270 card->idat.isa.rcvignore = 1;
271 printk(KERN_WARNING
272 "act2000_isa_receive: no memory\n");
273 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
274 return;
275 }
276 memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
277 card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
278 } else {
279 card->idat.isa.rcvidx = 0;
280 printk(KERN_WARNING
281 "act2000_isa_receive: Invalid CAPI msg\n");
282 {
283 int i; __u8 *p; __u8 *c; __u8 tmp[30];
284 for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
285 c += sprintf(c, "%02x ", *(p++));
286 printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
287 }
288 }
289 }
290 } else {
291 if (!card->idat.isa.rcvignore)
292 *card->idat.isa.rcvptr++ = c;
293 if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
294 if (!card->idat.isa.rcvignore) {
295 skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
296 act2000_schedule_rx(card);
297 }
298 card->idat.isa.rcvidx = 0;
299 card->idat.isa.rcvlen = 8;
300 card->idat.isa.rcvignore = 0;
301 card->idat.isa.rcvskb = NULL;
302 card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
303 }
304 }
305 }
306 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
307 /* In polling mode, schedule myself */
308 if ((card->idat.isa.rcvidx) &&
309 (card->idat.isa.rcvignore ||
310 (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
311 act2000_schedule_poll(card);
312 }
313 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
314 }
315
316 void
317 act2000_isa_send(act2000_card * card)
318 {
319 unsigned long flags;
320 struct sk_buff *skb;
321 actcapi_msg *msg;
322 int l;
323
324 if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
325 return;
326 while (1) {
327 save_flags(flags);
328 cli();
329 if (!(card->sbuf)) {
330 if ((card->sbuf = skb_dequeue(&card->sndq))) {
331 card->ack_msg = card->sbuf->data;
332 msg = (actcapi_msg *)card->sbuf->data;
333 if ((msg->hdr.cmd.cmd == 0x86) &&
334 (msg->hdr.cmd.subcmd == 0) ) {
335 /* Save flags in message */
336 card->need_b3ack = msg->msg.data_b3_req.flags;
337 msg->msg.data_b3_req.flags = 0;
338 }
339 }
340 }
341 restore_flags(flags);
342 if (!(card->sbuf)) {
343 /* No more data to send */
344 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
345 return;
346 }
347 skb = card->sbuf;
348 l = 0;
349 while (skb->len) {
350 if (act2000_isa_writeb(card, *(skb->data))) {
351 /* Fifo is full, but more data to send */
352 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
353 /* Schedule myself */
354 act2000_schedule_tx(card);
355 return;
356 }
357 skb_pull(skb, 1);
358 l++;
359 }
360 msg = (actcapi_msg *)card->ack_msg;
361 if ((msg->hdr.cmd.cmd == 0x86) &&
362 (msg->hdr.cmd.subcmd == 0) ) {
363 /*
364 * If it's user data, reset data-ptr
365 * and put skb into ackq.
366 */
367 skb->data = card->ack_msg;
368 /* Restore flags in message */
369 msg->msg.data_b3_req.flags = card->need_b3ack;
370 skb_queue_tail(&card->ackq, skb);
371 } else
372 dev_kfree_skb(skb);
373 card->sbuf = NULL;
374 }
375 }
376
377 /*
378 * Get firmware ID, check for 'ISDN' signature.
379 */
380 static int
381 act2000_isa_getid(act2000_card * card)
382 {
383
384 act2000_fwid fid;
385 u_char *p = (u_char *) & fid;
386 int count = 0;
387
388 while (1) {
389 if (count > 510)
390 return -EPROTO;
391 if (act2000_isa_readb(card, p++))
392 break;
393 count++;
394 }
395 if (count <= 20) {
396 printk(KERN_WARNING "act2000: No Firmware-ID!\n");
397 return -ETIME;
398 }
399 *p = '\0';
400 fid.revlen[0] = '\0';
401 if (strcmp(fid.isdn, "ISDN")) {
402 printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
403 return -EPROTO;
404 }
405 if ((p = strchr(fid.revision, '\n')))
406 *p = '\0';
407 printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
408 if (card->flags & ACT2000_FLAGS_IVALID) {
409 printk(KERN_DEBUG "Enabling Interrupts ...\n");
410 act2000_isa_enable_irq(card);
411 }
412 return 0;
413 }
414
415 /*
416 * Download microcode into card, check Firmware signature.
417 */
418 int
419 act2000_isa_download(act2000_card * card, act2000_ddef * cb)
420 {
421 unsigned int length;
422 int ret;
423 int l;
424 int c;
425 long timeout;
426 u_char *b;
427 u_char *p;
428 u_char *buf;
429 act2000_ddef cblock;
430
431 if (!act2000_isa_reset(card->port))
432 return -ENXIO;
433 act2000_isa_delay(HZ / 2);
434 if(copy_from_user(&cblock, (char *) cb, sizeof(cblock)))
435 return -EFAULT;
436 length = cblock.length;
437 p = cblock.buffer;
438 if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
439 return ret;
440 buf = (u_char *) kmalloc(1024, GFP_KERNEL);
441 if (!buf)
442 return -ENOMEM;
443 timeout = 0;
444 while (length) {
445 l = (length > 1024) ? 1024 : length;
446 c = 0;
447 b = buf;
448 copy_from_user(buf, p, l);
449 while (c < l) {
450 if (act2000_isa_writeb(card, *b++)) {
451 printk(KERN_WARNING
452 "act2000: loader timed out"
453 " len=%d c=%d\n", length, c);
454 kfree(buf);
455 return -ETIME;
456 }
457 c++;
458 }
459 length -= l;
460 p += l;
461 }
462 kfree(buf);
463 act2000_isa_delay(HZ / 2);
464 return (act2000_isa_getid(card));
465 }
466