1139749Simp/*- 2130407Sdfr * Copyright (c) 2004 3130407Sdfr * Doug Rabson 4130407Sdfr * Copyright (c) 2002-2003 5130407Sdfr * Hidetoshi Shimokawa. All rights reserved. 6130407Sdfr * 7130407Sdfr * Redistribution and use in source and binary forms, with or without 8130407Sdfr * modification, are permitted provided that the following conditions 9130407Sdfr * are met: 10130407Sdfr * 1. Redistributions of source code must retain the above copyright 11130407Sdfr * notice, this list of conditions and the following disclaimer. 12130407Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13130407Sdfr * notice, this list of conditions and the following disclaimer in the 14130407Sdfr * documentation and/or other materials provided with the distribution. 15130407Sdfr * 3. All advertising materials mentioning features or use of this software 16130407Sdfr * must display the following acknowledgement: 17130407Sdfr * 18130407Sdfr * This product includes software developed by Hidetoshi Shimokawa. 19130407Sdfr * 20130407Sdfr * 4. Neither the name of the author nor the names of its contributors 21130407Sdfr * may be used to endorse or promote products derived from this software 22130407Sdfr * without specific prior written permission. 23130407Sdfr * 24130407Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25130407Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26130407Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27130407Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28130407Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29130407Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30130407Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31130407Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32130407Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33130407Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34130407Sdfr * SUCH DAMAGE. 35130407Sdfr * 36130407Sdfr * $FreeBSD: stable/11/sys/dev/firewire/if_fwip.c 315221 2017-03-14 02:06:03Z pfg $ 37130407Sdfr */ 38130407Sdfr 39150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 40150968Sglebius#include "opt_device_polling.h" 41130407Sdfr#include "opt_inet.h" 42150968Sglebius#endif 43130407Sdfr 44130407Sdfr#include <sys/param.h> 45130407Sdfr#include <sys/kernel.h> 46130407Sdfr#include <sys/malloc.h> 47130407Sdfr#include <sys/mbuf.h> 48130407Sdfr#include <sys/socket.h> 49130407Sdfr#include <sys/sockio.h> 50130407Sdfr#include <sys/sysctl.h> 51130407Sdfr#include <sys/systm.h> 52130407Sdfr#include <sys/taskqueue.h> 53130407Sdfr#include <sys/module.h> 54130407Sdfr#include <sys/bus.h> 55130407Sdfr#include <machine/bus.h> 56130407Sdfr 57130407Sdfr#include <net/bpf.h> 58130407Sdfr#include <net/if.h> 59257176Sglebius#include <net/if_var.h> 60130407Sdfr#include <net/firewire.h> 61130407Sdfr#include <net/if_arp.h> 62147256Sbrooks#include <net/if_types.h> 63130407Sdfr#include <dev/firewire/firewire.h> 64130407Sdfr#include <dev/firewire/firewirereg.h> 65130411Sdfr#include <dev/firewire/iec13213.h> 66130407Sdfr#include <dev/firewire/if_fwipvar.h> 67130407Sdfr 68130407Sdfr/* 69130407Sdfr * We really need a mechanism for allocating regions in the FIFO 70130407Sdfr * address space. We pick a address in the OHCI controller's 'middle' 71130407Sdfr * address space. This means that the controller will automatically 72130407Sdfr * send responses for us, which is fine since we don't have any 73130407Sdfr * important information to put in the response anyway. 74130407Sdfr */ 75130407Sdfr#define INET_FIFO 0xfffe00000000LL 76130407Sdfr 77130407Sdfr#define FWIPDEBUG if (fwipdebug) if_printf 78130407Sdfr#define TX_MAX_QUEUE (FWMAXQUEUE - 1) 79130407Sdfr 80130407Sdfr/* network interface */ 81130407Sdfrstatic void fwip_start (struct ifnet *); 82130407Sdfrstatic int fwip_ioctl (struct ifnet *, u_long, caddr_t); 83130407Sdfrstatic void fwip_init (void *); 84130407Sdfr 85130407Sdfrstatic void fwip_post_busreset (void *); 86130407Sdfrstatic void fwip_output_callback (struct fw_xfer *); 87130407Sdfrstatic void fwip_async_output (struct fwip_softc *, struct ifnet *); 88130407Sdfrstatic void fwip_start_send (void *, int); 89130407Sdfrstatic void fwip_stream_input (struct fw_xferq *); 90130407Sdfrstatic void fwip_unicast_input(struct fw_xfer *); 91130407Sdfr 92130407Sdfrstatic int fwipdebug = 0; 93132445Sdfrstatic int broadcast_channel = 0xc0 | 0x1f; /* tag | channel(XXX) */ 94130407Sdfrstatic int tx_speed = 2; 95130407Sdfrstatic int rx_queue_len = FWMAXQUEUE; 96130407Sdfr 97227293Sedstatic MALLOC_DEFINE(M_FWIP, "if_fwip", "IP over FireWire interface"); 98130407SdfrSYSCTL_INT(_debug, OID_AUTO, if_fwip_debug, CTLFLAG_RW, &fwipdebug, 0, ""); 99130407SdfrSYSCTL_DECL(_hw_firewire); 100227309Sedstatic SYSCTL_NODE(_hw_firewire, OID_AUTO, fwip, CTLFLAG_RD, 0, 101130407Sdfr "Firewire ip subsystem"); 102267992ShselaskySYSCTL_INT(_hw_firewire_fwip, OID_AUTO, rx_queue_len, CTLFLAG_RWTUN, &rx_queue_len, 103130407Sdfr 0, "Length of the receive queue"); 104130407Sdfr 105130407Sdfr#ifdef DEVICE_POLLING 106130407Sdfrstatic poll_handler_t fwip_poll; 107130407Sdfr 108193096Sattiliostatic int 109130407Sdfrfwip_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 110130407Sdfr{ 111130407Sdfr struct fwip_softc *fwip; 112130407Sdfr struct firewire_comm *fc; 113130407Sdfr 114150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 115193096Sattilio return (0); 116150789Sglebius 117130407Sdfr fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 118130407Sdfr fc = fwip->fd.fc; 119130407Sdfr fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); 120193096Sattilio return (0); 121130407Sdfr} 122150789Sglebius#endif /* DEVICE_POLLING */ 123150789Sglebius 124130407Sdfrstatic void 125130407Sdfrfwip_identify(driver_t *driver, device_t parent) 126130407Sdfr{ 127130407Sdfr BUS_ADD_CHILD(parent, 0, "fwip", device_get_unit(parent)); 128130407Sdfr} 129130407Sdfr 130130407Sdfrstatic int 131130407Sdfrfwip_probe(device_t dev) 132130407Sdfr{ 133130407Sdfr device_t pa; 134130407Sdfr 135130407Sdfr pa = device_get_parent(dev); 136272214Skan if (device_get_unit(dev) != device_get_unit(pa)) { 137272214Skan return (ENXIO); 138130407Sdfr } 139130407Sdfr 140130407Sdfr device_set_desc(dev, "IP over FireWire"); 141130407Sdfr return (0); 142130407Sdfr} 143130407Sdfr 144130407Sdfrstatic int 145130407Sdfrfwip_attach(device_t dev) 146130407Sdfr{ 147130407Sdfr struct fwip_softc *fwip; 148130407Sdfr struct ifnet *ifp; 149130407Sdfr int unit, s; 150130407Sdfr struct fw_hwaddr *hwaddr; 151130407Sdfr 152130407Sdfr fwip = ((struct fwip_softc *)device_get_softc(dev)); 153130407Sdfr unit = device_get_unit(dev); 154147256Sbrooks ifp = fwip->fw_softc.fwip_ifp = if_alloc(IFT_IEEE1394); 155147256Sbrooks if (ifp == NULL) 156147256Sbrooks return (ENOSPC); 157130407Sdfr 158170374Ssimokawa mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF); 159130407Sdfr /* XXX */ 160130407Sdfr fwip->dma_ch = -1; 161130407Sdfr 162130407Sdfr fwip->fd.fc = device_get_ivars(dev); 163130407Sdfr if (tx_speed < 0) 164130407Sdfr tx_speed = fwip->fd.fc->speed; 165130407Sdfr 166130407Sdfr fwip->fd.dev = dev; 167130407Sdfr fwip->fd.post_explore = NULL; 168130407Sdfr fwip->fd.post_busreset = fwip_post_busreset; 169130407Sdfr fwip->fw_softc.fwip = fwip; 170130407Sdfr TASK_INIT(&fwip->start_send, 0, fwip_start_send, fwip); 171130407Sdfr 172130407Sdfr /* 173130407Sdfr * Encode our hardware the way that arp likes it. 174130407Sdfr */ 175147256Sbrooks hwaddr = &IFP2FWC(fwip->fw_softc.fwip_ifp)->fc_hwaddr; 176130407Sdfr hwaddr->sender_unique_ID_hi = htonl(fwip->fd.fc->eui.hi); 177130407Sdfr hwaddr->sender_unique_ID_lo = htonl(fwip->fd.fc->eui.lo); 178130407Sdfr hwaddr->sender_max_rec = fwip->fd.fc->maxrec; 179130407Sdfr hwaddr->sspd = fwip->fd.fc->speed; 180130407Sdfr hwaddr->sender_unicast_FIFO_hi = htons((uint16_t)(INET_FIFO >> 32)); 181130407Sdfr hwaddr->sender_unicast_FIFO_lo = htonl((uint32_t)INET_FIFO); 182130407Sdfr 183130407Sdfr /* fill the rest and attach interface */ 184130407Sdfr ifp->if_softc = &fwip->fw_softc; 185130407Sdfr 186130407Sdfr if_initname(ifp, device_get_name(dev), unit); 187130407Sdfr ifp->if_init = fwip_init; 188130407Sdfr ifp->if_start = fwip_start; 189130407Sdfr ifp->if_ioctl = fwip_ioctl; 190170374Ssimokawa ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 191130407Sdfr ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; 192150789Sglebius#ifdef DEVICE_POLLING 193150789Sglebius ifp->if_capabilities |= IFCAP_POLLING; 194150789Sglebius#endif 195130407Sdfr 196130407Sdfr s = splimp(); 197130407Sdfr firewire_ifattach(ifp, hwaddr); 198130407Sdfr splx(s); 199130407Sdfr 200130407Sdfr FWIPDEBUG(ifp, "interface created\n"); 201130407Sdfr return 0; 202130407Sdfr} 203130407Sdfr 204130407Sdfrstatic void 205130407Sdfrfwip_stop(struct fwip_softc *fwip) 206130407Sdfr{ 207130407Sdfr struct firewire_comm *fc; 208130407Sdfr struct fw_xferq *xferq; 209147256Sbrooks struct ifnet *ifp = fwip->fw_softc.fwip_ifp; 210130407Sdfr struct fw_xfer *xfer, *next; 211130407Sdfr int i; 212130407Sdfr 213130407Sdfr fc = fwip->fd.fc; 214130407Sdfr 215130407Sdfr if (fwip->dma_ch >= 0) { 216130407Sdfr xferq = fc->ir[fwip->dma_ch]; 217130407Sdfr 218130407Sdfr if (xferq->flag & FWXFERQ_RUNNING) 219130407Sdfr fc->irx_disable(fc, fwip->dma_ch); 220130407Sdfr xferq->flag &= 221130407Sdfr ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 222130407Sdfr FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 223130407Sdfr xferq->hand = NULL; 224130407Sdfr 225272214Skan for (i = 0; i < xferq->bnchunk; i++) 226130407Sdfr m_freem(xferq->bulkxfer[i].mbuf); 227130407Sdfr free(xferq->bulkxfer, M_FWIP); 228130407Sdfr 229130407Sdfr fw_bindremove(fc, &fwip->fwb); 230130407Sdfr for (xfer = STAILQ_FIRST(&fwip->fwb.xferlist); xfer != NULL; 231130407Sdfr xfer = next) { 232130407Sdfr next = STAILQ_NEXT(xfer, link); 233130407Sdfr fw_xfer_free(xfer); 234130407Sdfr } 235130407Sdfr 236130407Sdfr for (xfer = STAILQ_FIRST(&fwip->xferlist); xfer != NULL; 237130407Sdfr xfer = next) { 238130407Sdfr next = STAILQ_NEXT(xfer, link); 239130407Sdfr fw_xfer_free(xfer); 240130407Sdfr } 241130407Sdfr STAILQ_INIT(&fwip->xferlist); 242130407Sdfr 243130407Sdfr xferq->bulkxfer = NULL; 244130407Sdfr fwip->dma_ch = -1; 245130407Sdfr } 246130407Sdfr 247148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 248130407Sdfr} 249130407Sdfr 250130407Sdfrstatic int 251130407Sdfrfwip_detach(device_t dev) 252130407Sdfr{ 253130407Sdfr struct fwip_softc *fwip; 254150789Sglebius struct ifnet *ifp; 255130407Sdfr int s; 256130407Sdfr 257130407Sdfr fwip = (struct fwip_softc *)device_get_softc(dev); 258150789Sglebius ifp = fwip->fw_softc.fwip_ifp; 259150789Sglebius 260150789Sglebius#ifdef DEVICE_POLLING 261150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 262150789Sglebius ether_poll_deregister(ifp); 263150789Sglebius#endif 264150789Sglebius 265130407Sdfr s = splimp(); 266130407Sdfr 267130407Sdfr fwip_stop(fwip); 268150789Sglebius firewire_ifdetach(ifp); 269150789Sglebius if_free(ifp); 270170374Ssimokawa mtx_destroy(&fwip->mtx); 271130407Sdfr 272130407Sdfr splx(s); 273130407Sdfr return 0; 274130407Sdfr} 275130407Sdfr 276130407Sdfrstatic void 277130407Sdfrfwip_init(void *arg) 278130407Sdfr{ 279130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)arg)->fwip; 280130407Sdfr struct firewire_comm *fc; 281147256Sbrooks struct ifnet *ifp = fwip->fw_softc.fwip_ifp; 282130407Sdfr struct fw_xferq *xferq; 283130407Sdfr struct fw_xfer *xfer; 284130407Sdfr struct mbuf *m; 285130407Sdfr int i; 286130407Sdfr 287130407Sdfr FWIPDEBUG(ifp, "initializing\n"); 288130407Sdfr 289130407Sdfr fc = fwip->fd.fc; 290130407Sdfr#define START 0 291130407Sdfr if (fwip->dma_ch < 0) { 292170374Ssimokawa fwip->dma_ch = fw_open_isodma(fc, /* tx */0); 293170374Ssimokawa if (fwip->dma_ch < 0) 294170374Ssimokawa return; 295170374Ssimokawa xferq = fc->ir[fwip->dma_ch]; 296170374Ssimokawa xferq->flag |= FWXFERQ_EXTBUF | 297130407Sdfr FWXFERQ_HANDLER | FWXFERQ_STREAM; 298130407Sdfr xferq->flag &= ~0xff; 299130407Sdfr xferq->flag |= broadcast_channel & 0xff; 300130407Sdfr /* register fwip_input handler */ 301130407Sdfr xferq->sc = (caddr_t) fwip; 302130407Sdfr xferq->hand = fwip_stream_input; 303130407Sdfr xferq->bnchunk = rx_queue_len; 304130407Sdfr xferq->bnpacket = 1; 305130407Sdfr xferq->psize = MCLBYTES; 306130407Sdfr xferq->queued = 0; 307130407Sdfr xferq->buf = NULL; 308130407Sdfr xferq->bulkxfer = (struct fw_bulkxfer *) malloc( 309130407Sdfr sizeof(struct fw_bulkxfer) * xferq->bnchunk, 310130407Sdfr M_FWIP, M_WAITOK); 311130407Sdfr if (xferq->bulkxfer == NULL) { 312130407Sdfr printf("if_fwip: malloc failed\n"); 313130407Sdfr return; 314130407Sdfr } 315130407Sdfr STAILQ_INIT(&xferq->stvalid); 316130407Sdfr STAILQ_INIT(&xferq->stfree); 317130407Sdfr STAILQ_INIT(&xferq->stdma); 318130407Sdfr xferq->stproc = NULL; 319272214Skan for (i = 0; i < xferq->bnchunk; i++) { 320243857Sglebius m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); 321130407Sdfr xferq->bulkxfer[i].mbuf = m; 322177599Sru m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 323177599Sru STAILQ_INSERT_TAIL(&xferq->stfree, 324177599Sru &xferq->bulkxfer[i], link); 325130407Sdfr } 326130407Sdfr 327130407Sdfr fwip->fwb.start = INET_FIFO; 328130407Sdfr fwip->fwb.end = INET_FIFO + 16384; /* S3200 packet size */ 329130407Sdfr 330130407Sdfr /* pre-allocate xfer */ 331130407Sdfr STAILQ_INIT(&fwip->fwb.xferlist); 332272214Skan for (i = 0; i < rx_queue_len; i++) { 333130407Sdfr xfer = fw_xfer_alloc(M_FWIP); 334130407Sdfr if (xfer == NULL) 335130407Sdfr break; 336243857Sglebius m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); 337130407Sdfr xfer->recv.payload = mtod(m, uint32_t *); 338130407Sdfr xfer->recv.pay_len = MCLBYTES; 339167632Ssimokawa xfer->hand = fwip_unicast_input; 340130407Sdfr xfer->fc = fc; 341130407Sdfr xfer->sc = (caddr_t)fwip; 342130407Sdfr xfer->mbuf = m; 343130407Sdfr STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link); 344130407Sdfr } 345130407Sdfr fw_bindadd(fc, &fwip->fwb); 346130407Sdfr 347130407Sdfr STAILQ_INIT(&fwip->xferlist); 348130407Sdfr for (i = 0; i < TX_MAX_QUEUE; i++) { 349130407Sdfr xfer = fw_xfer_alloc(M_FWIP); 350130407Sdfr if (xfer == NULL) 351130407Sdfr break; 352130407Sdfr xfer->send.spd = tx_speed; 353130407Sdfr xfer->fc = fwip->fd.fc; 354130407Sdfr xfer->sc = (caddr_t)fwip; 355167632Ssimokawa xfer->hand = fwip_output_callback; 356130407Sdfr STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); 357130407Sdfr } 358130407Sdfr } else 359130407Sdfr xferq = fc->ir[fwip->dma_ch]; 360130407Sdfr 361130407Sdfr fwip->last_dest.hi = 0; 362130407Sdfr fwip->last_dest.lo = 0; 363130407Sdfr 364130407Sdfr /* start dma */ 365130407Sdfr if ((xferq->flag & FWXFERQ_RUNNING) == 0) 366130407Sdfr fc->irx_enable(fc, fwip->dma_ch); 367130407Sdfr 368148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 369148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 370130407Sdfr 371130407Sdfr#if 0 372130407Sdfr /* attempt to start output */ 373130407Sdfr fwip_start(ifp); 374130407Sdfr#endif 375130407Sdfr} 376130407Sdfr 377130407Sdfrstatic int 378130407Sdfrfwip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 379130407Sdfr{ 380130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 381130407Sdfr int s, error; 382130407Sdfr 383130407Sdfr switch (cmd) { 384130407Sdfr case SIOCSIFFLAGS: 385130407Sdfr s = splimp(); 386130407Sdfr if (ifp->if_flags & IFF_UP) { 387148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 388130407Sdfr fwip_init(&fwip->fw_softc); 389130407Sdfr } else { 390148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 391130407Sdfr fwip_stop(fwip); 392130407Sdfr } 393130407Sdfr splx(s); 394130407Sdfr break; 395130407Sdfr case SIOCADDMULTI: 396130407Sdfr case SIOCDELMULTI: 397130407Sdfr break; 398150789Sglebius case SIOCSIFCAP: 399150789Sglebius#ifdef DEVICE_POLLING 400150789Sglebius { 401150789Sglebius struct ifreq *ifr = (struct ifreq *) data; 402188394Sfjoe struct firewire_comm *fc = fwip->fd.fc; 403130407Sdfr 404150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 405150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 406150789Sglebius error = ether_poll_register(fwip_poll, ifp); 407150789Sglebius if (error) 408272214Skan return (error); 409150789Sglebius /* Disable interrupts */ 410150789Sglebius fc->set_intr(fc, 0); 411193096Sattilio ifp->if_capenable |= IFCAP_POLLING | 412193096Sattilio IFCAP_POLLING_NOCOUNT; 413150789Sglebius return (error); 414150789Sglebius } 415150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 416150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 417150789Sglebius error = ether_poll_deregister(ifp); 418150789Sglebius /* Enable interrupts. */ 419150789Sglebius fc->set_intr(fc, 1); 420150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 421193096Sattilio ifp->if_capenable &= ~IFCAP_POLLING_NOCOUNT; 422150789Sglebius return (error); 423150789Sglebius } 424150789Sglebius } 425150789Sglebius#endif /* DEVICE_POLLING */ 426150789Sglebius break; 427130407Sdfr default: 428130407Sdfr s = splimp(); 429130407Sdfr error = firewire_ioctl(ifp, cmd, data); 430130407Sdfr splx(s); 431130407Sdfr return (error); 432130407Sdfr } 433130407Sdfr 434130407Sdfr return (0); 435130407Sdfr} 436130407Sdfr 437130407Sdfrstatic void 438130407Sdfrfwip_post_busreset(void *arg) 439130407Sdfr{ 440130407Sdfr struct fwip_softc *fwip = arg; 441130411Sdfr struct crom_src *src; 442130411Sdfr struct crom_chunk *root; 443130407Sdfr 444130411Sdfr src = fwip->fd.fc->crom_src; 445130411Sdfr root = fwip->fd.fc->crom_root; 446130411Sdfr 447130411Sdfr /* RFC2734 IPv4 over IEEE1394 */ 448130411Sdfr bzero(&fwip->unit4, sizeof(struct crom_chunk)); 449130411Sdfr crom_add_chunk(src, root, &fwip->unit4, CROM_UDIR); 450130411Sdfr crom_add_entry(&fwip->unit4, CSRKEY_SPEC, CSRVAL_IETF); 451130411Sdfr crom_add_simple_text(src, &fwip->unit4, &fwip->spec4, "IANA"); 452130411Sdfr crom_add_entry(&fwip->unit4, CSRKEY_VER, 1); 453130411Sdfr crom_add_simple_text(src, &fwip->unit4, &fwip->ver4, "IPv4"); 454130411Sdfr 455130411Sdfr /* RFC3146 IPv6 over IEEE1394 */ 456130411Sdfr bzero(&fwip->unit6, sizeof(struct crom_chunk)); 457130411Sdfr crom_add_chunk(src, root, &fwip->unit6, CROM_UDIR); 458130411Sdfr crom_add_entry(&fwip->unit6, CSRKEY_SPEC, CSRVAL_IETF); 459130411Sdfr crom_add_simple_text(src, &fwip->unit6, &fwip->spec6, "IANA"); 460130411Sdfr crom_add_entry(&fwip->unit6, CSRKEY_VER, 2); 461130411Sdfr crom_add_simple_text(src, &fwip->unit6, &fwip->ver6, "IPv6"); 462130411Sdfr 463130407Sdfr fwip->last_dest.hi = 0; 464130407Sdfr fwip->last_dest.lo = 0; 465147256Sbrooks firewire_busreset(fwip->fw_softc.fwip_ifp); 466130407Sdfr} 467130407Sdfr 468130407Sdfrstatic void 469130407Sdfrfwip_output_callback(struct fw_xfer *xfer) 470130407Sdfr{ 471130407Sdfr struct fwip_softc *fwip; 472130407Sdfr struct ifnet *ifp; 473130407Sdfr int s; 474130407Sdfr 475130407Sdfr fwip = (struct fwip_softc *)xfer->sc; 476147256Sbrooks ifp = fwip->fw_softc.fwip_ifp; 477130407Sdfr /* XXX error check */ 478130407Sdfr FWIPDEBUG(ifp, "resp = %d\n", xfer->resp); 479130407Sdfr if (xfer->resp != 0) 480271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 481130407Sdfr m_freem(xfer->mbuf); 482130407Sdfr fw_xfer_unload(xfer); 483130407Sdfr 484130407Sdfr s = splimp(); 485170374Ssimokawa FWIP_LOCK(fwip); 486130407Sdfr STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); 487170374Ssimokawa FWIP_UNLOCK(fwip); 488130407Sdfr splx(s); 489130407Sdfr 490130407Sdfr /* for queue full */ 491170374Ssimokawa if (ifp->if_snd.ifq_head != NULL) { 492130407Sdfr fwip_start(ifp); 493170374Ssimokawa } 494130407Sdfr} 495130407Sdfr 496130407Sdfrstatic void 497130407Sdfrfwip_start(struct ifnet *ifp) 498130407Sdfr{ 499130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 500130407Sdfr int s; 501130407Sdfr 502130407Sdfr FWIPDEBUG(ifp, "starting\n"); 503130407Sdfr 504130407Sdfr if (fwip->dma_ch < 0) { 505130407Sdfr struct mbuf *m = NULL; 506130407Sdfr 507130407Sdfr FWIPDEBUG(ifp, "not ready\n"); 508130407Sdfr 509130407Sdfr s = splimp(); 510130407Sdfr do { 511130407Sdfr IF_DEQUEUE(&ifp->if_snd, m); 512130407Sdfr if (m != NULL) 513130407Sdfr m_freem(m); 514271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 515130407Sdfr } while (m != NULL); 516130407Sdfr splx(s); 517130407Sdfr 518130407Sdfr return; 519130407Sdfr } 520130407Sdfr 521130407Sdfr s = splimp(); 522148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 523130407Sdfr 524130407Sdfr if (ifp->if_snd.ifq_len != 0) 525130407Sdfr fwip_async_output(fwip, ifp); 526130407Sdfr 527148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 528130407Sdfr splx(s); 529130407Sdfr} 530130407Sdfr 531130407Sdfr/* Async. stream output */ 532130407Sdfrstatic void 533130407Sdfrfwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) 534130407Sdfr{ 535130407Sdfr struct firewire_comm *fc = fwip->fd.fc; 536130407Sdfr struct mbuf *m; 537130407Sdfr struct m_tag *mtag; 538130407Sdfr struct fw_hwaddr *destfw; 539130407Sdfr struct fw_xfer *xfer; 540130407Sdfr struct fw_xferq *xferq; 541130407Sdfr struct fw_pkt *fp; 542130407Sdfr uint16_t nodeid; 543130460Sdfr int error; 544130407Sdfr int i = 0; 545130407Sdfr 546130407Sdfr xfer = NULL; 547170374Ssimokawa xferq = fc->atq; 548170374Ssimokawa while ((xferq->queued < xferq->maxq - 1) && 549170374Ssimokawa (ifp->if_snd.ifq_head != NULL)) { 550170374Ssimokawa FWIP_LOCK(fwip); 551130407Sdfr xfer = STAILQ_FIRST(&fwip->xferlist); 552130407Sdfr if (xfer == NULL) { 553170374Ssimokawa FWIP_UNLOCK(fwip); 554170374Ssimokawa#if 0 555130407Sdfr printf("if_fwip: lack of xfer\n"); 556170374Ssimokawa#endif 557170374Ssimokawa break; 558130407Sdfr } 559170374Ssimokawa STAILQ_REMOVE_HEAD(&fwip->xferlist, link); 560170374Ssimokawa FWIP_UNLOCK(fwip); 561170374Ssimokawa 562130407Sdfr IF_DEQUEUE(&ifp->if_snd, m); 563170374Ssimokawa if (m == NULL) { 564170374Ssimokawa FWIP_LOCK(fwip); 565170374Ssimokawa STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link); 566170374Ssimokawa FWIP_UNLOCK(fwip); 567130407Sdfr break; 568170374Ssimokawa } 569130407Sdfr 570130407Sdfr /* 571130407Sdfr * Dig out the link-level address which 572130407Sdfr * firewire_output got via arp or neighbour 573130407Sdfr * discovery. If we don't have a link-level address, 574130407Sdfr * just stick the thing on the broadcast channel. 575130407Sdfr */ 576130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 0); 577130407Sdfr if (mtag == NULL) 578315221Spfg destfw = NULL; 579130407Sdfr else 580130407Sdfr destfw = (struct fw_hwaddr *) (mtag + 1); 581130407Sdfr 582130407Sdfr 583130407Sdfr /* 584130407Sdfr * We don't do any bpf stuff here - the generic code 585130407Sdfr * in firewire_output gives the packet to bpf before 586130407Sdfr * it adds the link-level encapsulation. 587130407Sdfr */ 588130407Sdfr 589130407Sdfr /* 590130407Sdfr * Put the mbuf in the xfer early in case we hit an 591130407Sdfr * error case below - fwip_output_callback will free 592130407Sdfr * the mbuf. 593130407Sdfr */ 594130407Sdfr xfer->mbuf = m; 595130407Sdfr 596130407Sdfr /* 597130407Sdfr * We use the arp result (if any) to add a suitable firewire 598130407Sdfr * packet header before handing off to the bus. 599130407Sdfr */ 600130407Sdfr fp = &xfer->send.hdr; 601130407Sdfr nodeid = FWLOCALBUS | fc->nodeid; 602130407Sdfr if ((m->m_flags & M_BCAST) || !destfw) { 603130407Sdfr /* 604130407Sdfr * Broadcast packets are sent as GASP packets with 605130407Sdfr * specifier ID 0x00005e, version 1 on the broadcast 606130407Sdfr * channel. To be conservative, we send at the 607130407Sdfr * slowest possible speed. 608130407Sdfr */ 609130407Sdfr uint32_t *p; 610130407Sdfr 611243857Sglebius M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT); 612130407Sdfr p = mtod(m, uint32_t *); 613130407Sdfr fp->mode.stream.len = m->m_pkthdr.len; 614130407Sdfr fp->mode.stream.chtag = broadcast_channel; 615130407Sdfr fp->mode.stream.tcode = FWTCODE_STREAM; 616130407Sdfr fp->mode.stream.sy = 0; 617130407Sdfr xfer->send.spd = 0; 618130407Sdfr p[0] = htonl(nodeid << 16); 619130407Sdfr p[1] = htonl((0x5e << 24) | 1); 620130407Sdfr } else { 621130407Sdfr /* 622130407Sdfr * Unicast packets are sent as block writes to the 623130407Sdfr * target's unicast fifo address. If we can't 624130407Sdfr * find the node address, we just give up. We 625130407Sdfr * could broadcast it but that might overflow 626130407Sdfr * the packet size limitations due to the 627130407Sdfr * extra GASP header. Note: the hardware 628130407Sdfr * address is stored in network byte order to 629130407Sdfr * make life easier for ARP. 630130407Sdfr */ 631130407Sdfr struct fw_device *fd; 632130407Sdfr struct fw_eui64 eui; 633130407Sdfr 634130407Sdfr eui.hi = ntohl(destfw->sender_unique_ID_hi); 635130407Sdfr eui.lo = ntohl(destfw->sender_unique_ID_lo); 636130407Sdfr if (fwip->last_dest.hi != eui.hi || 637130407Sdfr fwip->last_dest.lo != eui.lo) { 638130407Sdfr fd = fw_noderesolve_eui64(fc, &eui); 639130407Sdfr if (!fd) { 640130407Sdfr /* error */ 641271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 642130407Sdfr /* XXX set error code */ 643130407Sdfr fwip_output_callback(xfer); 644130407Sdfr continue; 645130407Sdfr 646130407Sdfr } 647130407Sdfr fwip->last_hdr.mode.wreqb.dst = FWLOCALBUS | fd->dst; 648130407Sdfr fwip->last_hdr.mode.wreqb.tlrt = 0; 649130407Sdfr fwip->last_hdr.mode.wreqb.tcode = FWTCODE_WREQB; 650130407Sdfr fwip->last_hdr.mode.wreqb.pri = 0; 651130407Sdfr fwip->last_hdr.mode.wreqb.src = nodeid; 652130407Sdfr fwip->last_hdr.mode.wreqb.dest_hi = 653130407Sdfr ntohs(destfw->sender_unicast_FIFO_hi); 654130407Sdfr fwip->last_hdr.mode.wreqb.dest_lo = 655130407Sdfr ntohl(destfw->sender_unicast_FIFO_lo); 656130407Sdfr fwip->last_hdr.mode.wreqb.extcode = 0; 657130407Sdfr fwip->last_dest = eui; 658130407Sdfr } 659130407Sdfr 660130407Sdfr fp->mode.wreqb = fwip->last_hdr.mode.wreqb; 661130407Sdfr fp->mode.wreqb.len = m->m_pkthdr.len; 662130407Sdfr xfer->send.spd = min(destfw->sspd, fc->speed); 663130407Sdfr } 664130407Sdfr 665130407Sdfr xfer->send.pay_len = m->m_pkthdr.len; 666130407Sdfr 667130460Sdfr error = fw_asyreq(fc, -1, xfer); 668130460Sdfr if (error == EAGAIN) { 669130460Sdfr /* 670130460Sdfr * We ran out of tlabels - requeue the packet 671130460Sdfr * for later transmission. 672130460Sdfr */ 673130460Sdfr xfer->mbuf = 0; 674170374Ssimokawa FWIP_LOCK(fwip); 675130460Sdfr STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); 676170374Ssimokawa FWIP_UNLOCK(fwip); 677130460Sdfr IF_PREPEND(&ifp->if_snd, m); 678130460Sdfr break; 679130460Sdfr } 680130460Sdfr if (error) { 681130407Sdfr /* error */ 682271849Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 683130407Sdfr /* XXX set error code */ 684130407Sdfr fwip_output_callback(xfer); 685130407Sdfr continue; 686130407Sdfr } else { 687271849Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 688130407Sdfr i++; 689130407Sdfr } 690130407Sdfr } 691130407Sdfr#if 0 692130407Sdfr if (i > 1) 693130407Sdfr printf("%d queued\n", i); 694130407Sdfr#endif 695170374Ssimokawa if (i > 0) 696130407Sdfr xferq->start(fc); 697130407Sdfr} 698130407Sdfr 699130407Sdfrstatic void 700130407Sdfrfwip_start_send (void *arg, int count) 701130407Sdfr{ 702130407Sdfr struct fwip_softc *fwip = arg; 703130407Sdfr 704130407Sdfr fwip->fd.fc->atq->start(fwip->fd.fc); 705130407Sdfr} 706130407Sdfr 707130407Sdfr/* Async. stream output */ 708130407Sdfrstatic void 709130407Sdfrfwip_stream_input(struct fw_xferq *xferq) 710130407Sdfr{ 711130407Sdfr struct mbuf *m, *m0; 712130407Sdfr struct m_tag *mtag; 713130407Sdfr struct ifnet *ifp; 714130407Sdfr struct fwip_softc *fwip; 715130407Sdfr struct fw_bulkxfer *sxfer; 716130407Sdfr struct fw_pkt *fp; 717130407Sdfr uint16_t src; 718130407Sdfr uint32_t *p; 719130407Sdfr 720130407Sdfr 721130407Sdfr fwip = (struct fwip_softc *)xferq->sc; 722147256Sbrooks ifp = fwip->fw_softc.fwip_ifp; 723150789Sglebius 724130407Sdfr while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 725130407Sdfr STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 726130407Sdfr fp = mtod(sxfer->mbuf, struct fw_pkt *); 727130407Sdfr if (fwip->fd.fc->irx_post != NULL) 728130407Sdfr fwip->fd.fc->irx_post(fwip->fd.fc, fp->mode.ld); 729130407Sdfr m = sxfer->mbuf; 730130407Sdfr 731130407Sdfr /* insert new rbuf */ 732243857Sglebius sxfer->mbuf = m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 733130407Sdfr if (m0 != NULL) { 734130407Sdfr m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size; 735130407Sdfr STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); 736130407Sdfr } else 737130407Sdfr printf("fwip_as_input: m_getcl failed\n"); 738130407Sdfr 739130407Sdfr /* 740130407Sdfr * We must have a GASP header - leave the 741130407Sdfr * encapsulation sanity checks to the generic 742298955Spfg * code. Remember that we also have the firewire async 743130407Sdfr * stream header even though that isn't accounted for 744130407Sdfr * in mode.stream.len. 745130407Sdfr */ 746130407Sdfr if (sxfer->resp != 0 || fp->mode.stream.len < 747130407Sdfr 2*sizeof(uint32_t)) { 748130407Sdfr m_freem(m); 749271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 750130407Sdfr continue; 751130407Sdfr } 752130407Sdfr m->m_len = m->m_pkthdr.len = fp->mode.stream.len 753130407Sdfr + sizeof(fp->mode.stream); 754130407Sdfr 755130407Sdfr /* 756130407Sdfr * If we received the packet on the broadcast channel, 757130407Sdfr * mark it as broadcast, otherwise we assume it must 758130407Sdfr * be multicast. 759130407Sdfr */ 760130407Sdfr if (fp->mode.stream.chtag == broadcast_channel) 761130407Sdfr m->m_flags |= M_BCAST; 762130407Sdfr else 763130407Sdfr m->m_flags |= M_MCAST; 764130407Sdfr 765130407Sdfr /* 766130407Sdfr * Make sure we recognise the GASP specifier and 767130407Sdfr * version. 768130407Sdfr */ 769130407Sdfr p = mtod(m, uint32_t *); 770130407Sdfr if ((((ntohl(p[1]) & 0xffff) << 8) | ntohl(p[2]) >> 24) != 0x00005e 771130407Sdfr || (ntohl(p[2]) & 0xffffff) != 1) { 772130407Sdfr FWIPDEBUG(ifp, "Unrecognised GASP header %#08x %#08x\n", 773130407Sdfr ntohl(p[1]), ntohl(p[2])); 774130407Sdfr m_freem(m); 775271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 776130407Sdfr continue; 777130407Sdfr } 778130407Sdfr 779130407Sdfr /* 780130407Sdfr * Record the sender ID for possible BPF usage. 781130407Sdfr */ 782130407Sdfr src = ntohl(p[1]) >> 16; 783165632Sjhb if (bpf_peers_present(ifp->if_bpf)) { 784130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, 785130407Sdfr MTAG_FIREWIRE_SENDER_EUID, 786130407Sdfr 2*sizeof(uint32_t), M_NOWAIT); 787130407Sdfr if (mtag) { 788130407Sdfr /* bpf wants it in network byte order */ 789130407Sdfr struct fw_device *fd; 790130407Sdfr uint32_t *p = (uint32_t *) (mtag + 1); 791130407Sdfr fd = fw_noderesolve_nodeid(fwip->fd.fc, 792130407Sdfr src & 0x3f); 793130407Sdfr if (fd) { 794130407Sdfr p[0] = htonl(fd->eui.hi); 795130407Sdfr p[1] = htonl(fd->eui.lo); 796130407Sdfr } else { 797130407Sdfr p[0] = 0; 798130407Sdfr p[1] = 0; 799130407Sdfr } 800130407Sdfr m_tag_prepend(m, mtag); 801130407Sdfr } 802130407Sdfr } 803130407Sdfr 804130407Sdfr /* 805130407Sdfr * Trim off the GASP header 806130407Sdfr */ 807130407Sdfr m_adj(m, 3*sizeof(uint32_t)); 808130407Sdfr m->m_pkthdr.rcvif = ifp; 809130407Sdfr firewire_input(ifp, m, src); 810271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 811130407Sdfr } 812130407Sdfr if (STAILQ_FIRST(&xferq->stfree) != NULL) 813130407Sdfr fwip->fd.fc->irx_enable(fwip->fd.fc, fwip->dma_ch); 814130407Sdfr} 815130407Sdfr 816130407Sdfrstatic __inline void 817130407Sdfrfwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer) 818130407Sdfr{ 819130407Sdfr struct mbuf *m; 820130407Sdfr 821130407Sdfr /* 822130407Sdfr * We have finished with a unicast xfer. Allocate a new 823130407Sdfr * cluster and stick it on the back of the input queue. 824130407Sdfr */ 825243857Sglebius m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); 826130407Sdfr xfer->mbuf = m; 827130407Sdfr xfer->recv.payload = mtod(m, uint32_t *); 828130407Sdfr xfer->recv.pay_len = MCLBYTES; 829130407Sdfr xfer->mbuf = m; 830130407Sdfr STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link); 831130407Sdfr} 832130407Sdfr 833130407Sdfrstatic void 834130407Sdfrfwip_unicast_input(struct fw_xfer *xfer) 835130407Sdfr{ 836130407Sdfr uint64_t address; 837130407Sdfr struct mbuf *m; 838130407Sdfr struct m_tag *mtag; 839130407Sdfr struct ifnet *ifp; 840130407Sdfr struct fwip_softc *fwip; 841130407Sdfr struct fw_pkt *fp; 842130407Sdfr //struct fw_pkt *sfp; 843130407Sdfr int rtcode; 844130407Sdfr 845130407Sdfr fwip = (struct fwip_softc *)xfer->sc; 846147256Sbrooks ifp = fwip->fw_softc.fwip_ifp; 847130407Sdfr m = xfer->mbuf; 848130407Sdfr xfer->mbuf = 0; 849130407Sdfr fp = &xfer->recv.hdr; 850130407Sdfr 851130407Sdfr /* 852130407Sdfr * Check the fifo address - we only accept addresses of 853130407Sdfr * exactly INET_FIFO. 854130407Sdfr */ 855130407Sdfr address = ((uint64_t)fp->mode.wreqb.dest_hi << 32) 856130407Sdfr | fp->mode.wreqb.dest_lo; 857130407Sdfr if (fp->mode.wreqb.tcode != FWTCODE_WREQB) { 858130407Sdfr rtcode = FWRCODE_ER_TYPE; 859130407Sdfr } else if (address != INET_FIFO) { 860130407Sdfr rtcode = FWRCODE_ER_ADDR; 861130407Sdfr } else { 862130407Sdfr rtcode = FWRCODE_COMPLETE; 863130407Sdfr } 864130407Sdfr 865130407Sdfr /* 866130407Sdfr * Pick up a new mbuf and stick it on the back of the receive 867130407Sdfr * queue. 868130407Sdfr */ 869130407Sdfr fwip_unicast_input_recycle(fwip, xfer); 870130407Sdfr 871130407Sdfr /* 872130407Sdfr * If we've already rejected the packet, give up now. 873130407Sdfr */ 874130407Sdfr if (rtcode != FWRCODE_COMPLETE) { 875130407Sdfr m_freem(m); 876271849Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 877130407Sdfr return; 878130407Sdfr } 879130407Sdfr 880165632Sjhb if (bpf_peers_present(ifp->if_bpf)) { 881130407Sdfr /* 882130407Sdfr * Record the sender ID for possible BPF usage. 883130407Sdfr */ 884130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 885130407Sdfr 2*sizeof(uint32_t), M_NOWAIT); 886130407Sdfr if (mtag) { 887130407Sdfr /* bpf wants it in network byte order */ 888130407Sdfr struct fw_device *fd; 889130407Sdfr uint32_t *p = (uint32_t *) (mtag + 1); 890130407Sdfr fd = fw_noderesolve_nodeid(fwip->fd.fc, 891130407Sdfr fp->mode.wreqb.src & 0x3f); 892130407Sdfr if (fd) { 893130407Sdfr p[0] = htonl(fd->eui.hi); 894130407Sdfr p[1] = htonl(fd->eui.lo); 895130407Sdfr } else { 896130407Sdfr p[0] = 0; 897130407Sdfr p[1] = 0; 898130407Sdfr } 899130407Sdfr m_tag_prepend(m, mtag); 900130407Sdfr } 901130407Sdfr } 902130407Sdfr 903130407Sdfr /* 904130407Sdfr * Hand off to the generic encapsulation code. We don't use 905130407Sdfr * ifp->if_input so that we can pass the source nodeid as an 906130407Sdfr * argument to facilitate link-level fragment reassembly. 907130407Sdfr */ 908130407Sdfr m->m_len = m->m_pkthdr.len = fp->mode.wreqb.len; 909130407Sdfr m->m_pkthdr.rcvif = ifp; 910130407Sdfr firewire_input(ifp, m, fp->mode.wreqb.src); 911271849Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 912130407Sdfr} 913130407Sdfr 914130407Sdfrstatic devclass_t fwip_devclass; 915130407Sdfr 916130407Sdfrstatic device_method_t fwip_methods[] = { 917130407Sdfr /* device interface */ 918130407Sdfr DEVMETHOD(device_identify, fwip_identify), 919130407Sdfr DEVMETHOD(device_probe, fwip_probe), 920130407Sdfr DEVMETHOD(device_attach, fwip_attach), 921130407Sdfr DEVMETHOD(device_detach, fwip_detach), 922130407Sdfr { 0, 0 } 923130407Sdfr}; 924130407Sdfr 925130407Sdfrstatic driver_t fwip_driver = { 926130407Sdfr "fwip", 927130407Sdfr fwip_methods, 928130407Sdfr sizeof(struct fwip_softc), 929130407Sdfr}; 930130407Sdfr 931130407Sdfr 932130407SdfrDRIVER_MODULE(fwip, firewire, fwip_driver, fwip_devclass, 0, 0); 933130407SdfrMODULE_VERSION(fwip, 1); 934130407SdfrMODULE_DEPEND(fwip, firewire, 1, 1, 1); 935