import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / isdn / hisax / sportster.c
1 /* $Id: sportster.c,v 1.1.1.1 2005/04/11 02:50:23 jack Exp $
2  *
3  * low level stuff for USR Sportster internal TA
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 Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
12  *
13  *
14  */
15 #define __NO_VERSION__
16 #include <linux/init.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
21
22 extern const char *CardType[];
23 const char *sportster_revision = "$Revision: 1.1.1.1 $";
24
25 #define byteout(addr,val) outb(val,addr)
26 #define bytein(addr) inb(addr)
27
28 #define  SPORTSTER_ISAC         0xC000
29 #define  SPORTSTER_HSCXA        0x0000
30 #define  SPORTSTER_HSCXB        0x4000
31 #define  SPORTSTER_RES_IRQ      0x8000
32 #define  SPORTSTER_RESET        0x80
33 #define  SPORTSTER_INTE         0x40
34
35 static inline int
36 calc_off(unsigned int base, unsigned int off)
37 {
38         return(base + ((off & 0xfc)<<8) + ((off & 3)<<1));
39 }
40
41 static inline void
42 read_fifo(unsigned int adr, u_char * data, int size)
43 {
44         insb(adr, data, size);
45 }
46
47 static void
48 write_fifo(unsigned int adr, u_char * data, int size)
49 {
50         outsb(adr, data, size);
51 }
52
53 /* Interface functions */
54
55 static u_char
56 ReadISAC(struct IsdnCardState *cs, u_char offset)
57 {
58         return (bytein(calc_off(cs->hw.spt.isac, offset)));
59 }
60
61 static void
62 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
63 {
64         byteout(calc_off(cs->hw.spt.isac, offset), value);
65 }
66
67 static void
68 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
69 {
70         read_fifo(cs->hw.spt.isac, data, size);
71 }
72
73 static void
74 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
75 {
76         write_fifo(cs->hw.spt.isac, data, size);
77 }
78
79 static u_char
80 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
81 {
82         return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
83 }
84
85 static void
86 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
87 {
88         byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
89 }
90
91 /*
92  * fast interrupt HSCX stuff goes here
93  */
94
95 #define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
96 #define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
97 #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
98 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
99
100 #include "hscx_irq.c"
101
102 static void
103 sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
104 {
105         struct IsdnCardState *cs = dev_id;
106         u_char val;
107
108         if (!cs) {
109                 printk(KERN_WARNING "Sportster: Spurious interrupt!\n");
110                 return;
111         }
112         val = READHSCX(cs, 1, HSCX_ISTA);
113       Start_HSCX:
114         if (val)
115                 hscx_int_main(cs, val);
116         val = ReadISAC(cs, ISAC_ISTA);
117       Start_ISAC:
118         if (val)
119                 isac_interrupt(cs, val);
120         val = READHSCX(cs, 1, HSCX_ISTA);
121         if (val) {
122                 if (cs->debug & L1_DEB_HSCX)
123                         debugl1(cs, "HSCX IntStat after IntRoutine");
124                 goto Start_HSCX;
125         }
126         val = ReadISAC(cs, ISAC_ISTA);
127         if (val) {
128                 if (cs->debug & L1_DEB_ISAC)
129                         debugl1(cs, "ISAC IntStat after IntRoutine");
130                 goto Start_ISAC;
131         }
132         /* get a new irq impulse if there any pending */
133         bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
134 }
135
136 void
137 release_io_sportster(struct IsdnCardState *cs)
138 {
139         int i, adr;
140
141         byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
142         for (i=0; i<64; i++) {
143                 adr = cs->hw.spt.cfg_reg + i *1024;
144                 release_region(adr, 8);
145         }
146 }
147
148 void
149 reset_sportster(struct IsdnCardState *cs)
150 {
151         long flags;
152
153         cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
154         byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
155         save_flags(flags);
156         sti();
157         set_current_state(TASK_UNINTERRUPTIBLE);
158         schedule_timeout((10*HZ)/1000);
159         cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
160         byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
161         set_current_state(TASK_UNINTERRUPTIBLE);
162         schedule_timeout((10*HZ)/1000);
163         restore_flags(flags);
164 }
165
166 static int
167 Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
168 {
169         switch (mt) {
170                 case CARD_RESET:
171                         reset_sportster(cs);
172                         return(0);
173                 case CARD_RELEASE:
174                         release_io_sportster(cs);
175                         return(0);
176                 case CARD_INIT:
177                         inithscxisac(cs, 1);
178                         cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
179                         byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
180                         inithscxisac(cs, 2);
181                         return(0);
182                 case CARD_TEST:
183                         return(0);
184         }
185         return(0);
186 }
187
188 static int __init
189 get_io_range(struct IsdnCardState *cs)
190 {
191         int i, j, adr;
192         
193         for (i=0;i<64;i++) {
194                 adr = cs->hw.spt.cfg_reg + i *1024;
195                 if (check_region(adr, 8)) {
196                         printk(KERN_WARNING
197                                 "HiSax: %s config port %x-%x already in use\n",
198                                 CardType[cs->typ], adr, adr + 8);
199                         break;
200                 } else
201                         request_region(adr, 8, "sportster");
202         }
203         if (i==64)
204                 return(1);
205         else {
206                 for (j=0; j<i; j++) {
207                         adr = cs->hw.spt.cfg_reg + j *1024;
208                         release_region(adr, 8);
209                 }
210                 return(0);
211         }
212 }
213
214 int __init
215 setup_sportster(struct IsdnCard *card)
216 {
217         struct IsdnCardState *cs = card->cs;
218         char tmp[64];
219
220         strcpy(tmp, sportster_revision);
221         printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
222         if (cs->typ != ISDN_CTYPE_SPORTSTER)
223                 return (0);
224
225         cs->hw.spt.cfg_reg = card->para[1];
226         cs->irq = card->para[0];
227         if (!get_io_range(cs))
228                 return (0);
229         cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
230         cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
231         cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
232         
233         switch(cs->irq) {
234                 case 5: cs->hw.spt.res_irq = 1;
235                         break;
236                 case 7: cs->hw.spt.res_irq = 2;
237                         break;
238                 case 10:cs->hw.spt.res_irq = 3;
239                         break;
240                 case 11:cs->hw.spt.res_irq = 4;
241                         break;
242                 case 12:cs->hw.spt.res_irq = 5;
243                         break;
244                 case 14:cs->hw.spt.res_irq = 6;
245                         break;
246                 case 15:cs->hw.spt.res_irq = 7;
247                         break;
248                 default:release_io_sportster(cs);
249                         printk(KERN_WARNING "Sportster: wrong IRQ\n");
250                         return(0);
251         }
252         reset_sportster(cs);
253         printk(KERN_INFO
254                "HiSax: %s config irq:%d cfg:0x%X\n",
255                CardType[cs->typ], cs->irq,
256                cs->hw.spt.cfg_reg);
257
258         cs->readisac = &ReadISAC;
259         cs->writeisac = &WriteISAC;
260         cs->readisacfifo = &ReadISACfifo;
261         cs->writeisacfifo = &WriteISACfifo;
262         cs->BC_Read_Reg = &ReadHSCX;
263         cs->BC_Write_Reg = &WriteHSCX;
264         cs->BC_Send_Data = &hscx_fill_fifo;
265         cs->cardmsg = &Sportster_card_msg;
266         cs->irq_func = &sportster_interrupt;
267         ISACVersion(cs, "Sportster:");
268         if (HscxVersion(cs, "Sportster:")) {
269                 printk(KERN_WARNING
270                        "Sportster: wrong HSCX versions check IO address\n");
271                 release_io_sportster(cs);
272                 return (0);
273         }
274         return (1);
275 }