]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/contrib/dev/oltr/if_oltr_isa.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / contrib / dev / oltr / if_oltr_isa.c
1 /*
2  * Copyright (c) 1998, Larry Lile
3  * All rights reserved.
4  *
5  * For latest sources and information on this driver, please
6  * go to http://anarchy.stdio.com.
7  *
8  * Questions, comments or suggestions should be directed to
9  * Larry Lile <lile@stdio.com>.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice unmodified, this list of conditions, and the following
16  *    disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD$
34  */
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/socket.h>
40
41 #include <net/if.h>
42 #include <net/if_arp.h>
43 #include <net/iso88025.h>
44 #include <net/if_media.h>
45 #include <net/bpf.h>
46
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49
50 #include <sys/bus.h>
51 #include <sys/rman.h>
52
53 #include <isa/isavar.h>
54 #include <isa/pnpvar.h>
55
56 #include "contrib/dev/oltr/trlld.h"
57 #include "contrib/dev/oltr/if_oltrvar.h"
58
59 extern TRlldDriver_t LldDriver;
60
61 struct AdapterNameEntry {
62         int type;
63         char *name; } ;
64
65 static struct AdapterNameEntry AdapterNameList[] = {
66         { 1, "Olicom OC-3115" },
67         { 2, "Olicom ISA 16/4 Adapter (OC-3117)" },
68         { 3, "Olicom ISA 16/4 Adapter (OC-3118)" },
69         { 0, "Olicom Unsupported Adapter" }
70 };
71
72 static int oltr_isa_probe       __P((device_t));
73 static int oltr_isa_attach      __P((device_t));
74
75 static struct isa_pnp_id oltr_ids[] = {
76         { 0x0100833d,   NULL },         /* OLC9430 */
77         { 0,            NULL },
78 };
79
80
81 static int
82 oltr_isa_probe(dev)
83         device_t dev;
84 {
85         TRlldAdapterConfig_t    config;
86         struct resource         *port_res;
87         int                     port_rid;
88         struct AdapterNameEntry *list;
89         int                     error;
90         int                     iobase;
91         int                     success;
92
93         error = ISA_PNP_PROBE(device_get_parent(dev), dev, oltr_ids);
94         if (error != 0 && error != ENOENT)
95                 return (error);
96
97         iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
98         if (iobase == 0)
99                 return (ENXIO);
100
101         if (error == ENOENT
102             && bus_set_resource(dev, SYS_RES_IOPORT, 0, iobase,
103                                 OLTR_PORT_COUNT) < 0)
104                  return (ENXIO);
105
106         port_rid = 0;
107         port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
108                                       0, ~0, 0, RF_ACTIVE);
109         if (port_res == NULL)
110                 return (ENXIO);
111
112         success = TRlldIOAddressConfig(&LldDriver, &config, iobase);
113
114         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
115
116         if (!success)
117                 return (ENXIO);
118
119         for (list = AdapterNameList;
120              list->type != 0 && list->type != config.type;
121              list++) ;
122         device_set_desc(dev, list->name);
123  
124         return (0);
125 }
126
127
128 static void
129 oltr_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
130 {
131         *(unsigned long *)arg = segs->ds_addr;
132 }
133
134
135 static int
136 oltr_isa_attach(dev)
137         device_t dev;
138 {
139         struct oltr_softc       *sc = device_get_softc(dev);
140         bus_dma_filter_t        *filter;
141         void                    *filter_arg;
142         int                     scratch_size;
143         int                     buffer_size;
144         int                     iobase;
145         int                     success;
146         int                     s, i;
147
148         s = splimp();
149
150         bzero(sc, sizeof(struct oltr_softc));
151         sc->unit = device_get_unit(dev);
152         sc->state = OL_UNKNOWN;
153
154         iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
155         if (iobase == 0) {
156                 device_printf(dev, "couldn't get base address\n");
157                 goto config_failed;
158         }
159
160         sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
161                                  0, ~0, 0, RF_ACTIVE);
162         if (sc->port_res == NULL) {
163                 device_printf(dev, "couldn't allocate io port\n");
164                 goto config_failed;
165         }
166
167         success = TRlldIOAddressConfig(&LldDriver, &sc->config, iobase);
168         if (success == 0) {
169                 device_printf(dev, "adapter configuration failed\n");
170                 goto config_failed;
171         }
172
173         device_printf(dev, "MAC address %6D\n", sc->config.macaddress, ":");
174
175         if (sc->config.dmalevel != TRLLD_DMA_PIO) {
176                 sc->drq_rid = 0;
177                 sc->drq_res = bus_alloc_resource(dev, SYS_RES_DRQ,
178                                          &sc->drq_rid, 0, ~0, 1, RF_ACTIVE);
179                 if (sc->drq_res == NULL) {
180                         device_printf(dev, "couldn't setup dma channel\n");
181                         goto config_failed;
182                 } else
183                         isa_dmacascade(sc->config.dmalevel);
184         }
185
186         filter = NULL;
187         filter_arg = NULL;
188
189         if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_24BIT,
190                                 BUS_SPACE_MAXADDR, filter,
191                 filter_arg, BUS_SPACE_MAXSIZE_24BIT, BUS_SPACE_UNRESTRICTED,
192                 BUS_SPACE_MAXSIZE_24BIT, 0, NULL, NULL, &sc->bus_tag) != 0) {
193
194                 device_printf(dev, "couldn't setup parent dma tag\n");
195                 return (ENOMEM);
196         }
197
198         scratch_size = TRlldAdapterSize();
199         buffer_size = RING_BUFFER_LEN * (RX_BUFFER_LEN + TX_BUFFER_LEN);
200
201         if (bus_dma_tag_create(sc->bus_tag, 1, 0, BUS_SPACE_MAXADDR,
202                                BUS_SPACE_MAXADDR, NULL, NULL,
203                                scratch_size + buffer_size,
204                                1, BUS_SPACE_MAXSIZE_24BIT, 0,
205                                NULL, NULL, &sc->mem_tag) != 0) {
206
207                 device_printf(dev, "couldn't setup buffer dma tag\n");
208                 goto config_failed;
209         }
210         
211         if (bus_dmamem_alloc(sc->mem_tag, (void **)&sc->TRlldAdapter,
212                              BUS_DMA_NOWAIT, &sc->mem_map) != 0) {
213
214                 device_printf(dev, "couldn't alloc buffer memory\n");
215                 goto config_failed;
216         }
217
218         bus_dmamap_load(sc->mem_tag, sc->mem_map, sc->TRlldAdapter,
219                         scratch_size + buffer_size, oltr_dmamap_callback,
220                         (void *)&sc->TRlldAdapter_phys, 0);
221
222         if (sc->TRlldAdapter_phys == 0) {
223                 device_printf(dev, "couldn't load buffer memory\n");
224                 goto config_failed;
225         }
226
227         /*
228          * Allocate RX/TX Pools
229          */
230
231         for (i = 0; i < RING_BUFFER_LEN; i++) {
232                 sc->rx_ring[i].index = i;
233                 sc->rx_ring[i].data = (char *)sc->TRlldAdapter + scratch_size +
234                     i * (RX_BUFFER_LEN + TX_BUFFER_LEN);
235                 sc->rx_ring[i].address = sc->TRlldAdapter_phys + scratch_size +
236                     i * (RX_BUFFER_LEN + TX_BUFFER_LEN);
237                 sc->tx_ring[i].index = i;
238                 sc->tx_ring[i].data = (char *)sc->TRlldAdapter + scratch_size +
239                     i * (RX_BUFFER_LEN + TX_BUFFER_LEN) + RX_BUFFER_LEN;
240                 sc->tx_ring[i].address = sc->TRlldAdapter_phys + scratch_size +
241                     i * (RX_BUFFER_LEN + TX_BUFFER_LEN) + RX_BUFFER_LEN;
242         }
243
244         if (oltr_attach(dev) != 0)
245                 goto config_failed;
246
247         splx(s);
248         return (0);
249
250 config_failed:
251
252         if (sc->port_res) {
253                 bus_release_resource(dev, SYS_RES_IOPORT,
254                                      sc->port_rid, sc->port_res);
255                 sc->port_res = NULL;
256                 sc->port_rid = 0;
257         }
258
259         if (sc->oltr_intrhand) {
260                 bus_teardown_intr(dev, sc->irq_res, sc->oltr_intrhand);
261                 sc->oltr_intrhand = NULL;
262         }
263
264         if (sc->irq_res) {
265                 bus_release_resource(dev, SYS_RES_MEMORY,
266                                      sc->irq_rid, sc->irq_res);
267                 sc->irq_res = NULL;
268                 sc->irq_rid = 0;
269         }
270
271         if (sc->drq_res) {
272                 bus_release_resource(dev, SYS_RES_DRQ,
273                                      sc->drq_rid, sc->drq_res);
274                 sc->drq_res = NULL;
275                 sc->drq_rid = 0;
276         }
277
278         if (sc->TRlldAdapter) {
279                 bus_dmamem_free(sc->mem_tag, sc->TRlldAdapter, sc->mem_map);
280                 sc->TRlldAdapter = NULL;
281         }
282
283         if (sc->mem_map) {
284                 bus_dmamap_destroy(sc->mem_tag, sc->mem_map);
285                 sc->mem_map = NULL;
286         }
287
288         if (sc->mem_tag) {
289                 bus_dma_tag_destroy(sc->mem_tag);
290                 sc->mem_tag = NULL;
291         }
292
293         if (sc->bus_tag) {
294                 bus_dma_tag_destroy(sc->bus_tag);
295                 sc->bus_tag = NULL;
296         }
297
298         splx(s);
299         return (ENXIO);
300 }
301
302
303 static device_method_t oltr_isa_methods[] = {
304         /* Device interface */
305         DEVMETHOD(device_probe,         oltr_isa_probe),
306         DEVMETHOD(device_attach,        oltr_isa_attach),
307
308         { 0, 0 }
309 };
310
311 static driver_t oltr_isa_driver = {
312         "oltr",
313         oltr_isa_methods,
314         sizeof(struct oltr_softc)
315 };
316
317 static devclass_t oltr_isa_devclass;
318
319 DRIVER_MODULE(oltr, isa, oltr_isa_driver, oltr_isa_devclass, 0, 0);
320 MODULE_DEPEND(oltr, isa, 1, 1, 1);
321 MODULE_DEPEND(oltr, iso88025, 1, 1, 1);