Beispiel #1
0
static int
settunnel(prop_dictionary_t env, prop_dictionary_t oenv)
{
	const struct paddr_prefix *srcpfx, *dstpfx;
	struct if_laddrreq req;
	prop_data_t srcdata, dstdata;

	srcdata = (prop_data_t)prop_dictionary_get(env, "tunsrc");
	dstdata = (prop_data_t)prop_dictionary_get(env, "tundst");

	if (srcdata == NULL || dstdata == NULL) {
		warnx("%s.%d", __func__, __LINE__);
		errno = ENOENT;
		return -1;
	}

	srcpfx = prop_data_data_nocopy(srcdata);
	dstpfx = prop_data_data_nocopy(dstdata);

	if (srcpfx->pfx_addr.sa_family != dstpfx->pfx_addr.sa_family)
		errx(EXIT_FAILURE,
		    "source and destination address families do not match");

	memset(&req, 0, sizeof(req));
	memcpy(&req.addr, &srcpfx->pfx_addr,
	    MIN(sizeof(req.addr), srcpfx->pfx_addr.sa_len));
	memcpy(&req.dstaddr, &dstpfx->pfx_addr,
	    MIN(sizeof(req.dstaddr), dstpfx->pfx_addr.sa_len));

#ifdef INET6
	if (req.addr.ss_family == AF_INET6) {
		struct sockaddr_in6 *s6, *d;

		s6 = (struct sockaddr_in6 *)&req.addr;
		d = (struct sockaddr_in6 *)&req.dstaddr;
		if (s6->sin6_scope_id != d->sin6_scope_id) {
			errx(EXIT_FAILURE, "scope mismatch");
			/* NOTREACHED */
		}
		if (IN6_IS_ADDR_MULTICAST(&d->sin6_addr) ||
		    IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
			errx(EXIT_FAILURE, "tunnel src/dst is multicast");
		/* embed scopeid */
		if (s6->sin6_scope_id &&
		    IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) {
			*(u_int16_t *)&s6->sin6_addr.s6_addr[2] =
			    htons(s6->sin6_scope_id);
		}
		if (d->sin6_scope_id && IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr)) {
			*(u_int16_t *)&d->sin6_addr.s6_addr[2] =
			    htons(d->sin6_scope_id);
		}
	}
#endif /* INET6 */

	if (direct_ioctl(env, SIOCSLIFPHYADDR, &req) == -1)
		warn("SIOCSLIFPHYADDR");
	return 0;
}
Beispiel #2
0
/*
 * return appropriate mode for HID descriptor
 */
