Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/bkm_a4t.c
15115 views
1
/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
2
*
3
* low level stuff for T-Berkom A4T
4
*
5
* Author Roland Klabunde
6
* Copyright by Roland Klabunde <[email protected]>
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
14
#include <linux/init.h>
15
#include "hisax.h"
16
#include "isac.h"
17
#include "hscx.h"
18
#include "jade.h"
19
#include "isdnl1.h"
20
#include <linux/pci.h>
21
#include "bkm_ax.h"
22
23
static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
24
25
26
static inline u_char
27
readreg(unsigned int ale, unsigned long adr, u_char off)
28
{
29
register u_int ret;
30
unsigned int *po = (unsigned int *) adr; /* Postoffice */
31
32
*po = (GCS_2 | PO_WRITE | off);
33
__WAITI20__(po);
34
*po = (ale | PO_READ);
35
__WAITI20__(po);
36
ret = *po;
37
return ((unsigned char) ret);
38
}
39
40
41
static inline void
42
readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
43
{
44
int i;
45
for (i = 0; i < size; i++)
46
*data++ = readreg(ale, adr, off);
47
}
48
49
50
static inline void
51
writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
52
{
53
unsigned int *po = (unsigned int *) adr; /* Postoffice */
54
*po = (GCS_2 | PO_WRITE | off);
55
__WAITI20__(po);
56
*po = (ale | PO_WRITE | data);
57
__WAITI20__(po);
58
}
59
60
61
static inline void
62
writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size)
63
{
64
int i;
65
66
for (i = 0; i < size; i++)
67
writereg(ale, adr, off, *data++);
68
}
69
70
71
/* Interface functions */
72
73
static u_char
74
ReadISAC(struct IsdnCardState *cs, u_char offset)
75
{
76
return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
77
}
78
79
static void
80
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
81
{
82
writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
83
}
84
85
static void
86
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
87
{
88
readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
89
}
90
91
static void
92
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
93
{
94
writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
95
}
96
97
static u_char
98
ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
99
{
100
return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
101
}
102
103
static void
104
WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
105
{
106
writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
107
}
108
109
/*
110
* fast interrupt JADE stuff goes here
111
*/
112
113
#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
114
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
115
#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
116
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
117
118
#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
119
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
120
#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
121
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
122
123
#include "jade_irq.c"
124
125
static irqreturn_t
126
bkm_interrupt(int intno, void *dev_id)
127
{
128
struct IsdnCardState *cs = dev_id;
129
u_char val = 0;
130
u_long flags;
131
I20_REGISTER_FILE *pI20_Regs;
132
133
spin_lock_irqsave(&cs->lock, flags);
134
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
135
136
/* ISDN interrupt pending? */
137
if (pI20_Regs->i20IntStatus & intISDN) {
138
/* Reset the ISDN interrupt */
139
pI20_Regs->i20IntStatus = intISDN;
140
/* Disable ISDN interrupt */
141
pI20_Regs->i20IntCtrl &= ~intISDN;
142
/* Channel A first */
143
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
144
if (val) {
145
jade_int_main(cs, val, 0);
146
}
147
/* Channel B */
148
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
149
if (val) {
150
jade_int_main(cs, val, 1);
151
}
152
/* D-Channel */
153
val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
154
if (val) {
155
isac_interrupt(cs, val);
156
}
157
/* Reenable ISDN interrupt */
158
pI20_Regs->i20IntCtrl |= intISDN;
159
spin_unlock_irqrestore(&cs->lock, flags);
160
return IRQ_HANDLED;
161
} else {
162
spin_unlock_irqrestore(&cs->lock, flags);
163
return IRQ_NONE;
164
}
165
}
166
167
static void
168
release_io_bkm(struct IsdnCardState *cs)
169
{
170
if (cs->hw.ax.base) {
171
iounmap((void *) cs->hw.ax.base);
172
cs->hw.ax.base = 0;
173
}
174
}
175
176
static void
177
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
178
{
179
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
180
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
181
if (bEnable)
182
pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
183
else
184
/* CAUTION: This disables the video capture driver too */
185
pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
186
}
187
}
188
189
static void
190
reset_bkm(struct IsdnCardState *cs)
191
{
192
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
193
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
194
/* Issue the I20 soft reset */
195
pI20_Regs->i20SysControl = 0xFF; /* all in */
196
mdelay(10);
197
/* Remove the soft reset */
198
pI20_Regs->i20SysControl = sysRESET | 0xFF;
199
mdelay(10);
200
/* Set our configuration */
201
pI20_Regs->i20SysControl = sysRESET | sysCFG;
202
/* Issue ISDN reset */
203
pI20_Regs->i20GuestControl = guestWAIT_CFG |
204
g_A4T_JADE_RES |
205
g_A4T_ISAR_RES |
206
g_A4T_ISAC_RES |
207
g_A4T_JADE_BOOTR |
208
g_A4T_ISAR_BOOTR;
209
mdelay(10);
210
211
/* Remove RESET state from ISDN */
212
pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
213
g_A4T_JADE_RES |
214
g_A4T_ISAR_RES);
215
mdelay(10);
216
}
217
}
218
219
static int
220
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
221
{
222
u_long flags;
223
224
switch (mt) {
225
case CARD_RESET:
226
/* Disable ints */
227
spin_lock_irqsave(&cs->lock, flags);
228
enable_bkm_int(cs, 0);
229
reset_bkm(cs);
230
spin_unlock_irqrestore(&cs->lock, flags);
231
return (0);
232
case CARD_RELEASE:
233
/* Sanity */
234
spin_lock_irqsave(&cs->lock, flags);
235
enable_bkm_int(cs, 0);
236
reset_bkm(cs);
237
spin_unlock_irqrestore(&cs->lock, flags);
238
release_io_bkm(cs);
239
return (0);
240
case CARD_INIT:
241
spin_lock_irqsave(&cs->lock, flags);
242
clear_pending_isac_ints(cs);
243
clear_pending_jade_ints(cs);
244
initisac(cs);
245
initjade(cs);
246
/* Enable ints */
247
enable_bkm_int(cs, 1);
248
spin_unlock_irqrestore(&cs->lock, flags);
249
return (0);
250
case CARD_TEST:
251
return (0);
252
}
253
return (0);
254
}
255
256
static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t,
257
struct IsdnCardState *cs,
258
u_int *found,
259
u_int *pci_memaddr)
260
{
261
u16 sub_sys;
262
u16 sub_vendor;
263
264
sub_vendor = dev_a4t->subsystem_vendor;
265
sub_sys = dev_a4t->subsystem_device;
266
if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
267
if (pci_enable_device(dev_a4t))
268
return (0); /* end loop & function */
269
*found = 1;
270
*pci_memaddr = pci_resource_start(dev_a4t, 0);
271
cs->irq = dev_a4t->irq;
272
return (1); /* end loop */
273
}
274
275
return (-1); /* continue looping */
276
}
277
278
static int __devinit a4t_cs_init(struct IsdnCard *card,
279
struct IsdnCardState *cs,
280
u_int pci_memaddr)
281
{
282
I20_REGISTER_FILE *pI20_Regs;
283
284
if (!cs->irq) { /* IRQ range check ?? */
285
printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n");
286
return (0);
287
}
288
cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
289
/* Check suspecious address */
290
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
291
if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
292
printk(KERN_WARNING "HiSax: Telekom A4T address "
293
"%lx-%lx suspicious\n",
294
cs->hw.ax.base, cs->hw.ax.base + 4096);
295
iounmap((void *) cs->hw.ax.base);
296
cs->hw.ax.base = 0;
297
return (0);
298
}
299
cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
300
cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
301
cs->hw.ax.isac_ale = GCS_1;
302
cs->hw.ax.jade_ale = GCS_3;
303
304
printk(KERN_INFO "HiSax: Telekom A4T: Card configured at "
305
"0x%lX IRQ %d\n",
306
cs->hw.ax.base, cs->irq);
307
308
setup_isac(cs);
309
cs->readisac = &ReadISAC;
310
cs->writeisac = &WriteISAC;
311
cs->readisacfifo = &ReadISACfifo;
312
cs->writeisacfifo = &WriteISACfifo;
313
cs->BC_Read_Reg = &ReadJADE;
314
cs->BC_Write_Reg = &WriteJADE;
315
cs->BC_Send_Data = &jade_fill_fifo;
316
cs->cardmsg = &BKM_card_msg;
317
cs->irq_func = &bkm_interrupt;
318
cs->irq_flags |= IRQF_SHARED;
319
ISACVersion(cs, "Telekom A4T:");
320
/* Jade version */
321
JadeVersion(cs, "Telekom A4T:");
322
323
return (1);
324
}
325
326
static struct pci_dev *dev_a4t __devinitdata = NULL;
327
328
int __devinit
329
setup_bkm_a4t(struct IsdnCard *card)
330
{
331
struct IsdnCardState *cs = card->cs;
332
char tmp[64];
333
u_int pci_memaddr = 0, found = 0;
334
int ret;
335
336
strcpy(tmp, bkm_a4t_revision);
337
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
338
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
339
cs->subtyp = BKM_A4T;
340
} else
341
return (0);
342
343
while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN,
344
PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
345
ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
346
if (!ret)
347
return (0);
348
if (ret > 0)
349
break;
350
}
351
if (!found) {
352
printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n");
353
return (0);
354
}
355
if (!pci_memaddr) {
356
printk(KERN_WARNING "HiSax: Telekom A4T: "
357
"No Memory base address\n");
358
return (0);
359
}
360
361
return a4t_cs_init(card, cs, pci_memaddr);
362
}
363
364