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