const char *
hid_mode(prop_data_t desc)
{
	report_desc_t r;
	hid_data_t d;
	struct hid_item h;
	const char *mode;

	hid_init(NULL);

	mode = BTDEVauth;	/* default */

	r = hid_use_report_desc(prop_data_data_nocopy(desc),
				prop_data_size(desc));
	if (r == NULL)
		err(EXIT_FAILURE, "hid_use_report_desc");

	d = hid_start_parse(r, ~0, -1);
	while (hid_get_item(d, &h) > 0) {
		if (h.kind == hid_collection
		    && HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP
		    && HID_USAGE(h.usage) == HUG_KEYBOARD)
			mode = BTDEVencrypt;
	}

	hid_end_parse(d);
	hid_dispose_report_desc(r);

	return mode;
}
Beispiel #3
0
static int __noinline
npf_mk_ncode(prop_object_t obj, void **code, size_t *csize,
    prop_dictionary_t errdict)
{
	const void *ncptr;
	int nc_err, errat;
	size_t nc_size;
	void *nc;

	/*
	 * Allocate, copy and validate n-code. XXX: Inefficient.
	 */
	ncptr = prop_data_data_nocopy(obj);
	nc_size = prop_data_size(obj);
	if (ncptr == NULL || nc_size > NPF_NCODE_LIMIT) {
		NPF_ERR_DEBUG(errdict);
		return ERANGE;
	}
	nc = npf_ncode_alloc(nc_size);
	if (nc == NULL) {
		NPF_ERR_DEBUG(errdict);
		return ENOMEM;
	}
	memcpy(nc, ncptr, nc_size);
	nc_err = npf_ncode_validate(nc, nc_size, &errat);
	if (nc_err) {
		npf_ncode_free(nc, nc_size);
		prop_dictionary_set_int32(errdict, "ncode-error", nc_err);
		prop_dictionary_set_int32(errdict, "ncode-errat", errat);
		return EINVAL;
	}
	*code = nc;
	*csize = nc_size;
	return 0;
}
Beispiel #4
0
static void
epe_attach(device_t parent, device_t self, void *aux)
{
	struct epe_softc		*sc = device_private(self);
	struct epsoc_attach_args	*sa;
	prop_data_t			 enaddr;

	aprint_normal("\n");
	sa = aux;
	sc->sc_dev = self;
	sc->sc_iot = sa->sa_iot;
	sc->sc_intr = sa->sa_intr;
	sc->sc_dmat = sa->sa_dmat;

	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 
		0, &sc->sc_ioh))
		panic("%s: Cannot map registers", device_xname(self));

	/* Fetch the Ethernet address from property if set. */
	enaddr = prop_dictionary_get(device_properties(self), "mac-address");
	if (enaddr != NULL) {
		KASSERT(prop_object_type(enaddr) == PROP_TYPE_DATA);
		KASSERT(prop_data_size(enaddr) == ETHER_ADDR_LEN);
		memcpy(sc->sc_enaddr, prop_data_data_nocopy(enaddr),
		       ETHER_ADDR_LEN);
		bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPE_AFP, 0);
		bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, EPE_IndAd,
					 sc->sc_enaddr, ETHER_ADDR_LEN);
	}

        ep93xx_intr_establish(sc->sc_intr, IPL_NET, epe_intr, sc);
	epe_init(sc);
}
Beispiel #5
0
static int __noinline
npf_mk_table_entries(npf_table_t *t, prop_array_t entries)
{
	prop_object_iterator_t eit;
	prop_dictionary_t ent;
	int error = 0;

	if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
		return EINVAL;
	}
	eit = prop_array_iterator(entries);
	while ((ent = prop_object_iterator_next(eit)) != NULL) {
		const npf_addr_t *addr;
		npf_netmask_t mask;
		int alen;

		/* Get address and mask.  Add a table entry. */
		prop_object_t obj = prop_dictionary_get(ent, "addr");
		addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
		prop_dictionary_get_uint8(ent, "mask", &mask);
		alen = prop_data_size(obj);

		error = npf_table_insert(t, alen, addr, mask);
		if (error)
			break;
	}
	prop_object_iterator_release(eit);
	return error;
}
Beispiel #6
0
static int __noinline
npf_mk_code(prop_object_t obj, int type, void **code, size_t *csize,
    prop_dictionary_t errdict)
{
	const void *cptr;
	size_t clen;
	void *bc;

	if (type != NPF_CODE_BPF) {
		return ENOTSUP;
	}
	cptr = prop_data_data_nocopy(obj);
	if (cptr == NULL || (clen = prop_data_size(obj)) == 0) {
		NPF_ERR_DEBUG(errdict);
		return EINVAL;
	}
	if (!npf_bpf_validate(cptr, clen)) {
		NPF_ERR_DEBUG(errdict);
		return EINVAL;
	}
	bc = kmem_alloc(clen, KM_SLEEP);
	memcpy(bc, cptr, clen);

	*code = bc;
	*csize = clen;
	return 0;
}
Beispiel #7
0
const void *
npf_rule_getinfo(nl_rule_t *rl, size_t *len)
{
	prop_dictionary_t rldict = rl->nrl_dict;
	prop_object_t obj = prop_dictionary_get(rldict, "info");

	*len = prop_data_size(obj);
	return prop_data_data_nocopy(obj);
}
Beispiel #8
0
void
npf_nat_getmap(nl_nat_t *nt, npf_addr_t *addr, size_t *alen, in_port_t *port)
{
	prop_dictionary_t rldict = nt->nrl_dict;
	prop_object_t obj = prop_dictionary_get(rldict, "translation-ip");

	*alen = prop_data_size(obj);
	memcpy(addr, prop_data_data_nocopy(obj), *alen);

	*port = 0;
	prop_dictionary_get_uint16(rldict, "translation-port", port);
}
Beispiel #9
0
static void
emac_attach(device_t parent, device_t self, void *aux)
{
	struct emac_softc		*sc = device_private(self);
	struct at91bus_attach_args	*sa = aux;
	prop_data_t			enaddr;
	uint32_t			u;

	printf("\n");
	sc->sc_dev = self;
	sc->sc_iot = sa->sa_iot;
	sc->sc_pid = sa->sa_pid;
	sc->sc_dmat = sa->sa_dmat;

	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh))
		panic("%s: Cannot map registers", device_xname(self));

	/* enable peripheral clock */
	at91_peripheral_clock(sc->sc_pid, 1);

	/* configure emac: */
	EMAC_WRITE(ETH_CTL, 0);			// disable everything
	EMAC_WRITE(ETH_IDR, -1);		// disable interrupts
	EMAC_WRITE(ETH_RBQP, 0);		// clear receive
	EMAC_WRITE(ETH_CFG, ETH_CFG_CLK_32 | ETH_CFG_SPD | ETH_CFG_FD | ETH_CFG_BIG);
	EMAC_WRITE(ETH_TCR, 0);			// send nothing
	//(void)EMAC_READ(ETH_ISR);
	u = EMAC_READ(ETH_TSR);
	EMAC_WRITE(ETH_TSR, (u & (ETH_TSR_UND | ETH_TSR_COMP | ETH_TSR_BNQ
				  | ETH_TSR_IDLE | ETH_TSR_RLE
				  | ETH_TSR_COL|ETH_TSR_OVR)));
	u = EMAC_READ(ETH_RSR);
	EMAC_WRITE(ETH_RSR, (u & (ETH_RSR_OVR|ETH_RSR_REC|ETH_RSR_BNA)));

	/* Fetch the Ethernet address from property if set. */
	enaddr = prop_dictionary_get(device_properties(self), "mac-addr");

	if (enaddr != NULL) {
		KASSERT(prop_object_type(enaddr) == PROP_TYPE_DATA);
		KASSERT(prop_data_size(enaddr) == ETHER_ADDR_LEN);
		memcpy(sc->sc_enaddr, prop_data_data_nocopy(enaddr),
		       ETHER_ADDR_LEN);
	} else {
		static const uint8_t hardcoded[ETHER_ADDR_LEN] = {
		  0x00, 0x0d, 0x10, 0x81, 0x0c, 0x94
		};
		memcpy(sc->sc_enaddr, hardcoded, ETHER_ADDR_LEN);
	}

        at91_intr_establish(sc->sc_pid, IPL_NET, INTR_HIGH_LEVEL, emac_intr, sc);
	emac_init(sc);
}
Beispiel #10
0
ssize_t
getargstr(prop_dictionary_t env, const char *key, char *buf, size_t buflen)
{
	prop_data_t data;
	size_t datalen;

	data = (prop_data_t)prop_dictionary_get(env, key);
	if (data == NULL) {
		errno = ENOENT;
		return -1;
	}
	datalen = prop_data_size(data);
	if (datalen >= buflen) {
		errno = ENAMETOOLONG; 
		return -1;
	}
	memset(buf, 0, buflen);
	memcpy(buf, prop_data_data_nocopy(data), datalen);
	return datalen;
}
int
wsdisplayio_get_edid(device_t dev, struct wsdisplayio_edid_info *d)
{
	prop_data_t edid_data;
	int edid_size;

	edid_data = prop_dictionary_get(device_properties(dev), "EDID");
	if (edid_data != NULL) {
		edid_size = prop_data_size(edid_data);
		/* less than 128 bytes is bogus */
		if (edid_size < 128)
			return ENODEV;
		d->data_size = edid_size;
		if (d->buffer_size < edid_size)
			return EAGAIN;
		return copyout(prop_data_data_nocopy(edid_data),
			       d->edid_data, edid_size);
	}
	return ENODEV;
}
/* ARGSUSED */
static void
smsh_axi_attach(device_t parent, device_t self, void *aux)
{
	struct lan9118_softc *sc = device_private(self);
	struct axi_attach_args *aa = aux;
	prop_dictionary_t dict = device_properties(self);
	void *ih;

	sc->sc_dev = self;

	/*
	 * Prefer the Ethernet address in device properties.
	 */
	prop_data_t ea = prop_dictionary_get(dict, "mac-address");
	if (ea != NULL) {
		KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
		KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
		memcpy(sc->sc_enaddr, prop_data_data_nocopy(ea),
		    ETHER_ADDR_LEN);
		sc->sc_flags |= LAN9118_FLAGS_NO_EEPROM;
	}
	/* Map i/o space. */
	if (bus_space_map(aa->aa_iot, aa->aa_addr, LAN9118_IOSIZE, 0,
		&sc->sc_ioh))
		panic("smsh_axi_attach: can't map i/o space");
	sc->sc_iot = aa->aa_iot;

	if (lan9118_attach(sc) != 0) {
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, LAN9118_IOSIZE);
		return;
	}
	/* Establish the interrupt handler. */
	ih = intr_establish(aa->aa_irq, IPL_NET, IST_LEVEL,
	    lan9118_intr, sc);
	if (ih == NULL) {
		aprint_error_dev(self,
		    "couldn't establish interrupt handler\n");
		bus_space_unmap(sc->sc_iot, sc->sc_ioh, LAN9118_IOSIZE);
		return;
	}
}
Beispiel #13
0
int
setcarp_passwd(prop_dictionary_t env, prop_dictionary_t oenv)
{
    struct carpreq carpr;
    prop_data_t data;

    data = (prop_data_t)prop_dictionary_get(env, "pass");
    if (data == NULL) {
        errno = ENOENT;
        return -1;
    }

    carp_get(env, &carpr);

    memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key));
    /* XXX Should hash the password into the key here, perhaps? */
    strlcpy((char *)carpr.carpr_key, prop_data_data_nocopy(data),
            MIN(CARP_KEY_LEN, prop_data_size(data)));

    carp_set(env, &carpr);
    return 0;
}
static int
bthub_print(void *aux, const char *pnp)
{
	prop_dictionary_t dict = aux;
	prop_object_t obj;
	const bdaddr_t *raddr;

	if (pnp != NULL) {
		obj = prop_dictionary_get(dict, BTDEVtype);
		aprint_normal("%s: %s '%s',", pnp, BTDEVtype,
					prop_string_cstring_nocopy(obj));
	}

	obj = prop_dictionary_get(dict, BTDEVraddr);
	raddr = prop_data_data_nocopy(obj);

	aprint_verbose(" %s %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
			BTDEVraddr,
			raddr->b[5], raddr->b[4], raddr->b[3],
			raddr->b[2], raddr->b[1], raddr->b[0]);

	return UNCONF;
}
static int
bthub_pioctl(dev_t devno, unsigned long cmd, prop_dictionary_t dict,
    int flag, struct lwp *l)
{
	prop_data_t laddr, raddr;
	prop_string_t service;
	prop_dictionary_t prop;
	prop_object_t obj;
	device_t dev, self;
	deviter_t di;
	int unit;

	/* validate local address */
	laddr = prop_dictionary_get(dict, BTDEVladdr);
	if (prop_data_size(laddr) != sizeof(bdaddr_t))
		return EINVAL;

	/* locate the relevant bthub */
	for (unit = 0 ; ; unit++) {
		if (unit == bthub_cd.cd_ndevs)
			return ENXIO;

		self = device_lookup(&bthub_cd, unit);
		if (self == NULL)
			continue;

		prop = device_properties(self);
		obj = prop_dictionary_get(prop, BTDEVladdr);
		if (prop_data_equals(laddr, obj))
			break;
	}

	/* validate remote address */
	raddr = prop_dictionary_get(dict, BTDEVraddr);
	if (prop_data_size(raddr) != sizeof(bdaddr_t)
	    || bdaddr_any(prop_data_data_nocopy(raddr)))
		return EINVAL;

	/* validate service name */
	service = prop_dictionary_get(dict, BTDEVservice);
	if (prop_object_type(service) != PROP_TYPE_STRING)
		return EINVAL;

	/* locate matching child device, if any */
	deviter_init(&di, 0);
	while ((dev = deviter_next(&di)) != NULL) {
		if (device_parent(dev) != self)
			continue;

		prop = device_properties(dev);

		obj = prop_dictionary_get(prop, BTDEVraddr);
		if (!prop_object_equals(raddr, obj))
			continue;

		obj = prop_dictionary_get(prop, BTDEVservice);
		if (!prop_object_equals(service, obj))
			continue;

		break;
	}
	deviter_release(&di);

	switch (cmd) {
	case BTDEV_ATTACH:	/* attach BTDEV */
		if (dev != NULL)
			return EADDRINUSE;

		dev = config_found(self, dict, bthub_print);
		if (dev == NULL)
			return ENXIO;

		prop = device_properties(dev);
		prop_dictionary_set(prop, BTDEVladdr, laddr);
		prop_dictionary_set(prop, BTDEVraddr, raddr);
		prop_dictionary_set(prop, BTDEVservice, service);
		break;

	case BTDEV_DETACH:	/* detach BTDEV */
		if (dev == NULL)
			return ENXIO;

		config_detach(dev, DETACH_FORCE);
		break;
	}

	return 0;
}
Beispiel #16
0
/*
 * ae_attach:
 *
 *	Attach an ae interface to the system.
 */
