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