1/* $Id: s0box.c,v 1.1.1.1 2008/10/15 03:26:33 james26_jang Exp $
2 *
3 * low level stuff for Creatix S0BOX
4 *
5 * Author       Enrik Berkhan
6 * Copyright    by Enrik Berkhan <enrik@starfleet.inka.de>
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#define __NO_VERSION__
14#include <linux/init.h>
15#include "hisax.h"
16#include "isac.h"
17#include "hscx.h"
18#include "isdnl1.h"
19
20extern const char *CardType[];
21const char *s0box_revision = "$Revision: 1.1.1.1 $";
22
23static inline void
24writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
25	unsigned long flags;
26
27	save_flags(flags);
28	cli();
29	outb_p(0x1c,padr+2);
30	outb_p(0x14,padr+2);
31	outb_p((addr+off)&0x7f,padr);
32	outb_p(0x16,padr+2);
33	outb_p(val,padr);
34	outb_p(0x17,padr+2);
35	outb_p(0x14,padr+2);
36	outb_p(0x1c,padr+2);
37	restore_flags(flags);
38}
39
40static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
41			 0, 0, 0, 0, 0, 0, 0, 0,
42			 0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ;
43
44static inline u_char
45readreg(unsigned int padr, signed int addr, u_char off) {
46	register u_char n1, n2;
47	unsigned long flags;
48
49	save_flags(flags);
50	cli();
51	outb_p(0x1c,padr+2);
52	outb_p(0x14,padr+2);
53	outb_p((addr+off)|0x80,padr);
54	outb_p(0x16,padr+2);
55	outb_p(0x17,padr+2);
56	n1 = (inb_p(padr+1) >> 3) & 0x17;
57	outb_p(0x16,padr+2);
58	n2 = (inb_p(padr+1) >> 3) & 0x17;
59	outb_p(0x14,padr+2);
60	outb_p(0x1c,padr+2);
61	restore_flags(flags);
62	return nibtab[n1] | (nibtab[n2] << 4);
63}
64
65static inline void
66read_fifo(unsigned int padr, signed int adr, u_char * data, int size)
67{
68	int i;
69	register u_char n1, n2;
70
71	outb_p(0x1c, padr+2);
72	outb_p(0x14, padr+2);
73	outb_p(adr|0x80, padr);
74	outb_p(0x16, padr+2);
75	for (i=0; i<size; i++) {
76		outb_p(0x17, padr+2);
77		n1 = (inb_p(padr+1) >> 3) & 0x17;
78		outb_p(0x16,padr+2);
79		n2 = (inb_p(padr+1) >> 3) & 0x17;
80		*(data++)=nibtab[n1] | (nibtab[n2] << 4);
81	}
82	outb_p(0x14,padr+2);
83	outb_p(0x1c,padr+2);
84	return;
85}
86
87static inline void
88write_fifo(unsigned int padr, signed int adr, u_char * data, int size)
89{
90	int i;
91	outb_p(0x1c, padr+2);
92	outb_p(0x14, padr+2);
93	outb_p(adr&0x7f, padr);
94	for (i=0; i<size; i++) {
95		outb_p(0x16, padr+2);
96		outb_p(*(data++), padr);
97		outb_p(0x17, padr+2);
98	}
99	outb_p(0x14,padr+2);
100	outb_p(0x1c,padr+2);
101	return;
102}
103
104/* Interface functions */
105
106static u_char
107ReadISAC(struct IsdnCardState *cs, u_char offset)
108{
109	return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
110}
111
112static void
113WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
114{
115	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
116}
117
118static void
119ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
120{
121	read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
122}
123
124static void
125WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
126{
127	write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
128}
129
130static u_char
131ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
132{
133	return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
134}
135
136static void
137WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
138{
139	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
140}
141
142/*
143 * fast interrupt HSCX stuff goes here
144 */
145
146#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
147#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
148#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
149#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
150
151#include "hscx_irq.c"
152
153static void
154s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
155{
156#define MAXCOUNT 5
157	struct IsdnCardState *cs = dev_id;
158	u_char val;
159	int count = 0;
160
161	if (!cs) {
162		printk(KERN_WARNING "Teles: Spurious interrupt!\n");
163		return;
164	}
165	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
166      Start_HSCX:
167	if (val)
168		hscx_int_main(cs, val);
169	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
170      Start_ISAC:
171	if (val)
172		isac_interrupt(cs, val);
173	count++;
174	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
175	if (val && count < MAXCOUNT) {
176		if (cs->debug & L1_DEB_HSCX)
177			debugl1(cs, "HSCX IntStat after IntRoutine");
178		goto Start_HSCX;
179	}
180	val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
181	if (val && count < MAXCOUNT) {
182		if (cs->debug & L1_DEB_ISAC)
183			debugl1(cs, "ISAC IntStat after IntRoutine");
184		goto Start_ISAC;
185	}
186	if (count >= MAXCOUNT)
187		printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
188	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
189	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
190	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
191	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
192	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
193	writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
194}
195
196void
197release_io_s0box(struct IsdnCardState *cs)
198{
199	release_region(cs->hw.teles3.cfg_reg, 8);
200}
201
202static int
203S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
204{
205	switch (mt) {
206		case CARD_RESET:
207			break;
208		case CARD_RELEASE:
209			release_io_s0box(cs);
210			break;
211		case CARD_INIT:
212			inithscxisac(cs, 3);
213			break;
214		case CARD_TEST:
215			break;
216	}
217	return(0);
218}
219
220int __init
221setup_s0box(struct IsdnCard *card)
222{
223	struct IsdnCardState *cs = card->cs;
224	char tmp[64];
225
226	strcpy(tmp, s0box_revision);
227	printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
228	if (cs->typ != ISDN_CTYPE_S0BOX)
229		return (0);
230
231	cs->hw.teles3.cfg_reg = card->para[1];
232	cs->hw.teles3.hscx[0] = -0x20;
233	cs->hw.teles3.hscx[1] = 0x0;
234	cs->hw.teles3.isac = 0x20;
235	cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
236	cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
237	cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
238	cs->irq = card->para[0];
239	if (check_region(cs->hw.teles3.cfg_reg,8)) {
240		printk(KERN_WARNING
241		       "HiSax: %s ports %x-%x already in use\n",
242		       CardType[cs->typ],
243                       cs->hw.teles3.cfg_reg,
244                       cs->hw.teles3.cfg_reg + 7);
245		return 0;
246	} else
247		request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O");
248	printk(KERN_INFO
249	       "HiSax: %s config irq:%d isac:0x%x  cfg:0x%x\n",
250	       CardType[cs->typ], cs->irq,
251	       cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
252	printk(KERN_INFO
253	       "HiSax: hscx A:0x%x  hscx B:0x%x\n",
254	       cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
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 = &S0Box_card_msg;
263	cs->irq_func = &s0box_interrupt;
264	ISACVersion(cs, "S0Box:");
265	if (HscxVersion(cs, "S0Box:")) {
266		printk(KERN_WARNING
267		       "S0Box: wrong HSCX versions check IO address\n");
268		release_io_s0box(cs);
269		return (0);
270	}
271	return (1);
272}
273