1 /* $NetBSD: if_fw.c,v 1.20 2003/07/03 11:36:18 drochner Exp $ */
2
3 /* XXX ALTQ XXX */
4
5 /*
6 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Atsushi Onoe.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following 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 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: if_fw.c,v 1.20 2003/07/03 11:36:18 drochner Exp $");
43
44 #include "opt_inet.h"
45 #include "bpfilter.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/kernel.h>
52 #include <sys/mbuf.h>
53 #include <sys/device.h>
54
55 #include <net/if.h>
56 #include <net/if_dl.h>
57 #include <net/if_ieee1394.h>
58 #include <net/if_types.h>
59 #include <net/if_media.h>
60 #include <net/route.h>
61
62 #ifdef INET
63 #include <netinet/in.h>
64 #endif /* INET */
65
66 #ifdef INET6
67 #include <netinet/in.h>
68 #include <netinet6/in6_var.h>
69 #endif /* INET6 */
70
71 #if NBPFILTER > 0
72 #include <net/bpf.h>
73 #endif
74
75 #include <machine/bus.h>
76
77 #include <dev/ieee1394/ieee1394reg.h>
78 #include <dev/ieee1394/ieee1394var.h>
79
80 struct fw_softc {
81 struct ieee1394_softc sc_sc1394;
82 struct ieee1394com sc_ic;
83
84 int sc_flags;
85
86 int (*sc_enable)(struct fw_softc *);
87 void (*sc_disable)(struct fw_softc *);
88 };
89
90 #define FWF_ATTACHED 0x0001
91 #define FWF_ENABLED 0x0002
92
93 int fw_match(struct device *, struct cfdata *, void *);
94 void fw_attach(struct device *, struct device *, void *);
95 int fw_detach(struct device *, int);
96 int fw_activate(struct device *, enum devact);
97
98 void fw_input(struct device *, struct mbuf *);
99 void fw_txint(struct device *, struct mbuf *);
100 int fw_ioctl(struct ifnet *, u_long, caddr_t);
101 void fw_start(struct ifnet *);
102 int fw_init(struct ifnet *);
103 void fw_stop(struct ifnet *, int);
104
105 CFATTACH_DECL(fw, sizeof(struct fw_softc),
106 fw_match, fw_attach, fw_detach, fw_activate);
107
108 int
109 fw_match(struct device *parent, struct cfdata *match, void *aux)
110 {
111 char *name = aux;
112
113 if (strcmp(name, "fw") == 0)
114 return 1;
115 return 0;
116 }
117
118 void
119 fw_attach(struct device *parent, struct device *self, void *aux)
120 {
121 struct fw_softc *sc = (struct fw_softc *)self;
122 struct ieee1394_softc *psc = (struct ieee1394_softc *)parent;
123 struct ifnet *ifp = &sc->sc_ic.ic_if;
124 int i, s;
125
126 s = splnet();
127
128 memcpy(&sc->sc_ic.ic_hwaddr.iha_uid, psc->sc1394_guid,
129 IEEE1394_ADDR_LEN);
130 sc->sc_ic.ic_hwaddr.iha_speed = psc->sc1394_link_speed;
131 for (i = 0; i < 32; i++) {
132 if ((psc->sc1394_max_receive >> (i + 2)) == 0)
133 break;
134 }
135 sc->sc_ic.ic_hwaddr.iha_maxrec = i;
136 if (i < 8) {
137 printf("%s: maximum receive packet (%d) is too small\n",
138 sc->sc_sc1394.sc1394_dev.dv_xname, psc->sc1394_max_receive);
139 splx(s);
140 return;
141 }
142 sc->sc_ic.ic_hwaddr.iha_offset[0] = (FW_FIFO_HI >> 8) & 0xff;
143 sc->sc_ic.ic_hwaddr.iha_offset[1] = FW_FIFO_HI & 0xff;
144 sc->sc_ic.ic_hwaddr.iha_offset[2] = (FW_FIFO_LO >> 24) & 0xff;
145 sc->sc_ic.ic_hwaddr.iha_offset[3] = (FW_FIFO_LO >> 16) & 0xff;
146 sc->sc_ic.ic_hwaddr.iha_offset[4] = (FW_FIFO_LO >> 8) & 0xff;
147 sc->sc_ic.ic_hwaddr.iha_offset[5] = FW_FIFO_LO & 0xff;
148 strcpy(ifp->if_xname, sc->sc_sc1394.sc1394_dev.dv_xname);
149 ifp->if_softc = sc;
150 #if __NetBSD_Version__ >= 105080000
151 ifp->if_init = fw_init;
152 ifp->if_stop = fw_stop;
153 #endif
154 ifp->if_start = fw_start;
155 ifp->if_ioctl = fw_ioctl;
156 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
157 ifp->if_baudrate = IF_Mbps(100 << sc->sc_ic.ic_hwaddr.iha_speed);
158 ifp->if_addrlen = sizeof(struct ieee1394_hwaddr);
159 IFQ_SET_READY(&ifp->if_snd);
160
161 printf(":");
162 for (i = 0; i < sizeof(sc->sc_ic.ic_hwaddr); i++)
163 printf("%c%02x", (i == 0 ? ' ' : ':'),
164 ((u_int8_t *)&sc->sc_ic.ic_hwaddr)[i]);
165 printf("\n");
166 if_attach(ifp);
167 ieee1394_ifattach(ifp, &sc->sc_ic.ic_hwaddr);
168
169 sc->sc_flags |= FWF_ATTACHED;
170
171 splx(s);
172 }
173
174 int
175 fw_detach(struct device *self, int flags)
176 {
177 struct fw_softc *sc = (struct fw_softc *)self;
178 struct ifnet *ifp = &sc->sc_ic.ic_if;
179
180 /* Succeed if there is no work to do. */
181 if ((sc->sc_flags & FWF_ATTACHED) == 0)
182 return 0;
183
184 ieee1394_ifdetach(ifp);
185 if_detach(ifp);
186 if (sc->sc_flags & FWF_ENABLED) {
187 if (sc->sc_disable)
188 (*sc->sc_disable)(sc);
189 sc->sc_flags &= ~FWF_ENABLED;
190 }
191 return 0;
192 }
193
194 int
195 fw_activate(struct device *self, enum devact act)
196 {
197 struct fw_softc *sc = (struct fw_softc *)self;
198 int s, error = 0;
199
200 s = splnet();
201 switch (act) {
202 case DVACT_ACTIVATE:
203 error = EOPNOTSUPP;
204 break;
205
206 case DVACT_DEACTIVATE:
207 if_deactivate(&sc->sc_ic.ic_if);
208 break;
209 }
210 splx(s);
211
212 return error;
213 }
214
215 int
216 fw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
217 {
218 int s, error = 0;
219
220 s = splnet();
221
222 switch (cmd) {
223 default:
224 error = ieee1394_ioctl(ifp, cmd, data);
225 break;
226 }
227 splx(s);
228 return error;
229 }
230
231 void
232 fw_start(struct ifnet *ifp)
233 {
234 struct fw_softc *sc = (struct fw_softc *)ifp->if_softc;
235 struct ieee1394_softc *psc =
236 (struct ieee1394_softc *)sc->sc_sc1394.sc1394_dev.dv_parent;
237 struct mbuf *m0;
238 int error;
239
240 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
241 return;
242 for (;;) {
243 IFQ_DEQUEUE(&ifp->if_snd, m0);
244 if (m0 == NULL)
245 break;
246 error = (*psc->sc1394_ifoutput)
247 (sc->sc_sc1394.sc1394_dev.dv_parent, m0, fw_txint);
248 if (error)
249 break;
250 }
251 if (m0 != NULL)
252 ifp->if_flags |= IFF_OACTIVE;
253 }
254
255 void
256 fw_txint(struct device *self, struct mbuf *m0)
257 {
258 struct fw_softc *sc = (struct fw_softc *)self;
259 struct ifnet *ifp = &sc->sc_ic.ic_if;
260
261 ifp->if_opackets++;
262 m_freem(m0);
263 if (ifp->if_flags & IFF_OACTIVE) {
264 ifp->if_flags &= ~IFF_OACTIVE;
265 fw_start(ifp);
266 }
267 }
268
269 int
270 fw_init(struct ifnet *ifp)
271 {
272 struct fw_softc *sc = (struct fw_softc *)ifp->if_softc;
273 struct ieee1394_softc *psc =
274 (struct ieee1394_softc *)sc->sc_sc1394.sc1394_dev.dv_parent;
275
276 (*psc->sc1394_ifinreg)
277 (sc->sc_sc1394.sc1394_dev.dv_parent, FW_FIFO_HI, FW_FIFO_LO,
278 fw_input);
279 ifp->if_flags |= IFF_RUNNING;
280 return 0;
281 }
282
283 void
284 fw_stop(struct ifnet *ifp, int disable)
285 {
286 struct fw_softc *sc = (struct fw_softc *)ifp->if_softc;
287 struct ieee1394_softc *psc =
288 (struct ieee1394_softc *)sc->sc_sc1394.sc1394_dev.dv_parent;
289
290 (*psc->sc1394_ifinreg)
291 (sc->sc_sc1394.sc1394_dev.dv_parent, FW_FIFO_HI, FW_FIFO_LO,
292 NULL);
293 IFQ_PURGE(&ifp->if_snd);
294 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
295 }
296
297 void
298 fw_input(struct device *self, struct mbuf *m0)
299 {
300 struct fw_softc *sc = (struct fw_softc *)self;
301 struct ifnet *ifp = &sc->sc_ic.ic_if;
302
303 ifp->if_ipackets++;
304 m0->m_pkthdr.rcvif = ifp;
305 (*ifp->if_input)(ifp, m0);
306 }
Cache object: 89d5ae7ad17e2b3b6af375c1aa4d79dd
|