void
ae_attach(device_t parent, device_t self, void *aux)
{
	const uint8_t *enaddr;
	prop_data_t ea;
	struct ae_softc *sc = device_private(self);
	struct arbus_attach_args *aa = aux;
	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
	int i, error;

	sc->sc_dev = self;

	callout_init(&sc->sc_tick_callout, 0);

	printf(": Atheros AR531X 10/100 Ethernet\n");

	/*
	 * Try to get MAC address.
	 */
	ea = prop_dictionary_get(device_properties(sc->sc_dev), "mac-address");
	if (ea == NULL) {
		printf("%s: unable to get mac-addr property\n",
		    device_xname(sc->sc_dev));
		return;
	}
	KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
	KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
	enaddr = prop_data_data_nocopy(ea);

	/* Announce ourselves. */
	printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev),
	    ether_sprintf(enaddr));

	sc->sc_cirq = aa->aa_cirq;
	sc->sc_mirq = aa->aa_mirq;
	sc->sc_st = aa->aa_bst;
	sc->sc_dmat = aa->aa_dmat;

	SIMPLEQ_INIT(&sc->sc_txfreeq);
	SIMPLEQ_INIT(&sc->sc_txdirtyq);

	/*
	 * Map registers.
	 */
	sc->sc_size = aa->aa_size;
	if ((error = bus_space_map(sc->sc_st, aa->aa_addr, sc->sc_size, 0,
	    &sc->sc_sh)) != 0) {
		printf("%s: unable to map registers, error = %d\n",
		    device_xname(sc->sc_dev), error);
		goto fail_0;
	}

	/*
	 * Allocate the control data structures, and create and load the
	 * DMA map for it.
	 */
	if ((error = bus_dmamem_alloc(sc->sc_dmat,
	    sizeof(struct ae_control_data), PAGE_SIZE, 0, &sc->sc_cdseg,
	    1, &sc->sc_cdnseg, 0)) != 0) {
		printf("%s: unable to allocate control data, error = %d\n",
		    device_xname(sc->sc_dev), error);
		goto fail_1;
	}

	if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg,
	    sizeof(struct ae_control_data), (void **)&sc->sc_control_data,
	    BUS_DMA_COHERENT)) != 0) {
		printf("%s: unable to map control data, error = %d\n",
		    device_xname(sc->sc_dev), error);
		goto fail_2;
	}

	if ((error = bus_dmamap_create(sc->sc_dmat,
	    sizeof(struct ae_control_data), 1,
	    sizeof(struct ae_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
		printf("%s: unable to create control data DMA map, "
		    "error = %d\n", device_xname(sc->sc_dev), error);
		goto fail_3;
	}

	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
	    sc->sc_control_data, sizeof(struct ae_control_data), NULL,
	    0)) != 0) {
		printf("%s: unable to load control data DMA map, error = %d\n",
		    device_xname(sc->sc_dev), error);
		goto fail_4;
	}

	/*
	 * Create the transmit buffer DMA maps.
	 */
	for (i = 0; i < AE_TXQUEUELEN; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    AE_NTXSEGS, MCLBYTES, 0, 0,
		    &sc->sc_txsoft[i].txs_dmamap)) != 0) {
			printf("%s: unable to create tx DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			goto fail_5;
		}
	}

	/*
	 * Create the receive buffer DMA maps.
	 */
	for (i = 0; i < AE_NRXDESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, 0, &sc->sc_rxsoft[i].rxs_dmamap)) != 0) {
			printf("%s: unable to create rx DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			goto fail_6;
		}
		sc->sc_rxsoft[i].rxs_mbuf = NULL;
	}

	/*
	 * Reset the chip to a known state.
	 */
	ae_reset(sc);

	/*
	 * From this point forward, the attachment cannot fail.  A failure
	 * before this point releases all resources that may have been
	 * allocated.
	 */
	sc->sc_flags |= AE_ATTACHED;

	/*
	 * Initialize our media structures.  This may probe the MII, if
	 * present.
	 */
	sc->sc_mii.mii_ifp = ifp;
	sc->sc_mii.mii_readreg = ae_mii_readreg;
	sc->sc_mii.mii_writereg = ae_mii_writereg;
	sc->sc_mii.mii_statchg = ae_mii_statchg;
	sc->sc_ethercom.ec_mii = &sc->sc_mii;
	ifmedia_init(&sc->sc_mii.mii_media, 0, ether_mediachange,
	    ether_mediastatus);
	mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
	    MII_OFFSET_ANY, 0);

	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
	} else
		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);

	sc->sc_tick = ae_mii_tick;

	strcpy(ifp->if_xname, device_xname(sc->sc_dev));
	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	sc->sc_if_flags = ifp->if_flags;
	ifp->if_ioctl = ae_ioctl;
	ifp->if_start = ae_start;
	ifp->if_watchdog = ae_watchdog;
	ifp->if_init = ae_init;
	ifp->if_stop = ae_stop;
	IFQ_SET_READY(&ifp->if_snd);

	/*
	 * We can support 802.1Q VLAN-sized frames.
	 */
	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;

	/*
	 * Attach the interface.
	 */
	if_attach(ifp);
	ether_ifattach(ifp, enaddr);
	ether_set_ifflags_cb(&sc->sc_ethercom, ae_ifflags_cb);

	rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dev),
	    RND_TYPE_NET, RND_FLAG_DEFAULT);

	/*
	 * Make sure the interface is shutdown during reboot.
	 */
	sc->sc_sdhook = shutdownhook_establish(ae_shutdown, sc);
	if (sc->sc_sdhook == NULL)
		printf("%s: WARNING: unable to establish shutdown hook\n",
		    device_xname(sc->sc_dev));

	/*
	 * Add a suspend hook to make sure we come back up after a
	 * resume.
	 */
	sc->sc_powerhook = powerhook_establish(device_xname(sc->sc_dev),
	    ae_power, sc);
	if (sc->sc_powerhook == NULL)
		printf("%s: WARNING: unable to establish power hook\n",
		    device_xname(sc->sc_dev));
	return;

	/*
	 * Free any resources we've allocated during the failed attach
	 * attempt.  Do this in reverse order and fall through.
	 */
 fail_6:
	for (i = 0; i < AE_NRXDESC; i++) {
		if (sc->sc_rxsoft[i].rxs_dmamap != NULL)
			bus_dmamap_destroy(sc->sc_dmat,
			    sc->sc_rxsoft[i].rxs_dmamap);
	}
 fail_5:
	for (i = 0; i < AE_TXQUEUELEN; i++) {
		if (sc->sc_txsoft[i].txs_dmamap != NULL)
			bus_dmamap_destroy(sc->sc_dmat,
			    sc->sc_txsoft[i].txs_dmamap);
	}
	bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
 fail_4:
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
 fail_3:
	bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data,
	    sizeof(struct ae_control_data));
 fail_2:
	bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg);
 fail_1:
	bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_size);
 fail_0:
	return;
}
Beispiel #17
0
static int __noinline
npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
    prop_dictionary_t errdict)
{
	prop_object_iterator_t it;
	prop_dictionary_t tbldict;
	int error = 0;

	/* Tables - array. */
	if (prop_object_type(tables) != PROP_TYPE_ARRAY) {
		NPF_ERR_DEBUG(errdict);
		return EINVAL;
	}

	it = prop_array_iterator(tables);
	while ((tbldict = prop_object_iterator_next(it)) != NULL) {
		prop_dictionary_t ent;
		prop_object_iterator_t eit;
		prop_array_t entries;
		npf_table_t *t;
		u_int tid;
		int type;

		/* Table - dictionary. */
		if (prop_object_type(tbldict) != PROP_TYPE_DICTIONARY) {
			NPF_ERR_DEBUG(errdict);
			error = EINVAL;
			break;
		}

		/* Table ID and type. */
		prop_dictionary_get_uint32(tbldict, "id", &tid);
		prop_dictionary_get_int32(tbldict, "type", &type);

		/* Validate them, check for duplicate IDs. */
		error = npf_table_check(tblset, tid, type);
		if (error)
			break;

		/* Create and insert the table. */
		t = npf_table_create(tid, type, 1024);	/* XXX */
		if (t == NULL) {
			NPF_ERR_DEBUG(errdict);
			error = ENOMEM;
			break;
		}
		error = npf_tableset_insert(tblset, t);
		KASSERT(error == 0);

		/* Entries. */
		entries = prop_dictionary_get(tbldict, "entries");
		if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
			NPF_ERR_DEBUG(errdict);
			error = EINVAL;
			break;
		}
		eit = prop_array_iterator(entries);
		while ((ent = prop_object_iterator_next(eit)) != NULL) {
			const npf_addr_t *addr;
			npf_netmask_t mask;
			int alen;

			/* Get address and mask.  Add a table entry. */
			prop_object_t obj = prop_dictionary_get(ent, "addr");
			addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
			prop_dictionary_get_uint8(ent, "mask", &mask);
			alen = prop_data_size(obj);

			error = npf_table_insert(tblset, tid, alen, addr, mask);
			if (error)
				break;
		}
		prop_object_iterator_release(eit);
		if (error)
			break;
	}
	prop_object_iterator_release(it);
	/*
	 * Note: in a case of error, caller will free the tableset.
	 */
	return error;
}
Beispiel #18
0
static void
btsco_attach(device_t parent, device_t self, void *aux)
{
	struct btsco_softc *sc = device_private(self);
	prop_dictionary_t dict = aux;
	prop_object_t obj;

	/*
	 * Init softc
	 */
	sc->sc_vgs = 200;
	sc->sc_vgm = 200;
	sc->sc_state = BTSCO_CLOSED;
	sc->sc_name = device_xname(self);
	cv_init(&sc->sc_connect, "connect");
	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);

	/*
	 * copy in our configuration info
	 */
	obj = prop_dictionary_get(dict, BTDEVladdr);
	bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVraddr);
	bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVservice);
	if (prop_string_equals_cstring(obj, "HF")) {
		sc->sc_flags |= BTSCO_LISTEN;
		aprint_verbose(" listen mode");
	}

	obj = prop_dictionary_get(dict, BTSCOchannel);
	if (prop_object_type(obj) != PROP_TYPE_NUMBER
	    || prop_number_integer_value(obj) < RFCOMM_CHANNEL_MIN
	    || prop_number_integer_value(obj) > RFCOMM_CHANNEL_MAX) {
		aprint_error(" invalid %s", BTSCOchannel);
		return;
	}
	sc->sc_channel = prop_number_integer_value(obj);

	aprint_verbose(" channel %d", sc->sc_channel);
	aprint_normal("\n");

	DPRINTF("sc=%p\n", sc);

	/*
	 * set up transmit interrupt
	 */
	sc->sc_intr = softint_establish(SOFTINT_NET, btsco_intr, sc);
	if (sc->sc_intr == NULL) {
		aprint_error_dev(self, "softint_establish failed\n");
		return;
	}

	/*
	 * attach audio device
	 */
	sc->sc_audio = audio_attach_mi(&btsco_if, sc, self);
	if (sc->sc_audio == NULL) {
		aprint_error_dev(self, "audio_attach_mi failed\n");
		return;
	}

	pmf_device_register(self, NULL, NULL);
}
static void
tlp_pci_attach(device_t parent, device_t self, void *aux)
{
	struct tulip_pci_softc *psc = device_private(self);
	struct tulip_softc *sc = &psc->sc_tulip;
	struct pci_attach_args *pa = aux;
	pci_chipset_tag_t pc = pa->pa_pc;
	pci_intr_handle_t ih;
	const char *intrstr = NULL;
	bus_space_tag_t iot, memt;
	bus_space_handle_t ioh, memh;
	int ioh_valid, memh_valid, i, j;
	const struct tulip_pci_product *tpp;
	prop_data_t ea;
	uint8_t enaddr[ETHER_ADDR_LEN];
	uint32_t val = 0;
	pcireg_t reg;
	int error;
	bus_size_t iosize = 0, memsize = 0;

	sc->sc_dev = self;
	sc->sc_devno = pa->pa_device;
	psc->sc_pc = pa->pa_pc;
	psc->sc_pcitag = pa->pa_tag;

	LIST_INIT(&psc->sc_intrslaves);

	tpp = tlp_pci_lookup(pa);
	if (tpp == NULL) {
		printf("\n");
		panic("tlp_pci_attach: impossible");
	}
	sc->sc_chip = tpp->tpp_chip;

	/*
	 * By default, Tulip registers are 8 bytes long (4 bytes
	 * followed by a 4 byte pad).
	 */
	sc->sc_regshift = 3;

	/*
	 * No power management hooks.
	 * XXX Maybe we should add some!
	 */
	sc->sc_flags |= TULIPF_ENABLED;

	/*
	 * Get revision info, and set some chip-specific variables.
	 */
	sc->sc_rev = PCI_REVISION(pa->pa_class);
	switch (sc->sc_chip) {
	case TULIP_CHIP_21140:
		if (sc->sc_rev >= 0x20)
			sc->sc_chip = TULIP_CHIP_21140A;
		break;

	case TULIP_CHIP_21142:
		if (sc->sc_rev >= 0x20)
			sc->sc_chip = TULIP_CHIP_21143;
		break;

	case TULIP_CHIP_82C168:
		if (sc->sc_rev >= 0x20)
			sc->sc_chip = TULIP_CHIP_82C169;
		break;

	case TULIP_CHIP_MX98713:
		if (sc->sc_rev >= 0x10)
			sc->sc_chip = TULIP_CHIP_MX98713A;
		break;

	case TULIP_CHIP_MX98715:
		if (sc->sc_rev >= 0x20)
			sc->sc_chip = TULIP_CHIP_MX98715A;
		if (sc->sc_rev >= 0x25)
			sc->sc_chip = TULIP_CHIP_MX98715AEC_X;
		if (sc->sc_rev >= 0x30)
			sc->sc_chip = TULIP_CHIP_MX98725;
		break;

	case TULIP_CHIP_WB89C840F:
		sc->sc_regshift = 2;
		break;

	case TULIP_CHIP_AN985:
		/*
		 * The AN983 and AN985 are very similar, and are
		 * differentiated by a "signature" register that
		 * is like, but not identical, to a PCI ID register.
		 */
		reg = pci_conf_read(pc, pa->pa_tag, 0x80);
		switch (reg) {
		case 0x09811317:
			sc->sc_chip = TULIP_CHIP_AN985;
			break;

		case 0x09851317:
			sc->sc_chip = TULIP_CHIP_AN983;
			break;

		default:
			/* Unknown -- use default. */
			break;
		}
		break;

	case TULIP_CHIP_AX88140:
		if (sc->sc_rev >= 0x10)
			sc->sc_chip = TULIP_CHIP_AX88141;
		break;

	case TULIP_CHIP_DM9102:
		if (sc->sc_rev >= 0x30)
			sc->sc_chip = TULIP_CHIP_DM9102A;
		break;

	default:
		/* Nothing. */
		break;
	}

	aprint_normal(": %s Ethernet, pass %d.%d\n",
	    tlp_chip_name(sc->sc_chip),
	    (sc->sc_rev >> 4) & 0xf, sc->sc_rev & 0xf);

	switch (sc->sc_chip) {
	case TULIP_CHIP_21040:
		if (sc->sc_rev < 0x20) {
			aprint_normal_dev(self,
			    "21040 must be at least pass 2.0\n");
			return;
		}
		break;

	case TULIP_CHIP_21140:
		if (sc->sc_rev < 0x11) {
			aprint_normal_dev(self,
			    "21140 must be at least pass 1.1\n");
			return;
		}
		break;

	default:
		/* Nothing. */
		break;
	}

	/*
	 * Check to see if the device is in power-save mode, and
	 * being it out if necessary.
	 */
	switch (sc->sc_chip) {
	case TULIP_CHIP_21140:
	case TULIP_CHIP_21140A:
	case TULIP_CHIP_21142:
	case TULIP_CHIP_21143:
	case TULIP_CHIP_MX98713A:
	case TULIP_CHIP_MX98715:
	case TULIP_CHIP_MX98715A:
	case TULIP_CHIP_MX98715AEC_X:
	case TULIP_CHIP_MX98725:
	case TULIP_CHIP_DM9102:
	case TULIP_CHIP_DM9102A:
	case TULIP_CHIP_AX88140:
	case TULIP_CHIP_AX88141:
	case TULIP_CHIP_RS7112:
		/*
		 * Clear the "sleep mode" bit in the CFDA register.
		 */
		reg = pci_conf_read(pc, pa->pa_tag, TULIP_PCI_CFDA);
		if (reg & (CFDA_SLEEP|CFDA_SNOOZE))
			pci_conf_write(pc, pa->pa_tag, TULIP_PCI_CFDA,
			    reg & ~(CFDA_SLEEP|CFDA_SNOOZE));
		break;

	default:
		/* Nothing. */
		break;
	}

	/* power up chip */
	if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self,
	    NULL)) && error != EOPNOTSUPP) {
		aprint_error_dev(self, "cannot activate %d\n",
		    error);
		return;
	}

	/*
	 * Map the device.
	 */

	ioh_valid = (pci_mapreg_map(pa, TULIP_PCI_IOBA,
	    PCI_MAPREG_TYPE_IO, 0,
	    &iot, &ioh, NULL, &iosize) == 0);
	memh_valid = (pci_mapreg_map(pa, TULIP_PCI_MMBA,
	    PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
	    &memt, &memh, NULL, &memsize) == 0);
	if (memh_valid) {
		sc->sc_st = memt;
		sc->sc_sh = memh;
		psc->sc_mapsize = memsize;
		if (ioh_valid) {
			bus_space_unmap(iot, ioh, iosize);
			ioh_valid = 0;
		}
	} else if (ioh_valid) {
		sc->sc_st = iot;
		sc->sc_sh = ioh;
		psc->sc_mapsize = iosize;
		if (memh_valid) {
			bus_space_unmap(memt, memh, memsize);
			memh_valid = 0;
		}
	} else {
		aprint_error_dev(self, "unable to map device registers\n");
		goto fail;
	}

	sc->sc_dmat = pa->pa_dmat;

	/*
	 * Make sure bus mastering is enabled.
	 */
	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
	    pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) |
	    PCI_COMMAND_MASTER_ENABLE);

	/*
	 * Get the cacheline size.
	 */
	sc->sc_cacheline = PCI_CACHELINE(pci_conf_read(pc, pa->pa_tag,
	    PCI_BHLC_REG));

	/*
	 * Get PCI data moving command info.
	 */
	if (pa->pa_flags & PCI_FLAGS_MRL_OKAY)
		sc->sc_flags |= TULIPF_MRL;
	if (pa->pa_flags & PCI_FLAGS_MRM_OKAY)
		sc->sc_flags |= TULIPF_MRM;
	if (pa->pa_flags & PCI_FLAGS_MWI_OKAY)
		sc->sc_flags |= TULIPF_MWI;

	/*
	 * Read the contents of the Ethernet Address ROM/SROM.
	 */
	switch (sc->sc_chip) {
	case TULIP_CHIP_21040:
		sc->sc_srom_addrbits = 6;
		sc->sc_srom = malloc(TULIP_ROM_SIZE(6), M_DEVBUF, M_NOWAIT);
		TULIP_WRITE(sc, CSR_MIIROM, MIIROM_SROMCS);
		for (i = 0; i < TULIP_ROM_SIZE(6); i++) {
			for (j = 0; j < 10000; j++) {
				val = TULIP_READ(sc, CSR_MIIROM);
				if ((val & MIIROM_DN) == 0)
					break;
			}
			sc->sc_srom[i] = val & MIIROM_DATA;
		}
		break;

	case TULIP_CHIP_82C168:
	case TULIP_CHIP_82C169:
	    {
		sc->sc_srom_addrbits = 2;
		sc->sc_srom = malloc(TULIP_ROM_SIZE(2), M_DEVBUF, M_NOWAIT);

		/*
		 * The Lite-On PNIC stores the Ethernet address in
		 * the first 3 words of the EEPROM.  EEPROM access
		 * is not like the other Tulip chips.
		 */
		for (i = 0; i < 6; i += 2) {
			TULIP_WRITE(sc, CSR_PNIC_SROMCTL,
			    PNIC_SROMCTL_READ | (i >> 1));
			for (j = 0; j < 500; j++) {
				delay(2);
				val = TULIP_READ(sc, CSR_MIIROM);
				if ((val & PNIC_MIIROM_BUSY) == 0)
					break;
			}
			if (val & PNIC_MIIROM_BUSY) {
				aprint_error_dev(self, "EEPROM timed out\n");
				goto fail;
			}
			val &= PNIC_MIIROM_DATA;
			sc->sc_srom[i] = val >> 8;
			sc->sc_srom[i + 1] = val & 0xff;
		}
		break;
	    }

	default:
		/*
		 * XXX This isn't quite the right way to do this; we should
		 * XXX be attempting to fetch the mac-addr property in the
		 * XXX bus-agnostic part of the driver independently.  But
		 * XXX that requires a larger change in the SROM handling
		 * XXX logic, and for now we can at least remove a machine-
		 * XXX dependent wart from the PCI front-end.
		 */
		ea = prop_dictionary_get(device_properties(self),
					 "mac-address");
		if (ea != NULL) {
			extern int tlp_srom_debug;
			KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
			KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);

			memcpy(enaddr, prop_data_data_nocopy(ea),
			       ETHER_ADDR_LEN);

			sc->sc_srom_addrbits = 6;
			sc->sc_srom = malloc(TULIP_ROM_SIZE(6), M_DEVBUF,
			    M_NOWAIT|M_ZERO);
			memcpy(sc->sc_srom, enaddr, sizeof(enaddr));
			if (tlp_srom_debug) {
				aprint_normal("SROM CONTENTS:");
				for (i = 0; i < TULIP_ROM_SIZE(6); i++) {
					if ((i % 8) == 0)
						aprint_normal("\n\t");
					aprint_normal("0x%02x ", sc->sc_srom[i]);
				}
				aprint_normal("\n");
			}
			break;
		}

		/* Check for a slaved ROM on a multi-port board. */
		tlp_pci_check_slaved(psc, TULIP_PCI_SHAREDROM,
		    TULIP_PCI_SLAVEROM);
		if (psc->sc_flags & TULIP_PCI_SLAVEROM) {
			sc->sc_srom_addrbits =
			    psc->sc_master->sc_tulip.sc_srom_addrbits;
			sc->sc_srom = psc->sc_master->sc_tulip.sc_srom;
			enaddr[5] +=
			    sc->sc_devno - psc->sc_master->sc_tulip.sc_devno;
		}
		else if (tlp_read_srom(sc) == 0)
			goto cant_cope;
		break;
	}

	/*
	 * Deal with chip/board quirks.  This includes setting up
	 * the mediasw, and extracting the Ethernet address from
	 * the rombuf.
	 */
	switch (sc->sc_chip) {
	case TULIP_CHIP_21040:
		/*
		 * Parse the Ethernet Address ROM.
		 */
		if (tlp_parse_old_srom(sc, enaddr) == 0)
			goto cant_cope;


		/*
		 * All 21040 boards start out with the same
		 * media switch.
		 */
		sc->sc_mediasw = &tlp_21040_mediasw;

		/*
		 * Deal with any quirks this board might have.
		 */
		tlp_pci_get_quirks(psc, enaddr, tlp_pci_21040_quirks);
		break;

	case TULIP_CHIP_21041:
		/* Check for new format SROM. */
		if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
			/*
			 * Not an ISV SROM; try the old DEC Ethernet Address
			 * ROM format.
			 */
			if (tlp_parse_old_srom(sc, enaddr) == 0)
				goto cant_cope;
		}

		/*
		 * All 21041 boards use the same media switch; they all
		 * work basically the same!  Yippee!
		 */
		sc->sc_mediasw = &tlp_21041_mediasw;

		/*
		 * Deal with any quirks this board might have.
		 */
		tlp_pci_get_quirks(psc, enaddr, tlp_pci_21041_quirks);
		break;

	case TULIP_CHIP_21140:
	case TULIP_CHIP_21140A:
		/* Check for new format SROM. */
		if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
			/*
			 * Not an ISV SROM; try the old DEC Ethernet Address
			 * ROM format.
			 */
			if (tlp_parse_old_srom(sc, enaddr) == 0)
				goto cant_cope;
		} else {
			/*
			 * We start out with the 2114x ISV media switch.
			 * When we search for quirks, we may change to
			 * a different switch.
			 */
			sc->sc_mediasw = &tlp_2114x_isv_mediasw;
		}

		/*
		 * Deal with any quirks this board might have.
		 */
		tlp_pci_get_quirks(psc, enaddr, tlp_pci_21140_quirks);

		/*
		 * Bail out now if we can't deal with this board.
		 */
		if (sc->sc_mediasw == NULL)
			goto cant_cope;
		break;

	case TULIP_CHIP_21142:
	case TULIP_CHIP_21143:
		/* Check for new format SROM. */
		if (tlp_isv_srom_enaddr(sc, enaddr) == 0) {
			/*
			 * Not an ISV SROM; try the old DEC Ethernet Address
			 * ROM format.
			 */
			if (tlp_parse_old_srom(sc, enaddr) == 0) {
				/*
				 * One last try: just copy the address
				 * from offset 20 and try to look
				 * up quirks.
				 */
				memcpy(enaddr, &sc->sc_srom[20],
				    ETHER_ADDR_LEN);
			}
		} else {
			/*
			 * We start out with the 2114x ISV media switch.
			 * When we search for quirks, we may change to
			 * a different switch.
			 */
			sc->sc_mediasw = &tlp_2114x_isv_mediasw;
		}

		/*
		 * Deal with any quirks this board might have.
		 */
		tlp_pci_get_quirks(psc, enaddr, tlp_pci_21142_quirks);

		/*
		 * Bail out now if we can't deal with this board.
		 */
		if (sc->sc_mediasw == NULL)
			goto cant_cope;
		break;

	case TULIP_CHIP_82C168:
	case TULIP_CHIP_82C169:
		/*
		 * Lite-On PNIC's Ethernet address is the first 6
		 * bytes of its EEPROM.
		 */
		memcpy(enaddr, sc->sc_srom, ETHER_ADDR_LEN);

		/*
		 * Lite-On PNICs always use the same mediasw; we
		 * select MII vs. internal NWAY automatically.
		 */
		sc->sc_mediasw = &tlp_pnic_mediasw;
		break;

	case TULIP_CHIP_MX98713:
		/*
		 * The Macronix MX98713 has an MII and GPIO, but no
		 * internal Nway block.  This chip is basically a
		 * perfect 21140A clone, with the exception of the
		 * a magic register frobbing in order to make the
		 * interface function.
		 */
		if (tlp_isv_srom_enaddr(sc, enaddr)) {
			sc->sc_mediasw = &tlp_2114x_isv_mediasw;
			break;
		}
		/* FALLTHROUGH */

	case TULIP_CHIP_82C115:
		/*
		 * Yippee!  The Lite-On 82C115 is a clone of
		 * the MX98725 (the data sheet even says `MXIC'
		 * on it)!  Imagine that, a clone of a clone.
		 *
		 * The differences are really minimal:
		 *
		 *	- Wake-On-LAN support
		 *	- 128-bit multicast hash table, rather than
		 *	  the standard 512-bit hash table
		 */
		/* FALLTHROUGH */

	case TULIP_CHIP_MX98713A:
	case TULIP_CHIP_MX98715A:
	case TULIP_CHIP_MX98715AEC_X:
	case TULIP_CHIP_MX98725:
		/*
		 * The MX98713A has an MII as well as an internal Nway block,
		 * but no GPIO.  The MX98715 and MX98725 have an internal
		 * Nway block only.
		 *
		 * The internal Nway block, unlike the Lite-On PNIC's, does
		 * just that - performs Nway.  Once autonegotiation completes,
		 * we must program the GPR media information into the chip.
		 *
		 * The byte offset of the Ethernet address is stored at
		 * offset 0x70.
		 */
		memcpy(enaddr, &sc->sc_srom[sc->sc_srom[0x70]], ETHER_ADDR_LEN);
		sc->sc_mediasw = &tlp_pmac_mediasw;
		break;

	case TULIP_CHIP_WB89C840F:
		/*
		 * Winbond 89C840F's Ethernet address is the first
		 * 6 bytes of its EEPROM.
		 */
		memcpy(enaddr, sc->sc_srom, ETHER_ADDR_LEN);

		/*
		 * Winbond 89C840F has an MII attached to the SIO.
		 */
		sc->sc_mediasw = &tlp_sio_mii_mediasw;
		break;

	case TULIP_CHIP_AL981:
		/*
		 * The ADMtek AL981's Ethernet address is located
		 * at offset 8 of its EEPROM.
		 */
		memcpy(enaddr, &sc->sc_srom[8], ETHER_ADDR_LEN);

		/*
		 * ADMtek AL981 has a built-in PHY accessed through
		 * special registers.
		 */
		sc->sc_mediasw = &tlp_al981_mediasw;
		break;

	case TULIP_CHIP_AN983:
	case TULIP_CHIP_AN985:
		/*
		 * The ADMtek AN985's Ethernet address is located
		 * at offset 8 of its EEPROM.
		 */
		memcpy(enaddr, &sc->sc_srom[8], ETHER_ADDR_LEN);

		/*
		 * The ADMtek AN985 can be configured in Single-Chip
		 * mode or MAC-only mode.  Single-Chip uses the built-in
		 * PHY, MAC-only has an external PHY (usually HomePNA).
		 * The selection is based on an EEPROM setting, and both
		 * PHYs are accessed via MII attached to SIO.
		 *
		 * The AN985 "ghosts" the internal PHY onto all
		 * MII addresses, so we have to use a media init
		 * routine that limits the search.
		 * XXX How does this work with MAC-only mode?
		 */
		sc->sc_mediasw = &tlp_an985_mediasw;
		break;

	case TULIP_CHIP_DM9102:
	case TULIP_CHIP_DM9102A:
		/*
		 * Some boards with the Davicom chip have an ISV
		 * SROM (mostly DM9102A boards -- trying to describe
		 * the HomePNA PHY, probably) although the data in
		 * them is generally wrong.  Check for ISV format
		 * and grab the Ethernet address that way, and if
		 * that fails, fall back on grabbing it from an
		 * observed offset of 20 (which is where it would
		 * be in an ISV SROM anyhow, tho ISV can cope with
		 * multi-port boards).
		 */
		if (!tlp_isv_srom_enaddr(sc, enaddr)) {

			prop_data_t eaddrprop;

			eaddrprop = prop_dictionary_get(
				device_properties(self), "mac-address");

			if (eaddrprop != NULL
			    && prop_data_size(eaddrprop) == ETHER_ADDR_LEN)
				memcpy(enaddr,
				    prop_data_data_nocopy(eaddrprop),
				    ETHER_ADDR_LEN);
			else
				memcpy(enaddr, &sc->sc_srom[20],
				    ETHER_ADDR_LEN);
		}

		/*
		 * Davicom chips all have an internal MII interface
		 * and a built-in PHY.  DM9102A also has a an external
		 * MII interface, usually with a HomePNA PHY attached
		 * to it.
		 */
		sc->sc_mediasw = &tlp_dm9102_mediasw;
		break;

	case TULIP_CHIP_AX88140:
	case TULIP_CHIP_AX88141:
		/*
		 * ASIX AX88140/AX88141 Ethernet Address is located at offset
		 * 20 of the SROM.
		 */
		memcpy(enaddr, &sc->sc_srom[20], ETHER_ADDR_LEN);

		/*
		 * ASIX AX88140A/AX88141 chip can have a built-in PHY or
		 * an external MII interface.
		 */
		sc->sc_mediasw = &tlp_asix_mediasw;
		break;

	case TULIP_CHIP_RS7112:
		/*
		 * RS7112 Ethernet Address is located of offset 0x19a
		 * of the SROM
		 */
		memcpy(enaddr, &sc->sc_srom[0x19a], ETHER_ADDR_LEN);

		/* RS7112 chip has a PHY at MII address 1 */
		sc->sc_mediasw = &tlp_rs7112_mediasw;
		break;

	default:
 cant_cope:
		aprint_error_dev(self, "sorry, unable to handle your board\n");
		goto fail;
	}

	/*
	 * Handle shared interrupts.
	 */
	if (psc->sc_flags & TULIP_PCI_SHAREDINTR) {
		if (psc->sc_master)
			psc->sc_flags |= TULIP_PCI_SLAVEINTR;
		else {
			tlp_pci_check_slaved(psc, TULIP_PCI_SHAREDINTR,
			    TULIP_PCI_SLAVEINTR);
			if (psc->sc_master == NULL)
				psc->sc_master = psc;
		}
		LIST_INSERT_HEAD(&psc->sc_master->sc_intrslaves,
		    psc, sc_intrq);
	}

	if (psc->sc_flags & TULIP_PCI_SLAVEINTR) {
		aprint_normal_dev(self, "sharing interrupt with %s\n",
		    device_xname(psc->sc_master->sc_tulip.sc_dev));
	} else {
		/*
		 * Map and establish our interrupt.
		 */
		if (pci_intr_map(pa, &ih)) {
			aprint_error_dev(self, "unable to map interrupt\n");
			goto fail;
		}
		intrstr = pci_intr_string(pc, ih);
		psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET,
		    (psc->sc_flags & TULIP_PCI_SHAREDINTR) ?
		    tlp_pci_shared_intr : tlp_intr, sc);
		if (psc->sc_ih == NULL) {
			aprint_error_dev(self, "unable to establish interrupt");
			if (intrstr != NULL)
				aprint_error(" at %s", intrstr);
			aprint_error("\n");
			goto fail;
		}
		aprint_normal_dev(self, "interrupting at %s\n",
		    intrstr);
	}

	/*
	 * Finish off the attach.
	 */
	error = tlp_attach(sc, enaddr);
	if (error)
		goto fail;
	return;

