Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / capi / iavc / iavc_pci.c
1 /*
2  * Copyright (c) 2001 Cubical Solutions Ltd. 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  * capi/iavc/iavc_pci.c
26  *              The AVM ISDN controllers' PCI bus attachment handling.
27  *
28  * $FreeBSD: src/sys/i4b/capi/iavc/iavc_pci.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
29  */
30
31 #include "iavc.h"
32 #include "i4bcapi.h"
33 #include "pci.h"
34
35 #if (NIAVC > 0) && (NI4BCAPI > 0) && (NPCI > 0)
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42 #include <net/if.h>
43
44 #include <machine/clock.h>
45
46 #include <machine/bus.h>
47 #include <machine/resource.h>
48 #include <sys/bus.h>
49 #include <sys/rman.h>
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52
53 #include <pci/pcireg.h>
54 #include <pci/pcivar.h>
55
56 #include <machine/i4b_debug.h>
57 #include <machine/i4b_ioctl.h>
58 #include <machine/i4b_trace.h>
59
60 #include <i4b/include/i4b_global.h>
61 #include <i4b/include/i4b_l3l4.h>
62 #include <i4b/include/i4b_mbuf.h>
63
64 #include <i4b/capi/capi.h>
65
66 #include <i4b/capi/iavc/iavc.h>
67
68 /* PCI device ids */
69
70 #define PCI_AVM_VID   0x1244
71 #define PCI_AVMT1_DID 0x1200
72 #define PCI_AVMB1_DID 0x0700
73
74 /* PCI driver linkage */
75
76 static void iavc_pci_intr(iavc_softc_t *sc);
77 static int iavc_pci_probe(device_t dev);
78 static int iavc_pci_attach(device_t dev);
79
80 static device_method_t iavc_pci_methods[] =
81 {
82     DEVMETHOD(device_probe,     iavc_pci_probe),
83     DEVMETHOD(device_attach,    iavc_pci_attach),
84     { 0, 0 }
85 };
86
87 static driver_t iavc_pci_driver =
88 {
89     "iavc",
90     iavc_pci_methods,
91     0
92 };
93
94 static devclass_t iavc_pci_devclass;
95
96 DRIVER_MODULE(iavc, pci, iavc_pci_driver, iavc_pci_devclass, 0, 0);
97
98 /* Driver soft contexts */
99
100 iavc_softc_t iavc_sc[IAVC_MAXUNIT];
101
102 /*---------------------------------------------------------------------------*
103  *
104  *---------------------------------------------------------------------------*/
105
106 static int
107 iavc_pci_probe(device_t dev)
108 {
109     u_int16_t did = pci_get_device(dev);
110     u_int16_t vid = pci_get_vendor(dev);
111
112     if ((vid == PCI_AVM_VID) && (did == PCI_AVMT1_DID)) {
113         device_set_desc(dev, "AVM T1 PCI");
114     } else if ((vid == PCI_AVM_VID) && (did == PCI_AVMB1_DID)) {
115         device_set_desc(dev, "AVM B1 PCI");
116     } else {
117         return(ENXIO);
118     }
119
120     return(0);
121 }
122
123 /*---------------------------------------------------------------------------*
124  *
125  *---------------------------------------------------------------------------*/
126
127 static int
128 iavc_pci_attach(device_t dev)
129 {
130     struct iavc_softc *sc;
131     void *ih = 0;
132     u_int16_t did = pci_get_device(dev);
133     int unit = device_get_unit(dev), ret;
134         
135     /* check max unit range */
136         
137     if (unit >= IAVC_MAXUNIT) {
138         printf("iavc%d: too many units\n", unit);
139         return(ENXIO);  
140     }   
141
142     sc = iavc_find_sc(unit);    /* get softc */ 
143         
144     sc->sc_unit = unit;
145
146     /* use the i/o mapped base address */
147         
148     sc->sc_resources.io_rid[0] = 0x14;
149         
150     if (!(sc->sc_resources.io_base[0] =
151          bus_alloc_resource(dev, SYS_RES_IOPORT,
152                             &sc->sc_resources.io_rid[0],
153                             0UL, ~0UL, 1, RF_ACTIVE))) {
154         printf("iavc%d: can't allocate io region\n", unit);
155         return(ENXIO);                                       
156     }
157
158     sc->sc_iobase = rman_get_start(sc->sc_resources.io_base[0]);
159     sc->sc_io_bt = rman_get_bustag(sc->sc_resources.io_base[0]);
160     sc->sc_io_bh = rman_get_bushandle(sc->sc_resources.io_base[0]);
161
162     /* use the memory mapped DMA controller */
163         
164     sc->sc_resources.mem_rid = 0x10;
165         
166     if (!(sc->sc_resources.mem =
167          bus_alloc_resource(dev, SYS_RES_MEMORY,
168                             &sc->sc_resources.mem_rid,
169                             0UL, ~0UL, 1, RF_ACTIVE))) {
170         printf("iavc%d: can't allocate memory region\n", unit);
171         return(ENXIO);                                       
172     }
173
174     sc->sc_membase = rman_get_start(sc->sc_resources.mem);
175     sc->sc_mem_bt = rman_get_bustag(sc->sc_resources.mem);
176     sc->sc_mem_bh = rman_get_bushandle(sc->sc_resources.mem);
177
178     /* do some detection */
179
180     sc->sc_t1 = FALSE;
181     sc->sc_dma = FALSE;
182     b1dma_reset(sc);
183
184     if (did == PCI_AVMT1_DID) {
185         sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI;
186         sc->sc_capi.sc_nbch = 30;
187         ret = t1_detect(sc);
188         if (ret) {
189             if (ret < 6) {
190                 printf("iavc%d: no card detected?\n", sc->sc_unit);
191             } else {
192                 printf("iavc%d: black box not on\n", sc->sc_unit);
193             }
194             return(ENXIO);
195         } else {
196             sc->sc_dma = TRUE;
197             sc->sc_t1 = TRUE;
198         }
199
200     } else if (did == PCI_AVMB1_DID) {
201         sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI;
202         sc->sc_capi.sc_nbch = 2;
203         ret = b1dma_detect(sc);
204         if (ret) {
205             ret = b1_detect(sc);
206             if (ret) {
207                 printf("iavc%d: no card detected?\n", sc->sc_unit);
208                 return(ENXIO);
209             }
210         } else {
211             sc->sc_dma = TRUE;
212         }
213     }
214
215     if (sc->sc_dma) b1dma_reset(sc);
216 #if 0
217     if (sc->sc_t1) t1_reset(sc);
218     else b1_reset(sc);
219 #endif
220
221     /* of course we need an interrupt */
222     
223     sc->sc_resources.irq_rid = 0x00;
224         
225     if(!(sc->sc_resources.irq =
226          bus_alloc_resource(dev, SYS_RES_IRQ,
227                             &sc->sc_resources.irq_rid,
228                             0UL, ~0UL, 1, RF_SHAREABLE|RF_ACTIVE))) {
229         printf("iavc%d: can't allocate irq\n",unit);
230         return(ENXIO);
231     }
232
233     /* finalize our own context */
234
235     memset(&sc->sc_txq, 0, sizeof(struct ifqueue));
236     sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4;
237
238 #if defined (__FreeBSD__) && __FreeBSD__ > 4
239     mtx_init(&sc->sc_txq.ifq_mtx, "i4b_ivac_pci", MTX_DEF);
240 #endif
241     
242     sc->sc_intr = FALSE;
243     sc->sc_state = IAVC_DOWN;
244     sc->sc_blocked = FALSE;
245
246     /* setup capi link */
247         
248     sc->sc_capi.load = iavc_load;
249     sc->sc_capi.reg_appl = iavc_register;
250     sc->sc_capi.rel_appl = iavc_release;
251     sc->sc_capi.send = iavc_send;
252     sc->sc_capi.ctx = (void*) sc;
253
254     if (capi_ll_attach(&sc->sc_capi)) {
255         printf("iavc%d: capi attach failed\n", unit);
256         return(ENXIO);
257     }
258
259     /* setup the interrupt */
260
261     if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET,
262                       (void(*)(void*))iavc_pci_intr,
263                       sc, &ih)) {
264         printf("iavc%d: irq setup failed\n", unit);
265         return(ENXIO);
266     }
267
268     /* the board is now ready to be loaded */
269
270     return(0);
271 }
272
273 /*---------------------------------------------------------------------------*
274  *      IRQ handler
275  *---------------------------------------------------------------------------*/
276
277 static void
278 iavc_pci_intr(struct iavc_softc *sc)
279 {
280     iavc_handle_intr(sc);
281 }
282
283 #endif