1 /*- 2 * Copyright (c) 2003 Hidetoshi Shimokawa 3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the acknowledgement as bellow: 16 * 17 * This product includes software developed by K. Kobayashi and H. Shimokawa 18 * 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD$ 35 * 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/types.h> 41 #include <sys/mbuf.h> 42 #include <sys/bio.h> 43 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/conf.h> 47 #include <sys/poll.h> 48 49 #include <sys/bus.h> 50 #include <sys/ctype.h> 51 #include <machine/bus.h> 52 53 #include <sys/ioccom.h> 54 55 #include <dev/firewire/firewire.h> 56 #include <dev/firewire/firewirereg.h> 57 #include <dev/firewire/fwdma.h> 58 #include <dev/firewire/fwmem.h> 59 #include <dev/firewire/iec68113.h> 60 61 #define FWNODE_INVAL 0xffff 62 63 static d_open_t fw_open; 64 static d_close_t fw_close; 65 static d_ioctl_t fw_ioctl; 66 static d_poll_t fw_poll; 67 static d_read_t fw_read; /* for Isochronous packet */ 68 static d_write_t fw_write; 69 static d_mmap_t fw_mmap; 70 static d_strategy_t fw_strategy; 71 72 struct cdevsw firewire_cdevsw = { 73 .d_version = D_VERSION, 74 .d_open = fw_open, 75 .d_close = fw_close, 76 .d_read = fw_read, 77 .d_write = fw_write, 78 .d_ioctl = fw_ioctl, 79 .d_poll = fw_poll, 80 .d_mmap = fw_mmap, 81 .d_strategy = fw_strategy, 82 .d_name = "fw", 83 }; 84 85 struct fw_drv1 { 86 struct firewire_comm *fc; 87 struct fw_xferq *ir; 88 struct fw_xferq *it; 89 struct fw_isobufreq bufreq; 90 STAILQ_HEAD(, fw_bind) binds; 91 STAILQ_HEAD(, fw_xfer) rq; 92 }; 93 94 static int 95 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 96 struct fw_bufspec *b) 97 { 98 int i; 99 100 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 101 return (EBUSY); 102 103 q->bulkxfer = malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 104 M_FW, M_WAITOK); 105 if (q->bulkxfer == NULL) 106 return (ENOMEM); 107 108 b->psize = roundup2(b->psize, sizeof(uint32_t)); 109 q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), 110 b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 111 112 if (q->buf == NULL) { 113 free(q->bulkxfer, M_FW); 114 q->bulkxfer = NULL; 115 return (ENOMEM); 116 } 117 q->bnchunk = b->nchunk; 118 q->bnpacket = b->npacket; 119 q->psize = (b->psize + 3) & ~3; 120 q->queued = 0; 121 122 STAILQ_INIT(&q->stvalid); 123 STAILQ_INIT(&q->stfree); 124 STAILQ_INIT(&q->stdma); 125 q->stproc = NULL; 126 127 for (i = 0; i < q->bnchunk; i++) { 128 q->bulkxfer[i].poffset = i * q->bnpacket; 129 q->bulkxfer[i].mbuf = NULL; 130 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 131 } 132 133 q->flag &= ~FWXFERQ_MODEMASK; 134 q->flag |= FWXFERQ_STREAM; 135 q->flag |= FWXFERQ_EXTBUF; 136 137 return (0); 138 } 139 140 static int 141 fwdev_freebuf(struct fw_xferq *q) 142 { 143 if (q->flag & FWXFERQ_EXTBUF) { 144 if (q->buf != NULL) 145 fwdma_free_multiseg(q->buf); 146 q->buf = NULL; 147 free(q->bulkxfer, M_FW); 148 q->bulkxfer = NULL; 149 q->flag &= ~FWXFERQ_EXTBUF; 150 q->psize = 0; 151 q->maxq = FWMAXQUEUE; 152 } 153 return (0); 154 } 155 156 157 static int 158 fw_open(struct cdev *dev, int flags, int fmt, fw_proc *td) 159 { 160 int err = 0; 161 int unit = DEV2UNIT(dev); 162 struct fw_drv1 *d; 163 struct firewire_softc *sc; 164 165 if (DEV_FWMEM(dev)) 166 return fwmem_open(dev, flags, fmt, td); 167 168 sc = devclass_get_softc(firewire_devclass, unit); 169 if (sc == NULL) 170 return (ENXIO); 171 172 FW_GLOCK(sc->fc); 173 if (dev->si_drv1 != NULL) { 174 FW_GUNLOCK(sc->fc); 175 return (EBUSY); 176 } 177 /* set dummy value for allocation */ 178 dev->si_drv1 = (void *)-1; 179 FW_GUNLOCK(sc->fc); 180 181 dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 182 if (dev->si_drv1 == NULL) 183 return (ENOMEM); 184 185 if ((dev->si_flags & SI_NAMED) == 0) { 186 int unit = DEV2UNIT(dev); 187 int sub = DEV2SUB(dev); 188 189 make_dev(&firewire_cdevsw, dev2unit(dev), 190 UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); 191 } 192 193 d = dev->si_drv1; 194 d->fc = sc->fc; 195 STAILQ_INIT(&d->binds); 196 STAILQ_INIT(&d->rq); 197 198 return err; 199 } 200 201 static int 202 fw_close(struct cdev *dev, int flags, int fmt, fw_proc *td) 203 { 204 struct firewire_comm *fc; 205 struct fw_drv1 *d; 206 struct fw_xfer *xfer; 207 struct fw_bind *fwb; 208 int err = 0; 209 210 if (DEV_FWMEM(dev)) 211 return fwmem_close(dev, flags, fmt, td); 212 213 d = dev->si_drv1; 214 fc = d->fc; 215 216 /* remove binding */ 217 for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 218 fwb = STAILQ_FIRST(&d->binds)) { 219 fw_bindremove(fc, fwb); 220 STAILQ_REMOVE_HEAD(&d->binds, chlist); 221 fw_xferlist_remove(&fwb->xferlist); 222 free(fwb, M_FW); 223 } 224 if (d->ir != NULL) { 225 struct fw_xferq *ir = d->ir; 226 227 if ((ir->flag & FWXFERQ_OPEN) == 0) 228 return (EINVAL); 229 if (ir->flag & FWXFERQ_RUNNING) { 230 ir->flag &= ~FWXFERQ_RUNNING; 231 fc->irx_disable(fc, ir->dmach); 232 } 233 /* free extbuf */ 234 fwdev_freebuf(ir); 235 /* drain receiving buffer */ 236 for (xfer = STAILQ_FIRST(&ir->q); 237 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 238 ir->queued--; 239 STAILQ_REMOVE_HEAD(&ir->q, link); 240 241 xfer->resp = 0; 242 fw_xfer_done(xfer); 243 } 244 ir->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | 245 FWXFERQ_CHTAGMASK); 246 d->ir = NULL; 247 248 } 249 if (d->it != NULL) { 250 struct fw_xferq *it = d->it; 251 252 if ((it->flag & FWXFERQ_OPEN) == 0) 253 return (EINVAL); 254 if (it->flag & FWXFERQ_RUNNING) { 255 it->flag &= ~FWXFERQ_RUNNING; 256 fc->itx_disable(fc, it->dmach); 257 } 258 /* free extbuf */ 259 fwdev_freebuf(it); 260 it->flag &= ~(FWXFERQ_OPEN | 261 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 262 d->it = NULL; 263 } 264 free(dev->si_drv1, M_FW); 265 dev->si_drv1 = NULL; 266 267 return err; 268 } 269 270 static int 271 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 272 { 273 int err = 0, s; 274 struct fw_xfer *xfer; 275 struct fw_bind *fwb; 276 struct fw_pkt *fp; 277 struct tcode_info *tinfo; 278 279 FW_GLOCK(d->fc); 280 while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 281 err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 282 283 if (err != 0) { 284 FW_GUNLOCK(d->fc); 285 return (err); 286 } 287 288 s = splfw(); 289 STAILQ_REMOVE_HEAD(&d->rq, link); 290 FW_GUNLOCK(xfer->fc); 291 splx(s); 292 fp = &xfer->recv.hdr; 293 #if 0 /* for GASP ?? */ 294 if (fc->irx_post != NULL) 295 fc->irx_post(fc, fp->mode.ld); 296 #endif 297 tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 298 err = uiomove(fp, tinfo->hdr_len, uio); 299 if (err) 300 goto out; 301 err = uiomove(xfer->recv.payload, xfer->recv.pay_len, uio); 302 303 out: 304 /* recycle this xfer */ 305 fwb = (struct fw_bind *)xfer->sc; 306 fw_xfer_unload(xfer); 307 xfer->recv.pay_len = PAGE_SIZE; 308 FW_GLOCK(xfer->fc); 309 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 310 FW_GUNLOCK(xfer->fc); 311 return (err); 312 } 313 314 /* 315 * read request. 316 */ 317 static int 318 fw_read(struct cdev *dev, struct uio *uio, int ioflag) 319 { 320 struct fw_drv1 *d; 321 struct fw_xferq *ir; 322 struct firewire_comm *fc; 323 int err = 0, s, slept = 0; 324 struct fw_pkt *fp; 325 326 if (DEV_FWMEM(dev)) 327 return (physio(dev, uio, ioflag)); 328 329 d = dev->si_drv1; 330 fc = d->fc; 331 ir = d->ir; 332 333 if (ir == NULL) 334 return (fw_read_async(d, uio, ioflag)); 335 336 if (ir->buf == NULL) 337 return (EIO); 338 339 FW_GLOCK(fc); 340 readloop: 341 if (ir->stproc == NULL) { 342 /* iso bulkxfer */ 343 ir->stproc = STAILQ_FIRST(&ir->stvalid); 344 if (ir->stproc != NULL) { 345 s = splfw(); 346 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 347 splx(s); 348 ir->queued = 0; 349 } 350 } 351 if (ir->stproc == NULL) { 352 /* no data available */ 353 if (slept == 0) { 354 slept = 1; 355 ir->flag |= FWXFERQ_WAKEUP; 356 err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 357 ir->flag &= ~FWXFERQ_WAKEUP; 358 if (err == 0) 359 goto readloop; 360 } else if (slept == 1) 361 err = EIO; 362 FW_GUNLOCK(fc); 363 return err; 364 } else if (ir->stproc != NULL) { 365 /* iso bulkxfer */ 366 FW_GUNLOCK(fc); 367 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 368 ir->stproc->poffset + ir->queued); 369 if (fc->irx_post != NULL) 370 fc->irx_post(fc, fp->mode.ld); 371 if (fp->mode.stream.len == 0) { 372 err = EIO; 373 return err; 374 } 375 err = uiomove((caddr_t)fp, 376 fp->mode.stream.len + sizeof(uint32_t), uio); 377 ir->queued++; 378 if (ir->queued >= ir->bnpacket) { 379 s = splfw(); 380 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 381 splx(s); 382 fc->irx_enable(fc, ir->dmach); 383 ir->stproc = NULL; 384 } 385 if (uio->uio_resid >= ir->psize) { 386 slept = -1; 387 FW_GLOCK(fc); 388 goto readloop; 389 } 390 } 391 return err; 392 } 393 394 static int 395 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 396 { 397 struct fw_xfer *xfer; 398 struct fw_pkt pkt; 399 struct tcode_info *tinfo; 400 int err; 401 402 bzero(&pkt, sizeof(struct fw_pkt)); 403 if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 404 return (err); 405 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 406 if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 407 tinfo->hdr_len - sizeof(uint32_t), uio))) 408 return (err); 409 410 if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 411 PAGE_SIZE/*XXX*/)) == NULL) 412 return (ENOMEM); 413 414 bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 415 xfer->send.pay_len = uio->uio_resid; 416 if (uio->uio_resid > 0) { 417 if ((err = uiomove((caddr_t)&xfer->send.payload[0], 418 uio->uio_resid, uio))) 419 goto out; 420 } 421 422 xfer->fc = d->fc; 423 xfer->sc = NULL; 424 xfer->hand = fw_xferwake; 425 xfer->send.spd = 2 /* XXX */; 426 427 if ((err = fw_asyreq(xfer->fc, -1, xfer))) 428 goto out; 429 430 if ((err = fw_xferwait(xfer))) 431 goto out; 432 433 if (xfer->resp != 0) { 434 err = xfer->resp; 435 goto out; 436 } 437 438 if (xfer->flag & FWXF_RCVD) { 439 FW_GLOCK(xfer->fc); 440 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 441 FW_GUNLOCK(xfer->fc); 442 return (0); 443 } 444 445 out: 446 fw_xfer_free(xfer); 447 return (err); 448 } 449 450 static int 451 fw_write(struct cdev *dev, struct uio *uio, int ioflag) 452 { 453 int err = 0; 454 int s, slept = 0; 455 struct fw_drv1 *d; 456 struct fw_pkt *fp; 457 struct firewire_comm *fc; 458 struct fw_xferq *it; 459 460 if (DEV_FWMEM(dev)) 461 return (physio(dev, uio, ioflag)); 462 463 d = dev->si_drv1; 464 fc = d->fc; 465 it = d->it; 466 467 if (it == NULL) 468 return (fw_write_async(d, uio, ioflag)); 469 470 if (it->buf == NULL) 471 return (EIO); 472 473 FW_GLOCK(fc); 474 isoloop: 475 if (it->stproc == NULL) { 476 it->stproc = STAILQ_FIRST(&it->stfree); 477 if (it->stproc != NULL) { 478 s = splfw(); 479 STAILQ_REMOVE_HEAD(&it->stfree, link); 480 splx(s); 481 it->queued = 0; 482 } else if (slept == 0) { 483 slept = 1; 484 #if 0 /* XXX to avoid lock recursion */ 485 err = fc->itx_enable(fc, it->dmach); 486 if (err) 487 goto out; 488 #endif 489 err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 490 if (err) 491 goto out; 492 goto isoloop; 493 } else { 494 err = EIO; 495 goto out; 496 } 497 } 498 FW_GUNLOCK(fc); 499 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 500 it->stproc->poffset + it->queued); 501 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 502 err = uiomove((caddr_t)fp->mode.stream.payload, 503 fp->mode.stream.len, uio); 504 it->queued++; 505 if (it->queued >= it->bnpacket) { 506 s = splfw(); 507 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 508 splx(s); 509 it->stproc = NULL; 510 err = fc->itx_enable(fc, it->dmach); 511 } 512 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 513 slept = 0; 514 FW_GLOCK(fc); 515 goto isoloop; 516 } 517 return err; 518 519 out: 520 FW_GUNLOCK(fc); 521 return err; 522 } 523 524 static void 525 fw_hand(struct fw_xfer *xfer) 526 { 527 struct fw_bind *fwb; 528 struct fw_drv1 *d; 529 530 fwb = (struct fw_bind *)xfer->sc; 531 d = fwb->sc; 532 FW_GLOCK(xfer->fc); 533 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 534 FW_GUNLOCK(xfer->fc); 535 wakeup(&d->rq); 536 } 537 538 /* 539 * ioctl support. 540 */ 541 int 542 fw_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 543 { 544 struct firewire_comm *fc; 545 struct fw_drv1 *d; 546 int i, len, err = 0; 547 struct fw_device *fwdev; 548 struct fw_bind *fwb; 549 struct fw_xferq *ir, *it; 550 struct fw_xfer *xfer; 551 struct fw_pkt *fp; 552 struct fw_devinfo *devinfo; 553 void *ptr; 554 555 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 556 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 557 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 558 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 559 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 560 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 561 562 if (DEV_FWMEM(dev)) 563 return fwmem_ioctl(dev, cmd, data, flag, td); 564 565 if (!data) 566 return (EINVAL); 567 568 d = dev->si_drv1; 569 fc = d->fc; 570 ir = d->ir; 571 it = d->it; 572 573 switch (cmd) { 574 case FW_STSTREAM: 575 if (it == NULL) { 576 i = fw_open_isodma(fc, /* tx */1); 577 if (i < 0) { 578 err = EBUSY; 579 break; 580 } 581 it = fc->it[i]; 582 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 583 if (err) { 584 it->flag &= ~FWXFERQ_OPEN; 585 break; 586 } 587 } 588 it->flag &= ~0xff; 589 it->flag |= (0x3f & ichreq->ch); 590 it->flag |= ((0x3 & ichreq->tag) << 6); 591 d->it = it; 592 break; 593 case FW_GTSTREAM: 594 if (it != NULL) { 595 ichreq->ch = it->flag & 0x3f; 596 ichreq->tag = it->flag >> 2 & 0x3; 597 } else 598 err = EINVAL; 599 break; 600 case FW_SRSTREAM: 601 if (ir == NULL) { 602 i = fw_open_isodma(fc, /* tx */0); 603 if (i < 0) { 604 err = EBUSY; 605 break; 606 } 607 ir = fc->ir[i]; 608 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 609 if (err) { 610 ir->flag &= ~FWXFERQ_OPEN; 611 break; 612 } 613 } 614 ir->flag &= ~0xff; 615 ir->flag |= (0x3f & ichreq->ch); 616 ir->flag |= ((0x3 & ichreq->tag) << 6); 617 d->ir = ir; 618 err = fc->irx_enable(fc, ir->dmach); 619 break; 620 case FW_GRSTREAM: 621 if (d->ir != NULL) { 622 ichreq->ch = ir->flag & 0x3f; 623 ichreq->tag = ir->flag >> 2 & 0x3; 624 } else 625 err = EINVAL; 626 break; 627 case FW_SSTBUF: 628 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 629 break; 630 case FW_GSTBUF: 631 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 632 if (ir != NULL) { 633 ibufreq->rx.nchunk = ir->bnchunk; 634 ibufreq->rx.npacket = ir->bnpacket; 635 ibufreq->rx.psize = ir->psize; 636 } 637 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 638 if (it != NULL) { 639 ibufreq->tx.nchunk = it->bnchunk; 640 ibufreq->tx.npacket = it->bnpacket; 641 ibufreq->tx.psize = it->psize; 642 } 643 break; 644 case FW_ASYREQ: 645 { 646 struct tcode_info *tinfo; 647 int pay_len = 0; 648 649 fp = &asyreq->pkt; 650 tinfo = &fc->tcode[fp->mode.hdr.tcode]; 651 652 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 653 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 654 655 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 656 if (xfer == NULL) 657 return (ENOMEM); 658 659 switch (asyreq->req.type) { 660 case FWASREQNODE: 661 break; 662 case FWASREQEUI: 663 fwdev = fw_noderesolve_eui64(fc, 664 &asyreq->req.dst.eui); 665 if (fwdev == NULL) { 666 device_printf(fc->bdev, 667 "cannot find node\n"); 668 err = EINVAL; 669 goto out; 670 } 671 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 672 break; 673 case FWASRESTL: 674 /* XXX what's this? */ 675 break; 676 case FWASREQSTREAM: 677 /* nothing to do */ 678 break; 679 } 680 681 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 682 if (pay_len > 0) 683 bcopy((char *)fp + tinfo->hdr_len, 684 xfer->send.payload, pay_len); 685 xfer->send.spd = asyreq->req.sped; 686 xfer->hand = fw_xferwake; 687 688 if ((err = fw_asyreq(fc, -1, xfer)) != 0) 689 goto out; 690 if ((err = fw_xferwait(xfer)) != 0) 691 goto out; 692 if (xfer->resp != 0) { 693 err = EIO; 694 goto out; 695 } 696 if ((tinfo->flag & FWTI_TLABEL) == 0) 697 goto out; 698 699 /* copy response */ 700 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 701 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 702 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 703 pay_len = xfer->recv.pay_len; 704 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 705 asyreq->req.len = xfer->recv.pay_len + 706 tinfo->hdr_len; 707 } else { 708 err = EINVAL; 709 pay_len = 0; 710 } 711 } else { 712 pay_len = 0; 713 } 714 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 715 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 716 out: 717 fw_xfer_free_buf(xfer); 718 break; 719 } 720 case FW_IBUSRST: 721 fc->ibr(fc); 722 break; 723 case FW_CBINDADDR: 724 fwb = fw_bindlookup(fc, 725 bindreq->start.hi, bindreq->start.lo); 726 if (fwb == NULL) { 727 err = EINVAL; 728 break; 729 } 730 fw_bindremove(fc, fwb); 731 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 732 fw_xferlist_remove(&fwb->xferlist); 733 free(fwb, M_FW); 734 break; 735 case FW_SBINDADDR: 736 if (bindreq->len <= 0) { 737 err = EINVAL; 738 break; 739 } 740 if (bindreq->start.hi > 0xffff) { 741 err = EINVAL; 742 break; 743 } 744 fwb = malloc(sizeof(struct fw_bind), M_FW, M_WAITOK); 745 if (fwb == NULL) { 746 err = ENOMEM; 747 break; 748 } 749 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 750 bindreq->start.lo; 751 fwb->end = fwb->start + bindreq->len; 752 fwb->sc = d; 753 STAILQ_INIT(&fwb->xferlist); 754 err = fw_bindadd(fc, fwb); 755 if (err == 0) { 756 fw_xferlist_add(&fwb->xferlist, M_FWXFER, 757 /* XXX */ 758 PAGE_SIZE, PAGE_SIZE, 5, 759 fc, fwb, fw_hand); 760 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 761 } 762 break; 763 case FW_GDEVLST: 764 i = len = 1; 765 /* myself */ 766 devinfo = &fwdevlst->dev[0]; 767 devinfo->dst = fc->nodeid; 768 devinfo->status = 0; /* XXX */ 769 devinfo->eui.hi = fc->eui.hi; 770 devinfo->eui.lo = fc->eui.lo; 771 STAILQ_FOREACH(fwdev, &fc->devices, link) { 772 if (len < FW_MAX_DEVLST) { 773 devinfo = &fwdevlst->dev[len++]; 774 devinfo->dst = fwdev->dst; 775 devinfo->status = 776 (fwdev->status == FWDEVINVAL) ? 0 : 1; 777 devinfo->eui.hi = fwdev->eui.hi; 778 devinfo->eui.lo = fwdev->eui.lo; 779 } 780 i++; 781 } 782 fwdevlst->n = i; 783 fwdevlst->info_len = len; 784 break; 785 case FW_GTPMAP: 786 bcopy(fc->topology_map, data, 787 (fc->topology_map->crc_len + 1) * 4); 788 break; 789 case FW_GCROM: 790 STAILQ_FOREACH(fwdev, &fc->devices, link) 791 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 792 break; 793 if (fwdev == NULL) { 794 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 795 err = FWNODE_INVAL; 796 break; 797 } 798 /* myself */ 799 ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 800 len = CROMSIZE; 801 for (i = 0; i < CROMSIZE/4; i++) 802 ((uint32_t *)ptr)[i] 803 = ntohl(fc->config_rom[i]); 804 } else { 805 /* found */ 806 ptr = (void *)&fwdev->csrrom[0]; 807 if (fwdev->rommax < CSRROMOFF) 808 len = 0; 809 else 810 len = fwdev->rommax - CSRROMOFF + 4; 811 } 812 if (crom_buf->len < len) 813 len = crom_buf->len; 814 else 815 crom_buf->len = len; 816 err = copyout(ptr, crom_buf->ptr, len); 817 if (fwdev == NULL) 818 /* myself */ 819 free(ptr, M_FW); 820 break; 821 default: 822 fc->ioctl(dev, cmd, data, flag, td); 823 break; 824 } 825 return err; 826 } 827 int 828 fw_poll(struct cdev *dev, int events, fw_proc *td) 829 { 830 struct fw_xferq *ir; 831 int revents; 832 int tmp; 833 834 if (DEV_FWMEM(dev)) 835 return fwmem_poll(dev, events, td); 836 837 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 838 revents = 0; 839 tmp = POLLIN | POLLRDNORM; 840 if (events & tmp) { 841 if (STAILQ_FIRST(&ir->q) != NULL) 842 revents |= tmp; 843 else 844 selrecord(td, &ir->rsel); 845 } 846 tmp = POLLOUT | POLLWRNORM; 847 if (events & tmp) { 848 /* XXX should be fixed */ 849 revents |= tmp; 850 } 851 852 return revents; 853 } 854 855 static int 856 fw_mmap (struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 857 int nproto, vm_memattr_t *memattr) 858 { 859 860 if (DEV_FWMEM(dev)) 861 return fwmem_mmap(dev, offset, paddr, nproto, memattr); 862 863 return EINVAL; 864 } 865 866 static void 867 fw_strategy(struct bio *bp) 868 { 869 struct cdev *dev; 870 871 dev = bp->bio_dev; 872 if (DEV_FWMEM(dev)) { 873 fwmem_strategy(bp); 874 return; 875 } 876 877 bp->bio_error = EOPNOTSUPP; 878 bp->bio_flags |= BIO_ERROR; 879 bp->bio_resid = bp->bio_bcount; 880 biodone(bp); 881 } 882 883 int 884 fwdev_makedev(struct firewire_softc *sc) 885 { 886 int err = 0; 887 888 struct cdev *d; 889 int unit; 890 891 unit = device_get_unit(sc->fc->bdev); 892 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 893 UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, 0); 894 d = make_dev(&firewire_cdevsw, MAKEMINOR(FWMEM_FLAG, unit, 0), 895 UID_ROOT, GID_OPERATOR, 0660, "fwmem%d.%d", unit, 0); 896 dev_depends(sc->dev, d); 897 make_dev_alias(sc->dev, "fw%d", unit); 898 make_dev_alias(d, "fwmem%d", unit); 899 900 return (err); 901 } 902 903 int 904 fwdev_destroydev(struct firewire_softc *sc) 905 { 906 int err = 0; 907 908 destroy_dev(sc->dev); 909 return (err); 910 } 911 912 #define NDEVTYPE 2 913 void 914 fwdev_clone(void *arg, struct ucred *cred, char *name, int namelen, 915 struct cdev **dev) 916 { 917 struct firewire_softc *sc; 918 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 919 char *subp = NULL; 920 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 921 int i, unit = 0, sub = 0; 922 923 if (*dev != NULL) 924 return; 925 926 for (i = 0; i < NDEVTYPE; i++) 927 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 928 goto found; 929 /* not match */ 930 return; 931 found: 932 933 if (subp == NULL || *subp++ != '.') 934 return; 935 936 /* /dev/fwU.S */ 937 while (isdigit(*subp)) { 938 sub *= 10; 939 sub += *subp++ - '0'; 940 } 941 if (*subp != '\0') 942 return; 943 944 sc = devclass_get_softc(firewire_devclass, unit); 945 if (sc == NULL) 946 return; 947 *dev = make_dev_credf(MAKEDEV_REF, &firewire_cdevsw, 948 MAKEMINOR(devflag[i], unit, sub), cred, UID_ROOT, GID_OPERATOR, 949 0660, "%s%d.%d", devnames[i], unit, sub); 950 dev_depends(sc->dev, *dev); 951 return; 952 } 953