fail:
	if (psc->sc_ih != NULL) {
		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
		psc->sc_ih = NULL;
	}

	if (ioh_valid)
		bus_space_unmap(iot, ioh, iosize);
	if (memh_valid)
		bus_space_unmap(memt, memh, memsize);
	psc->sc_mapsize = 0;
	return;
}
Beispiel #20
0
/*
 * npfctl_rule: add or remove dynamic rules in the specified ruleset.
 */
int
npfctl_rule(u_long cmd, void *data)
{
	struct plistref *pref = data;
	prop_dictionary_t npf_rule, retdict = NULL;
	npf_ruleset_t *rlset;
	npf_rule_t *rl = NULL;
	const char *ruleset_name;
	uint32_t rcmd = 0;
	int error;

	error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_rule);
	if (error) {
		return error;
	}
	prop_dictionary_get_uint32(npf_rule, "command", &rcmd);
	if (!prop_dictionary_get_cstring_nocopy(npf_rule,
	    "ruleset-name", &ruleset_name)) {
		error = EINVAL;
		goto out;
	}

	if (rcmd == NPF_CMD_RULE_ADD) {
		retdict = prop_dictionary_create();
		if (npf_mk_singlerule(npf_rule, NULL, &rl, retdict) != 0) {
			error = EINVAL;
			goto out;
		}
	}

	npf_config_enter();
	rlset = npf_config_ruleset();

	switch (rcmd) {
	case NPF_CMD_RULE_ADD: {
		if ((error = npf_ruleset_add(rlset, ruleset_name, rl)) == 0) {
			/* Success. */
			uint64_t id = npf_rule_getid(rl);
			prop_dictionary_set_uint64(retdict, "id", id);
			rl = NULL;
		}
		break;
	}
	case NPF_CMD_RULE_REMOVE: {
		uint64_t id;

		if (!prop_dictionary_get_uint64(npf_rule, "id", &id)) {
			error = EINVAL;
			break;
		}
		error = npf_ruleset_remove(rlset, ruleset_name, id);
		break;
	}
	case NPF_CMD_RULE_REMKEY: {
		prop_object_t obj = prop_dictionary_get(npf_rule, "key");
		const void *key = prop_data_data_nocopy(obj);
		size_t len = prop_data_size(obj);

		if (len == 0 || len > NPF_RULE_MAXKEYLEN) {
			error = EINVAL;
			break;
		}
		error = npf_ruleset_remkey(rlset, ruleset_name, key, len);
		break;
	}
	case NPF_CMD_RULE_LIST: {
		retdict = npf_ruleset_list(rlset, ruleset_name);
		if (!retdict) {
			error = ESRCH;
		}
		break;
	}
	case NPF_CMD_RULE_FLUSH: {
		error = npf_ruleset_flush(rlset, ruleset_name);
		break;
	}
	default:
		error = EINVAL;
		break;
	}

	/* Destroy any removed rules. */
	if (!error && rcmd != NPF_CMD_RULE_ADD && rcmd != NPF_CMD_RULE_LIST) {
		npf_config_sync();
		npf_ruleset_gc(rlset);
	}
	npf_config_exit();

	if (rl) {
		KASSERT(error);
		npf_rule_free(rl);
	}
