if_fwe.c revision 132430
140939Sdes/*
240939Sdes * Copyright (c) 2002-2003
340939Sdes * 	Hidetoshi Shimokawa. All rights reserved.
440939Sdes *
540939Sdes * Redistribution and use in source and binary forms, with or without
640939Sdes * modification, are permitted provided that the following conditions
740939Sdes * are met:
840939Sdes * 1. Redistributions of source code must retain the above copyright
940939Sdes *    notice, this list of conditions and the following disclaimer.
1040939Sdes * 2. Redistributions in binary form must reproduce the above copyright
1140939Sdes *    notice, this list of conditions and the following disclaimer in the
1240939Sdes *    documentation and/or other materials provided with the distribution.
1340939Sdes * 3. All advertising materials mentioning features or use of this software
1440939Sdes *    must display the following acknowledgement:
1540939Sdes *
1640939Sdes *	This product includes software developed by Hidetoshi Shimokawa.
1740939Sdes *
1840939Sdes * 4. Neither the name of the author nor the names of its contributors
1940939Sdes *    may be used to endorse or promote products derived from this software
2040939Sdes *    without specific prior written permission.
2140939Sdes *
2240939Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2340939Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2440939Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2540939Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2640939Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2740939Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2850476Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2940939Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3040939Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3141862Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3240939Sdes * SUCH DAMAGE.
3355557Sdes *
3440939Sdes * $FreeBSD: head/sys/dev/firewire/if_fwe.c 132430 2004-07-20 04:29:33Z simokawa $
3540939Sdes */
3640939Sdes
3740939Sdes#include "opt_inet.h"
3860924Sdes
3941862Sdes#include <sys/param.h>
4041862Sdes#include <sys/kernel.h>
4140939Sdes#include <sys/malloc.h>
4240939Sdes#include <sys/mbuf.h>
4340939Sdes#include <sys/socket.h>
4440939Sdes#include <sys/sockio.h>
4540939Sdes#include <sys/sysctl.h>
4640939Sdes#include <sys/systm.h>
4740975Sdes#include <sys/module.h>
4840939Sdes#include <sys/bus.h>
4940939Sdes#include <machine/bus.h>
5040939Sdes
5140939Sdes#include <net/bpf.h>
5240939Sdes#include <net/ethernet.h>
5340939Sdes#include <net/if.h>
5460737Sume#include <net/if_arp.h>
5560737Sume#ifdef __DragonFly__
5660737Sume#include <net/vlan/if_vlan_var.h>
5760737Sume#include <bus/firewire/firewire.h>
5840975Sdes#include <bus/firewire/firewirereg.h>
5940939Sdes#include "if_fwevar.h"
6040939Sdes#else
6140939Sdes#include <net/if_vlan_var.h>
6240939Sdes
6340939Sdes#include <dev/firewire/firewire.h>
6440939Sdes#include <dev/firewire/firewirereg.h>
6540939Sdes#include <dev/firewire/if_fwevar.h>
6640939Sdes#endif
6760924Sdes
6840975Sdes#define FWEDEBUG	if (fwedebug) if_printf
6940939Sdes#define TX_MAX_QUEUE	(FWMAXQUEUE - 1)
7060924Sdes
7160924Sdes/* network interface */
7260924Sdesstatic void fwe_start (struct ifnet *);
7340939Sdesstatic int fwe_ioctl (struct ifnet *, u_long, caddr_t);
7440939Sdesstatic void fwe_init (void *);
7540939Sdes
7640939Sdesstatic void fwe_output_callback (struct fw_xfer *);
7740939Sdesstatic void fwe_as_output (struct fwe_softc *, struct ifnet *);
7840939Sdesstatic void fwe_as_input (struct fw_xferq *);
7940939Sdes
8040939Sdesstatic int fwedebug = 0;
8160924Sdesstatic int stream_ch = 1;
8260924Sdesstatic int tx_speed = 2;
8360924Sdesstatic int rx_queue_len = FWMAXQUEUE;
8440939Sdes
8540939SdesMALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface");
8640939SdesSYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, "");
8740939SdesSYSCTL_DECL(_hw_firewire);
8840939SdesSYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0,
8940939Sdes	"Ethernet emulation subsystem");
9040939SdesSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0,
9140939Sdes	"Stream channel to use");
9241862SdesSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RW, &tx_speed, 0,
9341862Sdes	"Transmission speed");
9440975SdesSYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len,
9540975Sdes	0, "Length of the receive queue");
9640975Sdes
9741862SdesTUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch);
9840975SdesTUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed);
9940975SdesTUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len);
10040975Sdes
10140975Sdes#ifdef DEVICE_POLLING
10240975Sdes#define FWE_POLL_REGISTER(func, fwe, ifp)			\
10340975Sdes	if (ether_poll_register(func, ifp)) {			\
10441862Sdes		struct firewire_comm *fc = (fwe)->fd.fc;	\
10540975Sdes		fc->set_intr(fc, 0);				\
10640975Sdes	}
10740975Sdes
10841862Sdes#define FWE_POLL_DEREGISTER(fwe, ifp)				\
10940975Sdes	do {							\
11040975Sdes		struct firewire_comm *fc = (fwe)->fd.fc;	\
11141862Sdes		ether_poll_deregister(ifp);			\
11240975Sdes		fc->set_intr(fc, 1);				\
11340975Sdes	} while(0)						\
11440975Sdes
11541862Sdesstatic poll_handler_t fwe_poll;
11640975Sdes
11740975Sdesstatic void
11841862Sdesfwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
11940975Sdes{
12040975Sdes	struct fwe_softc *fwe;
12141862Sdes	struct firewire_comm *fc;
12240975Sdes
12340975Sdes	fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
12440975Sdes	fc = fwe->fd.fc;
12540975Sdes	if (cmd == POLL_DEREGISTER) {
12640975Sdes		/* enable interrupts */
12740975Sdes		fc->set_intr(fc, 1);
12840975Sdes		return;
12941862Sdes	}
13040975Sdes	fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count);
13140975Sdes}
13240975Sdes#else
13341862Sdes#define FWE_POLL_REGISTER(func, fwe, ifp)
13440975Sdes#define FWE_POLL_DEREGISTER(fwe, ifp)
13540975Sdes#endif
13641862Sdesstatic void
13740975Sdesfwe_identify(driver_t *driver, device_t parent)
13840975Sdes{
13940975Sdes	BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent));
14041862Sdes}
14140975Sdes
14240975Sdesstatic int
14341862Sdesfwe_probe(device_t dev)
14440975Sdes{
14560924Sdes	device_t pa;
14640939Sdes
14740939Sdes	pa = device_get_parent(dev);
14840939Sdes	if(device_get_unit(dev) != device_get_unit(pa)){
14941862Sdes		return(ENXIO);
15041862Sdes	}
15141862Sdes
15260924Sdes	device_set_desc(dev, "Ethernet over FireWire");
15341862Sdes	return (0);
15441862Sdes}
15541862Sdes
15641862Sdesstatic int
15741862Sdesfwe_attach(device_t dev)
15860924Sdes{
15941862Sdes	struct fwe_softc *fwe;
16060928Sdes	struct ifnet *ifp;
16141862Sdes	int unit, s;
16241862Sdes	u_char *eaddr;
16341862Sdes	struct fw_eui64 *eui;
16440939Sdes
16540939Sdes	fwe = ((struct fwe_softc *)device_get_softc(dev));
16640939Sdes	unit = device_get_unit(dev);
16740939Sdes
16840939Sdes	bzero(fwe, sizeof(struct fwe_softc));
16940939Sdes	/* XXX */
17060737Sume	fwe->stream_ch = stream_ch;
17140939Sdes	fwe->dma_ch = -1;
17260737Sume
17360737Sume	fwe->fd.fc = device_get_ivars(dev);
17460737Sume	if (tx_speed < 0)
17540939Sdes		tx_speed = fwe->fd.fc->speed;
17662964Sdes
17741862Sdes	fwe->fd.dev = dev;
17841862Sdes	fwe->fd.post_explore = NULL;
17941862Sdes	fwe->eth_softc.fwe = fwe;
18040939Sdes
18160737Sume	fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM;
18260737Sume	fwe->pkt_hdr.mode.stream.sy = 0;
18360737Sume	fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
18460737Sume
18560737Sume	/* generate fake MAC address: first and last 3bytes from eui64 */
18660737Sume#define LOCAL (0x02)
18760737Sume#define GROUP (0x01)
18860737Sume	eaddr = &fwe->eth_softc.arpcom.ac_enaddr[0];
18940939Sdes
19040939Sdes	eui = &fwe->fd.fc->eui;
19140939Sdes	eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP;
19241862Sdes	eaddr[1] = FW_EUI64_BYTE(eui, 1);
19341862Sdes	eaddr[2] = FW_EUI64_BYTE(eui, 2);
19441862Sdes	eaddr[3] = FW_EUI64_BYTE(eui, 5);
19540939Sdes	eaddr[4] = FW_EUI64_BYTE(eui, 6);
19660737Sume	eaddr[5] = FW_EUI64_BYTE(eui, 7);
19760737Sume	printf("if_fwe%d: Fake Ethernet address: "
19860737Sume		"%02x:%02x:%02x:%02x:%02x:%02x\n", unit,
19960737Sume		eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
20060737Sume
20160737Sume	/* fill the rest and attach interface */
20260737Sume	ifp = &fwe->fwe_if;
20360737Sume	ifp->if_softc = &fwe->eth_softc;
20460737Sume
20540939Sdes#if __FreeBSD_version >= 501113 || defined(__DragonFly__)
20662911Sume	if_initname(ifp, device_get_name(dev), unit);
20760737Sume#else
20840939Sdes	ifp->if_unit = unit;
20940939Sdes	ifp->if_name = "fwe";
21040939Sdes#endif
21140939Sdes	ifp->if_init = fwe_init;
21240939Sdes#if defined(__DragonFly__) || __FreeBSD_version < 500000
21340939Sdes	ifp->if_output = ether_output;
21441989Sdes#endif
21541989Sdes	ifp->if_start = fwe_start;
21655557Sdes	ifp->if_ioctl = fwe_ioctl;
21755557Sdes	ifp->if_mtu = ETHERMTU;
21855557Sdes	ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
21955557Sdes	ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE;
22055557Sdes
22155557Sdes	s = splimp();
22255557Sdes#if defined(__DragonFly__) || __FreeBSD_version < 500000
22355557Sdes	ether_ifattach(ifp, 1);
22455557Sdes#else
22555557Sdes	ether_ifattach(ifp, eaddr);
22655557Sdes#endif
22755557Sdes	splx(s);
22855557Sdes
22955557Sdes        /* Tell the upper layer(s) we support long frames. */
23055557Sdes	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
23155557Sdes#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
23255557Sdes	ifp->if_capabilities |= IFCAP_VLAN_MTU;
23355557Sdes	ifp->if_capenable |= IFCAP_VLAN_MTU;
23455557Sdes#endif
23555557Sdes
23655557Sdes
23755557Sdes	FWEDEBUG(ifp, "interface created\n");
23855557Sdes	return 0;
23955557Sdes}
24055557Sdes
24155557Sdesstatic void
24255557Sdesfwe_stop(struct fwe_softc *fwe)
24355557Sdes{
24455557Sdes	struct firewire_comm *fc;
24555557Sdes	struct fw_xferq *xferq;
24655557Sdes	struct ifnet *ifp = &fwe->fwe_if;
24755557Sdes	struct fw_xfer *xfer, *next;
24855557Sdes	int i;
24955557Sdes
25055557Sdes	fc = fwe->fd.fc;
25155557Sdes
25255557Sdes	FWE_POLL_DEREGISTER(fwe, ifp);
25355557Sdes
25455557Sdes	if (fwe->dma_ch >= 0) {
25555557Sdes		xferq = fc->ir[fwe->dma_ch];
25655557Sdes
25755557Sdes		if (xferq->flag & FWXFERQ_RUNNING)
25855557Sdes			fc->irx_disable(fc, fwe->dma_ch);
25955557Sdes		xferq->flag &=
26055557Sdes			~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
26155557Sdes			FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
26255557Sdes		xferq->hand =  NULL;
26355557Sdes
26455557Sdes		for (i = 0; i < xferq->bnchunk; i ++)
26555557Sdes			m_freem(xferq->bulkxfer[i].mbuf);
26655557Sdes		free(xferq->bulkxfer, M_FWE);
26755557Sdes
26855557Sdes		for (xfer = STAILQ_FIRST(&fwe->xferlist); xfer != NULL;
26955557Sdes					xfer = next) {
27055557Sdes			next = STAILQ_NEXT(xfer, link);
27155557Sdes			fw_xfer_free(xfer);
27255557Sdes		}
27355557Sdes		STAILQ_INIT(&fwe->xferlist);
27455557Sdes
27555557Sdes		xferq->bulkxfer =  NULL;
27655557Sdes		fwe->dma_ch = -1;
27755557Sdes	}
27855557Sdes
27955557Sdes	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
28055557Sdes}
28155557Sdes
28255557Sdesstatic int
28355557Sdesfwe_detach(device_t dev)
28455557Sdes{
28555557Sdes	struct fwe_softc *fwe;
28655557Sdes	int s;
28755557Sdes
28855557Sdes	fwe = (struct fwe_softc *)device_get_softc(dev);
28955557Sdes	s = splimp();
29055557Sdes
29155557Sdes	fwe_stop(fwe);
29255557Sdes#if defined(__DragonFly__) || __FreeBSD_version < 500000
29362964Sdes	ether_ifdetach(&fwe->fwe_if, 1);
29455557Sdes#else
29555557Sdes	ether_ifdetach(&fwe->fwe_if);
29655557Sdes#endif
29755557Sdes
29841989Sdes	splx(s);
29941989Sdes	return 0;
30041989Sdes}
30141989Sdes
30241989Sdesstatic void
30341989Sdesfwe_init(void *arg)
30441989Sdes{
30541989Sdes	struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe;
30641989Sdes	struct firewire_comm *fc;
30741989Sdes	struct ifnet *ifp = &fwe->fwe_if;
30841989Sdes	struct fw_xferq *xferq;
30941989Sdes	struct fw_xfer *xfer;
31041989Sdes	struct mbuf *m;
31141989Sdes	int i;
31241989Sdes
31341989Sdes	FWEDEBUG(ifp, "initializing\n");
31441989Sdes
31541989Sdes	/* XXX keep promiscoud mode */
31641989Sdes	ifp->if_flags |= IFF_PROMISC;
31741989Sdes
31841989Sdes	fc = fwe->fd.fc;
31941989Sdes#define START 0
32041989Sdes	if (fwe->dma_ch < 0) {
32141989Sdes		for (i = START; i < fc->nisodma; i ++) {
32241989Sdes			xferq = fc->ir[i];
32341989Sdes			if ((xferq->flag & FWXFERQ_OPEN) == 0)
32441989Sdes				goto found;
32541989Sdes		}
32641989Sdes		printf("no free dma channel\n");
32741989Sdes		return;
32841989Sdesfound:
32941989Sdes		fwe->dma_ch = i;
33041989Sdes		fwe->stream_ch = stream_ch;
33141989Sdes		fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
33241989Sdes		/* allocate DMA channel and init packet mode */
33341989Sdes		xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
33441989Sdes				FWXFERQ_HANDLER | FWXFERQ_STREAM;
33541989Sdes		xferq->flag &= ~0xff;
33641989Sdes		xferq->flag |= fwe->stream_ch & 0xff;
33741989Sdes		/* register fwe_input handler */
338		xferq->sc = (caddr_t) fwe;
339		xferq->hand = fwe_as_input;
340		xferq->bnchunk = rx_queue_len;
341		xferq->bnpacket = 1;
342		xferq->psize = MCLBYTES;
343		xferq->queued = 0;
344		xferq->buf = NULL;
345		xferq->bulkxfer = (struct fw_bulkxfer *) malloc(
346			sizeof(struct fw_bulkxfer) * xferq->bnchunk,
347							M_FWE, M_WAITOK);
348		if (xferq->bulkxfer == NULL) {
349			printf("if_fwe: malloc failed\n");
350			return;
351		}
352		STAILQ_INIT(&xferq->stvalid);
353		STAILQ_INIT(&xferq->stfree);
354		STAILQ_INIT(&xferq->stdma);
355		xferq->stproc = NULL;
356		for (i = 0; i < xferq->bnchunk; i ++) {
357			m =
358#if defined(__DragonFly__) || __FreeBSD_version < 500000
359				m_getcl(M_WAIT, MT_DATA, M_PKTHDR);
360#else
361				m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR);
362#endif
363			xferq->bulkxfer[i].mbuf = m;
364			if (m != NULL) {
365				m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
366				STAILQ_INSERT_TAIL(&xferq->stfree,
367						&xferq->bulkxfer[i], link);
368			} else
369				printf("fwe_as_input: m_getcl failed\n");
370		}
371		STAILQ_INIT(&fwe->xferlist);
372		for (i = 0; i < TX_MAX_QUEUE; i++) {
373			xfer = fw_xfer_alloc(M_FWE);
374			if (xfer == NULL)
375				break;
376			xfer->send.spd = tx_speed;
377			xfer->fc = fwe->fd.fc;
378			xfer->retry_req = fw_asybusy;
379			xfer->sc = (caddr_t)fwe;
380			xfer->act.hand = fwe_output_callback;
381			STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
382		}
383	} else
384		xferq = fc->ir[fwe->dma_ch];
385
386
387	/* start dma */
388	if ((xferq->flag & FWXFERQ_RUNNING) == 0)
389		fc->irx_enable(fc, fwe->dma_ch);
390
391	ifp->if_flags |= IFF_RUNNING;
392	ifp->if_flags &= ~IFF_OACTIVE;
393
394	FWE_POLL_REGISTER(fwe_poll, fwe, ifp);
395#if 0
396	/* attempt to start output */
397	fwe_start(ifp);
398#endif
399}
400
401
402static int
403fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
404{
405	struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
406	struct ifstat *ifs = NULL;
407	int s, error, len;
408
409	switch (cmd) {
410		case SIOCSIFFLAGS:
411			s = splimp();
412			if (ifp->if_flags & IFF_UP) {
413				if (!(ifp->if_flags & IFF_RUNNING))
414					fwe_init(&fwe->eth_softc);
415			} else {
416				if (ifp->if_flags & IFF_RUNNING)
417					fwe_stop(fwe);
418			}
419			/* XXX keep promiscoud mode */
420			ifp->if_flags |= IFF_PROMISC;
421			splx(s);
422			break;
423		case SIOCADDMULTI:
424		case SIOCDELMULTI:
425			break;
426
427		case SIOCGIFSTATUS:
428			s = splimp();
429			ifs = (struct ifstat *)data;
430			len = strlen(ifs->ascii);
431			if (len < sizeof(ifs->ascii))
432				snprintf(ifs->ascii + len,
433					sizeof(ifs->ascii) - len,
434					"\tch %d dma %d\n",
435						fwe->stream_ch, fwe->dma_ch);
436			splx(s);
437			break;
438#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
439		default:
440#else
441		case SIOCSIFADDR:
442		case SIOCGIFADDR:
443		case SIOCSIFMTU:
444#endif
445			s = splimp();
446			error = ether_ioctl(ifp, cmd, data);
447			splx(s);
448			return (error);
449#if defined(__DragonFly__) || __FreeBSD_version < 500000
450		default:
451			return (EINVAL);
452#endif
453	}
454
455	return (0);
456}
457
458static void
459fwe_output_callback(struct fw_xfer *xfer)
460{
461	struct fwe_softc *fwe;
462	struct ifnet *ifp;
463	int s;
464
465	fwe = (struct fwe_softc *)xfer->sc;
466	ifp = &fwe->fwe_if;
467	/* XXX error check */
468	FWEDEBUG(ifp, "resp = %d\n", xfer->resp);
469	if (xfer->resp != 0)
470		ifp->if_oerrors ++;
471
472	m_freem(xfer->mbuf);
473	fw_xfer_unload(xfer);
474
475	s = splimp();
476	STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
477	splx(s);
478
479	/* for queue full */
480	if (ifp->if_snd.ifq_head != NULL)
481		fwe_start(ifp);
482}
483
484static void
485fwe_start(struct ifnet *ifp)
486{
487	struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
488	int s;
489
490	FWEDEBUG(ifp, "starting\n");
491
492	if (fwe->dma_ch < 0) {
493		struct mbuf	*m = NULL;
494
495		FWEDEBUG(ifp, "not ready\n");
496
497		s = splimp();
498		do {
499			IF_DEQUEUE(&ifp->if_snd, m);
500			if (m != NULL)
501				m_freem(m);
502			ifp->if_oerrors ++;
503		} while (m != NULL);
504		splx(s);
505
506		return;
507	}
508
509	s = splimp();
510	ifp->if_flags |= IFF_OACTIVE;
511
512	if (ifp->if_snd.ifq_len != 0)
513		fwe_as_output(fwe, ifp);
514
515	ifp->if_flags &= ~IFF_OACTIVE;
516	splx(s);
517}
518
519#define HDR_LEN 4
520#ifndef ETHER_ALIGN
521#define ETHER_ALIGN 2
522#endif
523/* Async. stream output */
524static void
525fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
526{
527	struct mbuf *m;
528	struct fw_xfer *xfer;
529	struct fw_xferq *xferq;
530	struct fw_pkt *fp;
531	int i = 0;
532
533	xfer = NULL;
534	xferq = fwe->fd.fc->atq;
535	while (xferq->queued < xferq->maxq - 1) {
536		xfer = STAILQ_FIRST(&fwe->xferlist);
537		if (xfer == NULL) {
538			printf("if_fwe: lack of xfer\n");
539			return;
540		}
541		IF_DEQUEUE(&ifp->if_snd, m);
542		if (m == NULL)
543			break;
544		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
545#if defined(__DragonFly__) || __FreeBSD_version < 500000
546		if (ifp->if_bpf != NULL)
547			bpf_mtap(ifp, m);
548#else
549		BPF_MTAP(ifp, m);
550#endif
551
552		/* keep ip packet alignment for alpha */
553		M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT);
554		fp = &xfer->send.hdr;
555		*(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
556		fp->mode.stream.len = m->m_pkthdr.len;
557		xfer->mbuf = m;
558		xfer->send.pay_len = m->m_pkthdr.len;
559
560		if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
561			/* error */
562			ifp->if_oerrors ++;
563			/* XXX set error code */
564			fwe_output_callback(xfer);
565		} else {
566			ifp->if_opackets ++;
567			i++;
568		}
569	}
570#if 0
571	if (i > 1)
572		printf("%d queued\n", i);
573#endif
574	if (i > 0)
575		xferq->start(fwe->fd.fc);
576}
577
578/* Async. stream output */
579static void
580fwe_as_input(struct fw_xferq *xferq)
581{
582	struct mbuf *m, *m0;
583	struct ifnet *ifp;
584	struct fwe_softc *fwe;
585	struct fw_bulkxfer *sxfer;
586	struct fw_pkt *fp;
587	u_char *c;
588#if defined(__DragonFly__) || __FreeBSD_version < 500000
589	struct ether_header *eh;
590#endif
591
592	fwe = (struct fwe_softc *)xferq->sc;
593	ifp = &fwe->fwe_if;
594#if 0
595	FWE_POLL_REGISTER(fwe_poll, fwe, ifp);
596#endif
597	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
598		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
599		fp = mtod(sxfer->mbuf, struct fw_pkt *);
600		if (fwe->fd.fc->irx_post != NULL)
601			fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
602		m = sxfer->mbuf;
603
604		/* insert new rbuf */
605		sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
606		if (m0 != NULL) {
607			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
608			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
609		} else
610			printf("fwe_as_input: m_getcl failed\n");
611
612		if (sxfer->resp != 0 || fp->mode.stream.len <
613		    ETHER_ALIGN + sizeof(struct ether_header)) {
614			m_freem(m);
615			ifp->if_ierrors ++;
616			continue;
617		}
618
619		m->m_data += HDR_LEN + ETHER_ALIGN;
620		c = mtod(m, char *);
621#if defined(__DragonFly__) || __FreeBSD_version < 500000
622		eh = (struct ether_header *)c;
623		m->m_data += sizeof(struct ether_header);
624		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN
625		    - sizeof(struct ether_header);
626#else
627		m->m_len = m->m_pkthdr.len = fp->mode.stream.len - ETHER_ALIGN;
628#endif
629		m->m_pkthdr.rcvif = ifp;
630#if 0
631		FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n"
632			 "%02x %02x %02x %02x %02x %02x\n"
633			 "%02x %02x %02x %02x\n"
634			 "%02x %02x %02x %02x\n"
635			 "%02x %02x %02x %02x\n"
636			 "%02x %02x %02x %02x\n",
637			 c[0], c[1], c[2], c[3], c[4], c[5],
638			 c[6], c[7], c[8], c[9], c[10], c[11],
639			 c[12], c[13], c[14], c[15],
640			 c[16], c[17], c[18], c[19],
641			 c[20], c[21], c[22], c[23],
642			 c[20], c[21], c[22], c[23]
643		 );
644#endif
645#if defined(__DragonFly__) || __FreeBSD_version < 500000
646		ether_input(ifp, eh, m);
647#else
648		(*ifp->if_input)(ifp, m);
649#endif
650		ifp->if_ipackets ++;
651	}
652	if (STAILQ_FIRST(&xferq->stfree) != NULL)
653		fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch);
654}
655
656
657static devclass_t fwe_devclass;
658
659static device_method_t fwe_methods[] = {
660	/* device interface */
661	DEVMETHOD(device_identify,	fwe_identify),
662	DEVMETHOD(device_probe,		fwe_probe),
663	DEVMETHOD(device_attach,	fwe_attach),
664	DEVMETHOD(device_detach,	fwe_detach),
665	{ 0, 0 }
666};
667
668static driver_t fwe_driver = {
669        "fwe",
670	fwe_methods,
671	sizeof(struct fwe_softc),
672};
673
674
675#ifdef __DragonFly__
676DECLARE_DUMMY_MODULE(fwe);
677#endif
678DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0);
679MODULE_VERSION(fwe, 1);
680MODULE_DEPEND(fwe, firewire, 1, 1, 1);
681