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