out:
	if (retdict) {
		prop_object_release(npf_rule);
		prop_dictionary_copyout_ioctl(pref, cmd, retdict);
		prop_object_release(retdict);
	}
	return error;
}
Beispiel #21
0
void
smsc_attach(device_t parent, device_t self, void *aux)
{
    struct smsc_softc *sc = device_private(self);
    struct usb_attach_arg *uaa = aux;
    usbd_device_handle dev = uaa->device;
    usb_interface_descriptor_t *id;
    usb_endpoint_descriptor_t *ed;
    char *devinfop;
    struct mii_data *mii;
    struct ifnet *ifp;
    int err, s, i;
    uint32_t mac_h, mac_l;

    sc->sc_dev = self;
    sc->sc_udev = dev;

    aprint_naive("\n");
    aprint_normal("\n");

    devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
    aprint_normal_dev(self, "%s\n", devinfop);
    usbd_devinfo_free(devinfop);

    err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1);
    if (err) {
        aprint_error_dev(self, "failed to set configuration"
                         ", err=%s\n", usbd_errstr(err));
        return;
    }
    /* Setup the endpoints for the SMSC LAN95xx device(s) */
    usb_init_task(&sc->sc_tick_task, smsc_tick_task, sc, 0);
    usb_init_task(&sc->sc_stop_task, (void (*)(void *))smsc_stop, sc, 0);
    mutex_init(&sc->sc_mii_lock, MUTEX_DEFAULT, IPL_NONE);

    err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &sc->sc_iface);
    if (err) {
        aprint_error_dev(self, "getting interface handle failed\n");
        return;
    }

    id = usbd_get_interface_descriptor(sc->sc_iface);

    if (sc->sc_udev->speed >= USB_SPEED_HIGH)
        sc->sc_bufsz = SMSC_MAX_BUFSZ;
    else
        sc->sc_bufsz = SMSC_MIN_BUFSZ;

    /* Find endpoints. */
    for (i = 0; i < id->bNumEndpoints; i++) {
        ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
        if (!ed) {
            aprint_error_dev(self, "couldn't get ep %d\n", i);
            return;
        }
        if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
            sc->sc_ed[SMSC_ENDPT_RX] = ed->bEndpointAddress;
        } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
            sc->sc_ed[SMSC_ENDPT_TX] = ed->bEndpointAddress;
        } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
            sc->sc_ed[SMSC_ENDPT_INTR] = ed->bEndpointAddress;
        }
    }

    s = splnet();

    ifp = &sc->sc_ec.ec_if;
    ifp->if_softc = sc;
    strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    ifp->if_init = smsc_init;
    ifp->if_ioctl = smsc_ioctl;
    ifp->if_start = smsc_start;
    ifp->if_stop = smsc_stop;

