if_netdock_nubus.c revision 1.16.16.2
11.16.16.1Smjf/*	$NetBSD: if_netdock_nubus.c,v 1.16.16.2 2008/06/02 13:22:22 mjf Exp $	*/
21.1Sitojun
31.1Sitojun/*
41.1Sitojun * Copyright (C) 2000,2002 Daishi Kato <daishi@axlight.com>
51.1Sitojun * All rights reserved.
61.1Sitojun *
71.1Sitojun * Redistribution and use in source and binary forms, with or without
81.1Sitojun * modification, are permitted provided that the following conditions
91.1Sitojun * are met:
101.1Sitojun * 1. Redistributions of source code must retain the above copyright
111.1Sitojun *    notice, this list of conditions and the following disclaimer.
121.1Sitojun * 2. Redistributions in binary form must reproduce the above copyright
131.1Sitojun *    notice, this list of conditions and the following disclaimer in the
141.1Sitojun *    documentation and/or other materials provided with the distribution.
151.1Sitojun * 3. All advertising materials mentioning features or use of this software
161.1Sitojun *    must display the following acknowledgement:
171.1Sitojun *      This product includes software developed by Daishi Kato
181.1Sitojun * 4. The name of the author may not be used to endorse or promote products
191.1Sitojun *    derived from this software without specific prior written permission.
201.1Sitojun *
211.1Sitojun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221.1Sitojun * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
231.1Sitojun * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241.1Sitojun * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251.1Sitojun * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
261.1Sitojun * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
271.1Sitojun * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
281.1Sitojun * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291.1Sitojun * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
301.1Sitojun * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311.1Sitojun */
321.1Sitojun
331.1Sitojun/*
341.1Sitojun * Asante NetDock (for Duo series) driver
351.1Sitojun * the chip inside is not known
361.1Sitojun */
371.1Sitojun
381.1Sitojun/*
391.1Sitojun * The author would like to thank Takeo Kuwata <tkuwata@mac.com> for
401.1Sitojun * his help in stabilizing this driver.
411.1Sitojun */
421.1Sitojun
431.1Sitojun/***********************/
441.4Slukem
451.4Slukem#include <sys/cdefs.h>
461.16.16.1Smjf__KERNEL_RCSID(0, "$NetBSD: if_netdock_nubus.c,v 1.16.16.2 2008/06/02 13:22:22 mjf Exp $");
471.1Sitojun
481.1Sitojun#include <sys/param.h>
491.1Sitojun#include <sys/device.h>
501.1Sitojun#include <sys/socket.h>
511.1Sitojun#include <sys/systm.h>
521.1Sitojun#include <sys/mbuf.h>
531.1Sitojun#include <sys/ioctl.h>
541.1Sitojun
551.1Sitojun#include <net/if.h>
561.1Sitojun#include <net/if_dl.h>
571.1Sitojun#include <net/if_ether.h>
581.1Sitojun
591.1Sitojun#include "opt_inet.h"
601.1Sitojun#ifdef INET
611.1Sitojun#include <netinet/in.h>
621.1Sitojun#include <netinet/if_inarp.h>
631.1Sitojun#endif
641.1Sitojun
651.1Sitojun#include "bpfilter.h"
661.1Sitojun#if NBPFILTER > 0
671.1Sitojun#include <net/bpf.h>
681.1Sitojun#endif
691.1Sitojun
701.1Sitojun#include <machine/bus.h>
711.1Sitojun#include <machine/viareg.h>
721.1Sitojun#include <mac68k/nubus/nubus.h>
731.1Sitojun
741.1Sitojun/***********************/
751.1Sitojun
761.1Sitojun#define NETDOCK_DEBUG
771.1Sitojun
781.1Sitojun#define NETDOCK_NUBUS_CATEGORY	0x0020
791.1Sitojun#define NETDOCK_NUBUS_TYPE	0x0003
801.1Sitojun#define NETDOCK_NUBUS_DRSW	0x0103
811.1Sitojun#define NETDOCK_NUBUS_DRHW	0x0100
821.1Sitojun
831.1Sitojun#define ETHERMICRODOCK_NUBUS_CATEGORY	0x0020
841.1Sitojun#define ETHERMICRODOCK_NUBUS_TYPE	0x0003
851.1Sitojun#define ETHERMICRODOCK_NUBUS_DRSW	0x0102
861.1Sitojun#define ETHERMICRODOCK_NUBUS_DRHW	0x0100
871.1Sitojun
881.1Sitojun#define REG_ISR		0x000c
891.1Sitojun#define REG_000E	0x000e
901.1Sitojun#define REG_0000	0x0000
911.1Sitojun#define REG_0002	0x0002
921.1Sitojun#define REG_0004	0x0004
931.1Sitojun#define REG_0006	0x0006
941.1Sitojun#define REG_DATA	0x0008
951.1Sitojun#define REG_EFD00	0xefd00
961.1Sitojun
971.1Sitojun#define ISR_ALL		0x3300
981.1Sitojun#define ISR_TX		0x0200
991.1Sitojun#define ISR_RX		0x0100
1001.1Sitojun#define ISR_READY	0x0800
1011.1Sitojun#define ISR_BIT_0C	0x1000
1021.1Sitojun#define ISR_BIT_0D	0x2000
1031.1Sitojun#define ISR_MASK	0x0033
1041.1Sitojun#define ISR_BIT_03	0x0008
1051.1Sitojun
1061.1Sitojun#define REG_0002_BIT_04	0x0010
1071.1Sitojun#define REG_0000_BIT_08	0x0100
1081.1Sitojun#define REG_0004_BIT_0F	0x8000
1091.1Sitojun#define REG_0004_BIT_07 0x0080
1101.1Sitojun#define REG_DATA_BIT_02 0x0004
1111.1Sitojun#define REG_DATA_BIT_03 0x0008
1121.1Sitojun#define REG_DATA_BIT_04 0x0010
1131.1Sitojun#define REG_DATA_BIT_05 0x0020
1141.1Sitojun#define REG_DATA_BIT_08	0x0100
1151.1Sitojun#define REG_DATA_BIT_07	0x0080
1161.1Sitojun#define REG_DATA_BIT_0F	0x8000
1171.1Sitojun
1181.1Sitojun/***********************/
1191.1Sitojun
1201.1Sitojuntypedef struct netdock_softc {
1211.16.16.2Smjf	device_t	sc_dev;
1221.1Sitojun	struct ethercom	sc_ethercom;
1231.1Sitojun#define sc_if		sc_ethercom.ec_if
1241.1Sitojun
1251.1Sitojun	bus_space_tag_t		sc_regt;
1261.1Sitojun	bus_space_handle_t	sc_regh;
1271.1Sitojun
1281.1Sitojun	u_int8_t	sc_enaddr[ETHER_ADDR_LEN];
1291.1Sitojun
1301.1Sitojun} netdock_softc_t;
1311.1Sitojun
1321.1Sitojun/***********************/
1331.1Sitojun
1341.6Schsstatic int	netdock_nubus_match(struct device *, struct cfdata *, void *);
1351.6Schsstatic void	netdock_nubus_attach(struct device *, struct device *, void *);
1361.6Schsstatic int	netdock_nb_get_enaddr(bus_space_tag_t, bus_space_handle_t,
1371.6Schs			struct nubus_attach_args *, u_int8_t *);
1381.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER
1391.6Schsstatic void	netdock_print_driver(bus_space_tag_t, bus_space_handle_t,
1401.6Schs			struct nubus_attach_args *);
1411.1Sitojun#endif
1421.1Sitojun
1431.6Schsint	netdock_setup(struct netdock_softc *, u_int8_t *);
1441.6Schsvoid	netdock_intr(void *);
1451.1Sitojun
1461.6Schsstatic void	netdock_watchdog(struct ifnet *);
1471.6Schsstatic int	netdock_init(struct netdock_softc *);
1481.6Schsstatic int	netdock_stop(struct netdock_softc *);
1491.12Schristosstatic int	netdock_ioctl(struct ifnet *, u_long, void *);
1501.6Schsstatic void	netdock_start(struct ifnet *);
1511.6Schsstatic void	netdock_reset(struct netdock_softc *);
1521.6Schsstatic void	netdock_txint(struct netdock_softc *);
1531.6Schsstatic void	netdock_rxint(struct netdock_softc *);
1541.6Schs
1551.6Schsstatic u_int	netdock_put(struct netdock_softc *, struct mbuf *);
1561.6Schsstatic int	netdock_read(struct netdock_softc *, int);
1571.6Schsstatic struct mbuf *netdock_get(struct netdock_softc *, int);
1581.1Sitojun
1591.1Sitojun/***********************/
1601.1Sitojun
1611.1Sitojun#define NIC_GET_1(sc, o)	(bus_space_read_1((sc)->sc_regt,	\
1621.1Sitojun					(sc)->sc_regh, (o)))
1631.1Sitojun#define NIC_PUT_1(sc, o, val)	(bus_space_write_1((sc)->sc_regt,	\
1641.1Sitojun					(sc)->sc_regh, (o), (val)))
1651.1Sitojun#define NIC_GET_2(sc, o)	(bus_space_read_2((sc)->sc_regt,	\
1661.1Sitojun					(sc)->sc_regh, (o)))
1671.1Sitojun#define NIC_PUT_2(sc, o, val)	(bus_space_write_2((sc)->sc_regt,	\
1681.1Sitojun					(sc)->sc_regh, (o), (val)))
1691.1Sitojun#define NIC_GET_4(sc, o)	(bus_space_read_4((sc)->sc_regt,	\
1701.1Sitojun					(sc)->sc_regh, (o)))
1711.1Sitojun#define NIC_PUT_4(sc, o, val)	(bus_space_write_4((sc)->sc_regt,	\
1721.1Sitojun					(sc)->sc_regh, (o), (val)))
1731.1Sitojun
1741.1Sitojun#define NIC_BSET(sc, o, b)						\
1751.11Sperry	__asm volatile("bset %0,%1" : : "di" ((u_short)(b)),	\
1761.1Sitojun		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
1771.1Sitojun#define NIC_BCLR(sc, o, b)						\
1781.11Sperry	__asm volatile("bclr %0,%1" : : "di" ((u_short)(b)),	\
1791.1Sitojun		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
1801.1Sitojun#define NIC_ANDW(sc, o, b)						\
1811.11Sperry	__asm volatile("andw %0,%1" : : "di" ((u_short)(b)),	\
1821.1Sitojun		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
1831.1Sitojun#define NIC_ORW(sc, o, b)						\
1841.11Sperry	__asm volatile("orw %0,%1" : : "di" ((u_short)(b)),	\
1851.1Sitojun		"g" (*(u_int8_t *)((sc)->sc_regh.base + (o))))
1861.1Sitojun
1871.1Sitojun
1881.1Sitojun/***********************/
1891.1Sitojun
1901.3SthorpejCFATTACH_DECL(netdock_nubus, sizeof(struct netdock_softc),
1911.3Sthorpej    netdock_nubus_match, netdock_nubus_attach, NULL, NULL);
1921.1Sitojun
1931.1Sitojun/***********************/
1941.1Sitojun
1951.1Sitojunstatic int
1961.6Schsnetdock_nubus_match(struct device *parent, struct cfdata *cf, void *aux)
1971.1Sitojun{
1981.1Sitojun	struct nubus_attach_args *na = (struct nubus_attach_args *)aux;
1991.1Sitojun	bus_space_handle_t bsh;
2001.1Sitojun	int rv;
2011.1Sitojun
2021.1Sitojun	if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot),
2031.1Sitojun	    NBMEMSIZE, 0, &bsh))
2041.1Sitojun		return (0);
2051.1Sitojun
2061.1Sitojun	rv = 0;
2071.1Sitojun
2081.1Sitojun	if (na->category == NETDOCK_NUBUS_CATEGORY &&
2091.1Sitojun	    na->type == NETDOCK_NUBUS_TYPE &&
2101.1Sitojun	    na->drsw == NETDOCK_NUBUS_DRSW) {
2111.1Sitojun		/* assuming this IS Asante NetDock */
2121.1Sitojun		rv = 1;
2131.1Sitojun	}
2141.1Sitojun
2151.1Sitojun	if (na->category == ETHERMICRODOCK_NUBUS_CATEGORY &&
2161.1Sitojun	    na->type == ETHERMICRODOCK_NUBUS_TYPE &&
2171.1Sitojun	    na->drsw == ETHERMICRODOCK_NUBUS_DRSW) {
2181.1Sitojun		/* assuming this IS Newer EtherMicroDock */
2191.1Sitojun		rv = 1;
2201.1Sitojun	}
2211.1Sitojun
2221.1Sitojun	bus_space_unmap(na->na_tag, bsh, NBMEMSIZE);
2231.1Sitojun
2241.1Sitojun	return rv;
2251.1Sitojun}
2261.1Sitojun
2271.1Sitojunstatic void
2281.6Schsnetdock_nubus_attach(struct device *parent, struct device *self, void *aux)
2291.1Sitojun{
2301.1Sitojun	struct netdock_softc *sc = (struct netdock_softc *)self;
2311.1Sitojun	struct nubus_attach_args *na = (struct nubus_attach_args *)aux;
2321.1Sitojun	bus_space_tag_t bst;
2331.1Sitojun	bus_space_handle_t bsh;
2341.1Sitojun	u_int8_t enaddr[ETHER_ADDR_LEN];
2351.8Srjs	const char *cardtype;
2361.1Sitojun
2371.1Sitojun	bst = na->na_tag;
2381.1Sitojun	if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &bsh)) {
2391.1Sitojun		printf(": failed to map memory space.\n");
2401.1Sitojun		return;
2411.1Sitojun	}
2421.1Sitojun
2431.1Sitojun	sc->sc_regt = bst;
2441.1Sitojun	cardtype = nubus_get_card_name(bst, bsh, na->fmt);
2451.1Sitojun
2461.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER
2471.1Sitojun	netdock_print_driver(bst, bsh, na);
2481.1Sitojun#endif
2491.1Sitojun
2501.1Sitojun	if (netdock_nb_get_enaddr(bst, bsh, na, enaddr)) {
2511.1Sitojun		printf(": can't find MAC address.\n");
2521.1Sitojun		bus_space_unmap(bst, bsh, NBMEMSIZE);
2531.1Sitojun		return;
2541.1Sitojun	}
2551.1Sitojun
2561.1Sitojun	if (bus_space_subregion(bst, bsh, 0xe00300, 0xf0000, &sc->sc_regh)) {
2571.1Sitojun		printf(": failed to map register space.\n");
2581.1Sitojun		bus_space_unmap(bst, bsh, NBMEMSIZE);
2591.1Sitojun		return;
2601.1Sitojun	}
2611.1Sitojun
2621.1Sitojun	printf(": %s\n", cardtype);
2631.1Sitojun
2641.1Sitojun	if (netdock_setup(sc, enaddr)) {
2651.1Sitojun		bus_space_unmap(bst, bsh, NBMEMSIZE);
2661.1Sitojun		return;
2671.1Sitojun	}
2681.1Sitojun
2691.1Sitojun	add_nubus_intr(na->slot, netdock_intr, (void *)sc);
2701.1Sitojun
2711.1Sitojun	return;
2721.1Sitojun}
2731.1Sitojun
2741.1Sitojunstatic int
2751.6Schsnetdock_nb_get_enaddr(bus_space_tag_t bst, bus_space_handle_t bsh,
2761.6Schs    struct nubus_attach_args *na, u_int8_t *ep)
2771.1Sitojun{
2781.1Sitojun	nubus_dir dir;
2791.1Sitojun	nubus_dirent dirent;
2801.1Sitojun
2811.1Sitojun	/*
2821.1Sitojun	 * these hardwired resource IDs are only for NetDock
2831.1Sitojun	 */
2841.1Sitojun	nubus_get_main_dir(na->fmt, &dir);
2851.1Sitojun	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent) <= 0)
2861.1Sitojun		return 1;
2871.1Sitojun	nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
2881.1Sitojun	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent) <= 0)
2891.1Sitojun		return 1;
2901.1Sitojun	if (nubus_get_ind_data(bst, bsh, na->fmt, &dirent,
2911.1Sitojun		ep, ETHER_ADDR_LEN) <= 0)
2921.1Sitojun		return 1;
2931.1Sitojun
2941.1Sitojun	return 0;
2951.1Sitojun}
2961.1Sitojun
2971.1Sitojun#ifdef NETDOCK_DEBUG_DRIVER
2981.1Sitojunstatic void
2991.6Schsnetdock_print_driver(bus_space_tag_t bst, bus_space_handle_t bsh,
3001.6Schs    struct nubus_attach_args *na)
3011.1Sitojun{
3021.1Sitojun#define HEADSIZE	(8+4)
3031.1Sitojun#define CODESIZE	(6759-4)
3041.1Sitojun	unsigned char mydata[HEADSIZE + CODESIZE];
3051.1Sitojun	nubus_dir dir;
3061.1Sitojun	nubus_dirent dirent;
3071.1Sitojun	int i, rv;
3081.1Sitojun
3091.1Sitojun	nubus_get_main_dir(na->fmt, &dir);
3101.1Sitojun	rv = nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x81, &dirent);
3111.1Sitojun	if (rv <= 0) {
3121.1Sitojun		printf(": can't find sResource.\n");
3131.1Sitojun		return;
3141.1Sitojun	}
3151.1Sitojun	nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
3161.1Sitojun	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, NUBUS_RSRC_DRVRDIR,
3171.1Sitojun	    &dirent) <= 0) {
3181.1Sitojun		printf(": can't find sResource.\n");
3191.1Sitojun		return;
3201.1Sitojun	}
3211.1Sitojun	if (nubus_get_ind_data(bst, bsh, na->fmt,
3221.1Sitojun		&dirent, mydata, HEADSIZE+CODESIZE) <= 0) {
3231.1Sitojun		printf(": can't find indirect data.\n");
3241.1Sitojun		return;
3251.1Sitojun	}
3261.1Sitojun	printf("\n########## begin driver dir");
3271.1Sitojun	for (i = 0; i < HEADSIZE; i++) {
3281.1Sitojun		if (i % 16 == 0)
3291.1Sitojun			printf("\n%02x:",i);
3301.1Sitojun		printf(" %02x", mydata[i]);
3311.1Sitojun	}
3321.1Sitojun	printf("\n########## begin driver code");
3331.1Sitojun	for (i = 0; i < CODESIZE; i++) {
3341.1Sitojun		if (i % 16 == 0)
3351.1Sitojun			printf("\n%02x:",i);
3361.1Sitojun		printf(" %02x", mydata[i + HEADSIZE]);
3371.1Sitojun	}
3381.1Sitojun#if 0
3391.1Sitojun	printf("\n########## begin driver code (partial)\n");
3401.1Sitojun#define PARTSIZE 256
3411.1Sitojun#define OFFSET 0x1568
3421.1Sitojun	for (i = OFFSET; i < OFFSET + PARTSIZE; i++) {
3431.1Sitojun		if ((i - OFFSET) % 16 == 0)
3441.1Sitojun			printf("\n%02x:",i);
3451.1Sitojun		printf(" %02x", mydata[i + HEADSIZE]);
3461.1Sitojun	}
3471.1Sitojun#endif
3481.1Sitojun	printf("\n########## end\n");
3491.1Sitojun}
3501.1Sitojun#endif
3511.1Sitojun
3521.1Sitojun
3531.1Sitojunint
3541.6Schsnetdock_setup(struct netdock_softc *sc, u_int8_t *lladdr)
3551.1Sitojun{
3561.1Sitojun	struct ifnet *ifp = &sc->sc_if;
3571.1Sitojun
3581.6Schs	memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN);
3591.1Sitojun	printf("%s: Ethernet address %s\n",
3601.16.16.1Smjf	    sc->sc_dev->dv_xname, ether_sprintf(lladdr));
3611.1Sitojun
3621.16.16.2Smjf	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
3631.1Sitojun	ifp->if_softc = sc;
3641.1Sitojun	ifp->if_ioctl = netdock_ioctl;
3651.1Sitojun	ifp->if_start = netdock_start;
3661.1Sitojun	ifp->if_flags =
3671.1Sitojun	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
3681.1Sitojun	ifp->if_watchdog = netdock_watchdog;
3691.1Sitojun
3701.1Sitojun	if_attach(ifp);
3711.1Sitojun	ether_ifattach(ifp, lladdr);
3721.1Sitojun
3731.1Sitojun	return (0);
3741.1Sitojun}
3751.1Sitojun
3761.1Sitojunstatic int
3771.12Schristosnetdock_ioctl(struct ifnet *ifp, u_long cmd, void *data)
3781.1Sitojun{
3791.1Sitojun	struct ifaddr *ifa;
3801.1Sitojun	struct netdock_softc *sc = ifp->if_softc;
3811.1Sitojun	int s = splnet();
3821.1Sitojun	int err = 0;
3831.1Sitojun	int temp;
3841.1Sitojun
3851.1Sitojun	switch (cmd) {
3861.1Sitojun	case SIOCSIFADDR:
3871.1Sitojun		ifa = (struct ifaddr *)data;
3881.1Sitojun		ifp->if_flags |= IFF_UP;
3891.1Sitojun		switch (ifa->ifa_addr->sa_family) {
3901.1Sitojun#ifdef INET
3911.1Sitojun		case AF_INET:
3921.1Sitojun			(void)netdock_init(sc);
3931.1Sitojun			arp_ifinit(ifp, ifa);
3941.1Sitojun			break;
3951.1Sitojun#endif
3961.1Sitojun		default:
3971.1Sitojun			(void)netdock_init(sc);
3981.1Sitojun			break;
3991.1Sitojun		}
4001.1Sitojun		break;
4011.1Sitojun
4021.1Sitojun	case SIOCSIFFLAGS:
4031.1Sitojun		if ((ifp->if_flags & IFF_UP) == 0 &&
4041.1Sitojun		    (ifp->if_flags & IFF_RUNNING) != 0) {
4051.1Sitojun			netdock_stop(sc);
4061.1Sitojun			ifp->if_flags &= ~IFF_RUNNING;
4071.1Sitojun		} else if ((ifp->if_flags & IFF_UP) != 0 &&
4081.1Sitojun		    (ifp->if_flags & IFF_RUNNING) == 0) {
4091.1Sitojun			(void)netdock_init(sc);
4101.1Sitojun		} else {
4111.1Sitojun			temp = ifp->if_flags & IFF_UP;
4121.1Sitojun			netdock_reset(sc);
4131.1Sitojun			ifp->if_flags |= temp;
4141.1Sitojun			netdock_start(ifp);
4151.1Sitojun		}
4161.1Sitojun		break;
4171.1Sitojun
4181.1Sitojun	case SIOCADDMULTI:
4191.1Sitojun	case SIOCDELMULTI:
4201.15Sjmmv		if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
4211.5Sthorpej			if (ifp->if_flags & IFF_RUNNING) {
4221.5Sthorpej				temp = ifp->if_flags & IFF_UP;
4231.5Sthorpej				netdock_reset(sc);
4241.5Sthorpej				ifp->if_flags |= temp;
4251.5Sthorpej			}
4261.1Sitojun			err = 0;
4271.1Sitojun		}
4281.1Sitojun		break;
4291.1Sitojun	default:
4301.1Sitojun		err = EINVAL;
4311.1Sitojun		break;
4321.1Sitojun	}
4331.1Sitojun	splx(s);
4341.1Sitojun	return (err);
4351.1Sitojun}
4361.1Sitojun
4371.1Sitojunstatic void
4381.6Schsnetdock_start(struct ifnet *ifp)
4391.1Sitojun{
4401.1Sitojun	struct netdock_softc *sc = ifp->if_softc;
4411.1Sitojun	struct mbuf *m;
4421.1Sitojun
4431.1Sitojun	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
4441.1Sitojun		return;
4451.1Sitojun
4461.1Sitojun	while (1) {
4471.1Sitojun		IF_DEQUEUE(&ifp->if_snd, m);
4481.1Sitojun		if (m == 0)
4491.1Sitojun			return;
4501.1Sitojun
4511.1Sitojun		if ((m->m_flags & M_PKTHDR) == 0)
4521.1Sitojun			panic("%s: netdock_start: no header mbuf",
4531.16.16.2Smjf			    device_xname(sc->sc_dev));
4541.1Sitojun
4551.1Sitojun#if NBPFILTER > 0
4561.1Sitojun		if (ifp->if_bpf)
4571.1Sitojun			bpf_mtap(ifp->if_bpf, m);
4581.1Sitojun#endif
4591.1Sitojun
4601.1Sitojun		if ((netdock_put(sc, m)) == 0) {
4611.1Sitojun			IF_PREPEND(&ifp->if_snd, m);
4621.1Sitojun			return;
4631.1Sitojun		}
4641.1Sitojun
4651.1Sitojun		ifp->if_opackets++;
4661.1Sitojun	}
4671.1Sitojun
4681.1Sitojun}
4691.1Sitojun
4701.1Sitojunstatic void
4711.6Schsnetdock_reset(struct netdock_softc *sc)
4721.1Sitojun{
4731.1Sitojun
4741.1Sitojun	netdock_stop(sc);
4751.1Sitojun	netdock_init(sc);
4761.1Sitojun}
4771.1Sitojun
4781.1Sitojunstatic int
4791.6Schsnetdock_init(struct netdock_softc *sc)
4801.1Sitojun{
4811.1Sitojun	int s;
4821.1Sitojun	int saveisr;
4831.1Sitojun	int savetmp;
4841.1Sitojun
4851.1Sitojun	if (sc->sc_if.if_flags & IFF_RUNNING)
4861.1Sitojun		return (0);
4871.1Sitojun
4881.1Sitojun	s = splnet();
4891.1Sitojun
4901.1Sitojun	/* 0606 */
4911.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0200);
4921.1Sitojun	NIC_PUT_2(sc, REG_ISR , 0);
4931.1Sitojun	NIC_PUT_2(sc, REG_000E, 0);
4941.1Sitojun
4951.1Sitojun	NIC_PUT_2(sc, REG_0000, 0x8104);
4961.1Sitojun	NIC_PUT_2(sc, REG_0004, 0x0043);
4971.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0100);
4981.1Sitojun	NIC_PUT_2(sc, REG_0002, 0x6618);
4991.1Sitojun	NIC_PUT_2(sc, REG_0000, 0x8010);
5001.1Sitojun
5011.1Sitojun	NIC_PUT_1(sc, REG_0004 + 0, sc->sc_enaddr[0]);
5021.1Sitojun	NIC_PUT_1(sc, REG_0004 + 1, sc->sc_enaddr[1]);
5031.1Sitojun	NIC_PUT_1(sc, REG_0004 + 2, sc->sc_enaddr[2]);
5041.1Sitojun	NIC_PUT_1(sc, REG_0004 + 3, sc->sc_enaddr[3]);
5051.1Sitojun	NIC_PUT_1(sc, REG_0004 + 4, sc->sc_enaddr[4]);
5061.1Sitojun	NIC_PUT_1(sc, REG_0004 + 5, sc->sc_enaddr[5]);
5071.1Sitojun
5081.1Sitojun	NIC_PUT_2(sc, REG_ISR , 0x2008);
5091.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0200);
5101.1Sitojun	NIC_PUT_2(sc, REG_0000, 0x4000);
5111.1Sitojun	NIC_PUT_2(sc, REG_ISR, ISR_MASK);
5121.1Sitojun
5131.1Sitojun
5141.1Sitojun	/* 1320 */
5151.1Sitojun	saveisr = NIC_GET_2(sc, REG_ISR);
5161.1Sitojun	NIC_PUT_2(sc, REG_ISR , 0);
5171.1Sitojun	savetmp = NIC_GET_2(sc, REG_000E);
5181.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0100);
5191.1Sitojun	NIC_ANDW(sc, REG_ISR, ~ISR_BIT_03);
5201.1Sitojun	NIC_PUT_2(sc, REG_000E, savetmp);
5211.1Sitojun
5221.1Sitojun	/* 1382 */
5231.1Sitojun	savetmp = NIC_GET_2(sc, REG_000E);
5241.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0100);
5251.1Sitojun	NIC_ORW(sc, REG_ISR, ISR_BIT_03);
5261.1Sitojun	NIC_PUT_2(sc, REG_000E, savetmp);
5271.1Sitojun	NIC_PUT_2(sc, REG_ISR , saveisr);
5281.1Sitojun
5291.1Sitojun
5301.1Sitojun	sc->sc_if.if_flags |= IFF_RUNNING;
5311.1Sitojun	sc->sc_if.if_flags &= ~IFF_OACTIVE;
5321.1Sitojun
5331.1Sitojun	splx(s);
5341.1Sitojun	return (0);
5351.1Sitojun}
5361.1Sitojun
5371.1Sitojunstatic int
5381.6Schsnetdock_stop(struct netdock_softc *sc)
5391.1Sitojun{
5401.1Sitojun	int s = splnet();
5411.1Sitojun
5421.1Sitojun	sc->sc_if.if_timer = 0;
5431.1Sitojun	sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
5441.1Sitojun
5451.1Sitojun	splx(s);
5461.1Sitojun	return (0);
5471.1Sitojun}
5481.1Sitojun
5491.1Sitojunstatic void
5501.6Schsnetdock_watchdog(struct ifnet *ifp)
5511.1Sitojun{
5521.1Sitojun	struct netdock_softc *sc = ifp->if_softc;
5531.1Sitojun	int tmp;
5541.1Sitojun
5551.1Sitojun	printf("netdock_watchdog: resetting chip\n");
5561.1Sitojun	tmp = ifp->if_flags & IFF_UP;
5571.1Sitojun	netdock_reset(sc);
5581.1Sitojun	ifp->if_flags |= tmp;
5591.1Sitojun}
5601.1Sitojun
5611.1Sitojunstatic u_int
5621.6Schsnetdock_put(struct netdock_softc *sc, struct mbuf *m0)
5631.1Sitojun{
5641.1Sitojun	struct mbuf *m;
5651.1Sitojun	u_int totlen = 0;
5661.1Sitojun	u_int tmplen;
5671.1Sitojun	int isr;
5681.1Sitojun	int timeout;
5691.1Sitojun	int tmp;
5701.1Sitojun	u_int i;
5711.1Sitojun
5721.1Sitojun	for (m = m0; m; m = m->m_next)
5731.1Sitojun		totlen += m->m_len;
5741.1Sitojun
5751.1Sitojun	if (totlen >= ETHER_MAX_LEN)
5761.16.16.1Smjf		panic("%s: netdock_put: packet overflow",
5771.16.16.2Smjf		    device_xname(sc->sc_dev));
5781.1Sitojun
5791.1Sitojun	totlen += 6;
5801.1Sitojun	tmplen = totlen;
5811.1Sitojun	tmplen &= 0xff00;
5821.1Sitojun	tmplen |= 0x2000;
5831.1Sitojun	NIC_PUT_2(sc, REG_0000, tmplen);
5841.1Sitojun
5851.1Sitojun	timeout = 0x3000;
5861.1Sitojun	while ((((isr = NIC_GET_2(sc, REG_ISR)) & ISR_READY) == 0) &&
5871.1Sitojun	    timeout--) {
5881.1Sitojun		if (isr & ISR_TX)
5891.1Sitojun			netdock_txint(sc);
5901.1Sitojun	}
5911.1Sitojun	if (timeout == 0)
5921.1Sitojun		return (0);
5931.1Sitojun
5941.1Sitojun	tmp = NIC_GET_2(sc, REG_0002);
5951.1Sitojun	tmp <<= 8;
5961.1Sitojun	NIC_PUT_2(sc, REG_0002, tmp);
5971.1Sitojun	NIC_PUT_2(sc, REG_0006, 0x240);
5981.1Sitojun	NIC_GET_2(sc, REG_ISR);
5991.1Sitojun	tmplen = ((totlen << 8) & 0xfe00) | ((totlen >> 8) & 0x00ff);
6001.1Sitojun	NIC_PUT_2(sc, REG_DATA, tmplen);
6011.1Sitojun
6021.1Sitojun	for (m = m0; m; m = m->m_next) {
6031.1Sitojun		u_char *data = mtod(m, u_char *);
6041.1Sitojun		int len = m->m_len;
6051.1Sitojun		int len4 = len >> 2;
6061.1Sitojun		u_int32_t *data4 = (u_int32_t *)data;
6071.1Sitojun		for (i = 0; i < len4; i++)
6081.1Sitojun			NIC_PUT_4(sc, REG_DATA, data4[i]);
6091.1Sitojun		for (i = len4 << 2; i < len; i++)
6101.1Sitojun			NIC_PUT_1(sc, REG_DATA, data[i]);
6111.1Sitojun	}
6121.1Sitojun
6131.1Sitojun	if (totlen & 0x01)
6141.1Sitojun		NIC_PUT_2(sc, REG_DATA, 0x2020);
6151.1Sitojun	else
6161.1Sitojun		NIC_PUT_2(sc, REG_DATA, 0);
6171.1Sitojun
6181.1Sitojun	NIC_PUT_2(sc, REG_0000, 0xc000);
6191.1Sitojun
6201.1Sitojun	m_freem(m0);
6211.1Sitojun	/* sc->sc_if.if_timer = 5; */
6221.1Sitojun	return (totlen);
6231.1Sitojun}
6241.1Sitojun
6251.1Sitojunvoid
6261.6Schsnetdock_intr(void *arg)
6271.1Sitojun{
6281.1Sitojun	struct netdock_softc *sc = (struct netdock_softc *)arg;
6291.1Sitojun	int isr;
6301.1Sitojun	int tmp;
6311.1Sitojun
6321.1Sitojun	NIC_PUT_2(sc, REG_ISR, 0);
6331.1Sitojun	while ((isr = (NIC_GET_2(sc, REG_ISR) & ISR_ALL)) != 0) {
6341.1Sitojun		if (isr & ISR_TX)
6351.1Sitojun			netdock_txint(sc);
6361.1Sitojun
6371.1Sitojun		if (isr & ISR_RX)
6381.1Sitojun			netdock_rxint(sc);
6391.1Sitojun
6401.1Sitojun		if (isr & (ISR_BIT_0C | ISR_BIT_0D)) {
6411.1Sitojun			if (isr & ISR_BIT_0C) {
6421.1Sitojun				NIC_PUT_2(sc, REG_000E, 0);
6431.1Sitojun				NIC_BSET(sc, REG_0004, 0x08);
6441.1Sitojun				NIC_PUT_2(sc, REG_000E, 0x0200);
6451.1Sitojun			}
6461.1Sitojun			if (isr & ISR_BIT_0D) {
6471.1Sitojun				NIC_PUT_2(sc, REG_000E, 0);
6481.1Sitojun				tmp = NIC_GET_2(sc, REG_0002);
6491.1Sitojun				if (tmp & REG_0002_BIT_04)
6501.1Sitojun					NIC_GET_2(sc, REG_0006);
6511.1Sitojun				tmp = NIC_GET_2(sc, REG_0000);
6521.1Sitojun				if (tmp & REG_0000_BIT_08)
6531.1Sitojun					NIC_BSET(sc, REG_0000, 0x08);
6541.1Sitojun				NIC_PUT_2(sc, REG_000E, 0x0200);
6551.1Sitojun			}
6561.1Sitojun			NIC_PUT_2(sc, REG_ISR, isr);
6571.1Sitojun		}
6581.1Sitojun	}
6591.1Sitojun	NIC_PUT_2(sc, REG_ISR, ISR_MASK);
6601.1Sitojun}
6611.1Sitojun
6621.1Sitojunstatic void
6631.6Schsnetdock_txint(struct netdock_softc *sc)
6641.1Sitojun{
6651.1Sitojun	struct ifnet *ifp = &sc->sc_if;
6661.1Sitojun	int savereg0002;
6671.1Sitojun	int reg0004;
6681.1Sitojun	int regdata;
6691.1Sitojun
6701.1Sitojun	ifp->if_flags &= ~IFF_OACTIVE;
6711.1Sitojun	ifp->if_timer = 0;
6721.1Sitojun
6731.1Sitojun	savereg0002 = NIC_GET_2(sc, REG_0002);
6741.1Sitojun
6751.1Sitojun	while (((reg0004 = NIC_GET_2(sc, REG_0004)) & REG_0004_BIT_0F) == 0) {
6761.1Sitojun		NIC_PUT_2(sc, REG_0002, reg0004);
6771.1Sitojun		NIC_PUT_2(sc, REG_0006, 0x0060);
6781.1Sitojun		NIC_GET_2(sc, REG_ISR);
6791.1Sitojun		regdata = NIC_GET_2(sc, REG_DATA);
6801.1Sitojun		if ((regdata & REG_DATA_BIT_08) == 0) {
6811.1Sitojun			/* ifp->if_collisions++; */
6821.1Sitojun			if (regdata & REG_DATA_BIT_07)
6831.1Sitojun			/* ifp->if_oerrors++; */
6841.1Sitojun			NIC_PUT_2(sc, REG_000E, 0);
6851.1Sitojun			NIC_ORW(sc, REG_0000, 0x0100);
6861.1Sitojun			NIC_PUT_2(sc, REG_000E, 0x0200);
6871.1Sitojun		}
6881.1Sitojun		NIC_GET_2(sc ,REG_DATA);
6891.1Sitojun
6901.1Sitojun		if (regdata & REG_DATA_BIT_0F)
6911.1Sitojun			NIC_GET_4(sc, REG_EFD00);
6921.1Sitojun		NIC_PUT_2(sc, REG_0000, 0xa000);
6931.1Sitojun		NIC_PUT_2(sc, REG_ISR, ISR_TX);
6941.1Sitojun	}
6951.1Sitojun
6961.1Sitojun	NIC_PUT_2(sc, REG_0002, savereg0002);
6971.1Sitojun	NIC_PUT_2(sc, REG_000E, 0);
6981.1Sitojun	NIC_GET_2(sc, REG_0006);
6991.1Sitojun	NIC_PUT_2(sc, REG_000E, 0x0200);
7001.1Sitojun	NIC_PUT_2(sc, REG_0006, 0);
7011.1Sitojun}
7021.1Sitojun
7031.1Sitojunstatic void
7041.6Schsnetdock_rxint(struct netdock_softc *sc)
7051.1Sitojun{
7061.1Sitojun	struct ifnet *ifp = &sc->sc_if;
7071.1Sitojun	int regdata1;
7081.1Sitojun	int regdata2;
7091.1Sitojun	u_int len;
7101.1Sitojun	int timeout;
7111.1Sitojun
7121.1Sitojun	while ((NIC_GET_2(sc, REG_0004) & REG_0004_BIT_07) == 0) {
7131.1Sitojun		NIC_GET_2(sc, REG_ISR);
7141.1Sitojun		NIC_PUT_2(sc, REG_0006, 0x00e0);
7151.1Sitojun		NIC_GET_2(sc, REG_ISR);
7161.1Sitojun		regdata1 = NIC_GET_2(sc, REG_DATA);
7171.1Sitojun		regdata2 = NIC_GET_2(sc, REG_DATA);
7181.1Sitojun		len = ((regdata2 << 8) & 0x0700) | ((regdata2 >> 8) & 0x00ff);
7191.1Sitojun
7201.1Sitojun#if 0
7211.1Sitojun		printf("netdock_rxint: r1=0x%04x, r2=0x%04x, len=%d\n",
7221.1Sitojun		       regdata1, regdata2, len);
7231.1Sitojun#endif
7241.1Sitojun
7251.1Sitojun		if ((regdata1 & REG_DATA_BIT_04) == 0)
7261.1Sitojun			len -= 2;
7271.1Sitojun
7281.7Sthorpej		/* CRC is included with the packet; trim it off. */
7291.7Sthorpej		len -= ETHER_CRC_LEN;
7301.7Sthorpej
7311.1Sitojun		if ((regdata1 & 0x00ac) == 0) {
7321.1Sitojun			if (netdock_read(sc, len))
7331.1Sitojun				ifp->if_ipackets++;
7341.1Sitojun			else
7351.1Sitojun				ifp->if_ierrors++;
7361.1Sitojun		} else {
7371.1Sitojun			ifp->if_ierrors++;
7381.1Sitojun
7391.1Sitojun			if (regdata1 & REG_DATA_BIT_02)
7401.1Sitojun				NIC_GET_4(sc, REG_EFD00);
7411.1Sitojun			if (regdata1 & REG_DATA_BIT_03)
7421.1Sitojun				;
7431.1Sitojun			if (regdata1 & REG_DATA_BIT_05)
7441.1Sitojun				NIC_GET_4(sc, REG_EFD00);
7451.1Sitojun			if (regdata1 & REG_DATA_BIT_07)
7461.1Sitojun				;
7471.1Sitojun		}
7481.1Sitojun
7491.1Sitojun		timeout = 0x14;
7501.1Sitojun		while ((NIC_GET_2(sc, REG_0000) & REG_0000_BIT_08) && timeout--)
7511.1Sitojun			;
7521.1Sitojun		if (timeout == 0)
7531.1Sitojun			;
7541.1Sitojun
7551.1Sitojun		NIC_PUT_2(sc, REG_0000, 0x8000);
7561.1Sitojun	}
7571.1Sitojun	NIC_PUT_2(sc, REG_0006, 0);
7581.1Sitojun}
7591.1Sitojun
7601.1Sitojunstatic int
7611.6Schsnetdock_read(struct netdock_softc *sc, int len)
7621.1Sitojun{
7631.1Sitojun	struct ifnet *ifp = &sc->sc_if;
7641.1Sitojun	struct mbuf *m;
7651.1Sitojun
7661.1Sitojun	m = netdock_get(sc, len);
7671.1Sitojun	if (m == 0)
7681.1Sitojun		return (0);
7691.1Sitojun
7701.1Sitojun#if NBPFILTER > 0
7711.1Sitojun	if (ifp->if_bpf)
7721.1Sitojun		bpf_mtap(ifp->if_bpf, m);
7731.1Sitojun#endif
7741.1Sitojun
7751.1Sitojun	(*ifp->if_input)(ifp, m);
7761.1Sitojun
7771.1Sitojun	return (1);
7781.1Sitojun}
7791.1Sitojun
7801.1Sitojunstatic struct mbuf *
7811.6Schsnetdock_get(struct netdock_softc *sc, int datalen)
7821.1Sitojun{
7831.1Sitojun	struct mbuf *m, *top, **mp;
7841.1Sitojun	u_char *data;
7851.1Sitojun	int i;
7861.1Sitojun	int len;
7871.1Sitojun	int len4;
7881.1Sitojun	u_int32_t *data4;
7891.1Sitojun
7901.1Sitojun	MGETHDR(m, M_DONTWAIT, MT_DATA);
7911.1Sitojun	if (m == NULL)
7921.1Sitojun		return (NULL);
7931.1Sitojun	m->m_pkthdr.rcvif = &sc->sc_if;
7941.1Sitojun	m->m_pkthdr.len = datalen;
7951.1Sitojun	len = MHLEN;
7961.1Sitojun	top = NULL;
7971.1Sitojun	mp = &top;
7981.1Sitojun
7991.1Sitojun	while (datalen > 0) {
8001.1Sitojun		if (top) {
8011.1Sitojun			MGET(m, M_DONTWAIT, MT_DATA);
8021.1Sitojun			if (m == 0) {
8031.1Sitojun				m_freem(top);
8041.1Sitojun				return (NULL);
8051.1Sitojun			}
8061.1Sitojun			len = MLEN;
8071.1Sitojun		}
8081.1Sitojun		if (datalen >= MINCLSIZE) {
8091.1Sitojun			MCLGET(m, M_DONTWAIT);
8101.1Sitojun			if ((m->m_flags & M_EXT) == 0) {
8111.1Sitojun				if (top)
8121.1Sitojun					m_freem(top);
8131.1Sitojun				return (NULL);
8141.1Sitojun			}
8151.1Sitojun			len = MCLBYTES;
8161.1Sitojun		}
8171.1Sitojun
8181.1Sitojun		if (mp == &top) {
8191.13She			char *newdata = (char *)
8201.1Sitojun			    ALIGN(m->m_data + sizeof(struct ether_header)) -
8211.1Sitojun			    sizeof(struct ether_header);
8221.1Sitojun			len -= newdata - m->m_data;
8231.1Sitojun			m->m_data = newdata;
8241.1Sitojun		}
8251.1Sitojun
8261.1Sitojun		m->m_len = len = min(datalen, len);
8271.1Sitojun
8281.1Sitojun		data = mtod(m, u_char *);
8291.1Sitojun		len4 = len >> 2;
8301.1Sitojun		data4 = (u_int32_t *)data;
8311.1Sitojun		for (i = 0; i < len4; i++)
8321.1Sitojun			data4[i] = NIC_GET_4(sc, REG_DATA);
8331.1Sitojun		for (i = len4 << 2; i < len; i++)
8341.1Sitojun			data[i] = NIC_GET_1(sc, REG_DATA);
8351.1Sitojun
8361.1Sitojun		datalen -= len;
8371.1Sitojun		*mp = m;
8381.1Sitojun		mp = &m->m_next;
8391.1Sitojun	}
8401.1Sitojun
8411.1Sitojun	return (top);
8421.1Sitojun}
843