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