#ifdef notyet
    /*
     * We can do TCPv4, and UDPv4 checksums in hardware.
     */
    ifp->if_capabilities |=
        /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx |
        /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx;
#endif

    sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU;

    /* Setup some of the basics */
    sc->sc_phyno = 1;

    /*
     * Attempt to get the mac address, if an EEPROM is not attached this
     * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC
     * address based on urandom.
     */
    memset(sc->sc_enaddr, 0xff, ETHER_ADDR_LEN);

    prop_dictionary_t dict = device_properties(self);
    prop_data_t eaprop = prop_dictionary_get(dict, "mac-address");

    if (eaprop != NULL) {
        KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA);
        KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN);
        memcpy(sc->sc_enaddr, prop_data_data_nocopy(eaprop),
               ETHER_ADDR_LEN);
    } else
        /* Check if there is already a MAC address in the register */
        if ((smsc_read_reg(sc, SMSC_MAC_ADDRL, &mac_l) == 0) &&
                (smsc_read_reg(sc, SMSC_MAC_ADDRH, &mac_h) == 0)) {
            sc->sc_enaddr[5] = (uint8_t)((mac_h >> 8) & 0xff);
            sc->sc_enaddr[4] = (uint8_t)((mac_h) & 0xff);
            sc->sc_enaddr[3] = (uint8_t)((mac_l >> 24) & 0xff);
            sc->sc_enaddr[2] = (uint8_t)((mac_l >> 16) & 0xff);
            sc->sc_enaddr[1] = (uint8_t)((mac_l >> 8) & 0xff);
            sc->sc_enaddr[0] = (uint8_t)((mac_l) & 0xff);
        }
