kernel: Use NULL for pointers.
[dragonfly.git] / sys / net / i4b / layer1 / isic / i4b_elsa_qs1p.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      isic - I4B Siemens ISDN Chipset Driver for ELSA MicroLink ISDN/PCI
28  *      ==================================================================
29  *
30  * $FreeBSD: src/sys/i4b/layer1/isic/i4b_elsa_qs1p.c,v 1.6.2.1 2001/08/10 14:08:38 obrien Exp $
31  *
32  *      last edit-date: [Wed Jan 24 09:09:28 2001]
33  *
34  *      Note: ELSA Quickstep 1000pro PCI = ELSA MicroLink ISDN/PCI
35  *
36  *---------------------------------------------------------------------------*/
37
38 #include "use_isic.h"
39 #include "use_pci.h"
40 #include "opt_i4b.h"
41
42 #if (NISIC > 0) && (NPCI > 0) && defined(ELSA_QS1PCI)
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/socket.h>
48 #include <sys/bus.h>
49 #include <sys/rman.h>
50
51 #include <bus/pci/pcireg.h>
52 #include <bus/pci/pcivar.h>
53
54 #include <net/if.h>
55 #include <net/i4b/include/machine/i4b_ioctl.h>
56
57 #include "i4b_isic.h"
58 #include "i4b_ipac.h"
59
60 #define MEM0_MAPOFF     0
61 #define PORT0_MAPOFF    4
62 #define PORT1_MAPOFF    12
63
64 #define ELSA_PORT0_MAPOFF       (PCIR_MAPS+PORT0_MAPOFF)
65 #define ELSA_PORT1_MAPOFF       (PCIR_MAPS+PORT1_MAPOFF)
66
67 #define PCI_QS1000_DID  0x1000
68 #define PCI_QS1000_VID  0x1048
69
70 /* masks for register encoded in base addr */
71
72 #define ELSA_BASE_MASK          0x0ffff
73 #define ELSA_OFF_MASK           0xf0000
74
75 /* register id's to be encoded in base addr */
76
77 #define ELSA_IDISAC             0x00000
78 #define ELSA_IDHSCXA            0x10000
79 #define ELSA_IDHSCXB            0x20000
80 #define ELSA_IDIPAC             0x40000
81
82 /* offsets from base address */
83
84 #define ELSA_OFF_ALE            0x00
85 #define ELSA_OFF_RW             0x01
86
87
88 static int eqs1p_pci_probe(device_t dev);
89 static int eqs1p_pci_attach(device_t dev);
90
91 static device_method_t eqs1p_pci_methods[] = {
92         /* Device interface */
93         DEVMETHOD(device_probe,         eqs1p_pci_probe),
94         DEVMETHOD(device_attach,        eqs1p_pci_attach),
95         { 0, 0 }
96 };
97
98 static driver_t eqs1p_pci_driver = {
99         "isic",
100         eqs1p_pci_methods,
101         0
102 };
103
104 static devclass_t eqs1p_pci_devclass;
105
106 DRIVER_MODULE(eqs1p, pci, eqs1p_pci_driver, eqs1p_pci_devclass, NULL, NULL);
107
108 /*---------------------------------------------------------------------------*
109  *      ELSA MicroLink ISDN/PCI fifo read routine
110  *---------------------------------------------------------------------------*/
111 static void
112 eqs1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
113 {
114         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[1]);
115         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]);
116
117         switch(what)
118         {
119                 case ISIC_WHAT_ISAC:
120                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF);
121                         bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
122                         break;
123                 case ISIC_WHAT_HSCXA:
124                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF);
125                         bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
126                         break;
127                 case ISIC_WHAT_HSCXB:
128                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF);
129                         bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size);
130                         break;
131         }
132 }
133
134 /*---------------------------------------------------------------------------*
135  *      ELSA MicroLink ISDN/PCI fifo write routine
136  *---------------------------------------------------------------------------*/
137 static void
138 eqs1pp_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
139 {
140         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[1]);
141         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]);
142
143         switch(what)
144         {
145                 case ISIC_WHAT_ISAC:
146                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF);
147                         bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
148                         break;
149                 case ISIC_WHAT_HSCXA:
150                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF);
151                         bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
152                         break;
153                 case ISIC_WHAT_HSCXB:
154                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF);
155                         bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size);
156                         break;
157         }
158 }
159
160 /*---------------------------------------------------------------------------*
161  *      ELSA MicroLink ISDN/PCI register write routine
162  *---------------------------------------------------------------------------*/
163 static void
164 eqs1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)
165 {
166         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[1]);
167         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]);
168
169         switch(what)
170         {
171                 case ISIC_WHAT_ISAC:
172                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs);
173                         bus_space_write_1(t, h, ELSA_OFF_RW, data);
174                         break;
175                 case ISIC_WHAT_HSCXA:
176                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs);
177                         bus_space_write_1(t, h, ELSA_OFF_RW, data);
178                         break;
179                 case ISIC_WHAT_HSCXB:
180                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs);
181                         bus_space_write_1(t, h, ELSA_OFF_RW, data);
182                         break;
183                 case ISIC_WHAT_IPAC:
184                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs);
185                         bus_space_write_1(t, h, ELSA_OFF_RW, data);
186                         break;
187         }
188 }
189
190 /*---------------------------------------------------------------------------*
191  *      ELSA MicroLink ISDN/PCI register read routine
192  *---------------------------------------------------------------------------*/
193 static u_int8_t
194 eqs1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs)
195 {
196         bus_space_tag_t    t = rman_get_bustag(sc->sc_resources.io_base[1]);
197         bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]);
198
199         switch(what)
200         {
201                 case ISIC_WHAT_ISAC:
202                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs);
203                         return bus_space_read_1(t, h, ELSA_OFF_RW);
204                 case ISIC_WHAT_HSCXA:
205                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs);
206                         return bus_space_read_1(t, h, ELSA_OFF_RW);
207                 case ISIC_WHAT_HSCXB:
208                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs);
209                         return bus_space_read_1(t, h, ELSA_OFF_RW);
210                 case ISIC_WHAT_IPAC:
211                         bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs);
212                         return bus_space_read_1(t, h, ELSA_OFF_RW);
213         }
214         return 0;
215 }
216
217 /*---------------------------------------------------------------------------*
218  *      avma1pp_probe - probe for a card
219  *---------------------------------------------------------------------------*/
220 static int
221 eqs1p_pci_probe(device_t dev)
222 {
223         if((pci_get_vendor(dev) == PCI_QS1000_VID) &&
224            (pci_get_device(dev) == PCI_QS1000_DID))
225         {
226                 device_set_desc(dev, "ELSA MicroLink ISDN/PCI");
227                 return(0);
228         }
229         return(ENXIO);
230 }
231
232 /*---------------------------------------------------------------------------*
233  *      isic_attach_Eqs1pp - attach for ELSA MicroLink ISDN/PCI
234  *---------------------------------------------------------------------------*/
235 static int
236 eqs1p_pci_attach(device_t dev)
237 {
238         bus_space_tag_t t;
239         bus_space_handle_t h;
240         struct l1_softc *sc;
241         void *ih = NULL;
242         int unit = device_get_unit(dev);
243         
244         /* check max unit range */
245         
246         if(unit >= ISIC_MAXUNIT)
247         {
248                 kprintf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA MicroLink ISDN/PCI!\n",
249                                 unit, unit);
250                 return(ENXIO);  
251         }       
252
253         sc = &l1_sc[unit];              /* get softc */ 
254         
255         sc->sc_unit = unit;
256
257         /* get io_base */
258
259         sc->sc_resources.io_rid[0] = ELSA_PORT0_MAPOFF;
260         
261         if(!(sc->sc_resources.io_base[0] =
262                         bus_alloc_resource(dev, SYS_RES_IOPORT,
263                                                 &sc->sc_resources.io_rid[0],
264                                                 0UL, ~0UL, 1, RF_ACTIVE)))
265         {
266                 kprintf("isic%d: Couldn't get first iobase for ELSA MicroLink ISDN/PCI!\n", unit);
267                 return(ENXIO);                                       
268         }
269
270         sc->sc_resources.io_rid[1] = ELSA_PORT1_MAPOFF;
271         
272         if(!(sc->sc_resources.io_base[1] =
273                         bus_alloc_resource(dev, SYS_RES_IOPORT,
274                                                 &sc->sc_resources.io_rid[1],
275                                                 0UL, ~0UL, 1, RF_ACTIVE)))
276         {
277                 kprintf("isic%d: Couldn't get second iobase for ELSA MicroLink ISDN/PCI!\n", unit);
278                 isic_detach_common(dev);
279                 return(ENXIO);                                       
280         }
281
282         sc->sc_port = rman_get_start(sc->sc_resources.io_base[1]);
283
284         if(!(sc->sc_resources.irq =
285                         bus_alloc_resource(dev, SYS_RES_IRQ,
286                                            &sc->sc_resources.irq_rid,
287                                            0UL, ~0UL, 1, RF_ACTIVE | RF_SHAREABLE)))
288         {
289                 kprintf("isic%d: Could not get irq for ELSA MicroLink ISDN/PCI!\n",unit);
290                 isic_detach_common(dev);
291                 return(ENXIO);                                       
292         }
293         
294         sc->sc_irq = rman_get_start(sc->sc_resources.irq);
295
296         /* setup access routines */
297
298         sc->clearirq = NULL;
299         sc->readreg = eqs1pp_read_reg;
300         sc->writereg = eqs1pp_write_reg;
301
302         sc->readfifo = eqs1pp_read_fifo;
303         sc->writefifo = eqs1pp_write_fifo;
304
305         /* setup card type */
306         
307         sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI;
308
309         /* setup IOM bus type */
310         
311         sc->sc_bustyp = BUS_TYPE_IOM2;
312
313         /* setup chip type = IPAC ! */
314         
315         sc->sc_ipac = 1;
316         sc->sc_bfifolen = IPAC_BFIFO_LEN;
317
318         if(isic_attach_common(dev))
319         {
320                 isic_detach_common(dev);
321                 return(ENXIO);
322         }
323
324         if (bus_setup_intr(dev, sc->sc_resources.irq, 0,
325                                 (void(*)(void*))isicintr,
326                                 sc, &ih, NULL))
327         {
328                 kprintf("isic%d: Couldn't set up irq for ELSA MicroLink ISDN/PCI!\n", unit);
329                 isic_detach_common(dev);
330                 return(ENXIO);
331         }
332
333         /* enable hscx/isac irq's */
334
335         IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
336
337         IPAC_WRITE(IPAC_ACFG, 0);       /* outputs are open drain */
338         IPAC_WRITE(IPAC_AOE,            /* aux 5..2 are inputs, 7, 6 outputs */
339                 (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
340         IPAC_WRITE(IPAC_ATX, 0xff);     /* set all output lines high */
341
342         t = rman_get_bustag(sc->sc_resources.io_base[0]);
343         h = rman_get_bushandle(sc->sc_resources.io_base[0]);
344         
345         bus_space_write_1(t, h, 0x4c, 0x41);    /* enable card interrupt */
346         
347         return(0);
348 }
349
350 #endif /* (NISIC > 0) && (NPCI > 0) && defined(ELSA_QS1PCI) */