1 /* $Id: isurf.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2 *
3 * low level stuff for Siemens I-Surf/I-Talk 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 */
12
13 #define __NO_VERSION__
14 #include <linux/init.h>
15 #include "hisax.h"
16 #include "isac.h"
17 #include "isar.h"
18 #include "isdnl1.h"
19 #include <linux/isapnp.h>
20
21 extern const char *CardType[];
22
23 static const char *ISurf_revision = "$Revision: 1.1.4.1 $";
24
25 #define byteout(addr,val) outb(val,addr)
26 #define bytein(addr) inb(addr)
27
28 #define ISURF_ISAR_RESET 1
29 #define ISURF_ISAC_RESET 2
30 #define ISURF_ISAR_EA 4
31 #define ISURF_ARCOFI_RESET 8
32 #define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
33
34 #define ISURF_ISAR_OFFSET 0
35 #define ISURF_ISAC_OFFSET 0x100
36 #define ISURF_IOMEM_SIZE 0x400
37 /* Interface functions */
38
39 static u_char
ReadISAC(struct IsdnCardState * cs,u_char offset)40 ReadISAC(struct IsdnCardState *cs, u_char offset)
41 {
42 return (readb(cs->hw.isurf.isac + offset));
43 }
44
45 static void
WriteISAC(struct IsdnCardState * cs,u_char offset,u_char value)46 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
47 {
48 writeb(value, cs->hw.isurf.isac + offset); mb();
49 }
50
51 static void
ReadISACfifo(struct IsdnCardState * cs,u_char * data,int size)52 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
53 {
54 register int i;
55 for (i = 0; i < size; i++)
56 data[i] = readb(cs->hw.isurf.isac);
57 }
58
59 static void
WriteISACfifo(struct IsdnCardState * cs,u_char * data,int size)60 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
61 {
62 register int i;
63 for (i = 0; i < size; i++){
64 writeb(data[i], cs->hw.isurf.isac);mb();
65 }
66 }
67
68 /* ISAR access routines
69 * mode = 0 access with IRQ on
70 * mode = 1 access with IRQ off
71 * mode = 2 access with IRQ off and using last offset
72 */
73
74 static u_char
ReadISAR(struct IsdnCardState * cs,int mode,u_char offset)75 ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
76 {
77 return(readb(cs->hw.isurf.isar + offset));
78 }
79
80 static void
WriteISAR(struct IsdnCardState * cs,int mode,u_char offset,u_char value)81 WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
82 {
83 writeb(value, cs->hw.isurf.isar + offset);mb();
84 }
85
86 static void
isurf_interrupt(int intno,void * dev_id,struct pt_regs * regs)87 isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
88 {
89 struct IsdnCardState *cs = dev_id;
90 u_char val;
91 int cnt = 5;
92
93 if (!cs) {
94 printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
95 return;
96 }
97
98 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
99 Start_ISAR:
100 if (val & ISAR_IRQSTA)
101 isar_int_main(cs);
102 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
103 Start_ISAC:
104 if (val)
105 isac_interrupt(cs, val);
106 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
107 if ((val & ISAR_IRQSTA) && --cnt) {
108 if (cs->debug & L1_DEB_HSCX)
109 debugl1(cs, "ISAR IntStat after IntRoutine");
110 goto Start_ISAR;
111 }
112 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
113 if (val && --cnt) {
114 if (cs->debug & L1_DEB_ISAC)
115 debugl1(cs, "ISAC IntStat after IntRoutine");
116 goto Start_ISAC;
117 }
118 if (!cnt)
119 printk(KERN_WARNING "ISurf IRQ LOOP\n");
120
121 writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
122 writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
123 writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
124 writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
125 }
126
127 void
release_io_isurf(struct IsdnCardState * cs)128 release_io_isurf(struct IsdnCardState *cs)
129 {
130 release_region(cs->hw.isurf.reset, 1);
131 iounmap((unsigned char *)cs->hw.isurf.isar);
132 release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
133 }
134
135 static void
reset_isurf(struct IsdnCardState * cs,u_char chips)136 reset_isurf(struct IsdnCardState *cs, u_char chips)
137 {
138 long flags;
139
140 printk(KERN_INFO "ISurf: resetting card\n");
141
142 byteout(cs->hw.isurf.reset, chips); /* Reset On */
143 save_flags(flags);
144 sti();
145 set_current_state(TASK_UNINTERRUPTIBLE);
146 schedule_timeout((10*HZ)/1000);
147 byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
148 set_current_state(TASK_UNINTERRUPTIBLE);
149 schedule_timeout((10*HZ)/1000);
150 restore_flags(flags);
151 }
152
153 static int
ISurf_card_msg(struct IsdnCardState * cs,int mt,void * arg)154 ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
155 {
156 switch (mt) {
157 case CARD_RESET:
158 reset_isurf(cs, ISURF_RESET);
159 return(0);
160 case CARD_RELEASE:
161 release_io_isurf(cs);
162 return(0);
163 case CARD_INIT:
164 clear_pending_isac_ints(cs);
165 writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
166 initisac(cs);
167 initisar(cs);
168 /* Reenable ISAC IRQ */
169 cs->writeisac(cs, ISAC_MASK, 0);
170 /* RESET Receiver and Transmitter */
171 cs->writeisac(cs, ISAC_CMDR, 0x41);
172 return(0);
173 case CARD_TEST:
174 return(0);
175 }
176 return(0);
177 }
178
179 static int
isurf_auxcmd(struct IsdnCardState * cs,isdn_ctrl * ic)180 isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
181 int ret;
182
183 if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
184 ret = isar_auxcmd(cs, ic);
185 if (!ret) {
186 reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
187 ISURF_ARCOFI_RESET);
188 initisac(cs);
189 cs->writeisac(cs, ISAC_MASK, 0);
190 cs->writeisac(cs, ISAC_CMDR, 0x41);
191 }
192 return(ret);
193 }
194 return(isar_auxcmd(cs, ic));
195 }
196
197 #ifdef __ISAPNP__
198 static struct pci_bus *pnp_surf __devinitdata = NULL;
199 #endif
200
201 int __init
setup_isurf(struct IsdnCard * card)202 setup_isurf(struct IsdnCard *card)
203 {
204 int ver;
205 struct IsdnCardState *cs = card->cs;
206 char tmp[64];
207
208 strcpy(tmp, ISurf_revision);
209 printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
210
211 if (cs->typ != ISDN_CTYPE_ISURF)
212 return(0);
213 if (card->para[1] && card->para[2]) {
214 cs->hw.isurf.reset = card->para[1];
215 cs->hw.isurf.phymem = card->para[2];
216 cs->irq = card->para[0];
217 } else {
218 #ifdef __ISAPNP__
219 struct pci_bus *pb;
220 struct pci_dev *pd;
221
222 if (isapnp_present()) {
223 cs->subtyp = 0;
224 if ((pb = isapnp_find_card(
225 ISAPNP_VENDOR('S', 'I', 'E'),
226 ISAPNP_FUNCTION(0x0010), pnp_surf))) {
227 pnp_surf = pb;
228 pd = NULL;
229 if (!(pd = isapnp_find_dev(pnp_surf,
230 ISAPNP_VENDOR('S', 'I', 'E'),
231 ISAPNP_FUNCTION(0x0010), pd))) {
232 printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
233 return (0);
234 }
235 pd->prepare(pd);
236 pd->deactivate(pd);
237 pd->activate(pd);
238 /* The ISA-PnP logic apparently
239 * expects upper limit address to be
240 * set. Since the isa-pnp module
241 * doesn't do this, so we have to make
242 * up for it.
243 */
244 isapnp_cfg_begin(pd->bus->number, pd->devfn);
245 isapnp_write_word(ISAPNP_CFG_MEM+3,
246 pd->resource[8].end >> 8);
247 isapnp_cfg_end();
248 cs->hw.isurf.reset = pd->resource[0].start;
249 cs->hw.isurf.phymem = pd->resource[8].start;
250 cs->irq = pd->irq_resource[0].start;
251 if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
252 printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
253 cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
254 pd->deactivate(pd);
255 return(0);
256 }
257 } else {
258 printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
259 return(0);
260 }
261 } else {
262 printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
263 return(0);
264 }
265 #else
266 printk(KERN_WARNING "HiSax: %s port/mem not set\n",
267 CardType[card->typ]);
268 return (0);
269 #endif
270 }
271 if (check_region(cs->hw.isurf.reset, 1)) {
272 printk(KERN_WARNING
273 "HiSax: %s config port %x already in use\n",
274 CardType[card->typ],
275 cs->hw.isurf.reset);
276 return (0);
277 } else {
278 request_region(cs->hw.isurf.reset, 1, "isurf isdn");
279 }
280 if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) {
281 printk(KERN_WARNING
282 "HiSax: %s memory region %lx-%lx already in use\n",
283 CardType[card->typ],
284 cs->hw.isurf.phymem,
285 cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
286 release_region(cs->hw.isurf.reset, 1);
287 return (0);
288 } else {
289 request_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE,
290 "isurf iomem");
291 }
292 cs->hw.isurf.isar =
293 (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
294 cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
295 printk(KERN_INFO
296 "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
297 cs->hw.isurf.reset,
298 cs->hw.isurf.phymem,
299 cs->irq);
300
301 cs->cardmsg = &ISurf_card_msg;
302 cs->irq_func = &isurf_interrupt;
303 cs->auxcmd = &isurf_auxcmd;
304 cs->readisac = &ReadISAC;
305 cs->writeisac = &WriteISAC;
306 cs->readisacfifo = &ReadISACfifo;
307 cs->writeisacfifo = &WriteISACfifo;
308 cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
309 cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
310 reset_isurf(cs, ISURF_RESET);
311 test_and_set_bit(HW_ISAR, &cs->HW_Flags);
312 ISACVersion(cs, "ISurf:");
313 cs->BC_Read_Reg = &ReadISAR;
314 cs->BC_Write_Reg = &WriteISAR;
315 cs->BC_Send_Data = &isar_fill_fifo;
316 ver = ISARVersion(cs, "ISurf:");
317 if (ver < 0) {
318 printk(KERN_WARNING
319 "ISurf: wrong ISAR version (ret = %d)\n", ver);
320 release_io_isurf(cs);
321 return (0);
322 }
323 return (1);
324 }
325