]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pdq/if_fea.c
In order to reduce use of M_EXT outside of the mbuf allocator and
[FreeBSD/FreeBSD.git] / sys / dev / pdq / if_fea.c
1 /*-
2  * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. The name of the author may not be used to endorse or promote products
11  *    derived from this software without specific prior written permission
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * $FreeBSD$
25  */
26
27 /*
28  * DEC PDQ FDDI Controller
29  *
30  *      This module support the DEFEA EISA FDDI Controller.
31  */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/lock.h>
36 #include <sys/kernel.h>
37 #include <sys/socket.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/bus.h>
41
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/rman.h> 
45
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/if_media.h>
49 #include <net/fddi.h>
50
51 #include <dev/eisa/eisaconf.h>
52
53 #include <dev/pdq/pdq_freebsd.h>
54 #include <dev/pdq/pdqreg.h>
55
56 static void             pdq_eisa_subprobe       (pdq_bus_t, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *);
57 static void             pdq_eisa_devinit        (pdq_softc_t *);
58 static const char *     pdq_eisa_match          (eisa_id_t);
59
60 static int              pdq_eisa_probe          (device_t);
61 static int              pdq_eisa_attach         (device_t);
62 static int              pdq_eisa_detach         (device_t);
63 static int              pdq_eisa_shutdown       (device_t);
64 static void             pdq_eisa_ifintr         (void *);
65
66 #define DEFEA_IRQS                      0x0000FBA9U
67
68 #define DEFEA_INTRENABLE                0x8     /* level interrupt */
69 #define DEFEA_DECODE_IRQ(n)             ((DEFEA_IRQS >> ((n) << 2)) & 0x0f)
70
71 #define EISA_DEVICE_ID_DEC_DEC3001      0x10a33001
72 #define EISA_DEVICE_ID_DEC_DEC3002      0x10a33002
73 #define EISA_DEVICE_ID_DEC_DEC3003      0x10a33003
74 #define EISA_DEVICE_ID_DEC_DEC3004      0x10a33004
75
76 static void
77 pdq_eisa_subprobe(bc, iobase, maddr, msize, irq)
78         pdq_bus_t       bc;
79         u_int32_t       iobase;
80         u_int32_t       *maddr;
81         u_int32_t       *msize;
82         u_int32_t       *irq;
83 {
84         if (irq != NULL)
85                 *irq = DEFEA_DECODE_IRQ(PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_IO_CONFIG_STAT_0) & 3);
86         *maddr = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_0) << 8)
87                  | (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_1) << 16);
88         *msize = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_MASK_0) + 4) << 8;
89
90         return;
91 }
92
93 static void
94 pdq_eisa_devinit (sc)
95         pdq_softc_t     *sc;
96 {
97         pdq_uint8_t     data;
98
99         /*
100          * Do the standard initialization for the DEFEA registers.
101          */
102         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_FUNCTION_CTRL, 0x23);
103         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_IO_CMP_1_1, (sc->io_bsh >> 8) & 0xF0);
104         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_IO_CMP_0_1, (sc->io_bsh >> 8) & 0xF0);
105         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_SLOT_CTRL, 0x01);
106         data = PDQ_OS_IORD_8(sc->io_bst, sc->io_bsh, PDQ_EISA_BURST_HOLDOFF);
107 #if defined(PDQ_IOMAPPED)
108         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_BURST_HOLDOFF, data & ~1);
109 #else
110         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_BURST_HOLDOFF, data | 1);
111 #endif
112         data = PDQ_OS_IORD_8(sc->io_bst, sc->io_bsh, PDQ_EISA_IO_CONFIG_STAT_0);
113         PDQ_OS_IOWR_8(sc->io_bst, sc->io_bsh, PDQ_EISA_IO_CONFIG_STAT_0, data | DEFEA_INTRENABLE);
114
115         return;
116 }
117
118 static const char *
119 pdq_eisa_match (type)
120         eisa_id_t       type;
121 {
122         switch (type) {
123                 case EISA_DEVICE_ID_DEC_DEC3001:
124                 case EISA_DEVICE_ID_DEC_DEC3002:
125                 case EISA_DEVICE_ID_DEC_DEC3003:
126                 case EISA_DEVICE_ID_DEC_DEC3004:
127                         return ("DEC FDDIcontroller/EISA Adapter");
128                         break;
129                  default:
130                         break;
131         }
132         return (NULL);
133 }
134
135 static int
136 pdq_eisa_probe (dev)
137         device_t        dev;
138 {
139         const char      *desc;
140         u_int32_t       iobase;
141         u_int32_t       irq;
142         u_int32_t       maddr;
143         u_int32_t       msize;
144
145         u_int32_t       eisa_id = eisa_get_id(dev);
146
147         desc = pdq_eisa_match(eisa_id);
148         if (!desc) {
149                 return (ENXIO);
150         }
151
152         device_set_desc(dev, desc);
153
154         iobase = eisa_get_slot(dev) * EISA_SLOT_SIZE;
155         pdq_eisa_subprobe((pdq_bus_t)SYS_RES_IOPORT, iobase, &maddr, &msize, &irq);
156
157         eisa_add_iospace(dev, iobase, 0x200, RESVADDR_NONE);
158         eisa_add_mspace(dev, maddr, msize, RESVADDR_NONE);
159         eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);
160         
161         return (0);
162 }
163
164 static void
165 pdq_eisa_ifintr(arg)
166         void *          arg;
167 {
168         pdq_softc_t *   sc;
169
170         sc = arg;
171
172         PDQ_LOCK(sc);
173         (void) pdq_interrupt(sc->sc_pdq);
174         PDQ_LOCK(sc);
175
176         return;
177 }
178
179 static int
180 pdq_eisa_attach (dev)
181         device_t        dev;
182 {
183         pdq_softc_t *   sc;
184         int             error;
185
186         sc = device_get_softc(dev);
187
188         sc->dev = dev;
189
190         sc->io_rid = 0;
191         sc->io_type = SYS_RES_IOPORT;
192         sc->io = bus_alloc_resource_any(dev, sc->io_type, &sc->io_rid,
193                                         RF_ACTIVE);
194         if (!sc->io) {
195                 device_printf(dev, "Unable to allocate I/O space resource.\n");
196                 error = ENXIO;
197                 goto bad;
198         }
199         sc->io_bsh = rman_get_bushandle(sc->io);
200         sc->io_bst = rman_get_bustag(sc->io);
201
202         sc->mem_rid = 0;
203         sc->mem_type = SYS_RES_MEMORY;
204         sc->mem = bus_alloc_resource_any(dev, sc->mem_type, &sc->mem_rid,
205                                          RF_ACTIVE);
206         if (!sc->mem) {
207                 device_printf(dev, "Unable to allocate memory resource.\n");
208                 error = ENXIO;
209                 goto bad;
210         }
211         sc->mem_bsh = rman_get_bushandle(sc->mem);
212         sc->mem_bst = rman_get_bustag(sc->mem);
213
214         sc->irq_rid = 0;
215         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
216                                          RF_SHAREABLE | RF_ACTIVE);
217         if (!sc->irq) {
218                 device_printf(dev, "Unable to allocate interrupt resource.\n");
219                 error = ENXIO;
220                 goto bad;
221         }
222
223         pdq_eisa_devinit(sc);
224         error = pdq_ifattach(sc, sc->sc_pdq->pdq_hwaddr.lanaddr_bytes,
225             PDQ_DEFEA);
226         if (error)
227                 goto bad;
228
229         error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
230                                NULL, pdq_eisa_ifintr, sc, &sc->irq_ih);
231         if (error) {
232                 device_printf(dev, "Failed to setup interrupt handler.\n");
233                 pdq_ifdetach(sc);
234                 return (error);
235         }
236
237         return (0);
238 bad:
239         pdq_free(dev);
240         return (error);
241 }
242
243 static int
244 pdq_eisa_detach (dev)
245         device_t        dev;
246 {
247         pdq_softc_t *   sc;
248
249         sc = device_get_softc(dev);
250         pdq_ifdetach(sc);
251
252         return (0);
253 }
254
255 static int
256 pdq_eisa_shutdown(dev)
257         device_t        dev;
258 {
259         pdq_softc_t *   sc;
260
261         sc = device_get_softc(dev);
262         PDQ_LOCK(sc);
263         pdq_hwreset(sc->sc_pdq);
264         PDQ_UNLOCK(sc);
265
266         return (0);
267 }
268
269 static device_method_t pdq_eisa_methods[] = {
270         DEVMETHOD(device_probe,         pdq_eisa_probe),
271         DEVMETHOD(device_attach,        pdq_eisa_attach),
272         DEVMETHOD(device_attach,        pdq_eisa_detach),
273         DEVMETHOD(device_shutdown,      pdq_eisa_shutdown),
274
275         { 0, 0 }
276 };
277
278 static driver_t pdq_eisa_driver = {
279         "fea",
280         pdq_eisa_methods,
281         sizeof(pdq_softc_t),
282 };
283
284 DRIVER_MODULE(fea, eisa, pdq_eisa_driver, pdq_devclass, 0, 0);
285 /* MODULE_DEPEND(fea, eisa, 1, 1, 1); */
286 MODULE_DEPEND(fea, fddi, 1, 1, 1);