if_fwip.c revision 130411
1130407Sdfr/* 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: head/sys/dev/firewire/if_fwip.c 130411 2004-06-13 13:58:00Z dfr $ 37130407Sdfr */ 38130407Sdfr 39130407Sdfr#include "opt_inet.h" 40130407Sdfr 41130407Sdfr#include <sys/param.h> 42130407Sdfr#include <sys/kernel.h> 43130407Sdfr#include <sys/malloc.h> 44130407Sdfr#include <sys/mbuf.h> 45130407Sdfr#include <sys/socket.h> 46130407Sdfr#include <sys/sockio.h> 47130407Sdfr#include <sys/sysctl.h> 48130407Sdfr#include <sys/systm.h> 49130407Sdfr#include <sys/taskqueue.h> 50130407Sdfr#include <sys/module.h> 51130407Sdfr#include <sys/bus.h> 52130407Sdfr#include <machine/bus.h> 53130407Sdfr 54130407Sdfr#include <net/bpf.h> 55130407Sdfr#include <net/if.h> 56130407Sdfr#include <net/firewire.h> 57130407Sdfr#include <net/if_arp.h> 58130407Sdfr#ifdef __DragonFly__ 59130407Sdfr#include <bus/firewire/firewire.h> 60130407Sdfr#include <bus/firewire/firewirereg.h> 61130407Sdfr#include "if_fwipvar.h" 62130407Sdfr#else 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#endif 68130407Sdfr 69130407Sdfr/* 70130407Sdfr * We really need a mechanism for allocating regions in the FIFO 71130407Sdfr * address space. We pick a address in the OHCI controller's 'middle' 72130407Sdfr * address space. This means that the controller will automatically 73130407Sdfr * send responses for us, which is fine since we don't have any 74130407Sdfr * important information to put in the response anyway. 75130407Sdfr */ 76130407Sdfr#define INET_FIFO 0xfffe00000000LL 77130407Sdfr 78130407Sdfr#define FWIPDEBUG if (fwipdebug) if_printf 79130407Sdfr#define TX_MAX_QUEUE (FWMAXQUEUE - 1) 80130407Sdfr 81130407Sdfr/* network interface */ 82130407Sdfrstatic void fwip_start (struct ifnet *); 83130407Sdfrstatic int fwip_ioctl (struct ifnet *, u_long, caddr_t); 84130407Sdfrstatic void fwip_init (void *); 85130407Sdfr 86130407Sdfrstatic void fwip_post_busreset (void *); 87130407Sdfrstatic void fwip_output_callback (struct fw_xfer *); 88130407Sdfrstatic void fwip_async_output (struct fwip_softc *, struct ifnet *); 89130407Sdfrstatic void fwip_start_send (void *, int); 90130407Sdfrstatic void fwip_stream_input (struct fw_xferq *); 91130407Sdfrstatic void fwip_unicast_input(struct fw_xfer *); 92130407Sdfr 93130407Sdfrstatic int fwipdebug = 0; 94130407Sdfrstatic int broadcast_channel = 31; /* XXX */ 95130407Sdfrstatic int tx_speed = 2; 96130407Sdfrstatic int rx_queue_len = FWMAXQUEUE; 97130407Sdfr 98130407SdfrMALLOC_DEFINE(M_FWIP, "if_fwip", "IP over FireWire interface"); 99130407SdfrSYSCTL_INT(_debug, OID_AUTO, if_fwip_debug, CTLFLAG_RW, &fwipdebug, 0, ""); 100130407SdfrSYSCTL_DECL(_hw_firewire); 101130407SdfrSYSCTL_NODE(_hw_firewire, OID_AUTO, fwip, CTLFLAG_RD, 0, 102130407Sdfr "Firewire ip subsystem"); 103130407SdfrSYSCTL_INT(_hw_firewire_fwip, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len, 104130407Sdfr 0, "Length of the receive queue"); 105130407Sdfr 106130407SdfrTUNABLE_INT("hw.firewire.fwip.rx_queue_len", &rx_queue_len); 107130407Sdfr 108130407Sdfr#ifdef DEVICE_POLLING 109130407Sdfr#define FWIP_POLL_REGISTER(func, fwip, ifp) \ 110130407Sdfr if (ether_poll_register(func, ifp)) { \ 111130407Sdfr struct firewire_comm *fc = (fwip)->fd.fc; \ 112130407Sdfr fc->set_intr(fc, 0); \ 113130407Sdfr } 114130407Sdfr 115130407Sdfr#define FWIP_POLL_DEREGISTER(fwip, ifp) \ 116130407Sdfr do { \ 117130407Sdfr struct firewire_comm *fc = (fwip)->fd.fc; \ 118130407Sdfr ether_poll_deregister(ifp); \ 119130407Sdfr fc->set_intr(fc, 1); \ 120130407Sdfr } while(0) \ 121130407Sdfr 122130407Sdfrstatic poll_handler_t fwip_poll; 123130407Sdfr 124130407Sdfrstatic void 125130407Sdfrfwip_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 126130407Sdfr{ 127130407Sdfr struct fwip_softc *fwip; 128130407Sdfr struct firewire_comm *fc; 129130407Sdfr 130130407Sdfr fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 131130407Sdfr fc = fwip->fd.fc; 132130407Sdfr if (cmd == POLL_DEREGISTER) { 133130407Sdfr /* enable interrupts */ 134130407Sdfr fc->set_intr(fc, 1); 135130407Sdfr return; 136130407Sdfr } 137130407Sdfr fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); 138130407Sdfr} 139130407Sdfr#else 140130407Sdfr#define FWIP_POLL_REGISTER(func, fwip, ifp) 141130407Sdfr#define FWIP_POLL_DEREGISTER(fwip, ifp) 142130407Sdfr#endif 143130407Sdfrstatic void 144130407Sdfrfwip_identify(driver_t *driver, device_t parent) 145130407Sdfr{ 146130407Sdfr BUS_ADD_CHILD(parent, 0, "fwip", device_get_unit(parent)); 147130407Sdfr} 148130407Sdfr 149130407Sdfrstatic int 150130407Sdfrfwip_probe(device_t dev) 151130407Sdfr{ 152130407Sdfr device_t pa; 153130407Sdfr 154130407Sdfr pa = device_get_parent(dev); 155130407Sdfr if(device_get_unit(dev) != device_get_unit(pa)){ 156130407Sdfr return(ENXIO); 157130407Sdfr } 158130407Sdfr 159130407Sdfr device_set_desc(dev, "IP over FireWire"); 160130407Sdfr return (0); 161130407Sdfr} 162130407Sdfr 163130407Sdfrstatic int 164130407Sdfrfwip_attach(device_t dev) 165130407Sdfr{ 166130407Sdfr struct fwip_softc *fwip; 167130407Sdfr struct ifnet *ifp; 168130407Sdfr int unit, s; 169130407Sdfr struct fw_hwaddr *hwaddr; 170130407Sdfr 171130407Sdfr fwip = ((struct fwip_softc *)device_get_softc(dev)); 172130407Sdfr unit = device_get_unit(dev); 173130407Sdfr 174130407Sdfr bzero(fwip, sizeof(struct fwip_softc)); 175130407Sdfr /* XXX */ 176130407Sdfr fwip->dma_ch = -1; 177130407Sdfr 178130407Sdfr fwip->fd.fc = device_get_ivars(dev); 179130407Sdfr if (tx_speed < 0) 180130407Sdfr tx_speed = fwip->fd.fc->speed; 181130407Sdfr 182130407Sdfr fwip->fd.dev = dev; 183130407Sdfr fwip->fd.post_explore = NULL; 184130407Sdfr fwip->fd.post_busreset = fwip_post_busreset; 185130407Sdfr fwip->fw_softc.fwip = fwip; 186130407Sdfr TASK_INIT(&fwip->start_send, 0, fwip_start_send, fwip); 187130407Sdfr 188130407Sdfr /* 189130407Sdfr * Encode our hardware the way that arp likes it. 190130407Sdfr */ 191130407Sdfr hwaddr = &fwip->fw_softc.fwcom.fc_hwaddr; 192130407Sdfr hwaddr->sender_unique_ID_hi = htonl(fwip->fd.fc->eui.hi); 193130407Sdfr hwaddr->sender_unique_ID_lo = htonl(fwip->fd.fc->eui.lo); 194130407Sdfr hwaddr->sender_max_rec = fwip->fd.fc->maxrec; 195130407Sdfr hwaddr->sspd = fwip->fd.fc->speed; 196130407Sdfr hwaddr->sender_unicast_FIFO_hi = htons((uint16_t)(INET_FIFO >> 32)); 197130407Sdfr hwaddr->sender_unicast_FIFO_lo = htonl((uint32_t)INET_FIFO); 198130407Sdfr 199130407Sdfr /* fill the rest and attach interface */ 200130407Sdfr ifp = &fwip->fwip_if; 201130407Sdfr ifp->if_softc = &fwip->fw_softc; 202130407Sdfr 203130407Sdfr#if __FreeBSD_version >= 501113 || defined(__DragonFly__) 204130407Sdfr if_initname(ifp, device_get_name(dev), unit); 205130407Sdfr#else 206130407Sdfr ifp->if_unit = unit; 207130407Sdfr ifp->if_name = "fwip"; 208130407Sdfr#endif 209130407Sdfr ifp->if_init = fwip_init; 210130407Sdfr ifp->if_start = fwip_start; 211130407Sdfr ifp->if_ioctl = fwip_ioctl; 212130407Sdfr ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 213130407Sdfr ifp->if_snd.ifq_maxlen = TX_MAX_QUEUE; 214130407Sdfr 215130407Sdfr s = splimp(); 216130407Sdfr firewire_ifattach(ifp, hwaddr); 217130407Sdfr splx(s); 218130407Sdfr 219130407Sdfr FWIPDEBUG(ifp, "interface created\n"); 220130407Sdfr return 0; 221130407Sdfr} 222130407Sdfr 223130407Sdfrstatic void 224130407Sdfrfwip_stop(struct fwip_softc *fwip) 225130407Sdfr{ 226130407Sdfr struct firewire_comm *fc; 227130407Sdfr struct fw_xferq *xferq; 228130407Sdfr struct ifnet *ifp = &fwip->fwip_if; 229130407Sdfr struct fw_xfer *xfer, *next; 230130407Sdfr int i; 231130407Sdfr 232130407Sdfr fc = fwip->fd.fc; 233130407Sdfr 234130407Sdfr FWIP_POLL_DEREGISTER(fwip, ifp); 235130407Sdfr 236130407Sdfr if (fwip->dma_ch >= 0) { 237130407Sdfr xferq = fc->ir[fwip->dma_ch]; 238130407Sdfr 239130407Sdfr if (xferq->flag & FWXFERQ_RUNNING) 240130407Sdfr fc->irx_disable(fc, fwip->dma_ch); 241130407Sdfr xferq->flag &= 242130407Sdfr ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 243130407Sdfr FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 244130407Sdfr xferq->hand = NULL; 245130407Sdfr 246130407Sdfr for (i = 0; i < xferq->bnchunk; i ++) 247130407Sdfr m_freem(xferq->bulkxfer[i].mbuf); 248130407Sdfr free(xferq->bulkxfer, M_FWIP); 249130407Sdfr 250130407Sdfr fw_bindremove(fc, &fwip->fwb); 251130407Sdfr for (xfer = STAILQ_FIRST(&fwip->fwb.xferlist); xfer != NULL; 252130407Sdfr xfer = next) { 253130407Sdfr next = STAILQ_NEXT(xfer, link); 254130407Sdfr fw_xfer_free(xfer); 255130407Sdfr } 256130407Sdfr 257130407Sdfr for (xfer = STAILQ_FIRST(&fwip->xferlist); xfer != NULL; 258130407Sdfr xfer = next) { 259130407Sdfr next = STAILQ_NEXT(xfer, link); 260130407Sdfr fw_xfer_free(xfer); 261130407Sdfr } 262130407Sdfr STAILQ_INIT(&fwip->xferlist); 263130407Sdfr 264130407Sdfr xferq->bulkxfer = NULL; 265130407Sdfr fwip->dma_ch = -1; 266130407Sdfr } 267130407Sdfr 268130407Sdfr ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 269130407Sdfr} 270130407Sdfr 271130407Sdfrstatic int 272130407Sdfrfwip_detach(device_t dev) 273130407Sdfr{ 274130407Sdfr struct fwip_softc *fwip; 275130407Sdfr int s; 276130407Sdfr 277130407Sdfr fwip = (struct fwip_softc *)device_get_softc(dev); 278130407Sdfr s = splimp(); 279130407Sdfr 280130407Sdfr fwip_stop(fwip); 281130407Sdfr firewire_ifdetach(&fwip->fwip_if); 282130407Sdfr 283130407Sdfr splx(s); 284130407Sdfr return 0; 285130407Sdfr} 286130407Sdfr 287130407Sdfrstatic void 288130407Sdfrfwip_init(void *arg) 289130407Sdfr{ 290130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)arg)->fwip; 291130407Sdfr struct firewire_comm *fc; 292130407Sdfr struct ifnet *ifp = &fwip->fwip_if; 293130407Sdfr struct fw_xferq *xferq; 294130407Sdfr struct fw_xfer *xfer; 295130407Sdfr struct mbuf *m; 296130407Sdfr int i; 297130407Sdfr 298130407Sdfr FWIPDEBUG(ifp, "initializing\n"); 299130407Sdfr 300130407Sdfr fc = fwip->fd.fc; 301130407Sdfr#define START 0 302130407Sdfr if (fwip->dma_ch < 0) { 303130407Sdfr for (i = START; i < fc->nisodma; i ++) { 304130407Sdfr xferq = fc->ir[i]; 305130407Sdfr if ((xferq->flag & FWXFERQ_OPEN) == 0) 306130407Sdfr goto found; 307130407Sdfr } 308130407Sdfr printf("no free dma channel\n"); 309130407Sdfr return; 310130407Sdfrfound: 311130407Sdfr fwip->dma_ch = i; 312130407Sdfr /* allocate DMA channel and init packet mode */ 313130407Sdfr xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | 314130407Sdfr FWXFERQ_HANDLER | FWXFERQ_STREAM; 315130407Sdfr xferq->flag &= ~0xff; 316130407Sdfr xferq->flag |= broadcast_channel & 0xff; 317130407Sdfr /* register fwip_input handler */ 318130407Sdfr xferq->sc = (caddr_t) fwip; 319130407Sdfr xferq->hand = fwip_stream_input; 320130407Sdfr xferq->bnchunk = rx_queue_len; 321130407Sdfr xferq->bnpacket = 1; 322130407Sdfr xferq->psize = MCLBYTES; 323130407Sdfr xferq->queued = 0; 324130407Sdfr xferq->buf = NULL; 325130407Sdfr xferq->bulkxfer = (struct fw_bulkxfer *) malloc( 326130407Sdfr sizeof(struct fw_bulkxfer) * xferq->bnchunk, 327130407Sdfr M_FWIP, M_WAITOK); 328130407Sdfr if (xferq->bulkxfer == NULL) { 329130407Sdfr printf("if_fwip: malloc failed\n"); 330130407Sdfr return; 331130407Sdfr } 332130407Sdfr STAILQ_INIT(&xferq->stvalid); 333130407Sdfr STAILQ_INIT(&xferq->stfree); 334130407Sdfr STAILQ_INIT(&xferq->stdma); 335130407Sdfr xferq->stproc = NULL; 336130407Sdfr for (i = 0; i < xferq->bnchunk; i ++) { 337130407Sdfr m = 338130407Sdfr#if defined(__DragonFly__) || __FreeBSD_version < 500000 339130407Sdfr m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 340130407Sdfr#else 341130407Sdfr m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); 342130407Sdfr#endif 343130407Sdfr xferq->bulkxfer[i].mbuf = m; 344130407Sdfr if (m != NULL) { 345130407Sdfr m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 346130407Sdfr STAILQ_INSERT_TAIL(&xferq->stfree, 347130407Sdfr &xferq->bulkxfer[i], link); 348130407Sdfr } else 349130407Sdfr printf("fwip_as_input: m_getcl failed\n"); 350130407Sdfr } 351130407Sdfr 352130407Sdfr fwip->fwb.start = INET_FIFO; 353130407Sdfr fwip->fwb.end = INET_FIFO + 16384; /* S3200 packet size */ 354130407Sdfr fwip->fwb.act_type = FWACT_XFER; 355130407Sdfr 356130407Sdfr /* pre-allocate xfer */ 357130407Sdfr STAILQ_INIT(&fwip->fwb.xferlist); 358130407Sdfr for (i = 0; i < rx_queue_len; i ++) { 359130407Sdfr xfer = fw_xfer_alloc(M_FWIP); 360130407Sdfr if (xfer == NULL) 361130407Sdfr break; 362130407Sdfr m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); 363130407Sdfr xfer->recv.payload = mtod(m, uint32_t *); 364130407Sdfr xfer->recv.pay_len = MCLBYTES; 365130407Sdfr xfer->act.hand = fwip_unicast_input; 366130407Sdfr xfer->fc = fc; 367130407Sdfr xfer->sc = (caddr_t)fwip; 368130407Sdfr xfer->mbuf = m; 369130407Sdfr STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link); 370130407Sdfr } 371130407Sdfr fw_bindadd(fc, &fwip->fwb); 372130407Sdfr 373130407Sdfr STAILQ_INIT(&fwip->xferlist); 374130407Sdfr for (i = 0; i < TX_MAX_QUEUE; i++) { 375130407Sdfr xfer = fw_xfer_alloc(M_FWIP); 376130407Sdfr if (xfer == NULL) 377130407Sdfr break; 378130407Sdfr xfer->send.spd = tx_speed; 379130407Sdfr xfer->fc = fwip->fd.fc; 380130407Sdfr xfer->retry_req = fw_asybusy; 381130407Sdfr xfer->sc = (caddr_t)fwip; 382130407Sdfr xfer->act.hand = fwip_output_callback; 383130407Sdfr STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); 384130407Sdfr } 385130407Sdfr } else 386130407Sdfr xferq = fc->ir[fwip->dma_ch]; 387130407Sdfr 388130407Sdfr fwip->last_dest.hi = 0; 389130407Sdfr fwip->last_dest.lo = 0; 390130407Sdfr 391130407Sdfr /* start dma */ 392130407Sdfr if ((xferq->flag & FWXFERQ_RUNNING) == 0) 393130407Sdfr fc->irx_enable(fc, fwip->dma_ch); 394130407Sdfr 395130407Sdfr ifp->if_flags |= IFF_RUNNING; 396130407Sdfr ifp->if_flags &= ~IFF_OACTIVE; 397130407Sdfr 398130407Sdfr FWIP_POLL_REGISTER(fwip_poll, fwip, ifp); 399130407Sdfr#if 0 400130407Sdfr /* attempt to start output */ 401130407Sdfr fwip_start(ifp); 402130407Sdfr#endif 403130407Sdfr} 404130407Sdfr 405130407Sdfrstatic int 406130407Sdfrfwip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 407130407Sdfr{ 408130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 409130407Sdfr int s, error; 410130407Sdfr 411130407Sdfr switch (cmd) { 412130407Sdfr case SIOCSIFFLAGS: 413130407Sdfr s = splimp(); 414130407Sdfr if (ifp->if_flags & IFF_UP) { 415130407Sdfr if (!(ifp->if_flags & IFF_RUNNING)) 416130407Sdfr fwip_init(&fwip->fw_softc); 417130407Sdfr } else { 418130407Sdfr if (ifp->if_flags & IFF_RUNNING) 419130407Sdfr fwip_stop(fwip); 420130407Sdfr } 421130407Sdfr splx(s); 422130407Sdfr break; 423130407Sdfr case SIOCADDMULTI: 424130407Sdfr case SIOCDELMULTI: 425130407Sdfr break; 426130407Sdfr 427130407Sdfr#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 428130407Sdfr default: 429130407Sdfr#else 430130407Sdfr case SIOCSIFADDR: 431130407Sdfr case SIOCGIFADDR: 432130407Sdfr case SIOCSIFMTU: 433130407Sdfr#endif 434130407Sdfr s = splimp(); 435130407Sdfr error = firewire_ioctl(ifp, cmd, data); 436130407Sdfr splx(s); 437130407Sdfr return (error); 438130407Sdfr#if defined(__DragonFly__) || __FreeBSD_version < 500000 439130407Sdfr default: 440130407Sdfr return (EINVAL); 441130407Sdfr#endif 442130407Sdfr } 443130407Sdfr 444130407Sdfr return (0); 445130407Sdfr} 446130407Sdfr 447130407Sdfrstatic void 448130407Sdfrfwip_post_busreset(void *arg) 449130407Sdfr{ 450130407Sdfr struct fwip_softc *fwip = arg; 451130411Sdfr struct crom_src *src; 452130411Sdfr struct crom_chunk *root; 453130407Sdfr 454130411Sdfr src = fwip->fd.fc->crom_src; 455130411Sdfr root = fwip->fd.fc->crom_root; 456130411Sdfr 457130411Sdfr /* RFC2734 IPv4 over IEEE1394 */ 458130411Sdfr bzero(&fwip->unit4, sizeof(struct crom_chunk)); 459130411Sdfr crom_add_chunk(src, root, &fwip->unit4, CROM_UDIR); 460130411Sdfr crom_add_entry(&fwip->unit4, CSRKEY_SPEC, CSRVAL_IETF); 461130411Sdfr crom_add_simple_text(src, &fwip->unit4, &fwip->spec4, "IANA"); 462130411Sdfr crom_add_entry(&fwip->unit4, CSRKEY_VER, 1); 463130411Sdfr crom_add_simple_text(src, &fwip->unit4, &fwip->ver4, "IPv4"); 464130411Sdfr 465130411Sdfr /* RFC3146 IPv6 over IEEE1394 */ 466130411Sdfr bzero(&fwip->unit6, sizeof(struct crom_chunk)); 467130411Sdfr crom_add_chunk(src, root, &fwip->unit6, CROM_UDIR); 468130411Sdfr crom_add_entry(&fwip->unit6, CSRKEY_SPEC, CSRVAL_IETF); 469130411Sdfr crom_add_simple_text(src, &fwip->unit6, &fwip->spec6, "IANA"); 470130411Sdfr crom_add_entry(&fwip->unit6, CSRKEY_VER, 2); 471130411Sdfr crom_add_simple_text(src, &fwip->unit6, &fwip->ver6, "IPv6"); 472130411Sdfr 473130407Sdfr fwip->last_dest.hi = 0; 474130407Sdfr fwip->last_dest.lo = 0; 475130407Sdfr firewire_busreset(&fwip->fwip_if); 476130407Sdfr} 477130407Sdfr 478130407Sdfrstatic void 479130407Sdfrfwip_output_callback(struct fw_xfer *xfer) 480130407Sdfr{ 481130407Sdfr struct fwip_softc *fwip; 482130407Sdfr struct ifnet *ifp; 483130407Sdfr int s; 484130407Sdfr 485130407Sdfr GIANT_REQUIRED; 486130407Sdfr 487130407Sdfr fwip = (struct fwip_softc *)xfer->sc; 488130407Sdfr ifp = &fwip->fwip_if; 489130407Sdfr /* XXX error check */ 490130407Sdfr FWIPDEBUG(ifp, "resp = %d\n", xfer->resp); 491130407Sdfr if (xfer->resp != 0) 492130407Sdfr ifp->if_oerrors ++; 493130407Sdfr 494130407Sdfr m_freem(xfer->mbuf); 495130407Sdfr fw_xfer_unload(xfer); 496130407Sdfr 497130407Sdfr s = splimp(); 498130407Sdfr STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link); 499130407Sdfr splx(s); 500130407Sdfr 501130407Sdfr /* for queue full */ 502130407Sdfr if (ifp->if_snd.ifq_head != NULL) 503130407Sdfr fwip_start(ifp); 504130407Sdfr} 505130407Sdfr 506130407Sdfrstatic void 507130407Sdfrfwip_start(struct ifnet *ifp) 508130407Sdfr{ 509130407Sdfr struct fwip_softc *fwip = ((struct fwip_eth_softc *)ifp->if_softc)->fwip; 510130407Sdfr int s; 511130407Sdfr 512130407Sdfr GIANT_REQUIRED; 513130407Sdfr 514130407Sdfr FWIPDEBUG(ifp, "starting\n"); 515130407Sdfr 516130407Sdfr if (fwip->dma_ch < 0) { 517130407Sdfr struct mbuf *m = NULL; 518130407Sdfr 519130407Sdfr FWIPDEBUG(ifp, "not ready\n"); 520130407Sdfr 521130407Sdfr s = splimp(); 522130407Sdfr do { 523130407Sdfr IF_DEQUEUE(&ifp->if_snd, m); 524130407Sdfr if (m != NULL) 525130407Sdfr m_freem(m); 526130407Sdfr ifp->if_oerrors ++; 527130407Sdfr } while (m != NULL); 528130407Sdfr splx(s); 529130407Sdfr 530130407Sdfr return; 531130407Sdfr } 532130407Sdfr 533130407Sdfr s = splimp(); 534130407Sdfr ifp->if_flags |= IFF_OACTIVE; 535130407Sdfr 536130407Sdfr if (ifp->if_snd.ifq_len != 0) 537130407Sdfr fwip_async_output(fwip, ifp); 538130407Sdfr 539130407Sdfr ifp->if_flags &= ~IFF_OACTIVE; 540130407Sdfr splx(s); 541130407Sdfr} 542130407Sdfr 543130407Sdfr/* Async. stream output */ 544130407Sdfrstatic void 545130407Sdfrfwip_async_output(struct fwip_softc *fwip, struct ifnet *ifp) 546130407Sdfr{ 547130407Sdfr struct firewire_comm *fc = fwip->fd.fc; 548130407Sdfr struct mbuf *m; 549130407Sdfr struct m_tag *mtag; 550130407Sdfr struct fw_hwaddr *destfw; 551130407Sdfr struct fw_xfer *xfer; 552130407Sdfr struct fw_xferq *xferq; 553130407Sdfr struct fw_pkt *fp; 554130407Sdfr uint16_t nodeid; 555130407Sdfr int i = 0; 556130407Sdfr 557130407Sdfr GIANT_REQUIRED; 558130407Sdfr 559130407Sdfr xfer = NULL; 560130407Sdfr xferq = fwip->fd.fc->atq; 561130407Sdfr while (xferq->queued < xferq->maxq - 1) { 562130407Sdfr xfer = STAILQ_FIRST(&fwip->xferlist); 563130407Sdfr if (xfer == NULL) { 564130407Sdfr printf("if_fwip: lack of xfer\n"); 565130407Sdfr return; 566130407Sdfr } 567130407Sdfr IF_DEQUEUE(&ifp->if_snd, m); 568130407Sdfr if (m == NULL) 569130407Sdfr break; 570130407Sdfr 571130407Sdfr /* 572130407Sdfr * Dig out the link-level address which 573130407Sdfr * firewire_output got via arp or neighbour 574130407Sdfr * discovery. If we don't have a link-level address, 575130407Sdfr * just stick the thing on the broadcast channel. 576130407Sdfr */ 577130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 0); 578130407Sdfr if (mtag == NULL) 579130407Sdfr destfw = 0; 580130407Sdfr else 581130407Sdfr destfw = (struct fw_hwaddr *) (mtag + 1); 582130407Sdfr 583130407Sdfr STAILQ_REMOVE_HEAD(&fwip->xferlist, link); 584130407Sdfr 585130407Sdfr /* 586130407Sdfr * We don't do any bpf stuff here - the generic code 587130407Sdfr * in firewire_output gives the packet to bpf before 588130407Sdfr * it adds the link-level encapsulation. 589130407Sdfr */ 590130407Sdfr 591130407Sdfr /* 592130407Sdfr * Put the mbuf in the xfer early in case we hit an 593130407Sdfr * error case below - fwip_output_callback will free 594130407Sdfr * the mbuf. 595130407Sdfr */ 596130407Sdfr xfer->mbuf = m; 597130407Sdfr 598130407Sdfr /* 599130407Sdfr * We use the arp result (if any) to add a suitable firewire 600130407Sdfr * packet header before handing off to the bus. 601130407Sdfr */ 602130407Sdfr fp = &xfer->send.hdr; 603130407Sdfr nodeid = FWLOCALBUS | fc->nodeid; 604130407Sdfr if ((m->m_flags & M_BCAST) || !destfw) { 605130407Sdfr /* 606130407Sdfr * Broadcast packets are sent as GASP packets with 607130407Sdfr * specifier ID 0x00005e, version 1 on the broadcast 608130407Sdfr * channel. To be conservative, we send at the 609130407Sdfr * slowest possible speed. 610130407Sdfr */ 611130407Sdfr uint32_t *p; 612130407Sdfr 613130407Sdfr M_PREPEND(m, 2*sizeof(uint32_t), M_DONTWAIT); 614130407Sdfr p = mtod(m, uint32_t *); 615130407Sdfr fp->mode.stream.len = m->m_pkthdr.len; 616130407Sdfr fp->mode.stream.chtag = broadcast_channel; 617130407Sdfr fp->mode.stream.tcode = FWTCODE_STREAM; 618130407Sdfr fp->mode.stream.sy = 0; 619130407Sdfr xfer->send.spd = 0; 620130407Sdfr p[0] = htonl(nodeid << 16); 621130407Sdfr p[1] = htonl((0x5e << 24) | 1); 622130407Sdfr } else { 623130407Sdfr /* 624130407Sdfr * Unicast packets are sent as block writes to the 625130407Sdfr * target's unicast fifo address. If we can't 626130407Sdfr * find the node address, we just give up. We 627130407Sdfr * could broadcast it but that might overflow 628130407Sdfr * the packet size limitations due to the 629130407Sdfr * extra GASP header. Note: the hardware 630130407Sdfr * address is stored in network byte order to 631130407Sdfr * make life easier for ARP. 632130407Sdfr */ 633130407Sdfr struct fw_device *fd; 634130407Sdfr struct fw_eui64 eui; 635130407Sdfr 636130407Sdfr eui.hi = ntohl(destfw->sender_unique_ID_hi); 637130407Sdfr eui.lo = ntohl(destfw->sender_unique_ID_lo); 638130407Sdfr if (fwip->last_dest.hi != eui.hi || 639130407Sdfr fwip->last_dest.lo != eui.lo) { 640130407Sdfr fd = fw_noderesolve_eui64(fc, &eui); 641130407Sdfr if (!fd) { 642130407Sdfr /* error */ 643130407Sdfr ifp->if_oerrors ++; 644130407Sdfr /* XXX set error code */ 645130407Sdfr fwip_output_callback(xfer); 646130407Sdfr continue; 647130407Sdfr 648130407Sdfr } 649130407Sdfr fwip->last_hdr.mode.wreqb.dst = FWLOCALBUS | fd->dst; 650130407Sdfr fwip->last_hdr.mode.wreqb.tlrt = 0; 651130407Sdfr fwip->last_hdr.mode.wreqb.tcode = FWTCODE_WREQB; 652130407Sdfr fwip->last_hdr.mode.wreqb.pri = 0; 653130407Sdfr fwip->last_hdr.mode.wreqb.src = nodeid; 654130407Sdfr fwip->last_hdr.mode.wreqb.dest_hi = 655130407Sdfr ntohs(destfw->sender_unicast_FIFO_hi); 656130407Sdfr fwip->last_hdr.mode.wreqb.dest_lo = 657130407Sdfr ntohl(destfw->sender_unicast_FIFO_lo); 658130407Sdfr fwip->last_hdr.mode.wreqb.extcode = 0; 659130407Sdfr fwip->last_dest = eui; 660130407Sdfr } 661130407Sdfr 662130407Sdfr fp->mode.wreqb = fwip->last_hdr.mode.wreqb; 663130407Sdfr fp->mode.wreqb.len = m->m_pkthdr.len; 664130407Sdfr xfer->send.spd = min(destfw->sspd, fc->speed); 665130407Sdfr } 666130407Sdfr 667130407Sdfr xfer->send.pay_len = m->m_pkthdr.len; 668130407Sdfr 669130407Sdfr if (fw_asyreq(fc, -1, xfer) != 0) { 670130407Sdfr /* error */ 671130407Sdfr ifp->if_oerrors ++; 672130407Sdfr /* XXX set error code */ 673130407Sdfr fwip_output_callback(xfer); 674130407Sdfr continue; 675130407Sdfr } else { 676130407Sdfr ifp->if_opackets ++; 677130407Sdfr i++; 678130407Sdfr } 679130407Sdfr } 680130407Sdfr#if 0 681130407Sdfr if (i > 1) 682130407Sdfr printf("%d queued\n", i); 683130407Sdfr#endif 684130407Sdfr if (i > 0) { 685130407Sdfr#if 1 686130407Sdfr xferq->start(fc); 687130407Sdfr#else 688130407Sdfr taskqueue_enqueue(taskqueue_swi_giant, &fwip->start_send); 689130407Sdfr#endif 690130407Sdfr } 691130407Sdfr} 692130407Sdfr 693130407Sdfrstatic void 694130407Sdfrfwip_start_send (void *arg, int count) 695130407Sdfr{ 696130407Sdfr struct fwip_softc *fwip = arg; 697130407Sdfr 698130407Sdfr GIANT_REQUIRED; 699130407Sdfr fwip->fd.fc->atq->start(fwip->fd.fc); 700130407Sdfr} 701130407Sdfr 702130407Sdfr/* Async. stream output */ 703130407Sdfrstatic void 704130407Sdfrfwip_stream_input(struct fw_xferq *xferq) 705130407Sdfr{ 706130407Sdfr struct mbuf *m, *m0; 707130407Sdfr struct m_tag *mtag; 708130407Sdfr struct ifnet *ifp; 709130407Sdfr struct fwip_softc *fwip; 710130407Sdfr struct fw_bulkxfer *sxfer; 711130407Sdfr struct fw_pkt *fp; 712130407Sdfr uint16_t src; 713130407Sdfr uint32_t *p; 714130407Sdfr 715130407Sdfr GIANT_REQUIRED; 716130407Sdfr 717130407Sdfr fwip = (struct fwip_softc *)xferq->sc; 718130407Sdfr ifp = &fwip->fwip_if; 719130407Sdfr#if 0 720130407Sdfr FWIP_POLL_REGISTER(fwip_poll, fwip, ifp); 721130407Sdfr#endif 722130407Sdfr while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 723130407Sdfr STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 724130407Sdfr fp = mtod(sxfer->mbuf, struct fw_pkt *); 725130407Sdfr if (fwip->fd.fc->irx_post != NULL) 726130407Sdfr fwip->fd.fc->irx_post(fwip->fd.fc, fp->mode.ld); 727130407Sdfr m = sxfer->mbuf; 728130407Sdfr 729130407Sdfr /* insert new rbuf */ 730130407Sdfr sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 731130407Sdfr if (m0 != NULL) { 732130407Sdfr m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size; 733130407Sdfr STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); 734130407Sdfr } else 735130407Sdfr printf("fwip_as_input: m_getcl failed\n"); 736130407Sdfr 737130407Sdfr /* 738130407Sdfr * We must have a GASP header - leave the 739130407Sdfr * encapsulation sanity checks to the generic 740130407Sdfr * code. Remeber that we also have the firewire async 741130407Sdfr * stream header even though that isn't accounted for 742130407Sdfr * in mode.stream.len. 743130407Sdfr */ 744130407Sdfr if (sxfer->resp != 0 || fp->mode.stream.len < 745130407Sdfr 2*sizeof(uint32_t)) { 746130407Sdfr m_freem(m); 747130407Sdfr ifp->if_ierrors ++; 748130407Sdfr continue; 749130407Sdfr } 750130407Sdfr m->m_len = m->m_pkthdr.len = fp->mode.stream.len 751130407Sdfr + sizeof(fp->mode.stream); 752130407Sdfr 753130407Sdfr /* 754130407Sdfr * If we received the packet on the broadcast channel, 755130407Sdfr * mark it as broadcast, otherwise we assume it must 756130407Sdfr * be multicast. 757130407Sdfr */ 758130407Sdfr if (fp->mode.stream.chtag == broadcast_channel) 759130407Sdfr m->m_flags |= M_BCAST; 760130407Sdfr else 761130407Sdfr m->m_flags |= M_MCAST; 762130407Sdfr 763130407Sdfr /* 764130407Sdfr * Make sure we recognise the GASP specifier and 765130407Sdfr * version. 766130407Sdfr */ 767130407Sdfr p = mtod(m, uint32_t *); 768130407Sdfr if ((((ntohl(p[1]) & 0xffff) << 8) | ntohl(p[2]) >> 24) != 0x00005e 769130407Sdfr || (ntohl(p[2]) & 0xffffff) != 1) { 770130407Sdfr FWIPDEBUG(ifp, "Unrecognised GASP header %#08x %#08x\n", 771130407Sdfr ntohl(p[1]), ntohl(p[2])); 772130407Sdfr m_freem(m); 773130407Sdfr ifp->if_ierrors ++; 774130407Sdfr continue; 775130407Sdfr } 776130407Sdfr 777130407Sdfr /* 778130407Sdfr * Record the sender ID for possible BPF usage. 779130407Sdfr */ 780130407Sdfr src = ntohl(p[1]) >> 16; 781130407Sdfr if (ifp->if_bpf) { 782130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, 783130407Sdfr MTAG_FIREWIRE_SENDER_EUID, 784130407Sdfr 2*sizeof(uint32_t), M_NOWAIT); 785130407Sdfr if (mtag) { 786130407Sdfr /* bpf wants it in network byte order */ 787130407Sdfr struct fw_device *fd; 788130407Sdfr uint32_t *p = (uint32_t *) (mtag + 1); 789130407Sdfr fd = fw_noderesolve_nodeid(fwip->fd.fc, 790130407Sdfr src & 0x3f); 791130407Sdfr if (fd) { 792130407Sdfr p[0] = htonl(fd->eui.hi); 793130407Sdfr p[1] = htonl(fd->eui.lo); 794130407Sdfr } else { 795130407Sdfr p[0] = 0; 796130407Sdfr p[1] = 0; 797130407Sdfr } 798130407Sdfr m_tag_prepend(m, mtag); 799130407Sdfr } 800130407Sdfr } 801130407Sdfr 802130407Sdfr /* 803130407Sdfr * Trim off the GASP header 804130407Sdfr */ 805130407Sdfr m_adj(m, 3*sizeof(uint32_t)); 806130407Sdfr m->m_pkthdr.rcvif = ifp; 807130407Sdfr firewire_input(ifp, m, src); 808130407Sdfr ifp->if_ipackets ++; 809130407Sdfr } 810130407Sdfr if (STAILQ_FIRST(&xferq->stfree) != NULL) 811130407Sdfr fwip->fd.fc->irx_enable(fwip->fd.fc, fwip->dma_ch); 812130407Sdfr} 813130407Sdfr 814130407Sdfrstatic __inline void 815130407Sdfrfwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer) 816130407Sdfr{ 817130407Sdfr struct mbuf *m; 818130407Sdfr 819130407Sdfr GIANT_REQUIRED; 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 */ 825130407Sdfr m = m_getcl(M_TRYWAIT, 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 GIANT_REQUIRED; 846130407Sdfr 847130407Sdfr fwip = (struct fwip_softc *)xfer->sc; 848130407Sdfr ifp = &fwip->fwip_if; 849130407Sdfr m = xfer->mbuf; 850130407Sdfr xfer->mbuf = 0; 851130407Sdfr fp = &xfer->recv.hdr; 852130407Sdfr 853130407Sdfr /* 854130407Sdfr * Check the fifo address - we only accept addresses of 855130407Sdfr * exactly INET_FIFO. 856130407Sdfr */ 857130407Sdfr address = ((uint64_t)fp->mode.wreqb.dest_hi << 32) 858130407Sdfr | fp->mode.wreqb.dest_lo; 859130407Sdfr if (fp->mode.wreqb.tcode != FWTCODE_WREQB) { 860130407Sdfr rtcode = FWRCODE_ER_TYPE; 861130407Sdfr } else if (address != INET_FIFO) { 862130407Sdfr rtcode = FWRCODE_ER_ADDR; 863130407Sdfr } else { 864130407Sdfr rtcode = FWRCODE_COMPLETE; 865130407Sdfr } 866130407Sdfr 867130407Sdfr /* 868130407Sdfr * Pick up a new mbuf and stick it on the back of the receive 869130407Sdfr * queue. 870130407Sdfr */ 871130407Sdfr fwip_unicast_input_recycle(fwip, xfer); 872130407Sdfr 873130407Sdfr /* 874130407Sdfr * If we've already rejected the packet, give up now. 875130407Sdfr */ 876130407Sdfr if (rtcode != FWRCODE_COMPLETE) { 877130407Sdfr m_freem(m); 878130407Sdfr ifp->if_ierrors ++; 879130407Sdfr return; 880130407Sdfr } 881130407Sdfr 882130407Sdfr if (ifp->if_bpf) { 883130407Sdfr /* 884130407Sdfr * Record the sender ID for possible BPF usage. 885130407Sdfr */ 886130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 887130407Sdfr 2*sizeof(uint32_t), M_NOWAIT); 888130407Sdfr if (mtag) { 889130407Sdfr /* bpf wants it in network byte order */ 890130407Sdfr struct fw_device *fd; 891130407Sdfr uint32_t *p = (uint32_t *) (mtag + 1); 892130407Sdfr fd = fw_noderesolve_nodeid(fwip->fd.fc, 893130407Sdfr fp->mode.wreqb.src & 0x3f); 894130407Sdfr if (fd) { 895130407Sdfr p[0] = htonl(fd->eui.hi); 896130407Sdfr p[1] = htonl(fd->eui.lo); 897130407Sdfr } else { 898130407Sdfr p[0] = 0; 899130407Sdfr p[1] = 0; 900130407Sdfr } 901130407Sdfr m_tag_prepend(m, mtag); 902130407Sdfr } 903130407Sdfr } 904130407Sdfr 905130407Sdfr /* 906130407Sdfr * Hand off to the generic encapsulation code. We don't use 907130407Sdfr * ifp->if_input so that we can pass the source nodeid as an 908130407Sdfr * argument to facilitate link-level fragment reassembly. 909130407Sdfr */ 910130407Sdfr m->m_len = m->m_pkthdr.len = fp->mode.wreqb.len; 911130407Sdfr m->m_pkthdr.rcvif = ifp; 912130407Sdfr firewire_input(ifp, m, fp->mode.wreqb.src); 913130407Sdfr ifp->if_ipackets ++; 914130407Sdfr} 915130407Sdfr 916130407Sdfrstatic devclass_t fwip_devclass; 917130407Sdfr 918130407Sdfrstatic device_method_t fwip_methods[] = { 919130407Sdfr /* device interface */ 920130407Sdfr DEVMETHOD(device_identify, fwip_identify), 921130407Sdfr DEVMETHOD(device_probe, fwip_probe), 922130407Sdfr DEVMETHOD(device_attach, fwip_attach), 923130407Sdfr DEVMETHOD(device_detach, fwip_detach), 924130407Sdfr { 0, 0 } 925130407Sdfr}; 926130407Sdfr 927130407Sdfrstatic driver_t fwip_driver = { 928130407Sdfr "fwip", 929130407Sdfr fwip_methods, 930130407Sdfr sizeof(struct fwip_softc), 931130407Sdfr}; 932130407Sdfr 933130407Sdfr 934130407Sdfr#ifdef __DragonFly__ 935130407SdfrDECLARE_DUMMY_MODULE(fwip); 936130407Sdfr#endif 937130407SdfrDRIVER_MODULE(fwip, firewire, fwip_driver, fwip_devclass, 0, 0); 938130407SdfrMODULE_VERSION(fwip, 1); 939130407SdfrMODULE_DEPEND(fwip, firewire, 1, 1, 1); 940