Beispiel #22
0
static void
bthidev_attach(device_t parent, device_t self, void *aux)
{
	struct bthidev_softc *sc = device_private(self);
	prop_dictionary_t dict = aux;
	prop_object_t obj;
	device_t dev;
	struct bthidev_attach_args bha;
	struct bthidev *hidev;
	struct hid_data *d;
	struct hid_item h;
	const void *desc;
	int locs[BTHIDBUSCF_NLOCS];
	int maxid, rep, dlen;

	/*
	 * Init softc
	 */
	sc->sc_dev = self;
	LIST_INIT(&sc->sc_list);
	callout_init(&sc->sc_reconnect, 0);
	callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc);
	sc->sc_state = BTHID_CLOSED;
	sc->sc_flags = BTHID_CONNECTING;
	sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL;
	sc->sc_intpsm = L2CAP_PSM_HID_INTR;

	sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0);

	/*
	 * extract config from proplist
	 */
	obj = prop_dictionary_get(dict, BTDEVladdr);
	bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVraddr);
	bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVmode);
	if (prop_object_type(obj) == PROP_TYPE_STRING) {
		if (prop_string_equals_cstring(obj, BTDEVauth))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH);
		else if (prop_string_equals_cstring(obj, BTDEVencrypt))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT);
		else if (prop_string_equals_cstring(obj, BTDEVsecure))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE);
		else  {
			aprint_error(" unknown %s\n", BTDEVmode);
			return;
		}

		aprint_verbose(" %s %s", BTDEVmode,
					 prop_string_cstring_nocopy(obj));
	}

	obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm);
	if (prop_object_type(obj) == PROP_TYPE_NUMBER) {
		sc->sc_ctlpsm = prop_number_integer_value(obj);
		if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) {
			aprint_error(" invalid %s\n", BTHIDEVcontrolpsm);
			return;
		}
	}

	obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm);
	if (prop_object_type(obj) == PROP_TYPE_NUMBER) {
		sc->sc_intpsm = prop_number_integer_value(obj);
		if (L2CAP_PSM_INVALID(sc->sc_intpsm)) {
			aprint_error(" invalid %s\n", BTHIDEVinterruptpsm);
			return;
		}
	}

	obj = prop_dictionary_get(dict, BTHIDEVdescriptor);
	if (prop_object_type(obj) == PROP_TYPE_DATA) {
		dlen = prop_data_size(obj);
		desc = prop_data_data_nocopy(obj);
	} else {
		aprint_error(" no %s\n", BTHIDEVdescriptor);
		return;
	}

	obj = prop_dictionary_get(dict, BTHIDEVreconnect);
	if (prop_object_type(obj) == PROP_TYPE_BOOL
	    && !prop_bool_true(obj))
		sc->sc_flags |= BTHID_RECONNECT;

	/*
	 * Parse the descriptor and attach child devices, one per report.
	 */
	maxid = -1;
	h.report_ID = 0;
	d = hid_start_parse(desc, dlen, hid_none);
	while (hid_get_item(d, &h)) {
		if (h.report_ID > maxid)
			maxid = h.report_ID;
	}
	hid_end_parse(d);

	if (maxid < 0) {
		aprint_error(" no reports found\n");
		return;
	}

	aprint_normal("\n");

	for (rep = 0 ; rep <= maxid ; rep++) {
		if (hid_report_size(desc, dlen, hid_feature, rep) == 0
		    && hid_report_size(desc, dlen, hid_input, rep) == 0
		    && hid_report_size(desc, dlen, hid_output, rep) == 0)
			continue;

		bha.ba_desc = desc;
		bha.ba_dlen = dlen;
		bha.ba_input = bthidev_null;
		bha.ba_feature = bthidev_null;
		bha.ba_output = bthidev_output;
		bha.ba_id = rep;

		locs[BTHIDBUSCF_REPORTID] = rep;

		dev = config_found_sm_loc(self, "bthidbus",
					locs, &bha, bthidev_print, config_stdsubmatch);
		if (dev != NULL) {
			hidev = device_private(dev);
			hidev->sc_dev = dev;
			hidev->sc_parent = self;
			hidev->sc_id = rep;
			hidev->sc_input = bha.ba_input;
			hidev->sc_feature = bha.ba_feature;
			LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next);
		}
	}

	/*
	 * start bluetooth connections
	 */
	mutex_enter(bt_lock);
	if ((sc->sc_flags & BTHID_RECONNECT) == 0)
		bthidev_listen(sc);

	if (sc->sc_flags & BTHID_CONNECTING)
		bthidev_connect(sc);
	mutex_exit(bt_lock);
}
static void
admsw_attach(device_t parent, device_t self, void *aux)
{
	uint8_t enaddr[ETHER_ADDR_LEN];
	struct admsw_softc *sc = device_private(self);
	struct obio_attach_args *aa = aux;
	struct ifnet *ifp;
	bus_dma_segment_t seg;
	int error, i, rseg;
	prop_data_t pd;

	printf(": ADM5120 Switch Engine, %d ports\n", SW_DEVS);

	sc->sc_dev = self;
	sc->sc_dmat = aa->oba_dt;
	sc->sc_st = aa->oba_st;

	pd = prop_dictionary_get(device_properties(self), "mac-address");

	if (pd == NULL) {
		enaddr[0] = 0x02;
		enaddr[1] = 0xaa;
		enaddr[2] = 0xbb;
		enaddr[3] = 0xcc;
		enaddr[4] = 0xdd;
		enaddr[5] = 0xee;
	} else
		memcpy(enaddr, prop_data_data_nocopy(pd), sizeof(enaddr));

	memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr));

	printf("%s: base Ethernet address %s\n", device_xname(sc->sc_dev),
	    ether_sprintf(enaddr));

	/* Map the device. */
	if (bus_space_map(sc->sc_st, aa->oba_addr, 512, 0, &sc->sc_ioh) != 0) {
		printf("%s: unable to map device\n", device_xname(sc->sc_dev));
		return;
	}

	/* Hook up the interrupt handler. */
	sc->sc_ih = adm5120_intr_establish(aa->oba_irq, INTR_IRQ, admsw_intr, sc);

	if (sc->sc_ih == NULL) {
		printf("%s: unable to register interrupt handler\n",
		    device_xname(sc->sc_dev));
		return;
	}

	/*
	 * Allocate the control data structures, and create and load the
	 * DMA map for it.
	 */
	if ((error = bus_dmamem_alloc(sc->sc_dmat,
	    sizeof(struct admsw_control_data), PAGE_SIZE, 0, &seg, 1, &rseg,
	    0)) != 0) {
		printf("%s: unable to allocate control data, error = %d\n",
		    device_xname(sc->sc_dev), error);
		return;
	}
	if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
	    sizeof(struct admsw_control_data), (void *)&sc->sc_control_data,
	    0)) != 0) {
		printf("%s: unable to map control data, error = %d\n",
		    device_xname(sc->sc_dev), error);
		return;
	}
	if ((error = bus_dmamap_create(sc->sc_dmat,
	    sizeof(struct admsw_control_data), 1,
	    sizeof(struct admsw_control_data), 0, 0, &sc->sc_cddmamap)) != 0) {
		printf("%s: unable to create control data DMA map, "
		    "error = %d\n", device_xname(sc->sc_dev), error);
		return;
	}
	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
	    sc->sc_control_data, sizeof(struct admsw_control_data), NULL,
	    0)) != 0) {
		printf("%s: unable to load control data DMA map, error = %d\n",
		    device_xname(sc->sc_dev), error);
		return;
	}

	/*
	 * Create the transmit buffer DMA maps.
	 */
	for (i = 0; i < ADMSW_NTXHDESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    2, MCLBYTES, 0, 0,
		    &sc->sc_txhsoft[i].ds_dmamap)) != 0) {
			printf("%s: unable to create txh DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			return;
		}
		sc->sc_txhsoft[i].ds_mbuf = NULL;
	}
	for (i = 0; i < ADMSW_NTXLDESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    2, MCLBYTES, 0, 0,
		    &sc->sc_txlsoft[i].ds_dmamap)) != 0) {
			printf("%s: unable to create txl DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			return;
		}
		sc->sc_txlsoft[i].ds_mbuf = NULL;
	}

	/*
	 * Create the receive buffer DMA maps.
	 */
	for (i = 0; i < ADMSW_NRXHDESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, 0, &sc->sc_rxhsoft[i].ds_dmamap)) != 0) {
			printf("%s: unable to create rxh DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			return;
		}
		sc->sc_rxhsoft[i].ds_mbuf = NULL;
	}
	for (i = 0; i < ADMSW_NRXLDESC; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, 0, &sc->sc_rxlsoft[i].ds_dmamap)) != 0) {
			printf("%s: unable to create rxl DMA map %d, "
			    "error = %d\n", device_xname(sc->sc_dev), i, error);
			return;
		}
		sc->sc_rxlsoft[i].ds_mbuf = NULL;
	}

	admsw_init_bufs(sc);

	admsw_reset(sc);

	for (i = 0; i < SW_DEVS; i++) {
		ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange, admsw_mediastatus);
		ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
		ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL);
		ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO);

		ifp = &sc->sc_ethercom[i].ec_if;
		strcpy(ifp->if_xname, device_xname(sc->sc_dev));
		ifp->if_xname[5] += i;
		ifp->if_softc = sc;
		ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
		ifp->if_ioctl = admsw_ioctl;
		ifp->if_start = admsw_start;
		ifp->if_watchdog = admsw_watchdog;
		ifp->if_init = admsw_init;
		ifp->if_stop = admsw_stop;
		ifp->if_capabilities |= IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx;
		IFQ_SET_MAXLEN(&ifp->if_snd, max(ADMSW_NTXLDESC, IFQ_MAXLEN));
		IFQ_SET_READY(&ifp->if_snd);

		/* Attach the interface. */
		if_attach(ifp);
		ether_ifattach(ifp, enaddr);
		enaddr[5]++;
	}

