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