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