import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / isdn / hisax / teles3.c
1 /* $Id: teles3.c,v 1.1.1.1 2005/04/11 02:50:24 jack Exp $
2  *
3  * low level stuff for Teles 16.3 & PNP isdn cards
4  *
5  * Author       Karsten Keil
6  * Copyright    by Karsten Keil      <keil@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    Jan den Ouden
12  *              Fritz Elfert
13  *              Beat Doebeli
14  *
15  */
16 #define __NO_VERSION__
17 #include <linux/init.h>
18 #include <linux/isapnp.h>
19 #include "hisax.h"
20 #include "isac.h"
21 #include "hscx.h"
22 #include "isdnl1.h"
23
24 extern const char *CardType[];
25 const char *teles3_revision = "$Revision: 1.1.1.1 $";
26
27 #define byteout(addr,val) outb(val,addr)
28 #define bytein(addr) inb(addr)
29
30 static inline u_char
31 readreg(unsigned int adr, u_char off)
32 {
33         return (bytein(adr + off));
34 }
35
36 static inline void
37 writereg(unsigned int adr, u_char off, u_char data)
38 {
39         byteout(adr + off, data);
40 }
41
42
43 static inline void
44 read_fifo(unsigned int adr, u_char * data, int size)
45 {
46         insb(adr, data, size);
47 }
48
49 static void
50 write_fifo(unsigned int adr, u_char * data, int size)
51 {
52         outsb(adr, data, size);
53 }
54
55 /* Interface functions */
56
57 static u_char
58 ReadISAC(struct IsdnCardState *cs, u_char offset)
59 {
60         return (readreg(cs->hw.teles3.isac, offset));
61 }
62
63 static void
64 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
65 {
66         writereg(cs->hw.teles3.isac, offset, value);
67 }
68
69 static void
70 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
71 {
72         read_fifo(cs->hw.teles3.isacfifo, data, size);
73 }
74
75 static void
76 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
77 {
78         write_fifo(cs->hw.teles3.isacfifo, data, size);
79 }
80
81 static u_char
82 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
83 {
84         return (readreg(cs->hw.teles3.hscx[hscx], offset));
85 }
86
87 static void
88 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
89 {
90         writereg(cs->hw.teles3.hscx[hscx], offset, value);
91 }
92
93 /*
94  * fast interrupt HSCX stuff goes here
95  */
96
97 #define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
98 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
99 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
100 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
101
102 #include "hscx_irq.c"
103
104 static void
105 teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
106 {
107 #define MAXCOUNT 5
108         struct IsdnCardState *cs = dev_id;
109         u_char val;
110         int count = 0;
111
112         if (!cs) {
113                 printk(KERN_WARNING "Teles: Spurious interrupt!\n");
114                 return;
115         }
116         val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
117       Start_HSCX:
118         if (val)
119                 hscx_int_main(cs, val);
120         val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
121       Start_ISAC:
122         if (val)
123                 isac_interrupt(cs, val);
124         count++;
125         val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
126         if (val && count < MAXCOUNT) {
127                 if (cs->debug & L1_DEB_HSCX)
128                         debugl1(cs, "HSCX IntStat after IntRoutine");
129                 goto Start_HSCX;
130         }
131         val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
132         if (val && count < MAXCOUNT) {
133                 if (cs->debug & L1_DEB_ISAC)
134                         debugl1(cs, "ISAC IntStat after IntRoutine");
135                 goto Start_ISAC;
136         }
137         if (count >= MAXCOUNT)
138                 printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
139         writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
140         writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
141         writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
142         writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
143         writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
144         writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
145 }
146
147 inline static void
148 release_ioregs(struct IsdnCardState *cs, int mask)
149 {
150         if (mask & 1)
151                 release_region(cs->hw.teles3.isac + 32, 32);
152         if (mask & 2)
153                 release_region(cs->hw.teles3.hscx[0] + 32, 32);
154         if (mask & 4)
155                 release_region(cs->hw.teles3.hscx[1] + 32, 32);
156 }
157
158 void
159 release_io_teles3(struct IsdnCardState *cs)
160 {
161         if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
162                 release_region(cs->hw.teles3.hscx[1], 96);
163         } else {
164                 if (cs->hw.teles3.cfg_reg) {
165                         if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
166                                 release_region(cs->hw.teles3.cfg_reg, 1);
167                         } else {
168                                 release_region(cs->hw.teles3.cfg_reg, 8);
169                         }
170                 }
171                 release_ioregs(cs, 0x7);
172         }
173 }
174
175 static int
176 reset_teles3(struct IsdnCardState *cs)
177 {
178         long flags;
179         u_char irqcfg;
180
181         if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
182                 if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
183                         switch (cs->irq) {
184                                 case 2:
185                                 case 9:
186                                         irqcfg = 0x00;
187                                         break;
188                                 case 3:
189                                         irqcfg = 0x02;
190                                         break;
191                                 case 4:
192                                         irqcfg = 0x04;
193                                         break;
194                                 case 5:
195                                         irqcfg = 0x06;
196                                         break;
197                                 case 10:
198                                         irqcfg = 0x08;
199                                         break;
200                                 case 11:
201                                         irqcfg = 0x0A;
202                                         break;
203                                 case 12:
204                                         irqcfg = 0x0C;
205                                         break;
206                                 case 15:
207                                         irqcfg = 0x0E;
208                                         break;
209                                 default:
210                                         return(1);
211                         }
212                         save_flags(flags);
213                         byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
214                         sti();
215                         HZDELAY(HZ / 10 + 1);
216                         byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
217                         HZDELAY(HZ / 10 + 1);
218                         restore_flags(flags);
219                 } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
220                         save_flags(flags);
221                         byteout(cs->hw.teles3.cfg_reg, 0xff);
222                         HZDELAY(2);
223                         byteout(cs->hw.teles3.cfg_reg, 0x00);
224                         HZDELAY(2);
225                         restore_flags(flags);
226                 } else {
227                         /* Reset off for 16.3 PnP , thanks to Georg Acher */
228                         save_flags(flags);
229                         byteout(cs->hw.teles3.isac + 0x3c, 0);
230                         HZDELAY(2);
231                         byteout(cs->hw.teles3.isac + 0x3c, 1);
232                         HZDELAY(2);
233                         restore_flags(flags);
234                 }
235         }
236         return(0);
237 }
238
239 static int
240 Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
241 {
242         switch (mt) {
243                 case CARD_RESET:
244                         reset_teles3(cs);
245                         return(0);
246                 case CARD_RELEASE:
247                         release_io_teles3(cs);
248                         return(0);
249                 case CARD_INIT:
250                         inithscxisac(cs, 3);
251                         return(0);
252                 case CARD_TEST:
253                         return(0);
254         }
255         return(0);
256 }
257
258 #ifdef __ISAPNP__
259 static struct isapnp_device_id teles_ids[] __initdata = {
260         { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
261           ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
262           (unsigned long) "Teles 16.3 PnP" },
263         { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
264           ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), 
265           (unsigned long) "Creatix 16.3 PnP" },
266         { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
267           ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), 
268           (unsigned long) "Compaq ISDN S0" },
269         { 0, }
270 };
271
272 static struct isapnp_device_id *tdev = &teles_ids[0];
273 static struct pci_bus *pnp_c __devinitdata = NULL;
274 #endif
275
276 int __devinit
277 setup_teles3(struct IsdnCard *card)
278 {
279         u_char val;
280         struct IsdnCardState *cs = card->cs;
281         char tmp[64];
282
283         strcpy(tmp, teles3_revision);
284         printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
285         if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
286             && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
287                 return (0);
288
289 #ifdef __ISAPNP__
290         if (!card->para[1] && isapnp_present()) {
291                 struct pci_bus *pb;
292                 struct pci_dev *pd;
293
294                 while(tdev->card_vendor) {
295                         if ((pb = isapnp_find_card(tdev->card_vendor,
296                                 tdev->card_device, pnp_c))) {
297                                 pnp_c = pb;
298                                 pd = NULL;
299                                 if ((pd = isapnp_find_dev(pnp_c,
300                                         tdev->vendor, tdev->function, pd))) {
301                                         printk(KERN_INFO "HiSax: %s detected\n",
302                                                 (char *)tdev->driver_data);
303                                         pd->prepare(pd);
304                                         pd->deactivate(pd);
305                                         pd->activate(pd);
306                                         card->para[3] = pd->resource[2].start;
307                                         card->para[2] = pd->resource[1].start;
308                                         card->para[1] = pd->resource[0].start;
309                                         card->para[0] = pd->irq_resource[0].start;
310                                         if (!card->para[0] || !card->para[1] || !card->para[2]) {
311                                                 printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
312                                                 card->para[0], card->para[1], card->para[2]);
313                                                 pd->deactivate(pd);
314                                                 return(0);
315                                         }
316                                         break;
317                                 } else {
318                                         printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
319                                 }
320                         }
321                         tdev++;
322                         pnp_c=NULL;
323                 } 
324                 if (!tdev->card_vendor) {
325                         printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
326                         return(0);
327                 }
328         }
329 #endif
330         if (cs->typ == ISDN_CTYPE_16_3) {
331                 cs->hw.teles3.cfg_reg = card->para[1];
332                 switch (cs->hw.teles3.cfg_reg) {
333                         case 0x180:
334                         case 0x280:
335                         case 0x380:
336                                 cs->hw.teles3.cfg_reg |= 0xc00;
337                                 break;
338                 }
339                 cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
340                 cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
341                 cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
342         } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
343                 cs->hw.teles3.cfg_reg = 0;
344                 cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
345                 cs->hw.teles3.hscx[1] = card->para[1];
346                 cs->hw.teles3.isac = card->para[1] + 0x20;
347         } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
348                 cs->hw.teles3.cfg_reg = card->para[3];
349                 cs->hw.teles3.isac = card->para[2] - 32;
350                 cs->hw.teles3.hscx[0] = card->para[1] - 32;
351                 cs->hw.teles3.hscx[1] = card->para[1];
352         } else {        /* PNP */
353                 cs->hw.teles3.cfg_reg = 0;
354                 cs->hw.teles3.isac = card->para[1] - 32;
355                 cs->hw.teles3.hscx[0] = card->para[2] - 32;
356                 cs->hw.teles3.hscx[1] = card->para[2];
357         }
358         cs->irq = card->para[0];
359         cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
360         cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
361         cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
362         if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
363                 if (check_region((cs->hw.teles3.hscx[1]), 96 )) {
364                         printk(KERN_WARNING
365                                "HiSax: %s ports %x-%x already in use\n",
366                                CardType[cs->typ],
367                                cs->hw.teles3.hscx[1],
368                                cs->hw.teles3.hscx[1] + 96);
369                         return (0);
370                 } else
371                         request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA");
372         } else {
373                 if (cs->hw.teles3.cfg_reg) {
374                         if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
375                                 if (check_region((cs->hw.teles3.cfg_reg), 1)) {
376                                         printk(KERN_WARNING
377                                                 "HiSax: %s config port %x already in use\n",
378                                                 CardType[card->typ],
379                                                 cs->hw.teles3.cfg_reg);
380                                         return (0);
381                                 } else
382                                         request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg");
383                         } else {
384                                 if (check_region((cs->hw.teles3.cfg_reg), 8)) {
385                                         printk(KERN_WARNING
386                                                "HiSax: %s config port %x-%x already in use\n",
387                                                CardType[card->typ],
388                                                cs->hw.teles3.cfg_reg,
389                                                 cs->hw.teles3.cfg_reg + 8);
390                                         return (0);
391                                 } else
392                                         request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg");
393                         }
394                 }
395                 if (check_region((cs->hw.teles3.isac + 32), 32)) {
396                         printk(KERN_WARNING
397                            "HiSax: %s isac ports %x-%x already in use\n",
398                                CardType[cs->typ],
399                                cs->hw.teles3.isac + 32,
400                                cs->hw.teles3.isac + 64);
401                         if (cs->hw.teles3.cfg_reg) {
402                                 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
403                                         release_region(cs->hw.teles3.cfg_reg, 1);
404                                 } else {
405                                         release_region(cs->hw.teles3.cfg_reg, 8);
406                                 }
407                         }
408                         return (0);
409                 } else
410                         request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac");
411                 if (check_region((cs->hw.teles3.hscx[0] + 32), 32)) {
412                         printk(KERN_WARNING
413                          "HiSax: %s hscx A ports %x-%x already in use\n",
414                                CardType[cs->typ],
415                                cs->hw.teles3.hscx[0] + 32,
416                                cs->hw.teles3.hscx[0] + 64);
417                         if (cs->hw.teles3.cfg_reg) {
418                                 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
419                                         release_region(cs->hw.teles3.cfg_reg, 1);
420                                 } else {
421                                         release_region(cs->hw.teles3.cfg_reg, 8);
422                                 }
423                         }
424                         release_ioregs(cs, 1);
425                         return (0);
426                 } else
427                         request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A");
428                 if (check_region((cs->hw.teles3.hscx[1] + 32), 32)) {
429                         printk(KERN_WARNING
430                          "HiSax: %s hscx B ports %x-%x already in use\n",
431                                CardType[cs->typ],
432                                cs->hw.teles3.hscx[1] + 32,
433                                cs->hw.teles3.hscx[1] + 64);
434                         if (cs->hw.teles3.cfg_reg) {
435                                 if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
436                                         release_region(cs->hw.teles3.cfg_reg, 1);
437                                 } else {
438                                         release_region(cs->hw.teles3.cfg_reg, 8);
439                                 }
440                         }
441                         release_ioregs(cs, 3);
442                         return (0);
443                 } else
444                         request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B");
445         }
446         if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
447                 if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
448                         printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
449                                cs->hw.teles3.cfg_reg + 0, val);
450                         release_io_teles3(cs);
451                         return (0);
452                 }
453                 if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
454                         printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
455                                cs->hw.teles3.cfg_reg + 1, val);
456                         release_io_teles3(cs);
457                         return (0);
458                 }
459                 val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
460                                                          * 0x1f=with AB
461                                                          * 0x1c 16.3 ???
462                                                          * 0x39 16.3 1.1
463                                                          * 0x38 16.3 1.3
464                                                          * 0x46 16.3 with AB + Video (Teles-Vision)
465                                                          */
466                 if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
467                         printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
468                                cs->hw.teles3.cfg_reg + 2, val);
469                         release_io_teles3(cs);
470                         return (0);
471                 }
472         }
473         printk(KERN_INFO
474                "HiSax: %s config irq:%d isac:0x%X  cfg:0x%X\n",
475                CardType[cs->typ], cs->irq,
476                cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
477         printk(KERN_INFO
478                "HiSax: hscx A:0x%X  hscx B:0x%X\n",
479                cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
480
481         if (reset_teles3(cs)) {
482                 printk(KERN_WARNING "Teles3: wrong IRQ\n");
483                 release_io_teles3(cs);
484                 return (0);
485         }
486         cs->readisac = &ReadISAC;
487         cs->writeisac = &WriteISAC;
488         cs->readisacfifo = &ReadISACfifo;
489         cs->writeisacfifo = &WriteISACfifo;
490         cs->BC_Read_Reg = &ReadHSCX;
491         cs->BC_Write_Reg = &WriteHSCX;
492         cs->BC_Send_Data = &hscx_fill_fifo;
493         cs->cardmsg = &Teles_card_msg;
494         cs->irq_func = &teles3_interrupt;
495         ISACVersion(cs, "Teles3:");
496         if (HscxVersion(cs, "Teles3:")) {
497                 printk(KERN_WARNING
498                        "Teles3: wrong HSCX versions check IO address\n");
499                 release_io_teles3(cs);
500                 return (0);
501         }
502         return (1);
503 }