#ifdef ADMSW_EVENT_COUNTERS
	evcnt_attach_dynamic(&sc->sc_ev_txstall, EVCNT_TYPE_MISC,
	    NULL, device_xname(sc->sc_dev), "txstall");
	evcnt_attach_dynamic(&sc->sc_ev_rxstall, EVCNT_TYPE_MISC,
	    NULL, device_xname(sc->sc_dev), "rxstall");
	evcnt_attach_dynamic(&sc->sc_ev_txintr, EVCNT_TYPE_MISC,
	    NULL, device_xname(sc->sc_dev), "txintr");
	evcnt_attach_dynamic(&sc->sc_ev_rxintr, EVCNT_TYPE_MISC,
	    NULL, device_xname(sc->sc_dev), "rxintr");
#if 1
	evcnt_attach_dynamic(&sc->sc_ev_rxsync, EVCNT_TYPE_MISC,
	    NULL, device_xname(sc->sc_dev), "rxsync");
#endif
#endif

	admwdog_attach(sc);

	/* Make sure the interface is shutdown during reboot. */
	sc->sc_sdhook = shutdownhook_establish(admsw_shutdown, sc);
	if (sc->sc_sdhook == NULL)
		printf("%s: WARNING: unable to establish shutdown hook\n",
		    device_xname(sc->sc_dev));

	/* leave interrupts and cpu port disabled */
	return;
}