import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / isdn / hisax / isurf.c
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
40 ReadISAC(struct IsdnCardState *cs, u_char offset)
41 {
42         return (readb(cs->hw.isurf.isac + offset));
43 }
44
45 static void
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
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
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
75 ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
76 {       
77         return(readb(cs->hw.isurf.isar + offset));
78 }
79
80 static void
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
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
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
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
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
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
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 }