Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/bkm_a8.c
15115 views
1
/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
2
*
3
* low level stuff for Scitel Quadro (4*S0, passive)
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 "ipac.h"
18
#include "hscx.h"
19
#include "isdnl1.h"
20
#include <linux/pci.h>
21
#include "bkm_ax.h"
22
23
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
24
25
static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
26
27
static const char *sct_quadro_subtypes[] =
28
{
29
"",
30
"#1",
31
"#2",
32
"#3",
33
"#4"
34
};
35
36
37
#define wordout(addr,val) outw(val,addr)
38
#define wordin(addr) inw(addr)
39
40
static inline u_char
41
readreg(unsigned int ale, unsigned int adr, u_char off)
42
{
43
register u_char ret;
44
wordout(ale, off);
45
ret = wordin(adr) & 0xFF;
46
return (ret);
47
}
48
49
static inline void
50
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
51
{
52
int i;
53
wordout(ale, off);
54
for (i = 0; i < size; i++)
55
data[i] = wordin(adr) & 0xFF;
56
}
57
58
59
static inline void
60
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
61
{
62
wordout(ale, off);
63
wordout(adr, data);
64
}
65
66
static inline void
67
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
68
{
69
int i;
70
wordout(ale, off);
71
for (i = 0; i < size; i++)
72
wordout(adr, data[i]);
73
}
74
75
/* Interface functions */
76
77
static u_char
78
ReadISAC(struct IsdnCardState *cs, u_char offset)
79
{
80
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
81
}
82
83
static void
84
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
85
{
86
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
87
}
88
89
static void
90
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
91
{
92
readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
93
}
94
95
static void
96
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
97
{
98
writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
99
}
100
101
102
static u_char
103
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
104
{
105
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
106
}
107
108
static void
109
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
110
{
111
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
112
}
113
114
/* Set the specific ipac to active */
115
static void
116
set_ipac_active(struct IsdnCardState *cs, u_int active)
117
{
118
/* set irq mask */
119
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
120
active ? 0xc0 : 0xff);
121
}
122
123
/*
124
* fast interrupt HSCX stuff goes here
125
*/
126
127
#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
128
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
129
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
130
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
131
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
132
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
133
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
134
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
135
136
#include "hscx_irq.c"
137
138
static irqreturn_t
139
bkm_interrupt_ipac(int intno, void *dev_id)
140
{
141
struct IsdnCardState *cs = dev_id;
142
u_char ista, val, icnt = 5;
143
u_long flags;
144
145
spin_lock_irqsave(&cs->lock, flags);
146
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
147
if (!(ista & 0x3f)) { /* not this IPAC */
148
spin_unlock_irqrestore(&cs->lock, flags);
149
return IRQ_NONE;
150
}
151
Start_IPAC:
152
if (cs->debug & L1_DEB_IPAC)
153
debugl1(cs, "IPAC ISTA %02X", ista);
154
if (ista & 0x0f) {
155
val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
156
if (ista & 0x01)
157
val |= 0x01;
158
if (ista & 0x04)
159
val |= 0x02;
160
if (ista & 0x08)
161
val |= 0x04;
162
if (val) {
163
hscx_int_main(cs, val);
164
}
165
}
166
if (ista & 0x20) {
167
val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
168
if (val) {
169
isac_interrupt(cs, val);
170
}
171
}
172
if (ista & 0x10) {
173
val = 0x01;
174
isac_interrupt(cs, val);
175
}
176
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
177
if ((ista & 0x3f) && icnt) {
178
icnt--;
179
goto Start_IPAC;
180
}
181
if (!icnt)
182
printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n",
183
sct_quadro_subtypes[cs->subtyp]);
184
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
185
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
186
spin_unlock_irqrestore(&cs->lock, flags);
187
return IRQ_HANDLED;
188
}
189
190
static void
191
release_io_sct_quadro(struct IsdnCardState *cs)
192
{
193
release_region(cs->hw.ax.base & 0xffffffc0, 128);
194
if (cs->subtyp == SCT_1)
195
release_region(cs->hw.ax.plx_adr, 64);
196
}
197
198
static void
199
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
200
{
201
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
202
if (bEnable)
203
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
204
else
205
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
206
}
207
}
208
209
static void
210
reset_bkm(struct IsdnCardState *cs)
211
{
212
if (cs->subtyp == SCT_1) {
213
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
214
mdelay(10);
215
/* Remove the soft reset */
216
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
217
mdelay(10);
218
}
219
}
220
221
static int
222
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
223
{
224
u_long flags;
225
226
switch (mt) {
227
case CARD_RESET:
228
spin_lock_irqsave(&cs->lock, flags);
229
/* Disable ints */
230
set_ipac_active(cs, 0);
231
enable_bkm_int(cs, 0);
232
reset_bkm(cs);
233
spin_unlock_irqrestore(&cs->lock, flags);
234
return (0);
235
case CARD_RELEASE:
236
/* Sanity */
237
spin_lock_irqsave(&cs->lock, flags);
238
set_ipac_active(cs, 0);
239
enable_bkm_int(cs, 0);
240
spin_unlock_irqrestore(&cs->lock, flags);
241
release_io_sct_quadro(cs);
242
return (0);
243
case CARD_INIT:
244
spin_lock_irqsave(&cs->lock, flags);
245
cs->debug |= L1_DEB_IPAC;
246
set_ipac_active(cs, 1);
247
inithscxisac(cs, 3);
248
/* Enable ints */
249
enable_bkm_int(cs, 1);
250
spin_unlock_irqrestore(&cs->lock, flags);
251
return (0);
252
case CARD_TEST:
253
return (0);
254
}
255
return (0);
256
}
257
258
static int __devinit
259
sct_alloc_io(u_int adr, u_int len)
260
{
261
if (!request_region(adr, len, "scitel")) {
262
printk(KERN_WARNING
263
"HiSax: Scitel port %#x-%#x already in use\n",
264
adr, adr + len);
265
return (1);
266
}
267
return(0);
268
}
269
270
static struct pci_dev *dev_a8 __devinitdata = NULL;
271
static u16 sub_vendor_id __devinitdata = 0;
272
static u16 sub_sys_id __devinitdata = 0;
273
static u_char pci_bus __devinitdata = 0;
274
static u_char pci_device_fn __devinitdata = 0;
275
static u_char pci_irq __devinitdata = 0;
276
277
int __devinit
278
setup_sct_quadro(struct IsdnCard *card)
279
{
280
struct IsdnCardState *cs = card->cs;
281
char tmp[64];
282
u_int found = 0;
283
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
284
285
strcpy(tmp, sct_quadro_revision);
286
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
287
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
288
cs->subtyp = SCT_1; /* Preset */
289
} else
290
return (0);
291
292
/* Identify subtype by para[0] */
293
if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
294
cs->subtyp = card->para[0];
295
else {
296
printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid "
297
"subcontroller in configuration, default to 1\n");
298
return (0);
299
}
300
if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
301
(sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
302
return (0);
303
if (cs->subtyp == SCT_1) {
304
while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
305
PCI_DEVICE_ID_PLX_9050, dev_a8))) {
306
307
sub_vendor_id = dev_a8->subsystem_vendor;
308
sub_sys_id = dev_a8->subsystem_device;
309
if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
310
(sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
311
if (pci_enable_device(dev_a8))
312
return(0);
313
pci_ioaddr1 = pci_resource_start(dev_a8, 1);
314
pci_irq = dev_a8->irq;
315
pci_bus = dev_a8->bus->number;
316
pci_device_fn = dev_a8->devfn;
317
found = 1;
318
break;
319
}
320
}
321
if (!found) {
322
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
323
"Card not found\n",
324
sct_quadro_subtypes[cs->subtyp]);
325
return (0);
326
}
327
#ifdef ATTEMPT_PCI_REMAPPING
328
/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
329
if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) {
330
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
331
"PLX rev 1, remapping required!\n",
332
sct_quadro_subtypes[cs->subtyp]);
333
/* Restart PCI negotiation */
334
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int) - 1);
335
/* Move up by 0x80 byte */
336
pci_ioaddr1 += 0x80;
337
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
338
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
339
dev_a8->resource[ 1].start = pci_ioaddr1;
340
}
341
#endif /* End HACK */
342
}
343
if (!pci_irq) { /* IRQ range check ?? */
344
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n",
345
sct_quadro_subtypes[cs->subtyp]);
346
return (0);
347
}
348
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
349
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
350
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
351
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
352
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
353
if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
354
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
355
"No IO base address(es)\n",
356
sct_quadro_subtypes[cs->subtyp]);
357
return (0);
358
}
359
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
360
pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
361
pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
362
pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
363
pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
364
/* Take over */
365
cs->irq = pci_irq;
366
cs->irq_flags |= IRQF_SHARED;
367
/* pci_ioaddr1 is unique to all subdevices */
368
/* pci_ioaddr2 is for the fourth subdevice only */
369
/* pci_ioaddr3 is for the third subdevice only */
370
/* pci_ioaddr4 is for the second subdevice only */
371
/* pci_ioaddr5 is for the first subdevice only */
372
cs->hw.ax.plx_adr = pci_ioaddr1;
373
/* Enter all ipac_base addresses */
374
switch(cs->subtyp) {
375
case 1:
376
cs->hw.ax.base = pci_ioaddr5 + 0x00;
377
if (sct_alloc_io(pci_ioaddr1, 128))
378
return(0);
379
if (sct_alloc_io(pci_ioaddr5, 64))
380
return(0);
381
/* disable all IPAC */
382
writereg(pci_ioaddr5, pci_ioaddr5 + 4,
383
IPAC_MASK, 0xFF);
384
writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
385
IPAC_MASK, 0xFF);
386
writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
387
IPAC_MASK, 0xFF);
388
writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
389
IPAC_MASK, 0xFF);
390
break;
391
case 2:
392
cs->hw.ax.base = pci_ioaddr4 + 0x08;
393
if (sct_alloc_io(pci_ioaddr4, 64))
394
return(0);
395
break;
396
case 3:
397
cs->hw.ax.base = pci_ioaddr3 + 0x10;
398
if (sct_alloc_io(pci_ioaddr3, 64))
399
return(0);
400
break;
401
case 4:
402
cs->hw.ax.base = pci_ioaddr2 + 0x20;
403
if (sct_alloc_io(pci_ioaddr2, 64))
404
return(0);
405
break;
406
}
407
/* For isac and hscx data path */
408
cs->hw.ax.data_adr = cs->hw.ax.base + 4;
409
410
printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at "
411
"0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
412
sct_quadro_subtypes[cs->subtyp],
413
cs->hw.ax.plx_adr,
414
cs->hw.ax.base,
415
cs->hw.ax.data_adr,
416
cs->irq);
417
418
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
419
420
cs->readisac = &ReadISAC;
421
cs->writeisac = &WriteISAC;
422
cs->readisacfifo = &ReadISACfifo;
423
cs->writeisacfifo = &WriteISACfifo;
424
425
cs->BC_Read_Reg = &ReadHSCX;
426
cs->BC_Write_Reg = &WriteHSCX;
427
cs->BC_Send_Data = &hscx_fill_fifo;
428
cs->cardmsg = &BKM_card_msg;
429
cs->irq_func = &bkm_interrupt_ipac;
430
431
printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n",
432
sct_quadro_subtypes[cs->subtyp],
433
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
434
return (1);
435
}
436
437