153897Smckusick /* 253897Smckusick * Copyright (c) 1992 The Regents of the University of California. 353897Smckusick * All rights reserved. 453897Smckusick * 553897Smckusick * This code is derived from software contributed to Berkeley by 653897Smckusick * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 753897Smckusick * 853897Smckusick * %sccs.include.redist.c% 953897Smckusick * 1053897Smckusick * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY 1153897Smckusick * 12*54522Sutashiro * @(#)if_en.c 7.4 (Berkeley) 06/27/92 1353897Smckusick */ 1453897Smckusick 1553897Smckusick #include "en.h" 1653897Smckusick #include "rawether.h" 1753897Smckusick #include "bpfilter.h" 1853897Smckusick 1953897Smckusick #if NEN > 0 2053897Smckusick 2153897Smckusick /* 2253897Smckusick * Interlan Ethernet Communications Controller interface 2353897Smckusick */ 2453897Smckusick #include "types.h" 2553897Smckusick #include "../include/fix_machine_type.h" 2653897Smckusick #include "../include/pte.h" 2753897Smckusick 2853897Smckusick #include "param.h" 2953897Smckusick #include "systm.h" 3053897Smckusick #include "mbuf.h" 3153897Smckusick #include "buf.h" 3253897Smckusick #include "protosw.h" 3353897Smckusick #include "socket.h" 3453897Smckusick #include "ioctl.h" 3553897Smckusick #include "errno.h" 3653897Smckusick #include "time.h" 3753897Smckusick #include "cdefs.h" 3853897Smckusick 3953897Smckusick #include "net/if.h" 4053897Smckusick #include "net/netisr.h" 4153897Smckusick #include "net/route.h" 4253897Smckusick 4353897Smckusick #ifdef INET 4453897Smckusick #include "netinet/in.h" 4553897Smckusick #include "netinet/in_systm.h" 4653897Smckusick #include "netinet/in_var.h" 4753897Smckusick #include "netinet/ip.h" 4853897Smckusick #include "netinet/if_ether.h" 4953897Smckusick #endif 5053897Smckusick 5153897Smckusick #include "../if/if_news.h" 5253897Smckusick #include "../if/if_en.h" 5353897Smckusick 5453897Smckusick #ifdef CPU_SINGLE 5553897Smckusick #include "../hbdev/hbvar.h" 5653897Smckusick #define iop_device hb_device 5753897Smckusick #define iop_driver hb_driver 5853897Smckusick #define ii_unit hi_unit 5953897Smckusick #define ii_intr hi_intr 6053897Smckusick #define ii_alive hi_alive 6153897Smckusick #else 6253897Smckusick #include "../iop/iopvar.h" 6353897Smckusick #endif 6453897Smckusick 6553897Smckusick int enprobe(), enattach(), enrint(), enxint(); 6653897Smckusick struct mbuf *m_devget(); 6753897Smckusick 6853897Smckusick #ifdef CPU_SINGLE 6953897Smckusick struct hb_device *eninfo[NEN]; 7053897Smckusick struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo }; 7153897Smckusick #else 7253897Smckusick struct iop_device *eninfo[NEN]; 7353897Smckusick struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo }; 7453897Smckusick #endif 7553897Smckusick 7653897Smckusick #define ENUNIT(x) minor(x) 7753897Smckusick 7854473Sutashiro int eninit(),enioctl(),enreset(),enwatch(),enstart(); 7953897Smckusick int endebug = 0; 8053897Smckusick 8153897Smckusick struct ether_addr { 8253897Smckusick u_char addr[6]; 8353897Smckusick }; 8453897Smckusick 8553897Smckusick extern struct ifnet loif; 8653897Smckusick 8753897Smckusick struct en_softc en_softc[NEN]; 8853897Smckusick 8953897Smckusick #if NBPFILTER > 0 9053897Smckusick #include "../net/bpf.h" 9153897Smckusick #endif 9253897Smckusick 9353897Smckusick enprobe(ii) 9453897Smckusick struct iop_device *ii; 9553897Smckusick { 9653897Smckusick 9753897Smckusick return (en_probe(ii)); 9853897Smckusick } 9953897Smckusick 10053897Smckusick /* 10153897Smckusick * Interface exists: make available by filling in network interface 10253897Smckusick * record. System will initialize the interface when it is ready 10353897Smckusick * to accept packets. A STATUS command is done to get the ethernet 10453897Smckusick * address and other interesting data. 10553897Smckusick */ 10653897Smckusick enattach(ii) 10753897Smckusick register struct iop_device *ii; 10853897Smckusick { 10953897Smckusick register struct en_softc *es = &en_softc[ii->ii_unit]; 11053897Smckusick register struct ifnet *ifp = &es->es_if; 11153897Smckusick extern char *ether_sprintf(); 11253897Smckusick 11353897Smckusick en_attach(ii->ii_unit); 11453897Smckusick printf("en%d: hardware address %s\n", 11553897Smckusick ii->ii_unit, ether_sprintf((u_char *)es->es_addr)); 11653897Smckusick ifp->if_unit = ii->ii_unit; 11753897Smckusick ifp->if_name = "en"; 11853897Smckusick ifp->if_mtu = ETHERMTU; 11953897Smckusick ifp->if_init = eninit; 12053897Smckusick ifp->if_ioctl = enioctl; 12153897Smckusick ifp->if_output = ether_output; 12253897Smckusick #ifdef NOTDEF /* KU:XXX if_reset is obsolete */ 12353897Smckusick ifp->if_reset = enreset; 12453897Smckusick #endif 12553897Smckusick ifp->if_start = enstart; 12654517Sutashiro ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 12753897Smckusick #if NBPFILTER > 0 12854517Sutashiro bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 12953897Smckusick #endif 13053897Smckusick if_attach(ifp); 13153897Smckusick } 13253897Smckusick 13353897Smckusick /* 13453897Smckusick * Reset of interface after IOP reset. 13553897Smckusick */ 13653897Smckusick enreset(unit) 13753897Smckusick int unit; 13853897Smckusick { 13953897Smckusick register struct iop_device *ii; 14053897Smckusick 14153897Smckusick if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0) 14253897Smckusick return; 14353897Smckusick printf(" en%d", unit); 14453897Smckusick en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 14553897Smckusick en_softc[unit].es_flags &= ~ENF_RUNNING; 14653897Smckusick eninit(unit); 14753897Smckusick } 14853897Smckusick 14953897Smckusick /* 15053897Smckusick * Initialization of interface; clear recorded pending 15153897Smckusick * operations, and reinitialize IOP usage. 15253897Smckusick */ 15353897Smckusick eninit(unit) 15453897Smckusick int unit; 15553897Smckusick { 15653897Smckusick register struct en_softc *es = &en_softc[unit]; 15753897Smckusick register struct ifnet *ifp = &es->es_if; 15853897Smckusick int s; 15953897Smckusick 16053897Smckusick /* not yet, if address still unknown */ 16153897Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 16253897Smckusick return; 16353897Smckusick if (es->es_flags & ENF_RUNNING) 16453897Smckusick return; 16553897Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 16653897Smckusick if (if_newsinit(&es->es_ifnews, 16753897Smckusick sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) { 16853897Smckusick printf("en%d: can't initialize\n", unit); 16953897Smckusick es->es_if.if_flags &= ~IFF_UP; 17053897Smckusick return; 17153897Smckusick } 17253897Smckusick ifp->if_watchdog = enwatch; 17353897Smckusick es->es_interval = ENWATCHINTERVAL; 17453897Smckusick ifp->if_timer = es->es_interval; 17553897Smckusick s = splimp(); 17653897Smckusick en_init(unit); 17753897Smckusick splx(s); 17853897Smckusick } 17953897Smckusick es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS; 18053897Smckusick es->es_flags |= ENF_RUNNING; 18153897Smckusick } 18253897Smckusick 18353897Smckusick /* 18453897Smckusick * Start output on interface. 18553897Smckusick * Get another datagram to send off of the interface queue, 18653897Smckusick * and map it to the interface before starting the output. 18753897Smckusick */ 18853897Smckusick enstart(ifp) 18953897Smckusick register struct ifnet *ifp; 19053897Smckusick { 19153897Smckusick int unit = ifp->if_unit, len; 19253897Smckusick register struct en_softc *es = &en_softc[unit]; 19353897Smckusick register struct mbuf *m; 19453897Smckusick 19553897Smckusick IF_DEQUEUE(&es->es_if.if_snd, m); 19653897Smckusick if (m == 0) 19753897Smckusick return(0); 19853897Smckusick #ifdef CPU_SINGLE 19953897Smckusick es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit); 20053897Smckusick #endif 20153897Smckusick len = if_wnewsput(&es->es_ifnews, m); 20253897Smckusick /* 20353897Smckusick * Ensure minimum packet length. 20453897Smckusick * This makes the safe assumtion that there are no virtual holes 20553897Smckusick * after the data. 20653897Smckusick * For security, it might be wise to zero out the added bytes, 20753897Smckusick * but we're mainly interested in speed at the moment. 20853897Smckusick */ 20953897Smckusick if (len - sizeof(struct ether_header) < ETHERMIN) 21053897Smckusick len = ETHERMIN + sizeof(struct ether_header); 21153897Smckusick en_start(unit, len); 21253897Smckusick #if NBPFILTER > 0 21353897Smckusick /* 21453897Smckusick * If bpf is listening on this interface, let it 21553897Smckusick * see the packet before we commit it to the wire. 21653897Smckusick */ 21754517Sutashiro if (es->es_bpf) { 21853897Smckusick #ifdef CPU_SINGLE 21954517Sutashiro bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len); 22053897Smckusick #else 22154517Sutashiro bpf_mtap(es->es_bpf, m); 22253897Smckusick #endif 22353897Smckusick } 22453897Smckusick #endif /* NBPFILTER > 0 */ 22553897Smckusick es->es_if.if_flags |= IFF_OACTIVE; 22653897Smckusick return(0); 22753897Smckusick } 22853897Smckusick 22953897Smckusick /* 23053897Smckusick * Transmit done interrupt. 23153897Smckusick */ 23253897Smckusick _enxint(unit, error, collision) 23353897Smckusick int unit; 23453897Smckusick int error, collision; 23553897Smckusick { 23653897Smckusick register struct en_softc *es = &en_softc[unit]; 23753897Smckusick 23853897Smckusick #ifdef notyet /* KU:XXX */ 23953897Smckusick intrcnt[INTR_ETHER0 + unit]++; 24053897Smckusick #endif 24153897Smckusick if ((es->es_if.if_flags & IFF_OACTIVE) == 0) { 24253897Smckusick printf("en%d: stray xmit interrupt\n", unit); 24353897Smckusick return; 24453897Smckusick } else { 24553897Smckusick es->es_if.if_flags &= ~IFF_OACTIVE; 24653897Smckusick es->es_if.if_opackets++; 24753897Smckusick } 24854517Sutashiro if (error) { 24954517Sutashiro #ifdef DEBUG 25054517Sutashiro printf("_enxint: error (unit=%d)\n", unit); 25154517Sutashiro #endif 25253897Smckusick es->es_if.if_oerrors++; 25354517Sutashiro } 25454517Sutashiro if (collision) { 25554517Sutashiro #ifdef DEBUG 25654517Sutashiro printf("_enxint: collision (unit=%d)\n", unit); 25754517Sutashiro #endif 25853897Smckusick es->es_if.if_collisions++; 25954517Sutashiro } 26053897Smckusick enstart(&es->es_if); 26153897Smckusick } 26253897Smckusick 26353897Smckusick /* 26453897Smckusick * Ethernet interface receiver interrupt. 26553897Smckusick * If input error just drop packet. 26653897Smckusick * Otherwise purge input buffered data path and examine 26753897Smckusick * packet to determine type. If can't determine length 26853897Smckusick * from type, then have to drop packet. Othewise decapsulate 26953897Smckusick * packet based on type and pass to type specific higher-level 27053897Smckusick * input routine. 27153897Smckusick */ 27253897Smckusick _enrint(unit, len) 27353897Smckusick int unit; 27453897Smckusick register int len; 27553897Smckusick { 27653897Smckusick register struct en_softc *es = &en_softc[unit]; 27753897Smckusick register struct en_rheader *en; 27853897Smckusick struct mbuf *m; 27953897Smckusick int off, resid, s; 280*54522Sutashiro int type; 28153897Smckusick register struct ensw *esp; 28253897Smckusick extern struct mbuf *if_rnewsget(); 283*54522Sutashiro #if defined(mips) && defined(CPU_SINGLE) 284*54522Sutashiro int bxcopy(); 285*54522Sutashiro #endif 28653897Smckusick 28753897Smckusick #ifdef notyet /* KU:XXX */ 28853897Smckusick intrcnt[INTR_ETHER0 + unit]++; 28953897Smckusick #endif 29053897Smckusick es->es_if.if_ipackets++; 29153897Smckusick if ((es->es_flags & ENF_RUNNING) == 0) 29253897Smckusick return; 29353897Smckusick en = (struct en_rheader *)(es->es_ifnews.ifn_raddr); 29453897Smckusick if (len < ETHERMIN || len > ETHERMTU) { 29553897Smckusick es->es_if.if_ierrors++; 29653897Smckusick return; 29753897Smckusick } 29853897Smckusick #if NBPFILTER > 0 29953897Smckusick /* 30053897Smckusick * Check if there's a bpf filter listening on this interface. 30153897Smckusick * If so, hand off the raw packet to enet. 30253897Smckusick */ 30354517Sutashiro if (es->es_bpf) { 30454517Sutashiro bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr, 30553897Smckusick len + sizeof(struct en_rheader)); 30653897Smckusick /* 30753897Smckusick * Note that the interface cannot be in promiscuous mode if 30853897Smckusick * there are no bpf listeners. And if we are in promiscuous 30953897Smckusick * mode, we have to check if this packet is really ours. 31053897Smckusick * 31153897Smckusick * XXX This test does not support multicasts. 31253897Smckusick */ 31353897Smckusick if ((es->es_if.if_flags & IFF_PROMISC) 31453897Smckusick && bcmp(en->enr_dhost, es->es_addr, 31553897Smckusick sizeof(en->enr_dhost)) != 0 31653897Smckusick && bcmp(en->enr_dhost, etherbroadcastaddr, 31753897Smckusick sizeof(en->enr_dhost)) != 0) 31853897Smckusick return; 31953897Smckusick } 32053897Smckusick #endif /* NBPFILTER > 0 */ 32153897Smckusick /* 32253897Smckusick * Deal with trailer protocol: if type is trailer type 32353897Smckusick * get true type from first 16-bit word past data. 32453897Smckusick * Remember that type was trailer by setting off. 32553897Smckusick */ 32653897Smckusick en->enr_type = ntohs((u_short)en->enr_type); 32753897Smckusick #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 32853897Smckusick if (en->enr_type >= ETHERTYPE_TRAIL && 32953897Smckusick en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 33053897Smckusick off = (en->enr_type - ETHERTYPE_TRAIL) * 512; 33153897Smckusick if (off >= ETHERMTU) 33253897Smckusick return; 33353897Smckusick en->enr_type = ntohs(*endataaddr(en, off, u_short *)); 33453897Smckusick resid = ntohs(*(endataaddr(en, off+2, u_short *))); 33553897Smckusick if (off + resid > len) 33653897Smckusick return; 33753897Smckusick len = off + resid; 33853897Smckusick } else 33953897Smckusick off = 0; 34053897Smckusick /* 34153897Smckusick * Pull packet off interface. Off is nonzero if packet 34253897Smckusick * has trailing header; m_devget will then force this header 34353897Smckusick * information to be at the front, but we still have to drop 34453897Smckusick * the type and length which are at the front of any trailer data. 34553897Smckusick * KU:XXX really? 34653897Smckusick */ 34753897Smckusick type = en->enr_type; 348*54522Sutashiro #if defined(mips) && defined(CPU_SINGLE) 349*54522Sutashiro m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy); 350*54522Sutashiro #else 35153897Smckusick m = m_devget((char *)(en + 1), len, off, &es->es_if, 0); 352*54522Sutashiro #endif 35353897Smckusick if (m == 0) 35453897Smckusick return; 35553897Smckusick ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m); 35653897Smckusick } 35753897Smckusick 35853897Smckusick /* 35953897Smckusick * Watchdog routine, request statistics from board. 36053897Smckusick */ 36153897Smckusick enwatch(unit) 36253897Smckusick int unit; 36353897Smckusick { 36453897Smckusick register struct en_softc *es = &en_softc[unit]; 36553897Smckusick register struct ifnet *ifp = &es->es_if; 36653897Smckusick 36753897Smckusick ifp->if_timer = es->es_interval; 36853897Smckusick } 36953897Smckusick 37053897Smckusick /* 37153897Smckusick * Process an ioctl request. 37253897Smckusick */ 37353897Smckusick enioctl(ifp, cmd, data) 37453897Smckusick register struct ifnet *ifp; 37553897Smckusick int cmd; 37653897Smckusick caddr_t data; 37753897Smckusick { 37853897Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 37953897Smckusick register struct en_softc *es = &en_softc[ifp->if_unit]; 38053897Smckusick register struct ensw *esp; 38153897Smckusick register int family; 38253897Smckusick int s = splimp(), error = 0; 38353897Smckusick 38453897Smckusick switch (cmd) { 38553897Smckusick 38653897Smckusick case SIOCSIFADDR: 38753897Smckusick ifp->if_flags |= IFF_UP; 38853897Smckusick eninit(ifp->if_unit); 38953897Smckusick switch (ifa->ifa_addr->sa_family) { 39053897Smckusick #ifdef INET 39153897Smckusick case AF_INET: 39253897Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 39353897Smckusick IA_SIN(ifa)->sin_addr; 39453897Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 39553897Smckusick break; 39653897Smckusick #endif 39753897Smckusick } 39853897Smckusick break; 39953897Smckusick 40053897Smckusick case SIOCSIFFLAGS: 40153897Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 40253897Smckusick es->es_flags & ENF_RUNNING) { 40353897Smckusick es->es_flags &= ~ENF_RUNNING; 40453897Smckusick } else if (ifp->if_flags & IFF_UP && 40553897Smckusick (es->es_flags & ENF_RUNNING) == 0) 40653897Smckusick eninit(ifp->if_unit); 40753897Smckusick #if NBPFILTER > 0 40853897Smckusick else if (ifp->if_flags & IFF_UP && 40953897Smckusick (ifp->if_flags & IFF_RUNNING) == 0) { 41053897Smckusick en_prom_mode(ifp->if_unit, 41153897Smckusick ifp->if_flags & IFF_PROMISC); 41253897Smckusick ifp->if_flags |= IFF_RUNNING; 41353897Smckusick } 41453897Smckusick #endif 41553897Smckusick break; 41653897Smckusick 41753897Smckusick default: 41853897Smckusick error = EINVAL; 41953897Smckusick } 42053897Smckusick splx(s); 42153897Smckusick return (error); 42253897Smckusick } 42353897Smckusick 42453897Smckusick /* 42553897Smckusick * set ethernet address for unit 42653897Smckusick */ 42753897Smckusick ensetaddr(physaddr, unit) 42853897Smckusick u_char *physaddr; 42953897Smckusick int unit; 43053897Smckusick { 43153897Smckusick register struct en_softc *es = &en_softc[unit]; 43253897Smckusick 43353897Smckusick if (!(es->es_flags & ENF_RUNNING)) 43453897Smckusick return; 43553897Smckusick 43653897Smckusick bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr); 43753897Smckusick es->es_flags &= ~ENF_RUNNING; 43853897Smckusick es->es_flags |= ENF_SETADDR; 43953897Smckusick eninit(unit); 44053897Smckusick } 44153897Smckusick 44253897Smckusick /* 44353897Smckusick * Machine dependent functions 44453897Smckusick * 44553897Smckusick * en_probe(); 44653897Smckusick * en_attach(); 44753897Smckusick * en_init(); 44853897Smckusick * enxint(); 44953897Smckusick * enrint(); 45053897Smckusick * en_prom_mode() 45153897Smckusick */ 45253897Smckusick #ifdef CPU_SINGLE 45353897Smckusick #include "../include/cpu.h" 45453897Smckusick 45553897Smckusick en_probe(hi) 45653897Smckusick struct hb_device *hi; 45753897Smckusick { 45853897Smckusick 45953897Smckusick return (lance_probe(hi->hi_unit)); 46053897Smckusick } 46153897Smckusick 46253897Smckusick en_attach(unit) 46353897Smckusick int unit; 46453897Smckusick { 46553897Smckusick register struct en_softc *es = &en_softc[unit]; 46653897Smckusick register u_char *p; 46753897Smckusick register int i; 46853897Smckusick extern lance_intr(); 46953897Smckusick 47053897Smckusick #if !defined(news700) && !defined(mips) 47153897Smckusick register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr); 47253897Smckusick #endif 47353897Smckusick if (lance_open(unit) < 0) 47453897Smckusick printf("lance initialize error\n"); 47553897Smckusick lance_get_addr(unit, (caddr_t)es->es_addr); 47653897Smckusick } 47753897Smckusick 47853897Smckusick en_init(unit) 47953897Smckusick int unit; 48053897Smckusick { 48153897Smckusick 48253897Smckusick } 48353897Smckusick 48453897Smckusick en_start(unit, len) 48553897Smckusick int unit; 48653897Smckusick int len; 48753897Smckusick { 48853897Smckusick 48953897Smckusick lance_transmit(unit, len); 49053897Smckusick } 49153897Smckusick 49253897Smckusick enxint(unit) 49353897Smckusick register int unit; 49453897Smckusick { 49553897Smckusick 49653897Smckusick _enxint(unit, lance_xmit_error(unit), lance_collision(unit)); 49753897Smckusick } 49853897Smckusick 49953897Smckusick enrint(unit) 50053897Smckusick register int unit; 50153897Smckusick { 50253897Smckusick register struct en_softc *es = &en_softc[unit]; 50353897Smckusick caddr_t get_recv_buffer(); 50453897Smckusick 50553897Smckusick while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) { 50653897Smckusick _enrint(unit, 50753897Smckusick get_recv_length(unit) - sizeof(struct en_rheader)); 50853897Smckusick free_recv_buffer(unit); 50953897Smckusick } 51053897Smckusick } 51153897Smckusick 51253897Smckusick en_prom_mode(unit, mode) 51353897Smckusick int unit, mode; 51453897Smckusick { 51553897Smckusick 51653897Smckusick lance_prom_mode(unit, mode); 51753897Smckusick } 51853897Smckusick #endif /* CPU_SINGLE */ 51953897Smckusick 52053897Smckusick #ifdef IPC_MRX 52153897Smckusick #include "../ipc/newsipc.h" 52253897Smckusick #include "../mrx/h/lancereg.h" 52353897Smckusick #include "../mrx/h/lance.h" 52453897Smckusick 52553897Smckusick int port_enxmit[NEN]; 52653897Smckusick int port_enrecv[NEN]; 52753897Smckusick int port_enctrl[NEN]; 52853897Smckusick int port_enxmit_iop[NEN]; 52953897Smckusick int port_enrecv_iop[NEN]; 53053897Smckusick int port_enctrl_iop[NEN]; 53153897Smckusick 53253897Smckusick en_probe(ii) 53353897Smckusick register struct iop_device *ii; 53453897Smckusick { 53553897Smckusick int unit = ii->ii_unit; 53653897Smckusick int lance_func, *reply; 53753897Smckusick char name[32]; 53853897Smckusick extern char *make_name(); 53953897Smckusick 54053897Smckusick if (port_enrecv[unit] == 0) { 54153897Smckusick 54253897Smckusick #define PT_CREATE(buf, name, unit, func) \ 54353897Smckusick port_create(make_name(buf, name, unit), func, unit) 54453897Smckusick #define OB_QUERY(buf, name, unit) \ 54553897Smckusick object_query(make_name(buf, name, unit)) 54653897Smckusick 54753897Smckusick make_name(name, "@enrecvX", unit); 54853897Smckusick port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint); 54953897Smckusick port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint); 55053897Smckusick port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL); 55153897Smckusick /* use NULL action port */ 55253897Smckusick port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit); 55353897Smckusick port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit); 55453897Smckusick port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit); 55553897Smckusick } 55653897Smckusick if (port_enctrl_iop[unit] < 0) 55753897Smckusick goto bad; 55853897Smckusick lance_func = EN_START; 55953897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 56053897Smckusick sizeof(lance_func), 0); 56153897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 56253897Smckusick if (*reply < 0) 56353897Smckusick goto bad; 56453897Smckusick lance_func = EN_STOP; 56553897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 56653897Smckusick sizeof(lance_func), 0); 56753897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 56853897Smckusick return (1); 56953897Smckusick bad: 57053897Smckusick return (0); 57153897Smckusick } 57253897Smckusick 57353897Smckusick en_attach(unit) 57453897Smckusick int unit; 57553897Smckusick { 57653897Smckusick register struct en_softc *es = &en_softc[unit]; 57753897Smckusick int lance_func; 57853897Smckusick struct ether_addr *ether_addr; 57953897Smckusick 58053897Smckusick lance_func = EN_GETADDR; 58153897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 58253897Smckusick sizeof(lance_func), 0); 58353897Smckusick msg_recv(port_enctrl[unit], NULL, ðer_addr, NULL, 0); 58453897Smckusick bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr)); 58553897Smckusick msg_free(port_enctrl[unit]); 58653897Smckusick } 58753897Smckusick 58853897Smckusick en_init(unit) 58953897Smckusick int unit; 59053897Smckusick { 59153897Smckusick register struct en_softc *es = &en_softc[unit]; 59253897Smckusick register int port; 59353897Smckusick struct lance_ctrl_req req; 59453897Smckusick int *reply; 59553897Smckusick 59653897Smckusick req.lance_func = EN_SETXMITBUF; 59753897Smckusick mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr, 59853897Smckusick ETHERMTU + sizeof(struct en_rheader)); 59953897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 60053897Smckusick &req, sizeof(req), 0); 60153897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 60253897Smckusick 60353897Smckusick req.lance_func = EN_START; 60453897Smckusick msg_send(port_enctrl_iop[unit], port_enctrl[unit], 60553897Smckusick &req, sizeof(req), 0); 60653897Smckusick msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 60753897Smckusick msg_free(port_enctrl[unit]); 60853897Smckusick 60953897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 61053897Smckusick es->es_ifnews.ifn_raddr, 61153897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 61253897Smckusick } 61353897Smckusick 61453897Smckusick en_start(unit, len) 61553897Smckusick int unit; 61653897Smckusick int len; 61753897Smckusick { 61853897Smckusick 61953897Smckusick msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0); 62053897Smckusick } 62153897Smckusick 62253897Smckusick enxint(unit) 62353897Smckusick register int unit; 62453897Smckusick { 62553897Smckusick int *len; 62653897Smckusick struct en_softc *es = &en_softc[unit]; 62753897Smckusick 62853897Smckusick if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) { 62953897Smckusick printf("stray enxint\n"); 63053897Smckusick return; 63153897Smckusick } 63253897Smckusick if (es->es_ifnews.ifn_mbuf) 63353897Smckusick m_freem(es->es_ifnews.ifn_mbuf); 63453897Smckusick _enxint(unit, *len < 0, *len & 0x10000); 63553897Smckusick } 63653897Smckusick 63753897Smckusick enrint(unit) 63853897Smckusick int unit; 63953897Smckusick { 64053897Smckusick int len; 64153897Smckusick int *reply; 64253897Smckusick 64353897Smckusick if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) { 64453897Smckusick printf("stray enrint\n"); 64553897Smckusick return; 64653897Smckusick } 64753897Smckusick len = *reply - sizeof(struct en_rheader); 64853897Smckusick msg_free(port_enrecv[unit]); 64953897Smckusick #ifdef mips 65053897Smckusick /* 65153897Smckusick * cache flush address must aligned long word boundary. 65253897Smckusick * so, add 3 for sanity. 65353897Smckusick */ 65453897Smckusick clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03, 65553897Smckusick len + sizeof (struct en_rheader) + 3); 65653897Smckusick #endif 65753897Smckusick _enrint(unit, len); 65853897Smckusick msg_send(port_enrecv_iop[unit], port_enrecv[unit], 65953897Smckusick en_softc[unit].es_ifnews.ifn_raddr, 66053897Smckusick ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 66153897Smckusick } 66253897Smckusick 66353897Smckusick en_prom_mode(unit, mode) 66453897Smckusick int unit, mode; 66553897Smckusick { 66653897Smckusick static int port; 66753897Smckusick struct lance_ctrl_req req; 66853897Smckusick extern int port_enctrl_iop[]; 66953897Smckusick 67053897Smckusick req.lance_func = EN_PROMMODE; 67153897Smckusick req.lance_mode = mode; 67253897Smckusick msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0); 67353897Smckusick } 67453897Smckusick #endif /* IPC_MRX */ 67553897Smckusick #endif /* NEN > 0 */ 676