File: /usr/src/linux/drivers/isdn/hisax/isurf.c
1 /* $Id: isurf.c,v 1.10.6.1 2001/02/16 16:43:27 kai Exp $
2 *
3 * isurf.c low level stuff for Siemens I-Surf/I-Talk cards
4 *
5 * Author Karsten Keil (keil@isdn4linux.de)
6 *
7 * This file is (c) under GNU General Public License
8 *
9 */
10
11 #define __NO_VERSION__
12 #include <linux/init.h>
13 #include "hisax.h"
14 #include "isac.h"
15 #include "isar.h"
16 #include "isdnl1.h"
17
18 extern const char *CardType[];
19
20 static const char *ISurf_revision = "$Revision: 1.10.6.1 $";
21
22 #define byteout(addr,val) outb(val,addr)
23 #define bytein(addr) inb(addr)
24
25 #define ISURF_ISAR_RESET 1
26 #define ISURF_ISAC_RESET 2
27 #define ISURF_ISAR_EA 4
28 #define ISURF_ARCOFI_RESET 8
29 #define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
30
31 #define ISURF_ISAR_OFFSET 0
32 #define ISURF_ISAC_OFFSET 0x100
33 #define ISURF_IOMEM_SIZE 0x400
34 /* Interface functions */
35
36 static u_char
37 ReadISAC(struct IsdnCardState *cs, u_char offset)
38 {
39 return (readb(cs->hw.isurf.isac + offset));
40 }
41
42 static void
43 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
44 {
45 writeb(value, cs->hw.isurf.isac + offset); mb();
46 }
47
48 static void
49 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
50 {
51 register int i;
52 for (i = 0; i < size; i++)
53 data[i] = readb(cs->hw.isurf.isac);
54 }
55
56 static void
57 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
58 {
59 register int i;
60 for (i = 0; i < size; i++){
61 writeb(data[i], cs->hw.isurf.isac);mb();
62 }
63 }
64
65 /* ISAR access routines
66 * mode = 0 access with IRQ on
67 * mode = 1 access with IRQ off
68 * mode = 2 access with IRQ off and using last offset
69 */
70
71 static u_char
72 ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
73 {
74 return(readb(cs->hw.isurf.isar + offset));
75 }
76
77 static void
78 WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
79 {
80 writeb(value, cs->hw.isurf.isar + offset);mb();
81 }
82
83 static void
84 isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
85 {
86 struct IsdnCardState *cs = dev_id;
87 u_char val;
88 int cnt = 5;
89
90 if (!cs) {
91 printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
92 return;
93 }
94
95 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
96 Start_ISAR:
97 if (val & ISAR_IRQSTA)
98 isar_int_main(cs);
99 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
100 Start_ISAC:
101 if (val)
102 isac_interrupt(cs, val);
103 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
104 if ((val & ISAR_IRQSTA) && --cnt) {
105 if (cs->debug & L1_DEB_HSCX)
106 debugl1(cs, "ISAR IntStat after IntRoutine");
107 goto Start_ISAR;
108 }
109 val = readb(cs->hw.isurf.isac + ISAC_ISTA);
110 if (val && --cnt) {
111 if (cs->debug & L1_DEB_ISAC)
112 debugl1(cs, "ISAC IntStat after IntRoutine");
113 goto Start_ISAC;
114 }
115 if (!cnt)
116 printk(KERN_WARNING "ISurf IRQ LOOP\n");
117
118 writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
119 writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
120 writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
121 writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
122 }
123
124 void
125 release_io_isurf(struct IsdnCardState *cs)
126 {
127 release_region(cs->hw.isurf.reset, 1);
128 iounmap((unsigned char *)cs->hw.isurf.isar);
129 release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
130 }
131
132 static void
133 reset_isurf(struct IsdnCardState *cs, u_char chips)
134 {
135 long flags;
136
137 printk(KERN_INFO "ISurf: resetting card\n");
138
139 byteout(cs->hw.isurf.reset, chips); /* Reset On */
140 save_flags(flags);
141 sti();
142 set_current_state(TASK_UNINTERRUPTIBLE);
143 schedule_timeout((10*HZ)/1000);
144 byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
145 set_current_state(TASK_UNINTERRUPTIBLE);
146 schedule_timeout((10*HZ)/1000);
147 restore_flags(flags);
148 }
149
150 static int
151 ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
152 {
153 switch (mt) {
154 case CARD_RESET:
155 reset_isurf(cs, ISURF_RESET);
156 return(0);
157 case CARD_RELEASE:
158 release_io_isurf(cs);
159 return(0);
160 case CARD_INIT:
161 clear_pending_isac_ints(cs);
162 writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
163 initisac(cs);
164 initisar(cs);
165 /* Reenable ISAC IRQ */
166 cs->writeisac(cs, ISAC_MASK, 0);
167 /* RESET Receiver and Transmitter */
168 cs->writeisac(cs, ISAC_CMDR, 0x41);
169 return(0);
170 case CARD_TEST:
171 return(0);
172 }
173 return(0);
174 }
175
176 static int
177 isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
178 int ret;
179
180 if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
181 ret = isar_auxcmd(cs, ic);
182 if (!ret) {
183 reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
184 ISURF_ARCOFI_RESET);
185 initisac(cs);
186 cs->writeisac(cs, ISAC_MASK, 0);
187 cs->writeisac(cs, ISAC_CMDR, 0x41);
188 }
189 return(ret);
190 }
191 return(isar_auxcmd(cs, ic));
192 }
193
194 int __init
195 setup_isurf(struct IsdnCard *card)
196 {
197 int ver;
198 struct IsdnCardState *cs = card->cs;
199 char tmp[64];
200
201 strcpy(tmp, ISurf_revision);
202 printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
203
204 if (cs->typ != ISDN_CTYPE_ISURF)
205 return(0);
206 if (card->para[1] && card->para[2]) {
207 cs->hw.isurf.reset = card->para[1];
208 cs->hw.isurf.phymem = card->para[2];
209 cs->irq = card->para[0];
210 } else {
211 printk(KERN_WARNING "HiSax: %s port/mem not set\n",
212 CardType[card->typ]);
213 return (0);
214 }
215 if (check_region(cs->hw.isurf.reset, 1)) {
216 printk(KERN_WARNING
217 "HiSax: %s config port %x already in use\n",
218 CardType[card->typ],
219 cs->hw.isurf.reset);
220 return (0);
221 } else {
222 request_region(cs->hw.isurf.reset, 1, "isurf isdn");
223 }
224 if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) {
225 printk(KERN_WARNING
226 "HiSax: %s memory region %lx-%lx already in use\n",
227 CardType[card->typ],
228 cs->hw.isurf.phymem,
229 cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
230 release_region(cs->hw.isurf.reset, 1);
231 return (0);
232 } else {
233 request_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE,
234 "isurf iomem");
235 }
236 cs->hw.isurf.isar =
237 (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
238 cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
239 printk(KERN_INFO
240 "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
241 cs->hw.isurf.reset,
242 cs->hw.isurf.phymem,
243 cs->irq);
244
245 cs->cardmsg = &ISurf_card_msg;
246 cs->irq_func = &isurf_interrupt;
247 cs->auxcmd = &isurf_auxcmd;
248 cs->readisac = &ReadISAC;
249 cs->writeisac = &WriteISAC;
250 cs->readisacfifo = &ReadISACfifo;
251 cs->writeisacfifo = &WriteISACfifo;
252 cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
253 cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
254 reset_isurf(cs, ISURF_RESET);
255 test_and_set_bit(HW_ISAR, &cs->HW_Flags);
256 ISACVersion(cs, "ISurf:");
257 cs->BC_Read_Reg = &ReadISAR;
258 cs->BC_Write_Reg = &WriteISAR;
259 cs->BC_Send_Data = &isar_fill_fifo;
260 ver = ISARVersion(cs, "ISurf:");
261 if (ver < 0) {
262 printk(KERN_WARNING
263 "ISurf: wrong ISAR version (ret = %d)\n", ver);
264 release_io_isurf(cs);
265 return (0);
266 }
267 return (1);
268 }
269