Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $ |
2 | * | |
3 | * low level stuff for HST Saphir 1 | |
4 | * | |
5 | * Author Karsten Keil | |
6 | * Copyright by Karsten Keil <keil@isdn4linux.de> | |
475be4d8 | 7 | * |
1da177e4 LT |
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 HST High Soft Tech GmbH | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <linux/init.h> | |
16 | #include "hisax.h" | |
17 | #include "isac.h" | |
18 | #include "hscx.h" | |
19 | #include "isdnl1.h" | |
20 | ||
1da177e4 LT |
21 | static char *saphir_rev = "$Revision: 1.10.2.4 $"; |
22 | ||
475be4d8 | 23 | #define byteout(addr, val) outb(val, addr) |
1da177e4 LT |
24 | #define bytein(addr) inb(addr) |
25 | ||
26 | #define ISAC_DATA 0 | |
27 | #define HSCX_DATA 1 | |
28 | #define ADDRESS_REG 2 | |
29 | #define IRQ_REG 3 | |
30 | #define SPARE_REG 4 | |
31 | #define RESET_REG 5 | |
32 | ||
33 | static inline u_char | |
34 | readreg(unsigned int ale, unsigned int adr, u_char off) | |
35 | { | |
36 | register u_char ret; | |
37 | ||
38 | byteout(ale, off); | |
39 | ret = bytein(adr); | |
40 | return (ret); | |
41 | } | |
42 | ||
43 | static inline void | |
475be4d8 | 44 | readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) |
1da177e4 LT |
45 | { |
46 | byteout(ale, off); | |
47 | insb(adr, data, size); | |
48 | } | |
49 | ||
50 | ||
51 | static inline void | |
52 | writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) | |
53 | { | |
54 | byteout(ale, off); | |
55 | byteout(adr, data); | |
56 | } | |
57 | ||
58 | static inline void | |
475be4d8 | 59 | writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) |
1da177e4 LT |
60 | { |
61 | byteout(ale, off); | |
62 | outsb(adr, data, size); | |
63 | } | |
64 | ||
65 | /* Interface functions */ | |
66 | ||
67 | static u_char | |
68 | ReadISAC(struct IsdnCardState *cs, u_char offset) | |
69 | { | |
70 | return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); | |
71 | } | |
72 | ||
73 | static void | |
74 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | |
75 | { | |
76 | writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); | |
77 | } | |
78 | ||
79 | static void | |
475be4d8 | 80 | ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) |
1da177e4 LT |
81 | { |
82 | readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); | |
83 | } | |
84 | ||
85 | static void | |
475be4d8 | 86 | WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) |
1da177e4 LT |
87 | { |
88 | writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); | |
89 | } | |
90 | ||
91 | static u_char | |
92 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) | |
93 | { | |
94 | return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, | |
475be4d8 | 95 | offset + (hscx ? 0x40 : 0))); |
1da177e4 LT |
96 | } |
97 | ||
98 | static void | |
99 | WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) | |
100 | { | |
101 | writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, | |
475be4d8 | 102 | offset + (hscx ? 0x40 : 0), value); |
1da177e4 LT |
103 | } |
104 | ||
475be4d8 JP |
105 | #define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ |
106 | cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) | |
107 | #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ | |
108 | cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) | |
1da177e4 | 109 | |
475be4d8 JP |
110 | #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ |
111 | cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) | |
1da177e4 | 112 | |
475be4d8 JP |
113 | #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ |
114 | cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) | |
1da177e4 LT |
115 | |
116 | #include "hscx_irq.c" | |
117 | ||
118 | static irqreturn_t | |
7d12e780 | 119 | saphir_interrupt(int intno, void *dev_id) |
1da177e4 LT |
120 | { |
121 | struct IsdnCardState *cs = dev_id; | |
122 | u_char val; | |
123 | u_long flags; | |
124 | ||
125 | spin_lock_irqsave(&cs->lock, flags); | |
126 | val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); | |
475be4d8 | 127 | Start_HSCX: |
1da177e4 LT |
128 | if (val) |
129 | hscx_int_main(cs, val); | |
130 | val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); | |
475be4d8 | 131 | Start_ISAC: |
1da177e4 LT |
132 | if (val) |
133 | isac_interrupt(cs, val); | |
134 | val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); | |
135 | if (val) { | |
136 | if (cs->debug & L1_DEB_HSCX) | |
137 | debugl1(cs, "HSCX IntStat after IntRoutine"); | |
138 | goto Start_HSCX; | |
139 | } | |
140 | val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); | |
141 | if (val) { | |
142 | if (cs->debug & L1_DEB_ISAC) | |
143 | debugl1(cs, "ISAC IntStat after IntRoutine"); | |
144 | goto Start_ISAC; | |
145 | } | |
146 | /* Watchdog */ | |
475be4d8 JP |
147 | if (cs->hw.saphir.timer.function) |
148 | mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); | |
1da177e4 LT |
149 | else |
150 | printk(KERN_WARNING "saphir: Spurious timer!\n"); | |
151 | writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); | |
152 | writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); | |
153 | writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); | |
154 | writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); | |
155 | writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); | |
156 | writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); | |
157 | spin_unlock_irqrestore(&cs->lock, flags); | |
158 | return IRQ_HANDLED; | |
159 | } | |
160 | ||
161 | static void | |
162 | SaphirWatchDog(struct IsdnCardState *cs) | |
163 | { | |
164 | u_long flags; | |
165 | ||
166 | spin_lock_irqsave(&cs->lock, flags); | |
475be4d8 | 167 | /* 5 sec WatchDog, so read at least every 4 sec */ |
1da177e4 LT |
168 | cs->readisac(cs, ISAC_RBCH); |
169 | spin_unlock_irqrestore(&cs->lock, flags); | |
475be4d8 | 170 | mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); |
1da177e4 LT |
171 | } |
172 | ||
672c3fd9 | 173 | static void |
1da177e4 LT |
174 | release_io_saphir(struct IsdnCardState *cs) |
175 | { | |
176 | byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); | |
177 | del_timer(&cs->hw.saphir.timer); | |
178 | cs->hw.saphir.timer.function = NULL; | |
179 | if (cs->hw.saphir.cfg_reg) | |
180 | release_region(cs->hw.saphir.cfg_reg, 6); | |
181 | } | |
182 | ||
183 | static int | |
184 | saphir_reset(struct IsdnCardState *cs) | |
185 | { | |
186 | u_char irq_val; | |
187 | ||
475be4d8 JP |
188 | switch (cs->irq) { |
189 | case 5: irq_val = 0; | |
190 | break; | |
191 | case 3: irq_val = 1; | |
192 | break; | |
193 | case 11: | |
194 | irq_val = 2; | |
195 | break; | |
196 | case 12: | |
197 | irq_val = 3; | |
198 | break; | |
199 | case 15: | |
200 | irq_val = 4; | |
201 | break; | |
202 | default: | |
203 | printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n", | |
204 | cs->irq); | |
205 | return (1); | |
1da177e4 LT |
206 | } |
207 | byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); | |
208 | byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); | |
209 | mdelay(10); | |
210 | byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); | |
211 | mdelay(10); | |
212 | byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); | |
213 | byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); | |
214 | return (0); | |
215 | } | |
216 | ||
217 | static int | |
218 | saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) | |
219 | { | |
220 | u_long flags; | |
221 | ||
222 | switch (mt) { | |
475be4d8 JP |
223 | case CARD_RESET: |
224 | spin_lock_irqsave(&cs->lock, flags); | |
225 | saphir_reset(cs); | |
226 | spin_unlock_irqrestore(&cs->lock, flags); | |
227 | return (0); | |
228 | case CARD_RELEASE: | |
229 | release_io_saphir(cs); | |
230 | return (0); | |
231 | case CARD_INIT: | |
232 | spin_lock_irqsave(&cs->lock, flags); | |
233 | inithscxisac(cs, 3); | |
234 | spin_unlock_irqrestore(&cs->lock, flags); | |
235 | return (0); | |
236 | case CARD_TEST: | |
237 | return (0); | |
1da177e4 | 238 | } |
475be4d8 | 239 | return (0); |
1da177e4 LT |
240 | } |
241 | ||
242 | ||
ed5a84cd | 243 | int setup_saphir(struct IsdnCard *card) |
1da177e4 LT |
244 | { |
245 | struct IsdnCardState *cs = card->cs; | |
246 | char tmp[64]; | |
247 | ||
248 | strcpy(tmp, saphir_rev); | |
249 | printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); | |
250 | if (cs->typ != ISDN_CTYPE_HSTSAPHIR) | |
251 | return (0); | |
252 | ||
253 | /* IO-Ports */ | |
254 | cs->hw.saphir.cfg_reg = card->para[1]; | |
255 | cs->hw.saphir.isac = card->para[1] + ISAC_DATA; | |
256 | cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; | |
257 | cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; | |
258 | cs->irq = card->para[0]; | |
259 | if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) { | |
260 | printk(KERN_WARNING | |
475be4d8 JP |
261 | "HiSax: HST Saphir config port %x-%x already in use\n", |
262 | cs->hw.saphir.cfg_reg, | |
263 | cs->hw.saphir.cfg_reg + 5); | |
1da177e4 LT |
264 | return (0); |
265 | } | |
266 | ||
8349304d JG |
267 | printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n", |
268 | cs->irq, cs->hw.saphir.cfg_reg); | |
1da177e4 LT |
269 | |
270 | setup_isac(cs); | |
271 | cs->hw.saphir.timer.function = (void *) SaphirWatchDog; | |
272 | cs->hw.saphir.timer.data = (long) cs; | |
273 | init_timer(&cs->hw.saphir.timer); | |
475be4d8 | 274 | cs->hw.saphir.timer.expires = jiffies + 4 * HZ; |
1da177e4 LT |
275 | add_timer(&cs->hw.saphir.timer); |
276 | if (saphir_reset(cs)) { | |
277 | release_io_saphir(cs); | |
278 | return (0); | |
279 | } | |
280 | cs->readisac = &ReadISAC; | |
281 | cs->writeisac = &WriteISAC; | |
282 | cs->readisacfifo = &ReadISACfifo; | |
283 | cs->writeisacfifo = &WriteISACfifo; | |
284 | cs->BC_Read_Reg = &ReadHSCX; | |
285 | cs->BC_Write_Reg = &WriteHSCX; | |
286 | cs->BC_Send_Data = &hscx_fill_fifo; | |
287 | cs->cardmsg = &saphir_card_msg; | |
288 | cs->irq_func = &saphir_interrupt; | |
289 | ISACVersion(cs, "saphir:"); | |
290 | if (HscxVersion(cs, "saphir:")) { | |
291 | printk(KERN_WARNING | |
475be4d8 | 292 | "saphir: wrong HSCX versions check IO address\n"); |
1da177e4 LT |
293 | release_io_saphir(cs); |
294 | return (0); | |
295 | } | |
296 | return (1); | |
297 | } |