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