1 /* $NetBSD: fwdev.c,v 1.3 2005/12/11 12:22:02 christos 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: /repoman/r/ncvs/src/sys/dev/firewire/fwdev.c,v 1.46 2005/03/31 12:19:42 phk 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 <machine/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 <machine/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 | D_NEEDGIANT 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, 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, 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 if (dev->si_drv1 != NULL) 237 return (EBUSY); 238 239 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 240 if ((dev->si_flags & SI_NAMED) == 0) { 241 int unit = DEV2UNIT(dev); 242 int sub = DEV2SUB(dev); 243 244 make_dev(&firewire_cdevsw, minor(dev), 245 UID_ROOT, GID_OPERATOR, 0660, 246 "fw%d.%d", unit, sub); 247 } 248 #endif 249 250 dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 251 if (dev->si_drv1 == NULL) 252 return (ENOMEM); 253 254 d = (struct fw_drv1 *)dev->si_drv1; 255 d->fc = sc->fc; 256 STAILQ_INIT(&d->binds); 257 STAILQ_INIT(&d->rq); 258 259 return err; 260 } 261 262 FW_CLOSE(fw) 263 { 264 struct firewire_comm *fc; 265 struct fw_drv1 *d; 266 struct fw_xfer *xfer; 267 struct fw_bind *fwb; 268 int err = 0; 269 FW_CLOSE_START; 270 271 FWDEV_CLOSE_START; 272 273 d = (struct fw_drv1 *)dev->si_drv1; 274 fc = d->fc; 275 276 /* remove binding */ 277 for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 278 fwb = STAILQ_FIRST(&d->binds)) { 279 fw_bindremove(fc, fwb); 280 STAILQ_REMOVE_HEAD(&d->binds, chlist); 281 fw_xferlist_remove(&fwb->xferlist); 282 free(fwb, M_FW); 283 } 284 if (d->ir != NULL) { 285 struct fw_xferq *ir = d->ir; 286 287 if ((ir->flag & FWXFERQ_OPEN) == 0) 288 return (EINVAL); 289 if (ir->flag & FWXFERQ_RUNNING) { 290 ir->flag &= ~FWXFERQ_RUNNING; 291 fc->irx_disable(fc, ir->dmach); 292 } 293 /* free extbuf */ 294 fwdev_freebuf(ir); 295 /* drain receiving buffer */ 296 for (xfer = STAILQ_FIRST(&ir->q); 297 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 298 ir->queued --; 299 STAILQ_REMOVE_HEAD(&ir->q, link); 300 301 xfer->resp = 0; 302 fw_xfer_done(xfer); 303 } 304 ir->flag &= ~(FWXFERQ_OPEN | 305 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 306 d->ir = NULL; 307 308 } 309 if (d->it != NULL) { 310 struct fw_xferq *it = d->it; 311 312 if ((it->flag & FWXFERQ_OPEN) == 0) 313 return (EINVAL); 314 if (it->flag & FWXFERQ_RUNNING) { 315 it->flag &= ~FWXFERQ_RUNNING; 316 fc->itx_disable(fc, it->dmach); 317 } 318 /* free extbuf */ 319 fwdev_freebuf(it); 320 it->flag &= ~(FWXFERQ_OPEN | 321 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 322 d->it = NULL; 323 } 324 free(dev->si_drv1, M_FW); 325 dev->si_drv1 = NULL; 326 327 return err; 328 } 329 330 static int 331 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 332 { 333 int err = 0, s; 334 struct fw_xfer *xfer; 335 struct fw_bind *fwb; 336 struct fw_pkt *fp; 337 const struct tcode_info *tinfo; 338 339 while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0) 340 err = tsleep(&d->rq, FWPRI, "fwra", 0); 341 342 if (err != 0) 343 return (err); 344 345 s = splfw(); 346 STAILQ_REMOVE_HEAD(&d->rq, link); 347 splx(s); 348 fp = &xfer->recv.hdr; 349 #if 0 /* for GASP ?? */ 350 if (fc->irx_post != NULL) 351 fc->irx_post(fc, fp->mode.ld); 352 #endif 353 tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 354 err = uiomove((void *)fp, tinfo->hdr_len, uio); 355 if (err) 356 goto out; 357 err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 358 359 out: 360 /* recycle this xfer */ 361 fwb = (struct fw_bind *)xfer->sc; 362 fw_xfer_unload(xfer); 363 xfer->recv.pay_len = PAGE_SIZE; 364 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 365 return (err); 366 } 367 368 /* 369 * read request. 370 */ 371 FW_READ(fw) 372 { 373 FW_READ_START; 374 struct fw_drv1 *d; 375 struct fw_xferq *ir; 376 struct firewire_comm *fc; 377 int err = 0, s, slept = 0; 378 struct fw_pkt *fp; 379 380 FWDEV_READ_START; 381 382 d = (struct fw_drv1 *)dev->si_drv1; 383 fc = d->fc; 384 ir = d->ir; 385 386 if (ir == NULL) 387 return (fw_read_async(d, uio, ioflag)); 388 389 if (ir->buf == NULL) 390 return (EIO); 391 392 readloop: 393 if (ir->stproc == NULL) { 394 /* iso bulkxfer */ 395 ir->stproc = STAILQ_FIRST(&ir->stvalid); 396 if (ir->stproc != NULL) { 397 s = splfw(); 398 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 399 splx(s); 400 ir->queued = 0; 401 } 402 } 403 if (ir->stproc == NULL) { 404 /* no data avaliable */ 405 if (slept == 0) { 406 slept = 1; 407 ir->flag |= FWXFERQ_WAKEUP; 408 err = tsleep(ir, FWPRI, "fw_read", hz); 409 ir->flag &= ~FWXFERQ_WAKEUP; 410 if (err == 0) 411 goto readloop; 412 } else if (slept == 1) 413 err = EIO; 414 return err; 415 } else if(ir->stproc != NULL) { 416 /* iso bulkxfer */ 417 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 418 ir->stproc->poffset + ir->queued); 419 if(fc->irx_post != NULL) 420 fc->irx_post(fc, fp->mode.ld); 421 if(fp->mode.stream.len == 0){ 422 err = EIO; 423 return err; 424 } 425 err = uiomove((caddr_t)fp, 426 fp->mode.stream.len + sizeof(uint32_t), uio); 427 ir->queued ++; 428 if(ir->queued >= ir->bnpacket){ 429 s = splfw(); 430 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 431 splx(s); 432 fc->irx_enable(fc, ir->dmach); 433 ir->stproc = NULL; 434 } 435 if (uio->uio_resid >= ir->psize) { 436 slept = -1; 437 goto readloop; 438 } 439 } 440 return err; 441 } 442 443 static int 444 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 445 { 446 struct fw_xfer *xfer; 447 struct fw_pkt pkt; 448 const struct tcode_info *tinfo; 449 int err; 450 451 bzero(&pkt, sizeof(struct fw_pkt)); 452 if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 453 return (err); 454 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 455 if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 456 tinfo->hdr_len - sizeof(uint32_t), uio))) 457 return (err); 458 459 if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 460 PAGE_SIZE/*XXX*/)) == NULL) 461 return (ENOMEM); 462 463 bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 464 xfer->send.pay_len = uio->uio_resid; 465 if (uio->uio_resid > 0) { 466 if ((err = uiomove((caddr_t)&xfer->send.payload[0], 467 uio->uio_resid, uio))); 468 goto out; 469 } 470 471 xfer->fc = d->fc; 472 xfer->sc = NULL; 473 xfer->hand = fw_asy_callback; 474 xfer->send.spd = 2 /* XXX */; 475 476 if ((err = fw_asyreq(xfer->fc, -1, xfer))) 477 goto out; 478 479 if ((err = tsleep(xfer, FWPRI, "fwwa", 0))) 480 goto out; 481 482 if (xfer->resp != 0) { 483 err = xfer->resp; 484 goto out; 485 } 486 487 if (xfer->state == FWXF_RCVD) { 488 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 489 return (0); 490 } 491 492 out: 493 fw_xfer_free(xfer); 494 return (err); 495 } 496 497 FW_WRITE(fw) 498 { 499 FW_WRITE_START; 500 int err = 0; 501 int s, slept = 0; 502 struct fw_drv1 *d; 503 struct fw_pkt *fp; 504 struct firewire_comm *fc; 505 struct fw_xferq *it; 506 507 FWDEV_WRITE_START; 508 d = (struct fw_drv1 *)dev->si_drv1; 509 fc = d->fc; 510 it = d->it; 511 512 if (it == NULL) 513 return (fw_write_async(d, uio, ioflag)); 514 515 if (it->buf == NULL) 516 return (EIO); 517 isoloop: 518 if (it->stproc == NULL) { 519 it->stproc = STAILQ_FIRST(&it->stfree); 520 if (it->stproc != NULL) { 521 s = splfw(); 522 STAILQ_REMOVE_HEAD(&it->stfree, link); 523 splx(s); 524 it->queued = 0; 525 } else if (slept == 0) { 526 slept = 1; 527 err = fc->itx_enable(fc, it->dmach); 528 if (err) 529 return err; 530 err = tsleep(it, FWPRI, "fw_write", hz); 531 if (err) 532 return err; 533 goto isoloop; 534 } else { 535 err = EIO; 536 return err; 537 } 538 } 539 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 540 it->stproc->poffset + it->queued); 541 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 542 err = uiomove((caddr_t)fp->mode.stream.payload, 543 fp->mode.stream.len, uio); 544 it->queued ++; 545 if (it->queued >= it->bnpacket) { 546 s = splfw(); 547 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 548 splx(s); 549 it->stproc = NULL; 550 err = fc->itx_enable(fc, it->dmach); 551 } 552 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 553 slept = 0; 554 goto isoloop; 555 } 556 return err; 557 } 558 559 static void 560 fw_hand(struct fw_xfer *xfer) 561 { 562 struct fw_bind *fwb; 563 struct fw_drv1 *d; 564 565 fwb = (struct fw_bind *)xfer->sc; 566 d = (struct fw_drv1 *)fwb->sc; 567 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 568 wakeup(&d->rq); 569 } 570 571 /* 572 * ioctl support. 573 */ 574 FW_IOCTL(fw) 575 { 576 FW_IOCTL_START; 577 struct firewire_comm *fc; 578 struct fw_drv1 *d; 579 int i, len, err = 0; 580 struct fw_device *fwdev; 581 struct fw_bind *fwb; 582 struct fw_xferq *ir, *it; 583 struct fw_xfer *xfer; 584 struct fw_pkt *fp; 585 struct fw_devinfo *devinfo; 586 void *ptr; 587 588 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 589 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 590 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 591 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 592 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 593 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 594 595 FWDEV_IOCTL_START; 596 597 if (!data) 598 return(EINVAL); 599 600 d = (struct fw_drv1 *)dev->si_drv1; 601 fc = d->fc; 602 ir = d->ir; 603 it = d->it; 604 605 switch (cmd) { 606 case FW_STSTREAM: 607 if (it == NULL) { 608 for (i = 0; i < fc->nisodma; i ++) { 609 it = fc->it[i]; 610 if ((it->flag & FWXFERQ_OPEN) == 0) 611 break; 612 } 613 if (i >= fc->nisodma) { 614 err = EBUSY; 615 break; 616 } 617 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 618 if (err) 619 break; 620 it->flag |= FWXFERQ_OPEN; 621 } 622 it->flag &= ~0xff; 623 it->flag |= (0x3f & ichreq->ch); 624 it->flag |= ((0x3 & ichreq->tag) << 6); 625 d->it = it; 626 break; 627 case FW_GTSTREAM: 628 if (it != NULL) { 629 ichreq->ch = it->flag & 0x3f; 630 ichreq->tag = it->flag >> 2 & 0x3; 631 } else 632 err = EINVAL; 633 break; 634 case FW_SRSTREAM: 635 if (ir == NULL) { 636 for (i = 0; i < fc->nisodma; i ++) { 637 ir = fc->ir[i]; 638 if ((ir->flag & FWXFERQ_OPEN) == 0) 639 break; 640 } 641 if (i >= fc->nisodma) { 642 err = EBUSY; 643 break; 644 } 645 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 646 if (err) 647 break; 648 ir->flag |= FWXFERQ_OPEN; 649 } 650 ir->flag &= ~0xff; 651 ir->flag |= (0x3f & ichreq->ch); 652 ir->flag |= ((0x3 & ichreq->tag) << 6); 653 d->ir = ir; 654 err = fc->irx_enable(fc, ir->dmach); 655 break; 656 case FW_GRSTREAM: 657 if (d->ir != NULL) { 658 ichreq->ch = ir->flag & 0x3f; 659 ichreq->tag = ir->flag >> 2 & 0x3; 660 } else 661 err = EINVAL; 662 break; 663 case FW_SSTBUF: 664 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 665 break; 666 case FW_GSTBUF: 667 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 668 if (ir != NULL) { 669 ibufreq->rx.nchunk = ir->bnchunk; 670 ibufreq->rx.npacket = ir->bnpacket; 671 ibufreq->rx.psize = ir->psize; 672 } 673 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 674 if (it != NULL) { 675 ibufreq->tx.nchunk = it->bnchunk; 676 ibufreq->tx.npacket = it->bnpacket; 677 ibufreq->tx.psize = it->psize; 678 } 679 break; 680 case FW_ASYREQ: 681 { 682 const struct tcode_info *tinfo; 683 int pay_len = 0; 684 685 fp = &asyreq->pkt; 686 tinfo = &fc->tcode[fp->mode.hdr.tcode]; 687 688 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 689 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 690 691 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 692 if (xfer == NULL) 693 return (ENOMEM); 694 695 switch (asyreq->req.type) { 696 case FWASREQNODE: 697 break; 698 case FWASREQEUI: 699 fwdev = fw_noderesolve_eui64(fc, 700 &asyreq->req.dst.eui); 701 if (fwdev == NULL) { 702 device_printf(fc->bdev, 703 "cannot find node\n"); 704 err = EINVAL; 705 goto out; 706 } 707 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 708 break; 709 case FWASRESTL: 710 /* XXX what's this? */ 711 break; 712 case FWASREQSTREAM: 713 /* nothing to do */ 714 break; 715 } 716 717 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 718 if (pay_len > 0) 719 bcopy((char *)fp + tinfo->hdr_len, 720 (void *)xfer->send.payload, pay_len); 721 xfer->send.spd = asyreq->req.sped; 722 xfer->hand = fw_asy_callback; 723 724 if ((err = fw_asyreq(fc, -1, xfer)) != 0) 725 goto out; 726 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) 727 goto out; 728 if (xfer->resp != 0) { 729 err = EIO; 730 goto out; 731 } 732 if ((tinfo->flag & FWTI_TLABEL) == 0) 733 goto out; 734 735 /* copy response */ 736 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 737 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 738 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 739 pay_len = xfer->recv.pay_len; 740 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 741 asyreq->req.len = xfer->recv.pay_len + 742 tinfo->hdr_len; 743 } else { 744 err = EINVAL; 745 pay_len = 0; 746 } 747 } else { 748 pay_len = 0; 749 } 750 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 751 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 752 out: 753 fw_xfer_free_buf(xfer); 754 break; 755 } 756 case FW_IBUSRST: 757 fc->ibr(fc); 758 break; 759 case FW_CBINDADDR: 760 fwb = fw_bindlookup(fc, 761 bindreq->start.hi, bindreq->start.lo); 762 if(fwb == NULL){ 763 err = EINVAL; 764 break; 765 } 766 fw_bindremove(fc, fwb); 767 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 768 fw_xferlist_remove(&fwb->xferlist); 769 free(fwb, M_FW); 770 break; 771 case FW_SBINDADDR: 772 if(bindreq->len <= 0 ){ 773 err = EINVAL; 774 break; 775 } 776 if(bindreq->start.hi > 0xffff ){ 777 err = EINVAL; 778 break; 779 } 780 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 781 if(fwb == NULL){ 782 err = ENOMEM; 783 break; 784 } 785 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 786 bindreq->start.lo; 787 fwb->end = fwb->start + bindreq->len; 788 fwb->sc = (void *)d; 789 STAILQ_INIT(&fwb->xferlist); 790 err = fw_bindadd(fc, fwb); 791 if (err == 0) { 792 fw_xferlist_add(&fwb->xferlist, M_FWXFER, 793 /* XXX */ 794 PAGE_SIZE, PAGE_SIZE, 5, 795 fc, (void *)fwb, fw_hand); 796 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 797 } 798 break; 799 case FW_GDEVLST: 800 i = len = 1; 801 /* myself */ 802 devinfo = &fwdevlst->dev[0]; 803 devinfo->dst = fc->nodeid; 804 devinfo->status = 0; /* XXX */ 805 devinfo->eui.hi = fc->eui.hi; 806 devinfo->eui.lo = fc->eui.lo; 807 STAILQ_FOREACH(fwdev, &fc->devices, link) { 808 if(len < FW_MAX_DEVLST){ 809 devinfo = &fwdevlst->dev[len++]; 810 devinfo->dst = fwdev->dst; 811 devinfo->status = 812 (fwdev->status == FWDEVINVAL)?0:1; 813 devinfo->eui.hi = fwdev->eui.hi; 814 devinfo->eui.lo = fwdev->eui.lo; 815 } 816 i++; 817 } 818 fwdevlst->n = i; 819 fwdevlst->info_len = len; 820 break; 821 case FW_GTPMAP: 822 bcopy(fc->topology_map, data, 823 (fc->topology_map->crc_len + 1) * 4); 824 break; 825 case FW_GCROM: 826 STAILQ_FOREACH(fwdev, &fc->devices, link) 827 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 828 break; 829 if (fwdev == NULL) { 830 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 831 err = FWNODE_INVAL; 832 break; 833 } 834 /* myself */ 835 ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 836 len = CROMSIZE; 837 for (i = 0; i < CROMSIZE/4; i++) 838 ((uint32_t *)ptr)[i] 839 = ntohl(fc->config_rom[i]); 840 } else { 841 /* found */ 842 ptr = (void *)&fwdev->csrrom[0]; 843 if (fwdev->rommax < CSRROMOFF) 844 len = 0; 845 else 846 len = fwdev->rommax - CSRROMOFF + 4; 847 } 848 if (crom_buf->len < len) 849 len = crom_buf->len; 850 else 851 crom_buf->len = len; 852 err = copyout(ptr, crom_buf->ptr, len); 853 if (fwdev == NULL) 854 /* myself */ 855 free(ptr, M_FW); 856 break; 857 default: 858 FWDEV_IOCTL_REDIRECT; 859 break; 860 } 861 return err; 862 } 863 864 FW_POLL(fw) 865 { 866 FW_POLL_START; 867 struct fw_xferq *ir; 868 int revents; 869 int tmp; 870 871 FWDEV_POLL_START; 872 873 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 874 revents = 0; 875 tmp = POLLIN | POLLRDNORM; 876 if (events & tmp) { 877 if (STAILQ_FIRST(&ir->q) != NULL) 878 revents |= tmp; 879 else 880 selrecord(td, &ir->rsel); 881 } 882 tmp = POLLOUT | POLLWRNORM; 883 if (events & tmp) { 884 /* XXX should be fixed */ 885 revents |= tmp; 886 } 887 888 return revents; 889 } 890 891 FW_MMAP(fw) 892 { 893 FW_MMAP_START; 894 895 FWDEV_MMAP_START; 896 897 return EINVAL; 898 } 899 900 void 901 fw_strategy(struct bio *bp) 902 { 903 FW_STRATEGY_START; 904 905 FWDEV_STRATEGY_START; 906 907 bp->bio_error = EOPNOTSUPP; 908 bp->bio_flags |= BIO_ERROR; 909 bp->bio_resid = bp->bio_bcount; 910 biodone(bp); 911 } 912 913 #if defined(__FreeBSD__) 914 int 915 fwdev_makedev(struct firewire_softc *sc) 916 { 917 int err = 0; 918 919 #if defined(__DragonFly__) 920 int unit; 921 922 unit = device_get_unit(sc->fc->bdev); 923 cdevsw_add(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit)); 924 #elif __FreeBSD_version < 500000 925 cdevsw_add(&firewire_cdevsw); 926 #else 927 DEV_T d; 928 int unit; 929 930 unit = device_get_unit(sc->fc->bdev); 931 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 932 UID_ROOT, GID_OPERATOR, 0660, 933 "fw%d.%d", unit, 0); 934 d = make_dev(&firewire_cdevsw, 935 MAKEMINOR(FWMEM_FLAG, unit, 0), 936 UID_ROOT, GID_OPERATOR, 0660, 937 "fwmem%d.%d", unit, 0); 938 dev_depends(sc->dev, d); 939 make_dev_alias(sc->dev, "fw%d", unit); 940 make_dev_alias(d, "fwmem%d", unit); 941 #endif 942 943 return (err); 944 } 945 946 int 947 fwdev_destroydev(struct firewire_softc *sc) 948 { 949 int err = 0; 950 951 #if defined(__DragonFly__) 952 int unit; 953 954 unit = device_get_unit(sc->fc->bdev); 955 cdevsw_remove(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit)); 956 #elif __FreeBSD_version < 500000 957 cdevsw_remove(&firewire_cdevsw); 958 #else 959 destroy_dev(sc->dev); 960 #endif 961 return (err); 962 } 963 964 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 965 #define NDEVTYPE 2 966 void 967 fwdev_clone(void *arg, char *name, int namelen, DEV_T *dev) 968 { 969 struct firewire_softc *sc; 970 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 971 char *subp = NULL; 972 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 973 int i, unit = 0, sub = 0; 974 975 if (*dev != NULL) 976 return; 977 978 for (i = 0; i < NDEVTYPE; i++) 979 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 980 goto found; 981 /* not match */ 982 return; 983 found: 984 985 if (subp == NULL || *subp++ != '.') 986 return; 987 988 /* /dev/fwU.S */ 989 while (isdigit(*subp)) { 990 sub *= 10; 991 sub += *subp++ - '0'; 992 } 993 if (*subp != '\0') 994 return; 995 996 sc = devclass_get_softc(firewire_devclass, unit); 997 if (sc == NULL) 998 return; 999 *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub), 1000 UID_ROOT, GID_OPERATOR, 0660, 1001 "%s%d.%d", devnames[i], unit, sub); 1002 dev_ref(*dev); 1003 (*dev)->si_flags |= SI_CHEAPCLONE; 1004 dev_depends(sc->dev, *dev); 1005 return; 1006 } 1007 #endif 1008 #endif 1009