Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/asuscom.c
15115 views
1
/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
2
*
3
* low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
4
*
5
* Author Karsten Keil
6
* Copyright by Karsten Keil <[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
* Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
12
*
13
*/
14
15
#include <linux/init.h>
16
#include <linux/isapnp.h>
17
#include "hisax.h"
18
#include "isac.h"
19
#include "ipac.h"
20
#include "hscx.h"
21
#include "isdnl1.h"
22
23
static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
24
25
#define byteout(addr,val) outb(val,addr)
26
#define bytein(addr) inb(addr)
27
28
#define ASUS_ISAC 0
29
#define ASUS_HSCX 1
30
#define ASUS_ADR 2
31
#define ASUS_CTRL_U7 3
32
#define ASUS_CTRL_POTS 5
33
34
#define ASUS_IPAC_ALE 0
35
#define ASUS_IPAC_DATA 1
36
37
#define ASUS_ISACHSCX 1
38
#define ASUS_IPAC 2
39
40
/* CARD_ADR (Write) */
41
#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
42
43
static inline u_char
44
readreg(unsigned int ale, unsigned int adr, u_char off)
45
{
46
register u_char ret;
47
48
byteout(ale, off);
49
ret = bytein(adr);
50
return (ret);
51
}
52
53
static inline void
54
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
55
{
56
byteout(ale, off);
57
insb(adr, data, size);
58
}
59
60
61
static inline void
62
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
63
{
64
byteout(ale, off);
65
byteout(adr, data);
66
}
67
68
static inline void
69
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
70
{
71
byteout(ale, off);
72
outsb(adr, data, size);
73
}
74
75
/* Interface functions */
76
77
static u_char
78
ReadISAC(struct IsdnCardState *cs, u_char offset)
79
{
80
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
81
}
82
83
static void
84
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
85
{
86
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
87
}
88
89
static void
90
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
91
{
92
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
93
}
94
95
static void
96
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
97
{
98
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
99
}
100
101
static u_char
102
ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
103
{
104
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80));
105
}
106
107
static void
108
WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
109
{
110
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value);
111
}
112
113
static void
114
ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
115
{
116
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
117
}
118
119
static void
120
WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
121
{
122
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
123
}
124
125
static u_char
126
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
127
{
128
return (readreg(cs->hw.asus.adr,
129
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
130
}
131
132
static void
133
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
134
{
135
writereg(cs->hw.asus.adr,
136
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
137
}
138
139
/*
140
* fast interrupt HSCX stuff goes here
141
*/
142
143
#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
144
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
145
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
146
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
147
148
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
149
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
150
151
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
152
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
153
154
#include "hscx_irq.c"
155
156
static irqreturn_t
157
asuscom_interrupt(int intno, void *dev_id)
158
{
159
struct IsdnCardState *cs = dev_id;
160
u_char val;
161
u_long flags;
162
163
spin_lock_irqsave(&cs->lock, flags);
164
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
165
Start_HSCX:
166
if (val)
167
hscx_int_main(cs, val);
168
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
169
Start_ISAC:
170
if (val)
171
isac_interrupt(cs, val);
172
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
173
if (val) {
174
if (cs->debug & L1_DEB_HSCX)
175
debugl1(cs, "HSCX IntStat after IntRoutine");
176
goto Start_HSCX;
177
}
178
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
179
if (val) {
180
if (cs->debug & L1_DEB_ISAC)
181
debugl1(cs, "ISAC IntStat after IntRoutine");
182
goto Start_ISAC;
183
}
184
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
185
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
186
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
187
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
188
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
189
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
190
spin_unlock_irqrestore(&cs->lock, flags);
191
return IRQ_HANDLED;
192
}
193
194
static irqreturn_t
195
asuscom_interrupt_ipac(int intno, void *dev_id)
196
{
197
struct IsdnCardState *cs = dev_id;
198
u_char ista, val, icnt = 5;
199
u_long flags;
200
201
spin_lock_irqsave(&cs->lock, flags);
202
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
203
Start_IPAC:
204
if (cs->debug & L1_DEB_IPAC)
205
debugl1(cs, "IPAC ISTA %02X", ista);
206
if (ista & 0x0f) {
207
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
208
if (ista & 0x01)
209
val |= 0x01;
210
if (ista & 0x04)
211
val |= 0x02;
212
if (ista & 0x08)
213
val |= 0x04;
214
if (val)
215
hscx_int_main(cs, val);
216
}
217
if (ista & 0x20) {
218
val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
219
if (val) {
220
isac_interrupt(cs, val);
221
}
222
}
223
if (ista & 0x10) {
224
val = 0x01;
225
isac_interrupt(cs, val);
226
}
227
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
228
if ((ista & 0x3f) && icnt) {
229
icnt--;
230
goto Start_IPAC;
231
}
232
if (!icnt)
233
printk(KERN_WARNING "ASUS IRQ LOOP\n");
234
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
235
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
236
spin_unlock_irqrestore(&cs->lock, flags);
237
return IRQ_HANDLED;
238
}
239
240
static void
241
release_io_asuscom(struct IsdnCardState *cs)
242
{
243
int bytecnt = 8;
244
245
if (cs->hw.asus.cfg_reg)
246
release_region(cs->hw.asus.cfg_reg, bytecnt);
247
}
248
249
static void
250
reset_asuscom(struct IsdnCardState *cs)
251
{
252
if (cs->subtyp == ASUS_IPAC)
253
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
254
else
255
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
256
mdelay(10);
257
if (cs->subtyp == ASUS_IPAC)
258
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
259
else
260
byteout(cs->hw.asus.adr, 0); /* Reset Off */
261
mdelay(10);
262
if (cs->subtyp == ASUS_IPAC) {
263
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
264
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
265
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
266
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
267
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
268
}
269
}
270
271
static int
272
Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
273
{
274
u_long flags;
275
276
switch (mt) {
277
case CARD_RESET:
278
spin_lock_irqsave(&cs->lock, flags);
279
reset_asuscom(cs);
280
spin_unlock_irqrestore(&cs->lock, flags);
281
return(0);
282
case CARD_RELEASE:
283
release_io_asuscom(cs);
284
return(0);
285
case CARD_INIT:
286
spin_lock_irqsave(&cs->lock, flags);
287
cs->debug |= L1_DEB_IPAC;
288
inithscxisac(cs, 3);
289
spin_unlock_irqrestore(&cs->lock, flags);
290
return(0);
291
case CARD_TEST:
292
return(0);
293
}
294
return(0);
295
}
296
297
#ifdef __ISAPNP__
298
static struct isapnp_device_id asus_ids[] __devinitdata = {
299
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
300
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
301
(unsigned long) "Asus1688 PnP" },
302
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
303
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
304
(unsigned long) "Asus1690 PnP" },
305
{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
306
ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
307
(unsigned long) "Isurf2 PnP" },
308
{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
309
ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
310
(unsigned long) "Iscas TE320" },
311
{ 0, }
312
};
313
314
static struct isapnp_device_id *ipid __devinitdata = &asus_ids[0];
315
static struct pnp_card *pnp_c __devinitdata = NULL;
316
#endif
317
318
int __devinit
319
setup_asuscom(struct IsdnCard *card)
320
{
321
int bytecnt;
322
struct IsdnCardState *cs = card->cs;
323
u_char val;
324
char tmp[64];
325
326
strcpy(tmp, Asuscom_revision);
327
printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
328
if (cs->typ != ISDN_CTYPE_ASUSCOM)
329
return (0);
330
#ifdef __ISAPNP__
331
if (!card->para[1] && isapnp_present()) {
332
struct pnp_dev *pnp_d;
333
while(ipid->card_vendor) {
334
if ((pnp_c = pnp_find_card(ipid->card_vendor,
335
ipid->card_device, pnp_c))) {
336
pnp_d = NULL;
337
if ((pnp_d = pnp_find_dev(pnp_c,
338
ipid->vendor, ipid->function, pnp_d))) {
339
int err;
340
341
printk(KERN_INFO "HiSax: %s detected\n",
342
(char *)ipid->driver_data);
343
pnp_disable_dev(pnp_d);
344
err = pnp_activate_dev(pnp_d);
345
if (err<0) {
346
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
347
__func__, err);
348
return(0);
349
}
350
card->para[1] = pnp_port_start(pnp_d, 0);
351
card->para[0] = pnp_irq(pnp_d, 0);
352
if (!card->para[0] || !card->para[1]) {
353
printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
354
card->para[0], card->para[1]);
355
pnp_disable_dev(pnp_d);
356
return(0);
357
}
358
break;
359
} else {
360
printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
361
}
362
}
363
ipid++;
364
pnp_c = NULL;
365
}
366
if (!ipid->card_vendor) {
367
printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
368
return(0);
369
}
370
}
371
#endif
372
bytecnt = 8;
373
cs->hw.asus.cfg_reg = card->para[1];
374
cs->irq = card->para[0];
375
if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
376
printk(KERN_WARNING
377
"HiSax: ISDNLink config port %x-%x already in use\n",
378
cs->hw.asus.cfg_reg,
379
cs->hw.asus.cfg_reg + bytecnt);
380
return (0);
381
}
382
printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
383
cs->hw.asus.cfg_reg, cs->irq);
384
setup_isac(cs);
385
cs->BC_Read_Reg = &ReadHSCX;
386
cs->BC_Write_Reg = &WriteHSCX;
387
cs->BC_Send_Data = &hscx_fill_fifo;
388
cs->cardmsg = &Asus_card_msg;
389
val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE,
390
cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
391
if ((val == 1) || (val == 2)) {
392
cs->subtyp = ASUS_IPAC;
393
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
394
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
395
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
396
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
397
cs->readisac = &ReadISAC_IPAC;
398
cs->writeisac = &WriteISAC_IPAC;
399
cs->readisacfifo = &ReadISACfifo_IPAC;
400
cs->writeisacfifo = &WriteISACfifo_IPAC;
401
cs->irq_func = &asuscom_interrupt_ipac;
402
printk(KERN_INFO "Asus: IPAC version %x\n", val);
403
} else {
404
cs->subtyp = ASUS_ISACHSCX;
405
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
406
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
407
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
408
cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
409
cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
410
cs->readisac = &ReadISAC;
411
cs->writeisac = &WriteISAC;
412
cs->readisacfifo = &ReadISACfifo;
413
cs->writeisacfifo = &WriteISACfifo;
414
cs->irq_func = &asuscom_interrupt;
415
ISACVersion(cs, "ISDNLink:");
416
if (HscxVersion(cs, "ISDNLink:")) {
417
printk(KERN_WARNING
418
"ISDNLink: wrong HSCX versions check IO address\n");
419
release_io_asuscom(cs);
420
return (0);
421
}
422
}
423
return (1);
424
}
425
426