diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/ix1_micro.c |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/ix1_micro.c')
-rw-r--r-- | drivers/isdn/hisax/ix1_micro.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c new file mode 100644 index 00000000000..b843b7509ae --- /dev/null +++ b/drivers/isdn/hisax/ix1_micro.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $ | ||
2 | * | ||
3 | * low level stuff for ITK ix1-micro Rev.2 isdn cards | ||
4 | * derived from the original file teles3.c from Karsten Keil | ||
5 | * | ||
6 | * Author Klaus-Peter Nischke | ||
7 | * Copyright by Klaus-Peter Nischke, ITK AG | ||
8 | * <klaus@nischke.do.eunet.de> | ||
9 | * by Karsten Keil <keil@isdn4linux.de> | ||
10 | * | ||
11 | * This software may be used and distributed according to the terms | ||
12 | * of the GNU General Public License, incorporated herein by reference. | ||
13 | * | ||
14 | * Klaus-Peter Nischke | ||
15 | * Deusener Str. 287 | ||
16 | * 44369 Dortmund | ||
17 | * Germany | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/isapnp.h> | ||
22 | #include "hisax.h" | ||
23 | #include "isac.h" | ||
24 | #include "hscx.h" | ||
25 | #include "isdnl1.h" | ||
26 | |||
27 | extern const char *CardType[]; | ||
28 | const char *ix1_revision = "$Revision: 2.12.2.4 $"; | ||
29 | |||
30 | #define byteout(addr,val) outb(val,addr) | ||
31 | #define bytein(addr) inb(addr) | ||
32 | |||
33 | #define SPECIAL_PORT_OFFSET 3 | ||
34 | |||
35 | #define ISAC_COMMAND_OFFSET 2 | ||
36 | #define ISAC_DATA_OFFSET 0 | ||
37 | #define HSCX_COMMAND_OFFSET 2 | ||
38 | #define HSCX_DATA_OFFSET 1 | ||
39 | |||
40 | #define TIMEOUT 50 | ||
41 | |||
42 | static inline u_char | ||
43 | readreg(unsigned int ale, unsigned int adr, u_char off) | ||
44 | { | ||
45 | register u_char ret; | ||
46 | |||
47 | byteout(ale, off); | ||
48 | ret = bytein(adr); | ||
49 | return (ret); | ||
50 | } | ||
51 | |||
52 | static inline void | ||
53 | readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) | ||
54 | { | ||
55 | byteout(ale, off); | ||
56 | insb(adr, data, size); | ||
57 | } | ||
58 | |||
59 | |||
60 | static inline void | ||
61 | writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) | ||
62 | { | ||
63 | byteout(ale, off); | ||
64 | byteout(adr, data); | ||
65 | } | ||
66 | |||
67 | static inline void | ||
68 | writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) | ||
69 | { | ||
70 | byteout(ale, off); | ||
71 | outsb(adr, data, size); | ||
72 | } | ||
73 | |||
74 | /* Interface functions */ | ||
75 | |||
76 | static u_char | ||
77 | ReadISAC(struct IsdnCardState *cs, u_char offset) | ||
78 | { | ||
79 | return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) | ||
84 | { | ||
85 | writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); | ||
86 | } | ||
87 | |||
88 | static void | ||
89 | ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) | ||
90 | { | ||
91 | readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); | ||
92 | } | ||
93 | |||
94 | static void | ||
95 | WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) | ||
96 | { | ||
97 | writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); | ||
98 | } | ||
99 | |||
100 | static u_char | ||
101 | ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) | ||
102 | { | ||
103 | return (readreg(cs->hw.ix1.hscx_ale, | ||
104 | cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) | ||
109 | { | ||
110 | writereg(cs->hw.ix1.hscx_ale, | ||
111 | cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); | ||
112 | } | ||
113 | |||
114 | #define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ | ||
115 | cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) | ||
116 | #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ | ||
117 | cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) | ||
118 | |||
119 | #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ | ||
120 | cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) | ||
121 | |||
122 | #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ | ||
123 | cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) | ||
124 | |||
125 | #include "hscx_irq.c" | ||
126 | |||
127 | static irqreturn_t | ||
128 | ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) | ||
129 | { | ||
130 | struct IsdnCardState *cs = dev_id; | ||
131 | u_char val; | ||
132 | u_long flags; | ||
133 | |||
134 | spin_lock_irqsave(&cs->lock, flags); | ||
135 | val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); | ||
136 | Start_HSCX: | ||
137 | if (val) | ||
138 | hscx_int_main(cs, val); | ||
139 | val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); | ||
140 | Start_ISAC: | ||
141 | if (val) | ||
142 | isac_interrupt(cs, val); | ||
143 | val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); | ||
144 | if (val) { | ||
145 | if (cs->debug & L1_DEB_HSCX) | ||
146 | debugl1(cs, "HSCX IntStat after IntRoutine"); | ||
147 | goto Start_HSCX; | ||
148 | } | ||
149 | val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); | ||
150 | if (val) { | ||
151 | if (cs->debug & L1_DEB_ISAC) | ||
152 | debugl1(cs, "ISAC IntStat after IntRoutine"); | ||
153 | goto Start_ISAC; | ||
154 | } | ||
155 | writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); | ||
156 | writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); | ||
157 | writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); | ||
158 | writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); | ||
159 | writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); | ||
160 | writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); | ||
161 | spin_unlock_irqrestore(&cs->lock, flags); | ||
162 | return IRQ_HANDLED; | ||
163 | } | ||
164 | |||
165 | void | ||
166 | release_io_ix1micro(struct IsdnCardState *cs) | ||
167 | { | ||
168 | if (cs->hw.ix1.cfg_reg) | ||
169 | release_region(cs->hw.ix1.cfg_reg, 4); | ||
170 | } | ||
171 | |||
172 | static void | ||
173 | ix1_reset(struct IsdnCardState *cs) | ||
174 | { | ||
175 | int cnt; | ||
176 | |||
177 | /* reset isac */ | ||
178 | cnt = 3 * (HZ / 10) + 1; | ||
179 | while (cnt--) { | ||
180 | byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1); | ||
181 | HZDELAY(1); /* wait >=10 ms */ | ||
182 | } | ||
183 | byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); | ||
184 | } | ||
185 | |||
186 | static int | ||
187 | ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) | ||
188 | { | ||
189 | u_long flags; | ||
190 | |||
191 | switch (mt) { | ||
192 | case CARD_RESET: | ||
193 | spin_lock_irqsave(&cs->lock, flags); | ||
194 | ix1_reset(cs); | ||
195 | spin_unlock_irqrestore(&cs->lock, flags); | ||
196 | return(0); | ||
197 | case CARD_RELEASE: | ||
198 | release_io_ix1micro(cs); | ||
199 | return(0); | ||
200 | case CARD_INIT: | ||
201 | spin_lock_irqsave(&cs->lock, flags); | ||
202 | ix1_reset(cs); | ||
203 | inithscxisac(cs, 3); | ||
204 | spin_unlock_irqrestore(&cs->lock, flags); | ||
205 | return(0); | ||
206 | case CARD_TEST: | ||
207 | return(0); | ||
208 | } | ||
209 | return(0); | ||
210 | } | ||
211 | |||
212 | #ifdef __ISAPNP__ | ||
213 | static struct isapnp_device_id itk_ids[] __initdata = { | ||
214 | { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), | ||
215 | ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), | ||
216 | (unsigned long) "ITK micro 2" }, | ||
217 | { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), | ||
218 | ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), | ||
219 | (unsigned long) "ITK micro 2." }, | ||
220 | { 0, } | ||
221 | }; | ||
222 | |||
223 | static struct isapnp_device_id *ipid __initdata = &itk_ids[0]; | ||
224 | static struct pnp_card *pnp_c __devinitdata = NULL; | ||
225 | #endif | ||
226 | |||
227 | |||
228 | int __init | ||
229 | setup_ix1micro(struct IsdnCard *card) | ||
230 | { | ||
231 | struct IsdnCardState *cs = card->cs; | ||
232 | char tmp[64]; | ||
233 | |||
234 | strcpy(tmp, ix1_revision); | ||
235 | printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); | ||
236 | if (cs->typ != ISDN_CTYPE_IX1MICROR2) | ||
237 | return (0); | ||
238 | |||
239 | #ifdef __ISAPNP__ | ||
240 | if (!card->para[1] && isapnp_present()) { | ||
241 | struct pnp_dev *pnp_d; | ||
242 | while(ipid->card_vendor) { | ||
243 | if ((pnp_c = pnp_find_card(ipid->card_vendor, | ||
244 | ipid->card_device, pnp_c))) { | ||
245 | pnp_d = NULL; | ||
246 | if ((pnp_d = pnp_find_dev(pnp_c, | ||
247 | ipid->vendor, ipid->function, pnp_d))) { | ||
248 | int err; | ||
249 | |||
250 | printk(KERN_INFO "HiSax: %s detected\n", | ||
251 | (char *)ipid->driver_data); | ||
252 | pnp_disable_dev(pnp_d); | ||
253 | err = pnp_activate_dev(pnp_d); | ||
254 | if (err<0) { | ||
255 | printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", | ||
256 | __FUNCTION__, err); | ||
257 | return(0); | ||
258 | } | ||
259 | card->para[1] = pnp_port_start(pnp_d, 0); | ||
260 | card->para[0] = pnp_irq(pnp_d, 0); | ||
261 | if (!card->para[0] || !card->para[1]) { | ||
262 | printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", | ||
263 | card->para[0], card->para[1]); | ||
264 | pnp_disable_dev(pnp_d); | ||
265 | return(0); | ||
266 | } | ||
267 | break; | ||
268 | } else { | ||
269 | printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); | ||
270 | } | ||
271 | } | ||
272 | ipid++; | ||
273 | pnp_c = NULL; | ||
274 | } | ||
275 | if (!ipid->card_vendor) { | ||
276 | printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); | ||
277 | return(0); | ||
278 | } | ||
279 | } | ||
280 | #endif | ||
281 | /* IO-Ports */ | ||
282 | cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; | ||
283 | cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; | ||
284 | cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; | ||
285 | cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; | ||
286 | cs->hw.ix1.cfg_reg = card->para[1]; | ||
287 | cs->irq = card->para[0]; | ||
288 | if (cs->hw.ix1.cfg_reg) { | ||
289 | if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { | ||
290 | printk(KERN_WARNING | ||
291 | "HiSax: %s config port %x-%x already in use\n", | ||
292 | CardType[card->typ], | ||
293 | cs->hw.ix1.cfg_reg, | ||
294 | cs->hw.ix1.cfg_reg + 4); | ||
295 | return (0); | ||
296 | } | ||
297 | } | ||
298 | printk(KERN_INFO "HiSax: %s config irq:%d io:0x%X\n", | ||
299 | CardType[cs->typ], cs->irq, cs->hw.ix1.cfg_reg); | ||
300 | setup_isac(cs); | ||
301 | cs->readisac = &ReadISAC; | ||
302 | cs->writeisac = &WriteISAC; | ||
303 | cs->readisacfifo = &ReadISACfifo; | ||
304 | cs->writeisacfifo = &WriteISACfifo; | ||
305 | cs->BC_Read_Reg = &ReadHSCX; | ||
306 | cs->BC_Write_Reg = &WriteHSCX; | ||
307 | cs->BC_Send_Data = &hscx_fill_fifo; | ||
308 | cs->cardmsg = &ix1_card_msg; | ||
309 | cs->irq_func = &ix1micro_interrupt; | ||
310 | ISACVersion(cs, "ix1-Micro:"); | ||
311 | if (HscxVersion(cs, "ix1-Micro:")) { | ||
312 | printk(KERN_WARNING | ||
313 | "ix1-Micro: wrong HSCX versions check IO address\n"); | ||
314 | release_io_ix1micro(cs); | ||
315 | return (0); | ||
316 | } | ||
317 | return (1); | ||
318 | } | ||