Commit | Line | Data |
---|---|---|
af5295ff KM |
1 | /* |
2 | * Copyright (c) 1992 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | * | |
10 | * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY | |
11 | * | |
5b7c2955 | 12 | * @(#)if_en.c 7.6 (Berkeley) %G% |
af5295ff KM |
13 | */ |
14 | ||
15 | #include "en.h" | |
16 | #include "rawether.h" | |
17 | #include "bpfilter.h" | |
18 | ||
19 | #if NEN > 0 | |
20 | ||
21 | /* | |
22 | * Interlan Ethernet Communications Controller interface | |
23 | */ | |
5b7c2955 KU |
24 | #include <sys/types.h> |
25 | #include <machine/fix_machine_type.h> | |
26 | #include <machine/pte.h> | |
27 | ||
28 | #include <sys/param.h> | |
29 | #include <sys/systm.h> | |
30 | #include <sys/mbuf.h> | |
31 | #include <sys/buf.h> | |
32 | #include <sys/protosw.h> | |
33 | #include <sys/socket.h> | |
34 | #include <sys/ioctl.h> | |
35 | #include <sys/errno.h> | |
36 | #include <sys/time.h> | |
37 | #include <sys/cdefs.h> | |
38 | ||
39 | #include <net/if.h> | |
40 | #include <net/netisr.h> | |
41 | #include <net/route.h> | |
af5295ff KM |
42 | |
43 | #ifdef INET | |
5b7c2955 KU |
44 | #include <netinet/in.h> |
45 | #include <netinet/in_systm.h> | |
46 | #include <netinet/in_var.h> | |
47 | #include <netinet/ip.h> | |
48 | #include <netinet/if_ether.h> | |
af5295ff KM |
49 | #endif |
50 | ||
5b7c2955 KU |
51 | #include <news3400/if/if_news.h> |
52 | #include <news3400/if/if_en.h> | |
af5295ff KM |
53 | |
54 | #ifdef CPU_SINGLE | |
5b7c2955 | 55 | #include <news3400/hbdev/hbvar.h> |
af5295ff KM |
56 | #define iop_device hb_device |
57 | #define iop_driver hb_driver | |
58 | #define ii_unit hi_unit | |
59 | #define ii_intr hi_intr | |
60 | #define ii_alive hi_alive | |
61 | #else | |
5b7c2955 | 62 | #include <news3400/iop/iopvar.h> |
af5295ff KM |
63 | #endif |
64 | ||
65 | int enprobe(), enattach(), enrint(), enxint(); | |
66 | struct mbuf *m_devget(); | |
67 | ||
68 | #ifdef CPU_SINGLE | |
69 | struct hb_device *eninfo[NEN]; | |
70 | struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo }; | |
71 | #else | |
72 | struct iop_device *eninfo[NEN]; | |
73 | struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo }; | |
74 | #endif | |
75 | ||
76 | #define ENUNIT(x) minor(x) | |
77 | ||
4fd05659 | 78 | int eninit(),enioctl(),enreset(),enwatch(),enstart(); |
af5295ff KM |
79 | int endebug = 0; |
80 | ||
81 | struct ether_addr { | |
82 | u_char addr[6]; | |
83 | }; | |
84 | ||
85 | extern struct ifnet loif; | |
86 | ||
87 | struct en_softc en_softc[NEN]; | |
af5295ff KM |
88 | |
89 | #if NBPFILTER > 0 | |
5b7c2955 | 90 | #include <net/bpf.h> |
af5295ff KM |
91 | #endif |
92 | ||
93 | enprobe(ii) | |
94 | struct iop_device *ii; | |
95 | { | |
96 | ||
97 | return (en_probe(ii)); | |
98 | } | |
99 | ||
100 | /* | |
101 | * Interface exists: make available by filling in network interface | |
102 | * record. System will initialize the interface when it is ready | |
103 | * to accept packets. A STATUS command is done to get the ethernet | |
104 | * address and other interesting data. | |
105 | */ | |
106 | enattach(ii) | |
107 | register struct iop_device *ii; | |
108 | { | |
109 | register struct en_softc *es = &en_softc[ii->ii_unit]; | |
110 | register struct ifnet *ifp = &es->es_if; | |
111 | extern char *ether_sprintf(); | |
112 | ||
113 | en_attach(ii->ii_unit); | |
af5295ff KM |
114 | printf("en%d: hardware address %s\n", |
115 | ii->ii_unit, ether_sprintf((u_char *)es->es_addr)); | |
116 | ifp->if_unit = ii->ii_unit; | |
117 | ifp->if_name = "en"; | |
118 | ifp->if_mtu = ETHERMTU; | |
119 | ifp->if_init = eninit; | |
120 | ifp->if_ioctl = enioctl; | |
121 | ifp->if_output = ether_output; | |
122 | #ifdef NOTDEF /* KU:XXX if_reset is obsolete */ | |
123 | ifp->if_reset = enreset; | |
124 | #endif | |
125 | ifp->if_start = enstart; | |
82cd4001 | 126 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; |
af5295ff | 127 | #if NBPFILTER > 0 |
82cd4001 | 128 | bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); |
af5295ff KM |
129 | #endif |
130 | if_attach(ifp); | |
131 | } | |
132 | ||
133 | /* | |
134 | * Reset of interface after IOP reset. | |
135 | */ | |
136 | enreset(unit) | |
137 | int unit; | |
138 | { | |
139 | register struct iop_device *ii; | |
140 | ||
141 | if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0) | |
142 | return; | |
143 | printf(" en%d", unit); | |
144 | en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); | |
145 | en_softc[unit].es_flags &= ~ENF_RUNNING; | |
146 | eninit(unit); | |
147 | } | |
148 | ||
149 | /* | |
150 | * Initialization of interface; clear recorded pending | |
151 | * operations, and reinitialize IOP usage. | |
152 | */ | |
153 | eninit(unit) | |
154 | int unit; | |
155 | { | |
156 | register struct en_softc *es = &en_softc[unit]; | |
157 | register struct ifnet *ifp = &es->es_if; | |
158 | int s; | |
159 | ||
160 | /* not yet, if address still unknown */ | |
161 | if (ifp->if_addrlist == (struct ifaddr *)0) | |
162 | return; | |
163 | if (es->es_flags & ENF_RUNNING) | |
164 | return; | |
165 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | |
166 | if (if_newsinit(&es->es_ifnews, | |
167 | sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) { | |
168 | printf("en%d: can't initialize\n", unit); | |
169 | es->es_if.if_flags &= ~IFF_UP; | |
170 | return; | |
171 | } | |
172 | ifp->if_watchdog = enwatch; | |
173 | es->es_interval = ENWATCHINTERVAL; | |
174 | ifp->if_timer = es->es_interval; | |
175 | s = splimp(); | |
176 | en_init(unit); | |
177 | splx(s); | |
178 | } | |
179 | es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS; | |
180 | es->es_flags |= ENF_RUNNING; | |
181 | } | |
182 | ||
183 | /* | |
184 | * Start output on interface. | |
185 | * Get another datagram to send off of the interface queue, | |
186 | * and map it to the interface before starting the output. | |
187 | */ | |
188 | enstart(ifp) | |
189 | register struct ifnet *ifp; | |
190 | { | |
191 | int unit = ifp->if_unit, len; | |
192 | register struct en_softc *es = &en_softc[unit]; | |
193 | register struct mbuf *m; | |
c1738274 | 194 | int s; |
af5295ff KM |
195 | |
196 | IF_DEQUEUE(&es->es_if.if_snd, m); | |
197 | if (m == 0) | |
198 | return(0); | |
199 | #ifdef CPU_SINGLE | |
200 | es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit); | |
201 | #endif | |
202 | len = if_wnewsput(&es->es_ifnews, m); | |
203 | /* | |
204 | * Ensure minimum packet length. | |
205 | * This makes the safe assumtion that there are no virtual holes | |
206 | * after the data. | |
207 | * For security, it might be wise to zero out the added bytes, | |
208 | * but we're mainly interested in speed at the moment. | |
209 | */ | |
210 | if (len - sizeof(struct ether_header) < ETHERMIN) | |
211 | len = ETHERMIN + sizeof(struct ether_header); | |
c1738274 | 212 | s = splclock(); /* KU:XXX should be gone */ |
af5295ff | 213 | en_start(unit, len); |
c1738274 KU |
214 | es->es_if.if_flags |= IFF_OACTIVE; |
215 | (void) splx(s); /* KU:XXX */ | |
af5295ff KM |
216 | #if NBPFILTER > 0 |
217 | /* | |
218 | * If bpf is listening on this interface, let it | |
219 | * see the packet before we commit it to the wire. | |
220 | */ | |
82cd4001 | 221 | if (es->es_bpf) { |
af5295ff | 222 | #ifdef CPU_SINGLE |
82cd4001 | 223 | bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len); |
af5295ff | 224 | #else |
82cd4001 | 225 | bpf_mtap(es->es_bpf, m); |
af5295ff KM |
226 | #endif |
227 | } | |
228 | #endif /* NBPFILTER > 0 */ | |
af5295ff KM |
229 | return(0); |
230 | } | |
231 | ||
232 | /* | |
233 | * Transmit done interrupt. | |
234 | */ | |
235 | _enxint(unit, error, collision) | |
236 | int unit; | |
237 | int error, collision; | |
238 | { | |
239 | register struct en_softc *es = &en_softc[unit]; | |
240 | ||
241 | #ifdef notyet /* KU:XXX */ | |
242 | intrcnt[INTR_ETHER0 + unit]++; | |
243 | #endif | |
244 | if ((es->es_if.if_flags & IFF_OACTIVE) == 0) { | |
245 | printf("en%d: stray xmit interrupt\n", unit); | |
af5295ff | 246 | return; |
af5295ff KM |
247 | } else { |
248 | es->es_if.if_flags &= ~IFF_OACTIVE; | |
249 | es->es_if.if_opackets++; | |
250 | } | |
82cd4001 KU |
251 | if (error) { |
252 | #ifdef DEBUG | |
253 | printf("_enxint: error (unit=%d)\n", unit); | |
254 | #endif | |
af5295ff | 255 | es->es_if.if_oerrors++; |
82cd4001 KU |
256 | } |
257 | if (collision) { | |
258 | #ifdef DEBUG | |
259 | printf("_enxint: collision (unit=%d)\n", unit); | |
260 | #endif | |
af5295ff | 261 | es->es_if.if_collisions++; |
82cd4001 | 262 | } |
af5295ff KM |
263 | enstart(&es->es_if); |
264 | } | |
265 | ||
266 | /* | |
267 | * Ethernet interface receiver interrupt. | |
268 | * If input error just drop packet. | |
269 | * Otherwise purge input buffered data path and examine | |
270 | * packet to determine type. If can't determine length | |
271 | * from type, then have to drop packet. Othewise decapsulate | |
272 | * packet based on type and pass to type specific higher-level | |
273 | * input routine. | |
274 | */ | |
275 | _enrint(unit, len) | |
276 | int unit; | |
277 | register int len; | |
278 | { | |
279 | register struct en_softc *es = &en_softc[unit]; | |
280 | register struct en_rheader *en; | |
281 | struct mbuf *m; | |
282 | int off, resid, s; | |
cd6e7c50 | 283 | int type; |
af5295ff KM |
284 | register struct ensw *esp; |
285 | extern struct mbuf *if_rnewsget(); | |
cd6e7c50 KU |
286 | #if defined(mips) && defined(CPU_SINGLE) |
287 | int bxcopy(); | |
288 | #endif | |
af5295ff KM |
289 | |
290 | #ifdef notyet /* KU:XXX */ | |
291 | intrcnt[INTR_ETHER0 + unit]++; | |
292 | #endif | |
293 | es->es_if.if_ipackets++; | |
294 | if ((es->es_flags & ENF_RUNNING) == 0) | |
295 | return; | |
296 | en = (struct en_rheader *)(es->es_ifnews.ifn_raddr); | |
297 | if (len < ETHERMIN || len > ETHERMTU) { | |
298 | es->es_if.if_ierrors++; | |
299 | return; | |
300 | } | |
301 | #if NBPFILTER > 0 | |
af5295ff KM |
302 | /* |
303 | * Check if there's a bpf filter listening on this interface. | |
304 | * If so, hand off the raw packet to enet. | |
305 | */ | |
82cd4001 KU |
306 | if (es->es_bpf) { |
307 | bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr, | |
af5295ff KM |
308 | len + sizeof(struct en_rheader)); |
309 | /* | |
310 | * Note that the interface cannot be in promiscuous mode if | |
311 | * there are no bpf listeners. And if we are in promiscuous | |
312 | * mode, we have to check if this packet is really ours. | |
313 | * | |
314 | * XXX This test does not support multicasts. | |
315 | */ | |
316 | if ((es->es_if.if_flags & IFF_PROMISC) | |
317 | && bcmp(en->enr_dhost, es->es_addr, | |
318 | sizeof(en->enr_dhost)) != 0 | |
319 | && bcmp(en->enr_dhost, etherbroadcastaddr, | |
320 | sizeof(en->enr_dhost)) != 0) | |
321 | return; | |
322 | } | |
af5295ff KM |
323 | #endif /* NBPFILTER > 0 */ |
324 | /* | |
325 | * Deal with trailer protocol: if type is trailer type | |
326 | * get true type from first 16-bit word past data. | |
327 | * Remember that type was trailer by setting off. | |
328 | */ | |
329 | en->enr_type = ntohs((u_short)en->enr_type); | |
330 | #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) | |
331 | if (en->enr_type >= ETHERTYPE_TRAIL && | |
332 | en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
333 | off = (en->enr_type - ETHERTYPE_TRAIL) * 512; | |
334 | if (off >= ETHERMTU) | |
335 | return; | |
336 | en->enr_type = ntohs(*endataaddr(en, off, u_short *)); | |
337 | resid = ntohs(*(endataaddr(en, off+2, u_short *))); | |
338 | if (off + resid > len) | |
339 | return; | |
340 | len = off + resid; | |
341 | } else | |
342 | off = 0; | |
343 | /* | |
344 | * Pull packet off interface. Off is nonzero if packet | |
345 | * has trailing header; m_devget will then force this header | |
346 | * information to be at the front, but we still have to drop | |
347 | * the type and length which are at the front of any trailer data. | |
348 | * KU:XXX really? | |
349 | */ | |
350 | type = en->enr_type; | |
cd6e7c50 KU |
351 | #if defined(mips) && defined(CPU_SINGLE) |
352 | m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy); | |
353 | #else | |
af5295ff | 354 | m = m_devget((char *)(en + 1), len, off, &es->es_if, 0); |
cd6e7c50 | 355 | #endif |
af5295ff KM |
356 | if (m == 0) |
357 | return; | |
358 | ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m); | |
359 | } | |
360 | ||
361 | /* | |
362 | * Watchdog routine, request statistics from board. | |
363 | */ | |
364 | enwatch(unit) | |
365 | int unit; | |
366 | { | |
367 | register struct en_softc *es = &en_softc[unit]; | |
368 | register struct ifnet *ifp = &es->es_if; | |
369 | ||
370 | ifp->if_timer = es->es_interval; | |
371 | } | |
372 | ||
373 | /* | |
374 | * Process an ioctl request. | |
375 | */ | |
376 | enioctl(ifp, cmd, data) | |
377 | register struct ifnet *ifp; | |
378 | int cmd; | |
379 | caddr_t data; | |
380 | { | |
381 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
382 | register struct en_softc *es = &en_softc[ifp->if_unit]; | |
383 | register struct ensw *esp; | |
384 | register int family; | |
385 | int s = splimp(), error = 0; | |
386 | ||
387 | switch (cmd) { | |
388 | ||
389 | case SIOCSIFADDR: | |
390 | ifp->if_flags |= IFF_UP; | |
391 | eninit(ifp->if_unit); | |
392 | switch (ifa->ifa_addr->sa_family) { | |
393 | #ifdef INET | |
394 | case AF_INET: | |
395 | ((struct arpcom *)ifp)->ac_ipaddr = | |
396 | IA_SIN(ifa)->sin_addr; | |
397 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
398 | break; | |
399 | #endif | |
400 | } | |
401 | break; | |
402 | ||
403 | case SIOCSIFFLAGS: | |
404 | if ((ifp->if_flags & IFF_UP) == 0 && | |
405 | es->es_flags & ENF_RUNNING) { | |
406 | es->es_flags &= ~ENF_RUNNING; | |
407 | } else if (ifp->if_flags & IFF_UP && | |
408 | (es->es_flags & ENF_RUNNING) == 0) | |
409 | eninit(ifp->if_unit); | |
410 | #if NBPFILTER > 0 | |
411 | else if (ifp->if_flags & IFF_UP && | |
412 | (ifp->if_flags & IFF_RUNNING) == 0) { | |
413 | en_prom_mode(ifp->if_unit, | |
414 | ifp->if_flags & IFF_PROMISC); | |
415 | ifp->if_flags |= IFF_RUNNING; | |
416 | } | |
417 | #endif | |
418 | break; | |
419 | ||
420 | default: | |
421 | error = EINVAL; | |
422 | } | |
423 | splx(s); | |
424 | return (error); | |
425 | } | |
426 | ||
427 | /* | |
428 | * set ethernet address for unit | |
429 | */ | |
430 | ensetaddr(physaddr, unit) | |
431 | u_char *physaddr; | |
432 | int unit; | |
433 | { | |
434 | register struct en_softc *es = &en_softc[unit]; | |
435 | ||
436 | if (!(es->es_flags & ENF_RUNNING)) | |
437 | return; | |
438 | ||
439 | bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr); | |
440 | es->es_flags &= ~ENF_RUNNING; | |
441 | es->es_flags |= ENF_SETADDR; | |
442 | eninit(unit); | |
443 | } | |
444 | ||
445 | /* | |
446 | * Machine dependent functions | |
447 | * | |
448 | * en_probe(); | |
449 | * en_attach(); | |
450 | * en_init(); | |
451 | * enxint(); | |
452 | * enrint(); | |
453 | * en_prom_mode() | |
454 | */ | |
455 | #ifdef CPU_SINGLE | |
5b7c2955 | 456 | #include <machine/cpu.h> |
af5295ff KM |
457 | |
458 | en_probe(hi) | |
459 | struct hb_device *hi; | |
460 | { | |
461 | ||
462 | return (lance_probe(hi->hi_unit)); | |
463 | } | |
464 | ||
465 | en_attach(unit) | |
466 | int unit; | |
467 | { | |
468 | register struct en_softc *es = &en_softc[unit]; | |
469 | register u_char *p; | |
470 | register int i; | |
471 | extern lance_intr(); | |
472 | ||
473 | #if !defined(news700) && !defined(mips) | |
474 | register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr); | |
475 | #endif | |
476 | if (lance_open(unit) < 0) | |
477 | printf("lance initialize error\n"); | |
478 | lance_get_addr(unit, (caddr_t)es->es_addr); | |
479 | } | |
480 | ||
481 | en_init(unit) | |
482 | int unit; | |
483 | { | |
484 | ||
485 | } | |
486 | ||
487 | en_start(unit, len) | |
488 | int unit; | |
489 | int len; | |
490 | { | |
491 | ||
492 | lance_transmit(unit, len); | |
493 | } | |
494 | ||
495 | enxint(unit) | |
496 | register int unit; | |
497 | { | |
498 | ||
499 | _enxint(unit, lance_xmit_error(unit), lance_collision(unit)); | |
500 | } | |
501 | ||
502 | enrint(unit) | |
503 | register int unit; | |
504 | { | |
505 | register struct en_softc *es = &en_softc[unit]; | |
506 | caddr_t get_recv_buffer(); | |
507 | ||
508 | while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) { | |
509 | _enrint(unit, | |
510 | get_recv_length(unit) - sizeof(struct en_rheader)); | |
511 | free_recv_buffer(unit); | |
512 | } | |
513 | } | |
514 | ||
515 | en_prom_mode(unit, mode) | |
516 | int unit, mode; | |
517 | { | |
518 | ||
519 | lance_prom_mode(unit, mode); | |
520 | } | |
521 | #endif /* CPU_SINGLE */ | |
522 | ||
523 | #ifdef IPC_MRX | |
524 | #include "../ipc/newsipc.h" | |
525 | #include "../mrx/h/lancereg.h" | |
526 | #include "../mrx/h/lance.h" | |
527 | ||
528 | int port_enxmit[NEN]; | |
529 | int port_enrecv[NEN]; | |
530 | int port_enctrl[NEN]; | |
531 | int port_enxmit_iop[NEN]; | |
532 | int port_enrecv_iop[NEN]; | |
533 | int port_enctrl_iop[NEN]; | |
534 | ||
535 | en_probe(ii) | |
536 | register struct iop_device *ii; | |
537 | { | |
538 | int unit = ii->ii_unit; | |
539 | int lance_func, *reply; | |
540 | char name[32]; | |
541 | extern char *make_name(); | |
542 | ||
543 | if (port_enrecv[unit] == 0) { | |
544 | ||
545 | #define PT_CREATE(buf, name, unit, func) \ | |
546 | port_create(make_name(buf, name, unit), func, unit) | |
547 | #define OB_QUERY(buf, name, unit) \ | |
548 | object_query(make_name(buf, name, unit)) | |
549 | ||
550 | make_name(name, "@enrecvX", unit); | |
551 | port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint); | |
552 | port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint); | |
553 | port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL); | |
554 | /* use NULL action port */ | |
555 | port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit); | |
556 | port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit); | |
557 | port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit); | |
558 | } | |
559 | if (port_enctrl_iop[unit] < 0) | |
560 | goto bad; | |
561 | lance_func = EN_START; | |
562 | msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, | |
563 | sizeof(lance_func), 0); | |
564 | msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); | |
565 | if (*reply < 0) | |
566 | goto bad; | |
567 | lance_func = EN_STOP; | |
568 | msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, | |
569 | sizeof(lance_func), 0); | |
570 | msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); | |
571 | return (1); | |
572 | bad: | |
573 | return (0); | |
574 | } | |
575 | ||
576 | en_attach(unit) | |
577 | int unit; | |
578 | { | |
579 | register struct en_softc *es = &en_softc[unit]; | |
580 | int lance_func; | |
581 | struct ether_addr *ether_addr; | |
582 | ||
583 | lance_func = EN_GETADDR; | |
584 | msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, | |
585 | sizeof(lance_func), 0); | |
586 | msg_recv(port_enctrl[unit], NULL, ðer_addr, NULL, 0); | |
587 | bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr)); | |
588 | msg_free(port_enctrl[unit]); | |
589 | } | |
590 | ||
591 | en_init(unit) | |
592 | int unit; | |
593 | { | |
594 | register struct en_softc *es = &en_softc[unit]; | |
595 | register int port; | |
596 | struct lance_ctrl_req req; | |
597 | int *reply; | |
598 | ||
599 | req.lance_func = EN_SETXMITBUF; | |
600 | mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr, | |
601 | ETHERMTU + sizeof(struct en_rheader)); | |
602 | msg_send(port_enctrl_iop[unit], port_enctrl[unit], | |
603 | &req, sizeof(req), 0); | |
604 | msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); | |
605 | ||
606 | req.lance_func = EN_START; | |
607 | msg_send(port_enctrl_iop[unit], port_enctrl[unit], | |
608 | &req, sizeof(req), 0); | |
609 | msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); | |
610 | msg_free(port_enctrl[unit]); | |
611 | ||
612 | msg_send(port_enrecv_iop[unit], port_enrecv[unit], | |
613 | es->es_ifnews.ifn_raddr, | |
614 | ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); | |
615 | } | |
616 | ||
617 | en_start(unit, len) | |
618 | int unit; | |
619 | int len; | |
620 | { | |
621 | ||
622 | msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0); | |
623 | } | |
624 | ||
625 | enxint(unit) | |
626 | register int unit; | |
627 | { | |
628 | int *len; | |
629 | struct en_softc *es = &en_softc[unit]; | |
630 | ||
631 | if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) { | |
632 | printf("stray enxint\n"); | |
633 | return; | |
634 | } | |
635 | if (es->es_ifnews.ifn_mbuf) | |
636 | m_freem(es->es_ifnews.ifn_mbuf); | |
637 | _enxint(unit, *len < 0, *len & 0x10000); | |
638 | } | |
639 | ||
640 | enrint(unit) | |
641 | int unit; | |
642 | { | |
643 | int len; | |
644 | int *reply; | |
645 | ||
646 | if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) { | |
647 | printf("stray enrint\n"); | |
648 | return; | |
649 | } | |
650 | len = *reply - sizeof(struct en_rheader); | |
651 | msg_free(port_enrecv[unit]); | |
652 | #ifdef mips | |
653 | /* | |
654 | * cache flush address must aligned long word boundary. | |
655 | * so, add 3 for sanity. | |
656 | */ | |
657 | clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03, | |
658 | len + sizeof (struct en_rheader) + 3); | |
659 | #endif | |
660 | _enrint(unit, len); | |
661 | msg_send(port_enrecv_iop[unit], port_enrecv[unit], | |
662 | en_softc[unit].es_ifnews.ifn_raddr, | |
663 | ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); | |
664 | } | |
665 | ||
666 | en_prom_mode(unit, mode) | |
667 | int unit, mode; | |
668 | { | |
669 | static int port; | |
670 | struct lance_ctrl_req req; | |
671 | extern int port_enctrl_iop[]; | |
672 | ||
673 | req.lance_func = EN_PROMMODE; | |
674 | req.lance_mode = mode; | |
675 | msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0); | |
676 | } | |
677 | #endif /* IPC_MRX */ | |
678 | #endif /* NEN > 0 */ |