File: /usr/src/linux/drivers/isdn/hisax/sportster.c

1     /* $Id: sportster.c,v 1.14.6.1 2001/02/16 16:43:29 kai Exp $
2      *
3      * sportster.c     low level stuff for USR Sportster internal TA
4      *
5      * Author       Karsten Keil (keil@isdn4linux.de)
6      *
7      * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
8      *
9      * This file is (c) under GNU General Public License
10      *
11      */
12     #define __NO_VERSION__
13     #include <linux/init.h>
14     #include "hisax.h"
15     #include "isac.h"
16     #include "hscx.h"
17     #include "isdnl1.h"
18     
19     extern const char *CardType[];
20     const char *sportster_revision = "$Revision: 1.14.6.1 $";
21     
22     #define byteout(addr,val) outb(val,addr)
23     #define bytein(addr) inb(addr)
24     
25     #define	 SPORTSTER_ISAC		0xC000
26     #define	 SPORTSTER_HSCXA	0x0000
27     #define	 SPORTSTER_HSCXB	0x4000
28     #define	 SPORTSTER_RES_IRQ	0x8000
29     #define	 SPORTSTER_RESET	0x80
30     #define	 SPORTSTER_INTE		0x40
31     
32     static inline int
33     calc_off(unsigned int base, unsigned int off)
34     {
35     	return(base + ((off & 0xfc)<<8) + ((off & 3)<<1));
36     }
37     
38     static inline void
39     read_fifo(unsigned int adr, u_char * data, int size)
40     {
41     	insb(adr, data, size);
42     }
43     
44     static void
45     write_fifo(unsigned int adr, u_char * data, int size)
46     {
47     	outsb(adr, data, size);
48     }
49     
50     /* Interface functions */
51     
52     static u_char
53     ReadISAC(struct IsdnCardState *cs, u_char offset)
54     {
55     	return (bytein(calc_off(cs->hw.spt.isac, offset)));
56     }
57     
58     static void
59     WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
60     {
61     	byteout(calc_off(cs->hw.spt.isac, offset), value);
62     }
63     
64     static void
65     ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
66     {
67     	read_fifo(cs->hw.spt.isac, data, size);
68     }
69     
70     static void
71     WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
72     {
73     	write_fifo(cs->hw.spt.isac, data, size);
74     }
75     
76     static u_char
77     ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
78     {
79     	return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
80     }
81     
82     static void
83     WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
84     {
85     	byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
86     }
87     
88     /*
89      * fast interrupt HSCX stuff goes here
90      */
91     
92     #define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
93     #define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
94     #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
95     #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
96     
97     #include "hscx_irq.c"
98     
99     static void
100     sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
101     {
102     	struct IsdnCardState *cs = dev_id;
103     	u_char val;
104     
105     	if (!cs) {
106     		printk(KERN_WARNING "Sportster: Spurious interrupt!\n");
107     		return;
108     	}
109     	val = READHSCX(cs, 1, HSCX_ISTA);
110           Start_HSCX:
111     	if (val)
112     		hscx_int_main(cs, val);
113     	val = ReadISAC(cs, ISAC_ISTA);
114           Start_ISAC:
115     	if (val)
116     		isac_interrupt(cs, val);
117     	val = READHSCX(cs, 1, HSCX_ISTA);
118     	if (val) {
119     		if (cs->debug & L1_DEB_HSCX)
120     			debugl1(cs, "HSCX IntStat after IntRoutine");
121     		goto Start_HSCX;
122     	}
123     	val = ReadISAC(cs, ISAC_ISTA);
124     	if (val) {
125     		if (cs->debug & L1_DEB_ISAC)
126     			debugl1(cs, "ISAC IntStat after IntRoutine");
127     		goto Start_ISAC;
128     	}
129     	/* get a new irq impulse if there any pending */
130     	bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1);
131     }
132     
133     void
134     release_io_sportster(struct IsdnCardState *cs)
135     {
136     	int i, adr;
137     
138     	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
139     	for (i=0; i<64; i++) {
140     		adr = cs->hw.spt.cfg_reg + i *1024;
141     		release_region(adr, 8);
142     	}
143     }
144     
145     void
146     reset_sportster(struct IsdnCardState *cs)
147     {
148     	long flags;
149     
150     	cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
151     	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
152     	save_flags(flags);
153     	sti();
154     	set_current_state(TASK_UNINTERRUPTIBLE);
155     	schedule_timeout((10*HZ)/1000);
156     	cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
157     	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
158     	set_current_state(TASK_UNINTERRUPTIBLE);
159     	schedule_timeout((10*HZ)/1000);
160     	restore_flags(flags);
161     }
162     
163     static int
164     Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
165     {
166     	switch (mt) {
167     		case CARD_RESET:
168     			reset_sportster(cs);
169     			return(0);
170     		case CARD_RELEASE:
171     			release_io_sportster(cs);
172     			return(0);
173     		case CARD_INIT:
174     			inithscxisac(cs, 1);
175     			cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
176     			byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
177     			inithscxisac(cs, 2);
178     			return(0);
179     		case CARD_TEST:
180     			return(0);
181     	}
182     	return(0);
183     }
184     
185     static int __init
186     get_io_range(struct IsdnCardState *cs)
187     {
188     	int i, j, adr;
189     	
190     	for (i=0;i<64;i++) {
191     		adr = cs->hw.spt.cfg_reg + i *1024;
192     		if (check_region(adr, 8)) {
193     			printk(KERN_WARNING
194     				"HiSax: %s config port %x-%x already in use\n",
195     				CardType[cs->typ], adr, adr + 8);
196     			break;
197     		} else
198     			request_region(adr, 8, "sportster");
199     	}
200     	if (i==64)
201     		return(1);
202     	else {
203     		for (j=0; j<i; j++) {
204     			adr = cs->hw.spt.cfg_reg + j *1024;
205     			release_region(adr, 8);
206     		}
207     		return(0);
208     	}
209     }
210     
211     int __init
212     setup_sportster(struct IsdnCard *card)
213     {
214     	struct IsdnCardState *cs = card->cs;
215     	char tmp[64];
216     
217     	strcpy(tmp, sportster_revision);
218     	printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
219     	if (cs->typ != ISDN_CTYPE_SPORTSTER)
220     		return (0);
221     
222     	cs->hw.spt.cfg_reg = card->para[1];
223     	cs->irq = card->para[0];
224     	if (!get_io_range(cs))
225     		return (0);
226     	cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
227     	cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
228     	cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
229     	
230     	switch(cs->irq) {
231     		case 5:	cs->hw.spt.res_irq = 1;
232     			break;
233     		case 7:	cs->hw.spt.res_irq = 2;
234     			break;
235     		case 10:cs->hw.spt.res_irq = 3;
236     			break;
237     		case 11:cs->hw.spt.res_irq = 4;
238     			break;
239     		case 12:cs->hw.spt.res_irq = 5;
240     			break;
241     		case 14:cs->hw.spt.res_irq = 6;
242     			break;
243     		case 15:cs->hw.spt.res_irq = 7;
244     			break;
245     		default:release_io_sportster(cs);
246     			printk(KERN_WARNING "Sportster: wrong IRQ\n");
247     			return(0);
248     	}
249     	reset_sportster(cs);
250     	printk(KERN_INFO
251     	       "HiSax: %s config irq:%d cfg:0x%X\n",
252     	       CardType[cs->typ], cs->irq,
253     	       cs->hw.spt.cfg_reg);
254     
255     	cs->readisac = &ReadISAC;
256     	cs->writeisac = &WriteISAC;
257     	cs->readisacfifo = &ReadISACfifo;
258     	cs->writeisacfifo = &WriteISACfifo;
259     	cs->BC_Read_Reg = &ReadHSCX;
260     	cs->BC_Write_Reg = &WriteHSCX;
261     	cs->BC_Send_Data = &hscx_fill_fifo;
262     	cs->cardmsg = &Sportster_card_msg;
263     	cs->irq_func = &sportster_interrupt;
264     	ISACVersion(cs, "Sportster:");
265     	if (HscxVersion(cs, "Sportster:")) {
266     		printk(KERN_WARNING
267     		       "Sportster: wrong HSCX versions check IO address\n");
268     		release_io_sportster(cs);
269     		return (0);
270     	}
271     	return (1);
272     }
273