1 /* 2 * Copyright (c) 2002-2003 3 * Hidetoshi Shimokawa. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * 16 * This product includes software developed by Hidetoshi Shimokawa. 17 * 18 * 4. Neither the name of the author nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $FreeBSD: src/sys/dev/firewire/if_fwe.c,v 1.27 2004/01/08 14:58:09 simokawa Exp $ 35 * $DragonFly: src/sys/dev/netif/fwe/if_fwe.c,v 1.14 2005/02/18 23:10:27 joerg Exp $ 36 */ 37 38 #include "opt_inet.h" 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/mbuf.h> 45 #include <sys/socket.h> 46 #include <sys/sockio.h> 47 #include <sys/sysctl.h> 48 #include <sys/systm.h> 49 #include <sys/module.h> 50 #include <sys/bus.h> 51 #include <machine/bus.h> 52 53 #include <net/bpf.h> 54 #include <net/ethernet.h> 55 #include <net/if.h> 56 #include <net/if_arp.h> 57 #ifdef __DragonFly__ 58 #include <net/ifq_var.h> 59 #include <net/vlan/if_vlan_var.h> 60 #include <bus/firewire/firewire.h> 61 #include <bus/firewire/firewirereg.h> 62 #include "if_fwevar.h" 63 #else 64 #include <net/if_vlan_var.h> 65 66 #include <dev/firewire/firewire.h> 67 #include <dev/firewire/firewirereg.h> 68 #include <dev/firewire/if_fwevar.h> 69 #endif 70 71 #define FWEDEBUG if (fwedebug) if_printf 72 #define TX_MAX_QUEUE (FWMAXQUEUE - 1) 73 74 /* network interface */ 75 static void fwe_start (struct ifnet *); 76 static int fwe_ioctl (struct ifnet *, u_long, caddr_t, struct ucred *); 77 static void fwe_init (void *); 78 79 static void fwe_output_callback (struct fw_xfer *); 80 static void fwe_as_output (struct fwe_softc *, struct ifnet *); 81 static void fwe_as_input (struct fw_xferq *); 82 83 static int fwedebug = 0; 84 static int stream_ch = 1; 85 static int tx_speed = 2; 86 static int rx_queue_len = FWMAXQUEUE; 87 88 MALLOC_DEFINE(M_FWE, "if_fwe", "Ethernet over FireWire interface"); 89 SYSCTL_INT(_debug, OID_AUTO, if_fwe_debug, CTLFLAG_RW, &fwedebug, 0, ""); 90 SYSCTL_DECL(_hw_firewire); 91 SYSCTL_NODE(_hw_firewire, OID_AUTO, fwe, CTLFLAG_RD, 0, 92 "Ethernet emulation subsystem"); 93 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, stream_ch, CTLFLAG_RW, &stream_ch, 0, 94 "Stream channel to use"); 95 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, tx_speed, CTLFLAG_RW, &tx_speed, 0, 96 "Transmission speed"); 97 SYSCTL_INT(_hw_firewire_fwe, OID_AUTO, rx_queue_len, CTLFLAG_RW, &rx_queue_len, 98 0, "Length of the receive queue"); 99 100 TUNABLE_INT("hw.firewire.fwe.stream_ch", &stream_ch); 101 TUNABLE_INT("hw.firewire.fwe.tx_speed", &tx_speed); 102 TUNABLE_INT("hw.firewire.fwe.rx_queue_len", &rx_queue_len); 103 104 #ifdef DEVICE_POLLING 105 #define FWE_POLL_REGISTER(func, fwe, ifp) \ 106 if (ether_poll_register(func, ifp)) { \ 107 struct firewire_comm *fc = (fwe)->fd.fc; \ 108 fc->set_intr(fc, 0); \ 109 } 110 111 #define FWE_POLL_DEREGISTER(fwe, ifp) \ 112 do { \ 113 struct firewire_comm *fc = (fwe)->fd.fc; \ 114 ether_poll_deregister(ifp); \ 115 fc->set_intr(fc, 1); \ 116 } while(0) \ 117 118 static poll_handler_t fwe_poll; 119 120 static void 121 fwe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 122 { 123 struct fwe_softc *fwe; 124 struct firewire_comm *fc; 125 126 fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 127 fc = fwe->fd.fc; 128 if (cmd == POLL_DEREGISTER) { 129 /* enable interrupts */ 130 fc->set_intr(fc, 1); 131 return; 132 } 133 fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count); 134 } 135 #else 136 #define FWE_POLL_REGISTER(func, fwe, ifp) 137 #define FWE_POLL_DEREGISTER(fwe, ifp) 138 #endif 139 static void 140 fwe_identify(driver_t *driver, device_t parent) 141 { 142 BUS_ADD_CHILD(parent, 0, "fwe", device_get_unit(parent)); 143 } 144 145 static int 146 fwe_probe(device_t dev) 147 { 148 device_t pa; 149 150 pa = device_get_parent(dev); 151 if(device_get_unit(dev) != device_get_unit(pa)){ 152 return(ENXIO); 153 } 154 155 device_set_desc(dev, "Ethernet over FireWire"); 156 return (0); 157 } 158 159 static int 160 fwe_attach(device_t dev) 161 { 162 struct fwe_softc *fwe; 163 struct ifnet *ifp; 164 int unit, s; 165 u_char *eaddr; 166 struct fw_eui64 *eui; 167 168 fwe = ((struct fwe_softc *)device_get_softc(dev)); 169 unit = device_get_unit(dev); 170 171 bzero(fwe, sizeof(struct fwe_softc)); 172 /* XXX */ 173 fwe->stream_ch = stream_ch; 174 fwe->dma_ch = -1; 175 176 fwe->fd.fc = device_get_ivars(dev); 177 if (tx_speed < 0) 178 tx_speed = fwe->fd.fc->speed; 179 180 fwe->fd.dev = dev; 181 fwe->fd.post_explore = NULL; 182 fwe->eth_softc.fwe = fwe; 183 184 fwe->pkt_hdr.mode.stream.tcode = FWTCODE_STREAM; 185 fwe->pkt_hdr.mode.stream.sy = 0; 186 fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 187 188 /* generate fake MAC address: first and last 3bytes from eui64 */ 189 #define LOCAL (0x02) 190 #define GROUP (0x01) 191 eaddr = &fwe->eth_softc.arpcom.ac_enaddr[0]; 192 193 eui = &fwe->fd.fc->eui; 194 eaddr[0] = (FW_EUI64_BYTE(eui, 0) | LOCAL) & ~GROUP; 195 eaddr[1] = FW_EUI64_BYTE(eui, 1); 196 eaddr[2] = FW_EUI64_BYTE(eui, 2); 197 eaddr[3] = FW_EUI64_BYTE(eui, 5); 198 eaddr[4] = FW_EUI64_BYTE(eui, 6); 199 eaddr[5] = FW_EUI64_BYTE(eui, 7); 200 printf("if_fwe%d: Fake Ethernet address: " 201 "%02x:%02x:%02x:%02x:%02x:%02x\n", unit, 202 eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5]); 203 204 /* fill the rest and attach interface */ 205 ifp = &fwe->fwe_if; 206 ifp->if_softc = &fwe->eth_softc; 207 208 #if __FreeBSD_version >= 501113 || defined(__DragonFly__) 209 if_initname(ifp, device_get_name(dev), unit); 210 #else 211 ifp->if_unit = unit; 212 ifp->if_name = "fwe"; 213 #endif 214 ifp->if_init = fwe_init; 215 ifp->if_start = fwe_start; 216 ifp->if_ioctl = fwe_ioctl; 217 ifp->if_mtu = ETHERMTU; 218 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 219 ifq_set_maxlen(&ifp->if_snd, TX_MAX_QUEUE); 220 ifq_set_ready(&ifp->if_snd); 221 222 s = splimp(); 223 ether_ifattach(ifp, eaddr); 224 splx(s); 225 226 /* Tell the upper layer(s) we support long frames. */ 227 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 228 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 229 ifp->if_capabilities |= IFCAP_VLAN_MTU; 230 #endif 231 232 233 FWEDEBUG(ifp, "interface created\n"); 234 return 0; 235 } 236 237 static void 238 fwe_stop(struct fwe_softc *fwe) 239 { 240 struct firewire_comm *fc; 241 struct fw_xferq *xferq; 242 struct ifnet *ifp = &fwe->fwe_if; 243 struct fw_xfer *xfer, *next; 244 int i; 245 246 fc = fwe->fd.fc; 247 248 FWE_POLL_DEREGISTER(fwe, ifp); 249 250 if (fwe->dma_ch >= 0) { 251 xferq = fc->ir[fwe->dma_ch]; 252 253 if (xferq->flag & FWXFERQ_RUNNING) 254 fc->irx_disable(fc, fwe->dma_ch); 255 xferq->flag &= 256 ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM | 257 FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK); 258 xferq->hand = NULL; 259 260 for (i = 0; i < xferq->bnchunk; i ++) 261 m_freem(xferq->bulkxfer[i].mbuf); 262 free(xferq->bulkxfer, M_FWE); 263 264 for (xfer = STAILQ_FIRST(&fwe->xferlist); xfer != NULL; 265 xfer = next) { 266 next = STAILQ_NEXT(xfer, link); 267 fw_xfer_free(xfer); 268 } 269 STAILQ_INIT(&fwe->xferlist); 270 271 xferq->bulkxfer = NULL; 272 fwe->dma_ch = -1; 273 } 274 275 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 276 } 277 278 static int 279 fwe_detach(device_t dev) 280 { 281 struct fwe_softc *fwe; 282 int s; 283 284 fwe = (struct fwe_softc *)device_get_softc(dev); 285 s = splimp(); 286 287 fwe_stop(fwe); 288 ether_ifdetach(&fwe->fwe_if); 289 290 splx(s); 291 return 0; 292 } 293 294 static void 295 fwe_init(void *arg) 296 { 297 struct fwe_softc *fwe = ((struct fwe_eth_softc *)arg)->fwe; 298 struct firewire_comm *fc; 299 struct ifnet *ifp = &fwe->fwe_if; 300 struct fw_xferq *xferq; 301 struct fw_xfer *xfer; 302 struct mbuf *m; 303 int i; 304 305 FWEDEBUG(ifp, "initializing\n"); 306 307 /* XXX keep promiscoud mode */ 308 ifp->if_flags |= IFF_PROMISC; 309 310 fc = fwe->fd.fc; 311 #define START 0 312 if (fwe->dma_ch < 0) { 313 for (i = START; i < fc->nisodma; i ++) { 314 xferq = fc->ir[i]; 315 if ((xferq->flag & FWXFERQ_OPEN) == 0) 316 goto found; 317 } 318 printf("no free dma channel\n"); 319 return; 320 found: 321 fwe->dma_ch = i; 322 fwe->stream_ch = stream_ch; 323 fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch; 324 /* allocate DMA channel and init packet mode */ 325 xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF | 326 FWXFERQ_HANDLER | FWXFERQ_STREAM; 327 xferq->flag &= ~0xff; 328 xferq->flag |= fwe->stream_ch & 0xff; 329 /* register fwe_input handler */ 330 xferq->sc = (caddr_t) fwe; 331 xferq->hand = fwe_as_input; 332 xferq->bnchunk = rx_queue_len; 333 xferq->bnpacket = 1; 334 xferq->psize = MCLBYTES; 335 xferq->queued = 0; 336 xferq->buf = NULL; 337 xferq->bulkxfer = (struct fw_bulkxfer *) malloc( 338 sizeof(struct fw_bulkxfer) * xferq->bnchunk, 339 M_FWE, M_WAITOK); 340 if (xferq->bulkxfer == NULL) { 341 printf("if_fwe: malloc failed\n"); 342 return; 343 } 344 STAILQ_INIT(&xferq->stvalid); 345 STAILQ_INIT(&xferq->stfree); 346 STAILQ_INIT(&xferq->stdma); 347 xferq->stproc = NULL; 348 for (i = 0; i < xferq->bnchunk; i ++) { 349 m = 350 #if defined(__DragonFly__) 351 m_getcl(MB_WAIT, MT_DATA, M_PKTHDR); 352 #elif __FreeBSD_version < 500000 353 m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 354 #else 355 m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); 356 #endif 357 xferq->bulkxfer[i].mbuf = m; 358 if (m != NULL) { 359 m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 360 STAILQ_INSERT_TAIL(&xferq->stfree, 361 &xferq->bulkxfer[i], link); 362 } else 363 printf("fwe_as_input: m_getcl failed\n"); 364 } 365 STAILQ_INIT(&fwe->xferlist); 366 for (i = 0; i < TX_MAX_QUEUE; i++) { 367 xfer = fw_xfer_alloc(M_FWE); 368 if (xfer == NULL) 369 break; 370 xfer->send.spd = tx_speed; 371 xfer->fc = fwe->fd.fc; 372 xfer->retry_req = fw_asybusy; 373 xfer->sc = (caddr_t)fwe; 374 xfer->act.hand = fwe_output_callback; 375 STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); 376 } 377 } else 378 xferq = fc->ir[fwe->dma_ch]; 379 380 381 /* start dma */ 382 if ((xferq->flag & FWXFERQ_RUNNING) == 0) 383 fc->irx_enable(fc, fwe->dma_ch); 384 385 ifp->if_flags |= IFF_RUNNING; 386 ifp->if_flags &= ~IFF_OACTIVE; 387 388 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); 389 #if 0 390 /* attempt to start output */ 391 fwe_start(ifp); 392 #endif 393 } 394 395 396 static int 397 fwe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 398 { 399 struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 400 struct ifstat *ifs = NULL; 401 int s, error, len; 402 403 switch (cmd) { 404 case SIOCSIFFLAGS: 405 s = splimp(); 406 if (ifp->if_flags & IFF_UP) { 407 if (!(ifp->if_flags & IFF_RUNNING)) 408 fwe_init(&fwe->eth_softc); 409 } else { 410 if (ifp->if_flags & IFF_RUNNING) 411 fwe_stop(fwe); 412 } 413 /* XXX keep promiscoud mode */ 414 ifp->if_flags |= IFF_PROMISC; 415 splx(s); 416 break; 417 case SIOCADDMULTI: 418 case SIOCDELMULTI: 419 break; 420 421 case SIOCGIFSTATUS: 422 s = splimp(); 423 ifs = (struct ifstat *)data; 424 len = strlen(ifs->ascii); 425 if (len < sizeof(ifs->ascii)) 426 snprintf(ifs->ascii + len, 427 sizeof(ifs->ascii) - len, 428 "\tch %d dma %d\n", 429 fwe->stream_ch, fwe->dma_ch); 430 splx(s); 431 break; 432 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 433 default: 434 #else 435 case SIOCSIFADDR: 436 case SIOCGIFADDR: 437 case SIOCSIFMTU: 438 #endif 439 s = splimp(); 440 error = ether_ioctl(ifp, cmd, data); 441 splx(s); 442 return (error); 443 #if defined(__DragonFly__) || __FreeBSD_version < 500000 444 default: 445 return (EINVAL); 446 #endif 447 } 448 449 return (0); 450 } 451 452 static void 453 fwe_output_callback(struct fw_xfer *xfer) 454 { 455 struct fwe_softc *fwe; 456 struct ifnet *ifp; 457 int s; 458 459 fwe = (struct fwe_softc *)xfer->sc; 460 ifp = &fwe->fwe_if; 461 /* XXX error check */ 462 FWEDEBUG(ifp, "resp = %d\n", xfer->resp); 463 if (xfer->resp != 0) 464 ifp->if_oerrors ++; 465 466 m_freem(xfer->mbuf); 467 fw_xfer_unload(xfer); 468 469 s = splimp(); 470 STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link); 471 splx(s); 472 473 /* for queue full */ 474 if (!ifq_is_empty(&ifp->if_snd)) 475 fwe_start(ifp); 476 } 477 478 static void 479 fwe_start(struct ifnet *ifp) 480 { 481 struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe; 482 int s; 483 484 FWEDEBUG(ifp, "starting\n"); 485 486 if (fwe->dma_ch < 0) { 487 FWEDEBUG(ifp, "not ready\n"); 488 489 s = splimp(); 490 ifq_purge(&ifp->if_snd); 491 splx(s); 492 493 return; 494 } 495 496 s = splimp(); 497 ifp->if_flags |= IFF_OACTIVE; 498 499 if (!ifq_is_empty(&ifp->if_snd)) 500 fwe_as_output(fwe, ifp); 501 502 ifp->if_flags &= ~IFF_OACTIVE; 503 splx(s); 504 } 505 506 #define HDR_LEN 4 507 #ifndef ETHER_ALIGN 508 #define ETHER_ALIGN 2 509 #endif 510 /* Async. stream output */ 511 static void 512 fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp) 513 { 514 struct mbuf *m; 515 struct fw_xfer *xfer; 516 struct fw_xferq *xferq; 517 struct fw_pkt *fp; 518 int i = 0; 519 520 xfer = NULL; 521 xferq = fwe->fd.fc->atq; 522 while (xferq->queued < xferq->maxq - 1) { 523 xfer = STAILQ_FIRST(&fwe->xferlist); 524 if (xfer == NULL) { 525 printf("if_fwe: lack of xfer\n"); 526 return; 527 } 528 m = ifq_dequeue(&ifp->if_snd); 529 if (m == NULL) 530 break; 531 STAILQ_REMOVE_HEAD(&fwe->xferlist, link); 532 BPF_MTAP(ifp, m); 533 534 /* keep ip packet alignment for alpha */ 535 M_PREPEND(m, ETHER_ALIGN, MB_DONTWAIT); 536 fp = &xfer->send.hdr; 537 *(u_int32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr; 538 fp->mode.stream.len = m->m_pkthdr.len; 539 xfer->mbuf = m; 540 xfer->send.pay_len = m->m_pkthdr.len; 541 542 if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) { 543 /* error */ 544 ifp->if_oerrors ++; 545 /* XXX set error code */ 546 fwe_output_callback(xfer); 547 } else { 548 ifp->if_opackets ++; 549 i++; 550 } 551 } 552 #if 0 553 if (i > 1) 554 printf("%d queued\n", i); 555 #endif 556 if (i > 0) 557 xferq->start(fwe->fd.fc); 558 } 559 560 /* Async. stream output */ 561 static void 562 fwe_as_input(struct fw_xferq *xferq) 563 { 564 struct mbuf *m, *m0; 565 struct ifnet *ifp; 566 struct fwe_softc *fwe; 567 struct fw_bulkxfer *sxfer; 568 struct fw_pkt *fp; 569 u_char *c; 570 571 fwe = (struct fwe_softc *)xferq->sc; 572 ifp = &fwe->fwe_if; 573 #if 0 574 FWE_POLL_REGISTER(fwe_poll, fwe, ifp); 575 #endif 576 while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) { 577 STAILQ_REMOVE_HEAD(&xferq->stvalid, link); 578 fp = mtod(sxfer->mbuf, struct fw_pkt *); 579 if (fwe->fd.fc->irx_post != NULL) 580 fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld); 581 m = sxfer->mbuf; 582 583 /* insert new rbuf */ 584 sxfer->mbuf = m0 = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR); 585 if (m0 != NULL) { 586 m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size; 587 STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link); 588 } else 589 printf("fwe_as_input: m_getcl failed\n"); 590 591 if (sxfer->resp != 0 || fp->mode.stream.len < 592 ETHER_ALIGN + sizeof(struct ether_header)) { 593 m_freem(m); 594 ifp->if_ierrors ++; 595 continue; 596 } 597 598 m->m_data += HDR_LEN + ETHER_ALIGN; 599 c = mtod(m, char *); 600 m->m_len = m->m_pkthdr.len = 601 fp->mode.stream.len - ETHER_ALIGN; 602 m->m_pkthdr.rcvif = ifp; 603 #if 0 604 FWEDEBUG(ifp, "%02x %02x %02x %02x %02x %02x\n" 605 "%02x %02x %02x %02x %02x %02x\n" 606 "%02x %02x %02x %02x\n" 607 "%02x %02x %02x %02x\n" 608 "%02x %02x %02x %02x\n" 609 "%02x %02x %02x %02x\n", 610 c[0], c[1], c[2], c[3], c[4], c[5], 611 c[6], c[7], c[8], c[9], c[10], c[11], 612 c[12], c[13], c[14], c[15], 613 c[16], c[17], c[18], c[19], 614 c[20], c[21], c[22], c[23], 615 c[20], c[21], c[22], c[23] 616 ); 617 #endif 618 (*ifp->if_input)(ifp, m); 619 ifp->if_ipackets ++; 620 } 621 if (STAILQ_FIRST(&xferq->stfree) != NULL) 622 fwe->fd.fc->irx_enable(fwe->fd.fc, fwe->dma_ch); 623 } 624 625 626 static devclass_t fwe_devclass; 627 628 static device_method_t fwe_methods[] = { 629 /* device interface */ 630 DEVMETHOD(device_identify, fwe_identify), 631 DEVMETHOD(device_probe, fwe_probe), 632 DEVMETHOD(device_attach, fwe_attach), 633 DEVMETHOD(device_detach, fwe_detach), 634 { 0, 0 } 635 }; 636 637 static driver_t fwe_driver = { 638 "fwe", 639 fwe_methods, 640 sizeof(struct fwe_softc), 641 }; 642 643 644 DECLARE_DUMMY_MODULE(fwe); 645 DRIVER_MODULE(fwe, firewire, fwe_driver, fwe_devclass, 0, 0); 646 MODULE_VERSION(fwe, 1); 647 MODULE_DEPEND(fwe, firewire, 1, 1, 1); 648