Linux 2.1.127
[davej-history.git] / drivers / isdn / act2000 / act2000_isa.c
blobd19ff99e472039d11940d49a053d002fd7a54d1c
1 /* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
5 * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
6 * Thanks to Friedemann Baitinger and IBM Germany
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.
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.
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.
22 * $Log: act2000_isa.c,v $
23 * Revision 1.5 1998/02/12 23:06:47 keil
24 * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
26 * Revision 1.4 1997/10/09 22:23:00 fritz
27 * New HL<->LL interface:
28 * New BSENT callback with nr. of bytes included.
29 * Sending without ACK.
31 * Revision 1.3 1997/09/25 17:25:38 fritz
32 * Support for adding cards at runtime.
33 * Support for new Firmware.
35 * Revision 1.2 1997/09/24 23:11:44 fritz
36 * Optimized IRQ load and polling-mode.
38 * Revision 1.1 1997/09/23 18:00:05 fritz
39 * New driver for IBM Active 2000.
43 #define __NO_VERSION__
44 #include "act2000.h"
45 #include "act2000_isa.h"
46 #include "capi.h"
48 static act2000_card *irq2card_map[16] =
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
53 static int isa_irqs[] =
55 3, 5, 7, 10, 11, 12, 15
57 #define ISA_NRIRQS (sizeof(isa_irqs)/sizeof(int))
59 static void
60 isa_delay(long t)
62 sti();
63 current->state = TASK_INTERRUPTIBLE;
64 schedule_timeout(t);
65 sti();
69 * Reset Controller, then try to read the Card's signature.
70 + Return:
71 * 1 = Signature found.
72 * 0 = Signature not found.
74 static int
75 isa_reset(unsigned short portbase)
77 unsigned char reg;
78 int i;
79 int found;
80 int serial = 0;
82 found = 0;
83 if ((reg = inb(portbase + ISA_COR)) != 0xff) {
84 outb(reg | ISA_COR_RESET, portbase + ISA_COR);
85 mdelay(10);
86 outb(reg, portbase + ISA_COR);
87 mdelay(10);
89 for (i = 0; i < 16; i++) {
90 if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
91 serial |= 0x10000;
92 serial >>= 1;
94 if (serial == ISA_SER_ID)
95 found++;
97 return found;
101 isa_detect(unsigned short portbase)
103 int ret = 0;
104 unsigned long flags;
106 save_flags(flags);
107 cli();
108 if (!check_region(portbase, ISA_REGION))
109 ret = isa_reset(portbase);
110 restore_flags(flags);
111 return ret;
114 static void
115 isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
117 act2000_card *card = irq2card_map[irq];
118 u_char istatus;
120 if (!card) {
121 printk(KERN_WARNING
122 "act2000: Spurious interrupt!\n");
123 return;
125 istatus = (inb(ISA_PORT_ISR) & 0x07);
126 if (istatus & ISA_ISR_OUT) {
127 /* RX fifo has data */
128 istatus &= ISA_ISR_OUT_MASK;
129 outb(0, ISA_PORT_SIS);
130 isa_receive(card);
131 outb(ISA_SIS_INT, ISA_PORT_SIS);
133 if (istatus & ISA_ISR_ERR) {
134 /* Error Interrupt */
135 istatus &= ISA_ISR_ERR_MASK;
136 printk(KERN_WARNING "act2000: errIRQ\n");
138 if (istatus)
139 printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
142 static void
143 isa_select_irq(act2000_card * card)
145 unsigned char reg;
147 reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
148 switch (card->irq) {
149 case 3:
150 reg = ISA_COR_IRQ03;
151 break;
152 case 5:
153 reg = ISA_COR_IRQ05;
154 break;
155 case 7:
156 reg = ISA_COR_IRQ07;
157 break;
158 case 10:
159 reg = ISA_COR_IRQ10;
160 break;
161 case 11:
162 reg = ISA_COR_IRQ11;
163 break;
164 case 12:
165 reg = ISA_COR_IRQ12;
166 break;
167 case 15:
168 reg = ISA_COR_IRQ15;
169 break;
171 outb(reg, ISA_PORT_COR);
174 static void
175 isa_enable_irq(act2000_card * card)
177 isa_select_irq(card);
178 /* Enable READ irq */
179 outb(ISA_SIS_INT, ISA_PORT_SIS);
183 * Install interrupt handler, enable irq on card.
184 * If irq is -1, choose next free irq, else irq is given explicitely.
187 isa_config_irq(act2000_card * card, short irq)
189 int i;
190 unsigned long flags;
192 if (card->flags & ACT2000_FLAGS_IVALID) {
193 free_irq(card->irq, NULL);
194 irq2card_map[card->irq] = NULL;
196 card->flags &= ~ACT2000_FLAGS_IVALID;
197 outb(ISA_COR_IRQOFF, ISA_PORT_COR);
198 if (!irq)
199 return 0;
200 save_flags(flags);
201 cli();
202 if (irq == -1) {
203 /* Auto select */
204 for (i = 0; i < ISA_NRIRQS; i++) {
205 if (!request_irq(isa_irqs[i], &isa_interrupt, 0, card->regname, NULL)) {
206 card->irq = isa_irqs[i];
207 irq2card_map[card->irq] = card;
208 card->flags |= ACT2000_FLAGS_IVALID;
209 break;
212 } else {
213 /* Fixed irq */
214 if (!request_irq(irq, &isa_interrupt, 0, card->regname, NULL)) {
215 card->irq = irq;
216 irq2card_map[card->irq] = card;
217 card->flags |= ACT2000_FLAGS_IVALID;
220 restore_flags(flags);
221 if (!card->flags & ACT2000_FLAGS_IVALID) {
222 printk(KERN_WARNING
223 "act2000: Could not request irq\n");
224 return -EBUSY;
225 } else {
226 isa_select_irq(card);
227 /* Disable READ and WRITE irq */
228 outb(0, ISA_PORT_SIS);
229 outb(0, ISA_PORT_SOS);
231 return 0;
235 isa_config_port(act2000_card * card, unsigned short portbase)
237 if (card->flags & ACT2000_FLAGS_PVALID) {
238 release_region(card->port, ISA_REGION);
239 card->flags &= ~ACT2000_FLAGS_PVALID;
241 if (!check_region(portbase, ISA_REGION)) {
242 request_region(portbase, ACT2000_PORTLEN, card->regname);
243 card->port = portbase;
244 card->flags |= ACT2000_FLAGS_PVALID;
245 return 0;
247 return -EBUSY;
251 * Release ressources, used by an adaptor.
253 void
254 isa_release(act2000_card * card)
256 unsigned long flags;
258 save_flags(flags);
259 cli();
260 if (card->flags & ACT2000_FLAGS_IVALID) {
261 free_irq(card->irq, NULL);
262 irq2card_map[card->irq] = NULL;
264 card->flags &= ~ACT2000_FLAGS_IVALID;
265 if (card->flags & ACT2000_FLAGS_PVALID)
266 release_region(card->port, ISA_REGION);
267 card->flags &= ~ACT2000_FLAGS_PVALID;
268 restore_flags(flags);
271 static int
272 isa_writeb(act2000_card * card, u_char data)
274 u_char timeout = 40;
276 while (timeout) {
277 if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
278 outb(data, ISA_PORT_SDO);
279 return 0;
280 } else {
281 timeout--;
282 udelay(10);
285 return 1;
288 static int
289 isa_readb(act2000_card * card, u_char * data)
291 u_char timeout = 40;
293 while (timeout) {
294 if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
295 *data = inb(ISA_PORT_SDI);
296 return 0;
297 } else {
298 timeout--;
299 udelay(10);
302 return 1;
305 void
306 isa_receive(act2000_card *card)
308 u_char c;
310 if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
311 return;
312 while (!isa_readb(card, &c)) {
313 if (card->idat.isa.rcvidx < 8) {
314 card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
315 if (card->idat.isa.rcvidx == 8) {
316 int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
318 if (valid) {
319 card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
320 card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
321 if (card->idat.isa.rcvskb == NULL) {
322 card->idat.isa.rcvignore = 1;
323 printk(KERN_WARNING
324 "isa_receive: no memory\n");
325 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
326 return;
328 memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
329 card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
330 } else {
331 card->idat.isa.rcvidx = 0;
332 printk(KERN_WARNING
333 "isa_receive: Invalid CAPI msg\n");
335 int i; __u8 *p; __u8 *c; __u8 tmp[30];
336 for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
337 c += sprintf(c, "%02x ", *(p++));
338 printk(KERN_WARNING "isa_receive: %s\n", tmp);
342 } else {
343 if (!card->idat.isa.rcvignore)
344 *card->idat.isa.rcvptr++ = c;
345 if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
346 if (!card->idat.isa.rcvignore) {
347 skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
348 act2000_schedule_rx(card);
350 card->idat.isa.rcvidx = 0;
351 card->idat.isa.rcvlen = 8;
352 card->idat.isa.rcvignore = 0;
353 card->idat.isa.rcvskb = NULL;
354 card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
358 if (!(card->flags & ACT2000_FLAGS_IVALID)) {
359 /* In polling mode, schedule myself */
360 if ((card->idat.isa.rcvidx) &&
361 (card->idat.isa.rcvignore ||
362 (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
363 act2000_schedule_poll(card);
365 test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
368 void
369 isa_send(act2000_card * card)
371 unsigned long flags;
372 struct sk_buff *skb;
373 actcapi_msg *msg;
374 int l;
376 if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
377 return;
378 while (1) {
379 save_flags(flags);
380 cli();
381 if (!(card->sbuf)) {
382 if ((card->sbuf = skb_dequeue(&card->sndq))) {
383 card->ack_msg = card->sbuf->data;
384 msg = (actcapi_msg *)card->sbuf->data;
385 if ((msg->hdr.cmd.cmd == 0x86) &&
386 (msg->hdr.cmd.subcmd == 0) ) {
387 /* Save flags in message */
388 card->need_b3ack = msg->msg.data_b3_req.flags;
389 msg->msg.data_b3_req.flags = 0;
393 restore_flags(flags);
394 if (!(card->sbuf)) {
395 /* No more data to send */
396 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
397 return;
399 skb = card->sbuf;
400 l = 0;
401 while (skb->len) {
402 if (isa_writeb(card, *(skb->data))) {
403 /* Fifo is full, but more data to send */
404 #if 0
405 printk(KERN_DEBUG "isa_send: %d bytes\n", l);
406 #endif
407 test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
408 /* Schedule myself */
409 act2000_schedule_tx(card);
410 return;
412 skb_pull(skb, 1);
413 l++;
415 msg = (actcapi_msg *)card->ack_msg;
416 if ((msg->hdr.cmd.cmd == 0x86) &&
417 (msg->hdr.cmd.subcmd == 0) ) {
419 * If it's user data, reset data-ptr
420 * and put skb into ackq.
422 skb->data = card->ack_msg;
423 /* Restore flags in message */
424 msg->msg.data_b3_req.flags = card->need_b3ack;
425 skb_queue_tail(&card->ackq, skb);
426 } else
427 dev_kfree_skb(skb);
428 card->sbuf = NULL;
429 #if 0
430 printk(KERN_DEBUG "isa_send: %d bytes\n", l);
431 #endif
436 * Get firmware ID, check for 'ISDN' signature.
438 static int
439 isa_getid(act2000_card * card)
442 act2000_fwid fid;
443 u_char *p = (u_char *) & fid;
444 int count = 0;
446 while (1) {
447 if (count > 510)
448 return -EPROTO;
449 if (isa_readb(card, p++))
450 break;
451 count++;
453 if (count <= 20) {
454 printk(KERN_WARNING "act2000: No Firmware-ID!\n");
455 return -ETIME;
457 *p = '\0';
458 fid.revlen[0] = '\0';
459 if (strcmp(fid.isdn, "ISDN")) {
460 printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
461 return -EPROTO;
463 if ((p = strchr(fid.revision, '\n')))
464 *p = '\0';
465 printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
466 if (card->flags & ACT2000_FLAGS_IVALID) {
467 printk(KERN_DEBUG "Enabling Interrupts ...\n");
468 isa_enable_irq(card);
470 return 0;
474 * Download microcode into card, check Firmware signature.
477 isa_download(act2000_card * card, act2000_ddef * cb)
479 int length;
480 int ret;
481 int l;
482 int c;
483 long timeout;
484 u_char *b;
485 u_char *p;
486 u_char *buf;
487 act2000_ddef cblock;
489 if (!isa_reset(card->port))
490 return -ENXIO;
491 isa_delay(HZ / 2);
492 if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
493 return ret;
494 copy_from_user(&cblock, (char *) cb, sizeof(cblock));
495 length = cblock.length;
496 p = cblock.buffer;
497 if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
498 return ret;
499 buf = (u_char *) kmalloc(1024, GFP_KERNEL);
500 if (!buf)
501 return -ENOMEM;
502 timeout = 0;
503 while (length) {
504 l = (length > 1024) ? 1024 : length;
505 c = 0;
506 b = buf;
507 copy_from_user(buf, p, l);
508 while (c < l) {
509 if (isa_writeb(card, *b++)) {
510 printk(KERN_WARNING
511 "act2000: loader timed out"
512 " len=%d c=%d\n", length, c);
513 kfree(buf);
514 return -ETIME;
516 c++;
518 length -= l;
519 p += l;
521 kfree(buf);
522 isa_delay(HZ / 2);
523 return (isa_getid(card));